Confusion about dependency availability

Hi!

I’m attempting to use the dependency ElixirALE and I’m very confused about getting it into my project.

I’m using mix and have declared it as a dependency, but the library doesn’t have an app file, so the usual mechanism of starting the library as an app isn’t available.

Despite lots of searching I don’t seem to be able to figure out how to do an equivalent of a Ruby require so I can use this library code. The instructions in their README are pretty standard and ain’t helping.

This lib is a little different in that it has a C core and a Makefile, but compilation is working OK. Here’s my dependency line from my mix.exs:

  defp deps do
    [
      {
        :elixir_ale, "~> 0.6.0",
        compile: ~s(CC="rpxc arm-linux-gnueabihf-gcc" CROSSCOMPILE=rpxc ERL_EI_INCLUDE_DIR=/rpxc/sysroot/usr/lib/erlang/usr/include ERL_EI_LIBDIR=/rpxc/sysroot/usr/lib/erlang/usr/lib make),
        app: false,
      }
    ]
  end

I’ve tried clearing and recompiling the dependencies a few times to no avail.

Any use of the library results in e.g.

warning: function ElixirALE.I2C.read/2 is undefined (module ElixirALE.I2C is not available)

Any thoughts? Am I doing something dumb?

Thanks,
Elliot

1 Like

Are you sure that library is not supposed to create an app file? I can’t find anything in elixir_ale’s code to suggest this and there is no mention that app: false in its documentation.

1 Like

Hi Eric, it looks like this might be related to me overriding the compile option to just do a make. I didn’t know that app files could be generated so I wasn’t really focused on that.

I’ve switched the compile override to do a mix compile with the appropriate ENV vars and I’m seeing Generated elixir_ale app in the output, but _build/dev/lib/elixir_ale/ is still empty. The .app file is generated correctly if I run the same command from a git checkout of the library.

What’s the correct way to override dependency compilation to add ENV vars while still having the library’s mix compile work correctly?

1 Like

You can try calling mix compile instead of make, the env vars should be preserved.

1 Like

That’s what I tried, but the _build/dev/lib/elixir_ale directory is still empty.

The deps declaration in my app currently looks like this:

  defp deps do
    [
      {
        :elixir_ale, "~> 0.6.0",
        compile: ~s(mix deps.get && mix deps.compile && CC="rpxc arm-linux-gnueabihf-gcc" CROSSCOMPILE=rpxc ERL_EI_INCLUDE_DIR=/rpxc/sysroot/usr/lib/erlang/usr/include ERL_EI_LIBDIR=/rpxc/sysroot/usr/lib/erlang/usr/lib mix compile),
      }
    ]
  end

Build output

$ mix deps.compile
==> elixir_make
Compiling 1 file (.ex)
Generated elixir_make app
==> [my app name]
Running dependency resolution...
Dependency resolution completed:
  earmark 1.2.0
  elixir_make 0.4.0
  ex_doc 0.15.0
* Getting elixir_make (Hex package)
  Checking package (https://repo.hex.pm/tarballs/elixir_make-0.4.0.tar)
  Fetched package
* Getting ex_doc (Hex package)
  Checking package (https://repo.hex.pm/tarballs/ex_doc-0.15.0.tar)
  Fetched package
* Getting earmark (Hex package)
  Checking package (https://repo.hex.pm/tarballs/earmark-1.2.0.tar)
  Fetched package
==> elixir_make
Compiling 1 file (.ex)
warning: redefining module Mix.Tasks.Compile.ElixirMake (current version loaded from /[path to app]/_build/dev/lib/elixir_make/ebin/Elixir.Mix.Tasks.Compile.ElixirMake.beam)
  lib/mix/tasks/compile.make.ex:1

Generated elixir_make app
==> earmark
Compiling 3 files (.erl)
Compiling 25 files (.ex)
Generated earmark app
==> ex_doc
Compiling 15 files (.ex)
warning: redefining module Mix.Tasks.Docs (current version defined in memory)
  lib/mix/tasks/docs.ex:1

Generated ex_doc app
rpxc arm-linux-gnueabihf-gcc -c -I/rpxc/sysroot/usr/lib/erlang/usr/include -O2 -Wall -Wextra -Wno-unused-parameter -o src/ale_main.o src/ale_main.c
rpxc arm-linux-gnueabihf-gcc -c -I/rpxc/sysroot/usr/lib/erlang/usr/include -O2 -Wall -Wextra -Wno-unused-parameter -o src/gpio_port.o src/gpio_port.c
rpxc arm-linux-gnueabihf-gcc -c -I/rpxc/sysroot/usr/lib/erlang/usr/include -O2 -Wall -Wextra -Wno-unused-parameter -o src/i2c_port.o src/i2c_port.c
rpxc arm-linux-gnueabihf-gcc -c -I/rpxc/sysroot/usr/lib/erlang/usr/include -O2 -Wall -Wextra -Wno-unused-parameter -o src/spi_port.o src/spi_port.c
rpxc arm-linux-gnueabihf-gcc -c -I/rpxc/sysroot/usr/lib/erlang/usr/include -O2 -Wall -Wextra -Wno-unused-parameter -o src/erlcmd.o src/erlcmd.c
rpxc arm-linux-gnueabihf-gcc src/ale_main.o src/gpio_port.o src/i2c_port.o src/spi_port.o src/erlcmd.o -L/rpxc/sysroot/usr/lib/erlang/usr/lib -lei  -o priv/ale
Compiling 4 files (.ex)
Generated elixir_ale app
1 Like

From your project-root, does find . -name 'ale_main.o' find anything? If so, where?

Also please do run find . -name 'Elixir.ElixirALE.I2C.beam', to find out if and where the BEAM-modules have been generated.

1 Like
$ find . -name 'ale_main.o'
./deps/elixir_ale/src/ale_main.o
$ find . -name 'Elixir.ElixirALE.I2C.beam'
./deps/elixir_ale/_build/dev/lib/elixir_ale/ebin/Elixir.ElixirALE.I2C.beam

Looks like the elixir_ale.app file is going into that deps directory too.

1 Like

I glanced over the code, and mix does alters some bits of the in memory config to put compilation output to your projects _build-folder, but by specifying mix compile as as compilation command, mix thinks it were in its project basedir and uses this. Have you tried to set the environment variables on your end when compiling deps?

$ CC="rpxc arm-linux-gnueabihf-gcc" CROSSCOMPILE=rpxc ERL_EI_INCLUDE_DIR=/rpxc/sysroot/usr/lib/erlang/usr/include ERL_EI_LIBDIR=/rpxc/sysroot/usr/lib/erlang/usr/lib mix deps.compile
$ MIX_ENV=test CC="rpxc arm-linux-gnueabihf-gcc" CROSSCOMPILE=rpxc ERL_EI_INCLUDE_DIR=/rpxc/sysroot/usr/lib/erlang/usr/include ERL_EI_LIBDIR=/rpxc/sysroot/usr/lib/erlang/usr/lib mix deps.compile
1 Like

That does work, but it’s somewhat awkward and reduces the utility of the compile option. Should I put together a suggestion to extend mix?

1 Like

Personally I’d try to convince the maintainer of ElixirALE to find a way to make the crosscompilation stuff work via regular mix-config capabilities.

edit

Or I’d set these ENV-VARs in my build machine permanently or per job. So that I can easily crosscompile to different targets by just using new values for ENV-VARS and without the necessity to alter the mix file or some other config on the fly.

1 Like

The catch with the latter being they’re effectively global variables across all dependencies at that point, with potential collisions between identically-named ENV vars in different libraries (though not in this case, yet).

Did you have any mix-config capabilities in mind for altering elixir ale? I don’t mind putting in a PR there myself.

1 Like

Well, I’m not quite sure how ElixirMake works, but if one can inject ENV-VARS into it by any means, then config/file.exs should be the way to go.

1 Like

OK, thanks, I’ll take a look.

1 Like