-
Notifications
You must be signed in to change notification settings - Fork 14
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
Expand cross compilation #124
Changes from 6 commits
f98f2a0
69a4642
d5e2a50
8bb966d
0cd6625
de375e6
9139cf3
03fdf70
e5403c7
3a66c99
c70ee1e
120367c
4b17561
bd5e822
9f3a369
f545ebd
32971f4
1c329dc
f22c30c
22d0efb
153e777
c191919
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -4,10 +4,12 @@ | |||||
[![API Docs](https://img.shields.io/badge/api-docs-yellow.svg?style=flat)](https://hexdocs.pm/bundlex/) | ||||||
[![CircleCI](https://circleci.com/gh/membraneframework/bundlex.svg?style=svg)](https://circleci.com/gh/membraneframework/bundlex) | ||||||
|
||||||
Bundlex is a multi-platform tool for compiling C code along with elixir projects, for use in NIFs, CNodes and Ports. The tool also provides a convenient way of accessing compiled code in elixir modules. | ||||||
Bundlex is a multi-platform tool for compiling C and C++ code along with elixir projects, for use in NIFs, CNodes and Ports. The tool also provides a convenient way of accessing compiled code in elixir modules. | ||||||
|
||||||
Bundlex has been tested on Linux, Mac OS and FreeBSD. There's some support for Windows as well, but it's experimental and unstable (see issues for details). | ||||||
|
||||||
Bundlex also supports cross-compilation and has been tested with platforms running Nerves. | ||||||
|
||||||
This tool is maintained by the [Membrane Framework](https://membraneframework.org/) team. | ||||||
|
||||||
## Installation | ||||||
|
@@ -29,7 +31,7 @@ defmodule MyApp.Mixfile do | |||||
|
||||||
defp deps() do | ||||||
[ | ||||||
{:bundlex, "~> 1.4"} | ||||||
{:bundlex, "~> 1.5"} | ||||||
] | ||||||
end | ||||||
end | ||||||
|
@@ -172,6 +174,20 @@ As in the case of NIFs, CNodes compiled with Bundlex can be used like any other | |||||
Similarly to CNodes Bundlex provides `Bundlex.Port` module for a little easier interacting with Ports. | ||||||
Please refer to the module's documentation to see how to use it. | ||||||
|
||||||
### Cross-compilation | ||||||
|
||||||
With proper setup Bundlex can support cross-compilation. When using Nerves the it should work out of the box. | ||||||
|
||||||
Not relying in Nerves and using your own toolchain is also possible, although it wasn't tested. In this scenario the following environment variables need to be set, since they're not handled by Nerves: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
- `CROSSCOMPILE` | ||||||
FelonEkonom marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
- `CC` - path to the C compiler for cross-compiling to the target | ||||||
- `CFLAGS` - C compilation flags | ||||||
- `CXX` - path to the C++ compiler for cross-compiling to the target | ||||||
- `CXXFLAGS` - C++ compilation flags | ||||||
- `LDFLAGS` - Linker flags | ||||||
|
||||||
When cross-compiling some warnings may be raised about not being able to load nifs, but that's expected, since they are most likely built for different architecture | ||||||
FelonEkonom marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
### Documentation of the native code | ||||||
|
||||||
Bundlex provides a way to generate documentation of the native code. The documentation is generated using [Doxygen](http://www.doxygen.nl/). | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,39 +6,73 @@ defmodule Bundlex do | |
alias Bundlex.Helper.MixHelper | ||
alias Bundlex.Platform | ||
|
||
@type platform_t :: :linux | :macosx | :windows32 | :windows64 | :nerves | ||
@type platform_t :: :linux | :macosx | :windows32 | :windows64 | :nerves | :custom | ||
|
||
@typedoc """ | ||
A map containing four fields that describe the platform. | ||
A map containing four fields that describe the target platform. | ||
|
||
It consists of: | ||
* architecture - e.g. `x86_64` or `arm64` | ||
* vendor - e.g. `pc` | ||
* os - operating system, e.g. `linux` or `darwin20.6.0` | ||
* abi - application binary interface, e.g. `musl` or `gnu` (nil if unknown / non-existent) | ||
* abi - application binary interface, e.g. `musl` or `gnu` | ||
""" | ||
@type target :: | ||
%{architecture: String.t(), vendor: String.t(), os: String.t(), abi: String.t() | nil} | ||
%{ | ||
architecture: String.t() | :unknown, | ||
vendor: String.t() | :unknown, | ||
os: String.t() | :unknown, | ||
abi: String.t() | :unknown | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd either use |
||
} | ||
|
||
@doc """ | ||
A function returning a target triplet for the environment on which it is run. | ||
A function returning information about the target platform. In case of cross-compilation the | ||
information can be provided by setting appropriate environment variables. | ||
""" | ||
@spec get_target() :: target() | ||
def get_target() do | ||
[architecture, vendor, os | maybe_abi] = | ||
:erlang.system_info(:system_architecture) |> List.to_string() |> String.split("-") | ||
|
||
%{ | ||
architecture: architecture, | ||
vendor: vendor, | ||
os: os, | ||
abi: List.first(maybe_abi) | ||
} | ||
case System.fetch_env("CROSSCOMPILE") do | ||
mat-hek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
:error -> | ||
def get_target() do | ||
[architecture, vendor, os | maybe_abi] = | ||
:erlang.system_info(:system_architecture) |> List.to_string() |> String.split("-") | ||
|
||
%{ | ||
architecture: architecture, | ||
vendor: vendor, | ||
os: os, | ||
abi: List.first(maybe_abi) || :unknown | ||
} | ||
end | ||
|
||
{:ok, _} -> | ||
def get_target() do | ||
unquote( | ||
Enum.map( | ||
[ | ||
{:architecture, "TARGET_ARCH"}, | ||
{:vendor, "TARGET_VENDOR"}, | ||
{:os, "TARGET_OS"}, | ||
{:abi, "TARGET_ABI"} | ||
mat-hek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
], | ||
fn {key, env} -> | ||
value = | ||
case System.fetch_env(env) do | ||
{:ok, value} -> value | ||
:error -> :unknown | ||
end | ||
|
||
{key, value} | ||
end | ||
) | ||
) | ||
|> Enum.into(%{}) | ||
end | ||
end | ||
|
||
@doc """ | ||
Returns current platform name. | ||
""" | ||
@deprecated "Use Bundlex.get_target/0 instead" | ||
@spec platform() :: platform_t() | ||
def platform() do | ||
Platform.get_target!() | ||
|
@@ -47,7 +81,7 @@ defmodule Bundlex do | |
@doc """ | ||
Returns family of the platform obtained with `platform/0`. | ||
""" | ||
@spec family() :: :unix | :windows | ||
@spec family() :: :unix | :windows | :custom | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we deprecate this function anyway, maybe let's keep it unchanged for better compatibility? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we deprecate platform, not family |
||
def family() do | ||
Platform.family(platform()) | ||
end | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -41,24 +41,25 @@ defmodule Bundlex.Platform do | |||||
Otherwise raises Mix error. | ||||||
""" | ||||||
@spec get_target!() :: name_t | ||||||
mix_target = Mix.target() | ||||||
|
||||||
if mix_target == :host do | ||||||
def get_target!(), do: get_host!() | ||||||
else | ||||||
def get_target!() do | ||||||
case System.fetch_env("NERVES_APP") do | ||||||
{:ok, _app} -> | ||||||
:nerves | ||||||
|
||||||
:error -> | ||||||
Output.warn( | ||||||
"MIX_TARGET #{inspect(unquote(mix_target))} is not supported. Bundlex will compile for the host platform." | ||||||
) | ||||||
|
||||||
get_host!() | ||||||
|
||||||
case System.fetch_env("CROSSCOMPILE") do | ||||||
:error -> | ||||||
def get_target!(), do: get_host!() | ||||||
|
||||||
{:ok, _} -> | ||||||
def get_target!() do | ||||||
case System.fetch_env("NERVES_APP") do | ||||||
{:ok, _app} -> | ||||||
:nerves | ||||||
|
||||||
:error -> | ||||||
Output.warn( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
"Cross-compiling without using Nerves. Make sure necessary environment variables are set correctly." | ||||||
) | ||||||
|
||||||
:custom | ||||||
end | ||||||
end | ||||||
end | ||||||
end | ||||||
|
||||||
@spec get_host!() :: name_t | ||||||
|
@@ -107,12 +108,14 @@ defmodule Bundlex.Platform do | |||||
def family(:macosx), do: :unix | ||||||
def family(:freebsd), do: :unix | ||||||
def family(:nerves), do: :unix | ||||||
def family(:custom), do: :custom | ||||||
|
||||||
@spec get_module(family_name_t) :: module | ||||||
def get_module(:windows32), do: Bundlex.Platform.Windows32 | ||||||
def get_module(:windows64), do: Bundlex.Platform.Windows64 | ||||||
def get_module(:macosx), do: Bundlex.Platform.MacOSX | ||||||
def get_module(:linux), do: Bundlex.Platform.Linux | ||||||
def get_module(:freebsd), do: Bundlex.Platform.Freebsd | ||||||
def get_module(:nerves), do: Bundlex.Platform.Nerves | ||||||
def get_module(:nerves), do: Bundlex.Platform.Custom | ||||||
def get_module(:custom), do: Bundlex.Platform.Custom | ||||||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
defmodule Bundlex.Platform.Nerves do | ||
defmodule Bundlex.Platform.Custom do | ||
@moduledoc false | ||
use Bundlex.Platform | ||
|
||
@impl true | ||
def toolchain_module() do | ||
Bundlex.Toolchain.Nerves | ||
Bundlex.Toolchain.Custom | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ defmodule Bundlex.Toolchain.Common.Unix.OSDeps do | |
@moduledoc false | ||
|
||
require Logger | ||
alias Bundlex.Output | ||
alias Bundlex.{Output, Platform} | ||
|
||
@spec resolve_os_deps(Bundlex.Native.t()) :: Bundlex.Native.t() | ||
def resolve_os_deps(native) do | ||
|
@@ -147,7 +147,7 @@ defmodule Bundlex.Toolchain.Common.Unix.OSDeps do | |
|
||
# TODO: pass the platform via arguments | ||
# $ORIGIN must be escaped so that it's not treated as an ENV variable | ||
rpath_root = if Bundlex.platform() == :macosx, do: "@loader_path", else: "\\$ORIGIN" | ||
rpath_root = if Platform.get_target!() == :macosx, do: "@loader_path", else: "\\$ORIGIN" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the difference between There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now deprecated There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So why won't you use |
||
|
||
[ | ||
"-L#{Path.join(dep_path, "lib")}", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.