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

Common cargo #302

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
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
6 changes: 4 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,10 @@ jobs:
- name: Extend PATH
run: echo "C:\\ProgramData\\chocolatey\\lib\\Elixir\\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

- name: Hex
run: mix local.hex --force
- name: Mix tools
run: |
mix local.hex --force
mix local.rebar --force

- name: Test rustler_mix
working-directory: rustler_mix
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Session.vim
# Generated by Cargo
**/target/*
/rustler/target/
/rustler_tests/priv/native/*
/rustler_tests/priv/crates/*
/rustler_tests/target/
/rustler_tests/_build
/rustler_tests/deps
Expand Down
19 changes: 0 additions & 19 deletions rustler_mix/lib/mix/tasks/compile.rustler.ex

This file was deleted.

37 changes: 35 additions & 2 deletions rustler_mix/lib/mix/tasks/rustler.new.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ defmodule Mix.Tasks.Rustler.New do

for {format, source, _} <- @basic do
unless format == :keep do
@external_resource Path.join(root, source)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the other occurrences of @external_resource will be readded.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, actually I don't like this, it would mean (if I understand things correctly) that automatic recompilation is only triggered if lib.rs is changed, not if any of its dependencies (like other .rs files or a crate dependencies) are changed, is that right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll do this via __mix_recompile__? instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__mix_recompile__? seems very new, I think we might not be able to support older versions of Elixir with that anymore?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just found it in the sources. Worst case: It won't be better than what we have now :)

The issue is that you can't really tell mix up-front what exact files will influence the final object files of a Rust project. I'll think about it.

defp render(unquote(source)), do: unquote(File.read!(Path.join(root, source)))
end
end
Expand Down Expand Up @@ -68,8 +67,12 @@ defmodule Mix.Tasks.Rustler.New do

check_module_name_validity!(module)

path = Path.join([File.cwd!(), "native/", name])
sub_path = Path.join("native", name)

path = Path.join([File.cwd!(), sub_path])
new(otp_app, path, module, name, opts)

add_to_workspace(sub_path)
end

defp new(otp_app, path, module, name, _opts) do
Expand All @@ -89,6 +92,36 @@ defmodule Mix.Tasks.Rustler.New do
Mix.Shell.IO.info([:green, "Ready to go! See #{path}/README.md for further instructions."])
end

defp add_to_workspace(sub_path) do
Mix.Shell.IO.info([:green, "Adding #{sub_path} to workspace"])
cargo_toml_fn = Path.join(File.cwd!(), "Cargo.toml")

cargo_toml =
case Toml.decode_file(cargo_toml_fn) do
{:ok, data} ->
data

{:error, _} ->
%{}
end

workspace = Map.get(cargo_toml, "workspace", %{})

members =
MapSet.new(Map.get(workspace, "members", []))
|> MapSet.put(sub_path)
|> MapSet.to_list()

workspace_section = """
[workspace]
members = [#{members |> Enum.map(&inspect/1) |> Enum.join(", ")}]
"""

# TODO: Only replace the existing workspace.members entry

File.write(cargo_toml_fn, workspace_section)
end

defp check_module_name_validity!(name) do
unless name =~ ~r/^[A-Z]\w*(\.[A-Z]\w*)*$/ do
Mix.raise(
Expand Down
61 changes: 30 additions & 31 deletions rustler_mix/lib/rustler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,8 @@ defmodule Rustler do
value. If you have more than one crate in your project, you will need to
be explicit about which crate you intend to use.

* `:default_features` - a boolean to specify whether the crate's default features
should be used.

* `:env` - Specify a list of environment variables when envoking the compiler.

* `:features` - a list of features to enable when compiling the crate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can probably readd this if required.

* `:load_data` - Any valid term. This value is passed into the NIF when it is
loaded (default: `0`)

Expand All @@ -56,12 +51,6 @@ defmodule Rustler do
- When `Mix.env()` is `:dev` or `:test`, the crate will be compiled in `:debug` mode.
- When `Mix.env()` is `:prod` or `:bench`, the crate will be compiled in `:release` mode.

* `:path` - By default, rustler expects the crate to be found in `native/<crate>` in the
root of the project. Use this option to override this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not necessary anymore, as we now expect a Cargo.toml in the root of the project.

* `:skip_compilation?` - This option skips envoking the rust compiler. Specify this option
in combination with `:load_from` to load a pre-compiled artifact.

* `:target` - Specify a compile [target] triple.

* `:target_dir`: Override the compiler output directory.
Expand All @@ -82,42 +71,52 @@ defmodule Rustler do
quote bind_quoted: [opts: opts] do
config = Rustler.Compiler.compile_crate(__MODULE__, opts)

for resource <- config.external_resources do
@external_resource resource
end
@load_from {config.otp_app, config.load_path}

if config.lib do
@load_from config.load_from
@load_data config.load_data

@before_compile {Rustler, :__before_compile_nif__}
else
@before_compile Rustler
end
end
end

defmacro __before_compile__(_env) do
quote do
@on_load :rustler_init

@doc false
def rustler_init do
# Remove any old modules that may be loaded so we don't get
# {:error, {:upgrade, 'Upgrade not supported by this NIF library.'}}
:code.purge(__MODULE__)

def rustler_path do
{otp_app, path} = @load_from

load_path =
otp_app
|> Application.app_dir(path)
|> to_charlist()

:erlang.load_nif(load_path, @load_data)
Path.join(:code.priv_dir(otp_app), path)
end
end
end

defmacro __before_compile_nif__(_env) do
quoted =
quote do
def rustler_path do
# TODO: Parametrise, and keep all crates in the list
{otp_app, path} = @load_from
Path.join(:code.priv_dir(otp_app), path)
end

@on_load :rustler_init
@doc false
def rustler_init do
# Remove any old modules that may be loaded so we don't get
# :error, {:upgrade, 'Upgrade not supported by this NIF library.'}}
:code.purge(__MODULE__)
load_path = String.to_charlist(rustler_path())
:ok = :erlang.load_nif(load_path, @load_data)
end
end

# quoted |> Macro.to_string |> IO.puts
quoted
end

@doc false
@spec rustler_version() :: binary()
def rustler_version, do: "0.22.0"

@doc """
Expand Down
Loading