Closed nlfiedler closed 8 years ago
This looks like the issue exactly: https://github.com/rust-lang/rust/issues/14344
So if I read that right, ruster_unsafe.o
must also be linked in to avoid those errors.
Found out that building the demo like this works:
$ cargo rustc -- --codegen link-args='-flat_namespace -undefined suppress'
Same problem. @nlfiedler's suggestion fixed it for me. Is there a way to fix this in ruster_unsafe?
Is @nlfiedler 's work-around still required on current(1.7) Rust?
Yep, still need it.
As an alternative to passing command line arguments to rustc, adding this to your NIF library file seems to accomplish the same thing.
#![feature(link_args)]
#[link_args = "-flat_namespace -undefined suppress"]
extern {}
Thanks to @bjz for finding this attribute.
I took a quick look at sinking this into the nif_init!
macro, but there are a few problems:
#![feature(link_args)]
is not available on stable Rust.#![feature(link_args)]
must appear at the top of the file; it won't work a little lower down where nif_init!
would typically appear.OS selection did work fine though. This fragment caused no problem on a linux compilation:
#[cfg(target_os="macos")]
#[link_args = "-flat_namespace -undefined suppress"]
extern {}
Semi-related topic/question for OS X users: I am working on a erlang.mk
plugin for building Rust crates in an Erlang application. It will build any crate with binary targets including non-NIF executables for port programs. I could automatically include those magic link args when building on OS X, but my question is... will that mess up non-dylib targets (ie, plain executables)?
I hope to make a rebar3
plugin once I have the kinks worked out of erlang.mk
.
Quick experiment:
$ cargo new --bin hello
$ cd hello/
$ cargo build
Compiling hello v0.1.0 (file:///Users/nfiedler/Downloads/hello)
$ cargo run
Running `target/debug/hello`
Hello, world!
After adding the aforementioned compiler directives:
$ cargo build
Compiling hello v0.1.0 (file:///Users/nfiedler/Downloads/hello)
src/main.rs:3:1: 3:10 error: the `link_args` attribute is not portable across platforms, it is recommended to use `#[link(name = "foo")]` instead (see issue #29596)
src/main.rs:3 extern {}
^~~~~~~~~
error: aborting due to previous error
error: Could not compile `hello`.
To learn more, run the command again with --verbose.
Okay, remove the pointless extern
for now...
$ cargo build
Compiling hello v0.1.0 (file:///Users/nfiedler/Downloads/hello)
src/main.rs:2:1: 2:53 warning: unused attribute, #[warn(unused_attributes)] on by default
src/main.rs:2 #[link_args = "-flat_namespace -undefined suppress"]
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ cargo run
Running `target/debug/hello`
Hello, world!
So link_args
is considered not portable, and it generates a warning for a binary (vs library).
So I think a resolution for this is to finish osx support for rust.mk. To do that I need to close out https://github.com/goertzenator/rust.mk/issues/1, which requires someone with a Mac to download and run the tests (cd tests/rustmk_demo && make tests
) in the osx branch. Any volunteers?
@goertzenator I tried running them but got:
⋊> ~/c/t/r/t/rustmk_demo on osx ◦ make tests 11:15:47
GEN clean-app
GEN coverdata-clean
GEN rust-clean
DEP find_crate
for dep in ; do \
mkdir -p $dep/ebin; \
done
for dep in ; do \
mkdir -p $dep/ebin; \
done
DEPEND find_crate.d
ERLC find_crate.erl
APP find_crate
DEPEND rustmk_demo.d
ERLC complex1.erl ruster_unsafe_demo.erl
APP rustmk_demo
make[1]: Nothing to be done for `test-dir'.
GEN test-build
CARGO erl_comm
[ -f /Users/theron/code/tmp/rust.mk/tests/rustmk_demo/priv/crates/erl_comm/*.dylib ] && (for file in /Users/theron/code/tmp/rust.mk/tests/rustmk_demo/priv/crates/erl_comm/*.dylib; do mv "ile" ".so"; done) || true
#[ -f /Users/theron/code/tmp/rust.mk/tests/rustmk_demo/priv/crates/erl_comm/*.so ] && (for file in /Users/theron/code/tmp/rust.mk/tests/rustmk_demo/priv/crates/erl_comm/*.so; do mv "$file" "${file%.so}.uprple"; done) || true
CARGO ruster_unsafe_demo
[ -f /Users/theron/code/tmp/rust.mk/tests/rustmk_demo/priv/crates/ruster_unsafe_demo/*.dylib ] && (for file in /Users/theron/code/tmp/rust.mk/tests/rustmk_demo/priv/crates/ruster_unsafe_demo/*.dylib; do mv "ile" ".so"; done) || true
mv: rename ile to .so: No such file or directory
#[ -f /Users/theron/code/tmp/rust.mk/tests/rustmk_demo/priv/crates/ruster_unsafe_demo/*.so ] && (for file in /Users/theron/code/tmp/rust.mk/tests/rustmk_demo/priv/crates/ruster_unsafe_demo/*.so; do mv "$file" "${file%.so}.uprple"; done) || true
GEN eunit
undefined
=ERROR REPORT==== 10-Jun-2016::11:16:02 ===
Error in process <0.39.0> with exit value:
{{badmatch,{error,not_found}},
[{ruster_unsafe_demo,init,0,[{file,"src/ruster_unsafe_demo.erl"},{line,9}]},
{code_server,'-handle_on_load/4-fun-0-',1,
[{file,"code_server.erl"},{line,1674}]}]}
*** test module not found ***
**ruster_unsafe_demo
=WARNING REPORT==== 10-Jun-2016::11:16:02 ===
The on_load function for module ruster_unsafe_demo returned {{badmatch,
{error,
not_found}},
[{ruster_unsafe_demo,
init,0,
[{file,...},
{...}]},
{code_server,
'-handle_on_load/4-fun-0-',
1,
[{...}|...]}]}
=======================================================
Failed: 0. Skipped: 0. Passed: 2.
One or more tests were cancelled.
make: *** [eunit] Error 2
Looks like the .dylib isn't being renamed to .so.
Thanks. Looks really close now. Do the tests go if you manually rename priv/crates/ruster_unsafe_demo/libruster_unsafe_demo.dylib
to .so
?
Yes, if I comment out the rm -rf
line in plugins.mk and rename the file.
Excellent! I just fixed a silly error in the mv
. I think it should all go now.
Latest commit works :).
Thanks for your help. I will clean that branch up and properly merge it into master when I get a chance.
rust.mk will now build for OSX. Closing this.
Sorry to bring this back up, as I understand it has been fixed in rust.mk, but I feel like getting this fixed in rust itself would be a better option.
Does anyone know what causes this to happen? I don't have a mac available, I can't really look into it.
This article seems to explain what the two-level namespace function does on mac. I am not sure what could be done to fix this issue in rust itself.
One issue here is that Erlang has chosen to go with a flat namespace on OSX instead of the 2-layer namespace. I would guess changing that is not hard but might create ABI problems with already compiled C NIF modules. So, say that happens and we can get rid of the -flat_namespace
flag. Which leaves the -undefined
flag. To make the linker happy it would have to see the beam executable... which surely means more linker flags and complexity.
So I don't think this can be fixed in Rust. It does default linking on OSX which seems like the right thing. Erlang could make it slightly better by going with a 2-layer namespace, but fixing the -unknown
flag just brings in other complexities.
BTW, rust.mk
is in the process of switching to using cargo-erlangapp
as a backend workhorse. This may or may not be a suitable tool to help with these linking issues for rustler
. The idea is to have all the ugly linking detail in this one app so higher level build tools don't have to replicate it, and so we can learn from each other's experience and have one high quality module to deal with this stuff.
I just finished the majority of the work needed to make rustler
work on Rust stable. Not having a need for a special build environment should make using a common build method a lot easier.
When I get to updating rustler_mix
, I will look into using cargo-erlangapp
. It seems like a good idea to have a common way of building rust crates.
The only thing about cargo-erlangapp
that doesn't fit into rustler
seems to be the autodetection of crates. Thus far you have to list crates to build in the build configuration, and unless there is a convincing argument for doing autodetection, I think I would prefer to keep it that way.
Feel free to file bugs against cargo-erlangapp
if it can support mix
and rustler_mix
better. I know little about the elixir
ecosystem.
With Erlang/OTP 17.5 from Homebrew and Rust 1.0.0 installing using their install script, building
ruster_unsafe
is fine, but building theruster_unsafe_demo
does not work (Daniel suggested I file this issue here rather than the demo).Please let me know if there is any other information I can provide. As time allows, I will continue trying to debug this and report anything I find. Thanks.