nerves-project / nerves

Craft and deploy bulletproof embedded software in Elixir
http://nerves-project.org
Apache License 2.0
2.26k stars 193 forks source link

Building for a different target does not rebuild NIF #444

Closed Qqwy closed 5 years ago

Qqwy commented 5 years ago

Environment

Elixir 1.9.1 (compiled with Erlang/OTP 22)


* Nerves environment: (`mix nerves.env --info`)

|nerves_bootstrap| Environment Package List

No packages found |nerves_bootstrap| Loadpaths Start

Nerves environment MIX_TARGET: host MIX_ENV: dev

NERVES_SYSTEM is unset NERVES_TOOLCHAIN is unset |nerves_bootstrap| Environment Variable List target: host toolchain: unset system: unset app: /some/folder/

|nerves_bootstrap| Loadpaths End


### Current behavior

When building a project that includes a library which uses a NIF. In my example it was the [crc library](https://hex.pm/packages/crc), the NIF does not get recompiled when switching targets.
This then crashes the build later on, because obviously running `make` for the host computer with an x86_64 architecture creates very different binary files than running it for an ARM architecture such as my Raspberry Pi 3 B.

To reproduce:

mix nerves.new nif_broken_example cd ./nif_broken_example

Add crc to mix.exs dependencies

mix deps.get MIX_TARGET=rpi3 mix deps.get mix compile MIX_TARGET=rpi3 mix firmware


At some point during this last command you can see:

==> crc make: Nothing to be done for 'all'.


and then after building all the other parts and attempting to combine them:

Got: readelf:Advanced Micro Devices X86-64;0x0

Expecting: readelf:ARM;0x5000400, Version5 EABI, hard-float ABI

This file was compiled for the host or a different target and probably will not work.

Check the following:

  1. Are you using a path dependency in your mix deps? If so, run 'mix clean' in that directory to avoid pulling in any of its build products.

  2. Did you recently upgrade to Nerves 1.3 or Distillery 2.0? Make sure that your 'rel/config.exs' has 'plugin Nerves'. See https://hexdocs.pm/nerves/updating-projects.html#updating-from-v1-0-to-v1-3-0

  3. Did you recently upgrade or change your Nerves system? If so, try cleaning and rebuilding this project and its deps.

  4. Are you building outside of Nerves' mix integration? If so, make sure that you've sourced 'nerves-env.sh'.

If you're still having trouble, please file an issue on Github at https://github.com/nerves-project/nerves_system_br/issues.

** (Mix) Nerves encountered an error. %IO.Stream{device: :standard_io, line_or_bytes: :line, raw: true}



### Expected behavior

I would expect a build process like this be able to recognize that the dependency in case needs to be rebuilt based on if there is a build _for that target_.

---

For now, the 'duct tape' way I was working around this issue was to do a `mix deps.clean crc; mix deps.get` each time I wanted to switch between `iex -S mix` and `mix firmware.burn`, but of course this is not really nice.
fhunleth commented 5 years ago

This is an issue with the crc library. It builds the NIF in the source directory and not under _build. Since the source directory is shared between all targets and environments, make doesn't know that it needs to be rebuilt.

This is a common problem with NIF projects. Could you file an issue with crc or PR an update to its Makefile to build under _build? The Elixir Circuits projects are NIFs that have Makefiles that put object files and libraries in the right place. See https://github.com/elixir-circuits/circuits_spi/blob/master/Makefile#L21 for an example.