Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abort compilation on macos if linker arguments are missing #439

Merged
merged 2 commits into from
Mar 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 56 additions & 38 deletions rustler_mix/lib/rustler/compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ defmodule Rustler.Compiler do
|> make_features_flag(config.features)
|> make_target_flag(config.target)
|> make_build_mode_flag(config.mode)
|> make_platform_hacks(crate_full_path, :os.type())

ensure_platform_requirements!(crate_full_path, config, :os.type())

compile_result =
System.cmd(cmd, args,
Expand Down Expand Up @@ -69,46 +70,63 @@ defmodule Rustler.Compiler do
["rustup", "run", version, "cargo", "rustc"]
end

defp make_platform_hacks(args, crate_path, {:unix, :darwin}) do
root = Path.join([".cargo", "config"])
path = Path.join([crate_path, ".cargo", "config"])

if File.exists?(root) || File.exists?(path) do
args
else
IO.write([
"\n",
IO.ANSI.yellow(),
"""
Compiling on macOS requires special link args in order to compile
correctly.

Rustler is currently working around this issue in the compiler task.
This will be removed in v1.0.0 in favor of a user supplied .cargo/config
file.

To remove this warning, please create #{path}
with the following content:

[target.'cfg(target_os = "macos")']
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]

See https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/MachOTopics/1-Articles/executing_files.html
for more details.

""",
IO.ANSI.default_color(),
"\n"
])

args ++ ["--", "-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"]
defp ensure_platform_requirements!(crate_path, config, {:unix, :darwin}) do
# We attempt to find a .cargo/config upwards from the crate_path, which
# has a target configuration for macos. If any such config exists, we
# assume that the config correctly encodes the needed linker arguments.

workspace_root = config.metadata["workspace_root"]

components =
crate_path
|> Path.relative_to(workspace_root)
|> Path.split()

{potential_config_files, _} =
Enum.map_reduce(["" | components], workspace_root, fn component, path ->
path = Path.join(path, component)
file = Path.join([path, ".cargo", "config"])
{file, path}
end)

has_macos_target_os_configuration? =
potential_config_files
|> Enum.filter(&File.exists?/1)
|> Enum.reverse()
|> Stream.map(&Toml.decode_file!/1)
|> Enum.find(&macos_target_configuration/1)

unless has_macos_target_os_configuration? do
raise """
Compiling on macOS requires special link args in order to compile
correctly.

To remove this error, please create .cargo/config
with the following content:

[target.'cfg(target_os = "macos")']
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]


See https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/MachOTopics/1-Articles/executing_files.html
for more details.
"""
end
end

defp make_platform_hacks(args, _, _), do: args
defp ensure_platform_requirements!(_, _, _), do: :ok

defp macos_target_configuration(toml) do
toml
|> Map.get("target", [])
|> Enum.filter(fn {key, _} ->
String.match?(key, ~r/(.*macos.*)|(.*darwin.*)/)
end)
|> Map.new()
end

defp make_no_default_features_flag(args, true), do: args
defp make_no_default_features_flag(args, false), do: args ++ ["--no-default-features"]
Expand Down
33 changes: 18 additions & 15 deletions rustler_mix/lib/rustler/compiler/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ defmodule Rustler.Compiler.Config do
priv_dir: "",
skip_compilation?: false,
target: nil,
target_dir: ""
target_dir: "",
metadata: nil

alias Rustler.Compiler.Config

Expand Down Expand Up @@ -58,25 +59,25 @@ defmodule Rustler.Compiler.Config do
end

defp build(opts) do
crate = Keyword.fetch!(opts, :crate)

resources =
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.get(:path)
|> external_resources(crate)
|> Keyword.put(:metadata, metadata)
|> Keyword.put(:external_resources, resources)
end

opts = Keyword.put(opts, :external_resources, resources)

struct!(Config, opts)
end

defp external_resources(crate_path, crate) do
crate_str = to_string(crate)

defp metadata!(crate_path) do
metadata =
case System.cmd("cargo", ~w(metadata --format-version=1), cd: crate_path) do
{metadata, 0} ->
Expand All @@ -86,10 +87,12 @@ defmodule Rustler.Compiler.Config do
raise "calling `cargo metadata` failed.\n" <> output
end

json = Jason.decode!(metadata)

packages = json["packages"]
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
Expand Down