Packages
rustler
0.36.2
0.38.0
0.37.3
0.37.1
0.37.0
retired
0.36.2
0.36.1
0.36.0
0.35.1
0.35.0
0.34.0
0.33.0
0.32.1
0.31.0
0.30.0
0.29.1
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.0
0.23.0
0.22.2
0.22.1
0.22.0
0.22.0-rc.2
0.22.0-rc.1
0.22.0-rc.0
0.21.1
0.21.0
0.20.0
0.19.1
0.19.0
0.18.0
0.17.1
0.17.0
0.16.0
0.10.1
0.10.0
0.9.0
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.0
0.1.1
0.1.0
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Mix compiler and runtime helpers for Rustler.
Current section
Files
Jump to
Current section
Files
lib/rustler/compiler/config.ex
defmodule Rustler.Compiler.Config do
@moduledoc false
@type rust_version :: :stable | :beta | :nightly | binary()
@type cargo :: :system | {:rustup, rust_version()} | {:bin, Path.t()}
@type crate :: binary()
@type default_features :: boolean()
@type env :: [{binary(), binary()}]
@type features :: [binary()]
@type mode :: :debug | :release
@type load_data :: term()
@type path :: Path.t()
defstruct cargo: :system,
crate: nil,
default_features: true,
env: [],
external_resources: [],
features: [],
lib: true,
load_data: 0,
load_data_fun: nil,
load_from: nil,
mode: :release,
otp_app: nil,
path: "",
priv_dir: "",
skip_compilation?: false,
target: nil,
target_dir: "",
metadata: nil
alias Rustler.Compiler.Config
def from(otp_app, config, opts) do
crate = config[:crate] || opts[:crate] || otp_app
defaults = %Config{
crate: crate,
load_from: {otp_app, "priv/native/lib#{crate}"},
mode: :release,
otp_app: otp_app,
path: "native/#{crate}",
target_dir: Application.app_dir(otp_app, "native/#{crate}")
}
defaults
|> Map.from_struct()
|> Enum.into([])
|> Keyword.merge(opts)
|> Keyword.merge(config)
|> build()
end
defp build(opts) do
opts =
if opts[:skip_compilation?] do
opts
else
crate = Keyword.fetch!(opts, :crate)
crate_path = Keyword.fetch!(opts, :path)
metadata = metadata!(crate_path)
resources = external_resources(crate_path, crate, metadata)
opts
|> Keyword.put(:metadata, metadata)
|> Keyword.put(:external_resources, resources)
end
struct!(Config, opts)
end
defp metadata!(crate_path) do
metadata =
case System.cmd("cargo", ~w(metadata --format-version=1), cd: crate_path) do
{metadata, 0} ->
metadata
{output, _code} ->
raise "calling `cargo metadata` failed.\n" <> output
end
Jason.decode!(metadata)
end
defp external_resources(crate_path, crate, metadata) do
crate_str = to_string(crate)
packages = Map.fetch!(metadata, "packages")
crate_spec = get_spec(packages, crate_str)
packages
|> gather_local_crates([crate_spec], [crate_path], MapSet.new([crate_str]))
|> Enum.flat_map(&expand_paths/1)
end
defp expand_paths(path) do
path
|> Path.join("**/*")
|> Path.wildcard()
|> Enum.reject(&(String.starts_with?(&1, "#{path}/target/") or File.dir?(&1)))
end
defp local_crate?(package) do
package["path"]
end
defp gather_local_crates(_, [], paths, _visited) do
paths
end
defp gather_local_crates(packages, [current_spec | rest], paths_acc, visited) do
local_deps =
current_spec["dependencies"]
|> Enum.filter(&local_crate?/1)
|> Enum.reject(fn dep -> MapSet.member?(visited, dep["name"]) end)
paths = Enum.map(local_deps, & &1["path"]) ++ paths_acc
as_specs =
local_deps
|> Enum.map(&get_spec(packages, &1["name"]))
|> Enum.reject(&is_nil/1)
visited =
local_deps
|> MapSet.new(& &1["name"])
|> MapSet.union(visited)
gather_local_crates(packages, as_specs ++ rest, paths, visited)
end
defp get_spec(packages, name) do
packages
|> Enum.filter(&(&1["name"] == name))
|> List.first()
end
end