0
votes

I’m looking to build an escript in an Elixir Umbrella project. I’ve got two sibling apps Compressor and Printer

Compressor depends on the snappyer package which is a nif wrapper around the google’s snappy compression algorithm.

# apps/compressor/mix.exs

defmodule Compressor.MixProject do
  # ..
  defp deps do
    [
      {:snappyer, "~> 1.2.4"},
    ]
  end
end

# apps/compressor/lib/compressor.ex

defmodule Compressor do
  def compress(message) do
    :snappyer.compress(message)
  end
end

Printer requires Compressor, compresses some data and prints the result.

# apps/printer/mix.exs

defmodule Printer.MixProject do
  # ..
  def project do
    [
      app: :printer,
      version: "0.1.0",
      build_path: "../../_build",
      config_path: "../../config/config.exs",
      deps_path: "../../deps",
      lockfile: "../../mix.lock",
      elixir: "~> 1.7",
      escript: escript(),
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  defp escript do
    [main_module: Printer.CLI]
  end

  defp deps do
    [
      {:compressor, in_umbrella: true},
    ]
  end
end

# apps/printer/lib/printer/cli.ex

defmodule Printer.CLI do
  def main(args \\ []) do
    IO.inspect Compressor.compress(<<1, 2, 3>>)
  end
end

When I run Printer.CLI.main([]) through mix it prints the result as expected

$ mix run -e "Printer.CLI.main([])"
{:ok, <<3, 8, 1, 2, 3>>}

However when I run it through an escript it fails with:

$  cd apps/printer && mix escript.build && ./printer
Generated escript printer with MIX_ENV=dev
** (UndefinedFunctionError) function :snappyer.compress/1 is undefined (module :snappyer is not available)
    (snappyer) :snappyer.compress(<<1, 2, 3>>)
    (printer) lib/printer/cli.ex:3: Printer.CLI.main/1
    (elixir) lib/kernel/cli.ex:105: anonymous fn/3 in Kernel.CLI.exec_fun/2

Are escripts allowed in sibling umbrella apps? If not are there any known work arounds?

Here's the minimal, complete, and verifiable example .

1

1 Answers

0
votes

I'm not sure if this helpful, but I think the issue may be unrelated to umbrella apps. I think the issue happens because of the nif you're trying to use.

From the escript docs:

Note: escripts do not support projects and dependencies that need to store or read artifacts from the priv directory.

Also, see this answer from an elixir issue:

Unfortunately that's a limitation of escripts. They cannot access anything in priv and therefore they cannot access embedded .so files. In other words, it is not currently possible to build escripts with NIFs in them.