Packages
rustler
0.3.0
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/task_compile.ex
defmodule Mix.Tasks.Compile.Rustler do
use Mix.Task
alias Rustler.Compiler.Messages
alias Rustler.Compiler.Rustup
def throw_error(error_descr) do
Mix.shell.error Messages.message(error_descr)
raise "Compilation error"
end
def run(_args) do
project = Mix.Project.config
crates = project[:rustler_crates]
base_project_dir = File.cwd!
if Rustup.version == :none do
throw_error(:rustup_not_installed)
end
unless Rustup.version_installed?(Rustler.rust_version) do
throw_error({:rust_version_not_installed, Rustler.rust_version})
end
nif_version = :erlang.system_info(:nif_version)
unless nif_version in Rustler.nif_versions do
throw_error({:unsupported_nif_version, nif_version})
end
File.mkdir_p!(Rustler.nif_lib_dir)
is_release = System.get_env("RUSTLER_DEBUG") != "true"
compile_crates(base_project_dir, crates, is_release)
end
def compile_crates(nil, _), do: throw_error(:no_crates_property)
def compile_crates(base_project_dir, crates, release) do
Enum.map(crates, fn crate ->
compile_crate(base_project_dir <> crate, release)
end)
end
def compile_crate(crate, release) do
cargo_data = check_crate_env(crate)
lib_name = Rustler.TomlParser.get_table_val(cargo_data, ["lib"], "name")
if lib_name == nil do
throw_error({:cargo_no_library, crate})
end
compiler_flags = if release, do: ["--release"], else: []
compile_flavor = if release, do: "release", else: "debug"
target_dir = "#{Rustler.nif_lib_dir}/#{crate}_target"
Mix.shell.info "Compiling NIF crate '#{crate}' (#{compile_flavor})..."
case Rustup.compile_with(crate, Rustler.rust_version, compiler_flags,
[{"CARGO_TARGET_DIR", target_dir}],
IO.stream(:stdio, :line)) do
{_, 0} -> nil
{_, code} -> raise "Compile error (exit code #{code})"
end
# TODO: Make build flavor specific
Enum.map(Path.wildcard("#{target_dir}/#{compile_flavor}/lib#{lib_name}.*"), fn
path ->
file_name = platform_library_name(Path.basename(path))
File.cp!(Path.absname(path), "#{Rustler.nif_lib_dir}/#{file_name}")
end)
end
def platform_library_name(base_name) do
ext = Path.extname(base_name)
case ext do
# For macs we need to rename the .dylib so .so for the BEAM to load it.
# See issue #3.
".dylib" -> Path.rootname(base_name) <> ".so"
_ -> base_name
end
end
def check_crate_env(crate) do
unless File.dir?(crate) do
Mix.shell.error Messages.message(:no_crates_property_message)
end
cargo_data =
case File.read("#{crate}/Cargo.toml") do
{:error, :enoent} ->
throw_error({:cargo_toml_not_found, crate})
{:ok, text} ->
Rustler.TomlParser.parse(text)
end
rustler_version = get_cargo_dep_info(cargo_data, "rustler")
rustler_codegen_version = get_cargo_dep_info(cargo_data, "rustler_codegen")
validate_versions(crate, rustler_version, rustler_codegen_version)
cargo_data
end
def validate_versions(crate, rustler, codegen)
when rustler == nil or codegen == nil do
throw_error({:no_rustler_deps, crate, Rustler.rustler_version})
end
def validate_versions(_, %{version: nil}, %{version: nil}) do
# Development, no validation
end
def validate_versions(crate, %{version: rustler_v}, %{version: codegen_v})
when rustler_v != codegen_v do
throw_error({:differing_versions, crate, rustler_v, codegen_v})
end
def validate_versions(crate, %{version: version}, %{version: version}) do
unless version == "=#{Rustler.rustler_version}" do
throw_error({:unsupported_rustler_version, crate,
"=#{Rustler.rustler_version}", version})
end
end
def get_cargo_dep_info(data, dep_name) do
table_path = ["dependencies", dep_name]
simple_key = Rustler.TomlParser.get_table_val(data, ["dependencies"], dep_name)
table = Rustler.TomlParser.get_table_vals(data, ["dependencies", dep_name])
cond do
simple_key != nil ->
%{version: simple_key}
table != nil ->
%{
version: Rustler.TomlParser.get_keys_key(table, "version"),
path: Rustler.TomlParser.get_keys_key(table, "path"),
git: Rustler.TomlParser.get_keys_key(table, "git"),
}
true ->
nil
end
end
end