rusterlium / erlang_nif-sys

Low level bindings to Erlang NIF API for Rust
Apache License 2.0
90 stars 19 forks source link

Demo does not build on Mac #3

Closed nlfiedler closed 8 years ago

nlfiedler commented 9 years ago

With Erlang/OTP 17.5 from Homebrew and Rust 1.0.0 installing using their install script, building ruster_unsafe is fine, but building the ruster_unsafe_demo does not work (Daniel suggested I file this issue here rather than the demo).

$ cargo build --verbose
   Compiling ruster_unsafe v0.1.0
     Running `rustc /Users/nfiedler/.cargo/registry/src/github.com-1ecc6299db9ec823/ruster_unsafe-0.1.0/build.rs --crate-name build_script_build --crate-type bin -C prefer-dynamic -g --out-dir /Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/build/ruster_unsafe-421b52893b529f99 --emit=dep-info,link -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps -Awarnings`
   Compiling libc v0.1.8
     Running `rustc /Users/nfiedler/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.1.8/rust/src/liblibc/lib.rs --crate-name libc --crate-type lib -g --cfg feature="cargo-build" --cfg feature="default" -C metadata=2eda841eb12a3090 -C extra-filename=-2eda841eb12a3090 --out-dir /Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps --emit=dep-info,link -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps -Awarnings`
     Running `/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/build/ruster_unsafe-421b52893b529f99/build-script-build`
     Running `rustc /Users/nfiedler/.cargo/registry/src/github.com-1ecc6299db9ec823/ruster_unsafe-0.1.0/src/lib.rs --crate-name ruster_unsafe --crate-type lib -g -C metadata=421b52893b529f99 -C extra-filename=-421b52893b529f99 --out-dir /Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps --emit=dep-info,link -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps --extern libc=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps/liblibc-2eda841eb12a3090.rlib -Awarnings`
   Compiling ruster_unsafe_demo v0.0.1 (file:///Users/nfiedler/Downloads/ruster_unsafe_demo)
     Running `rustc src/lib.rs --crate-name ruster_unsafe_demo --crate-type dylib -g --out-dir /Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug --emit=dep-info,link -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps --extern ruster_unsafe=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps/libruster_unsafe-421b52893b529f99.rlib`
error: linking with `cc` failed: exit code: 1
note: "cc" "-m64" "-L" "/usr/local/lib/rustlib/x86_64-apple-darwin/lib" "-o" "/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/libruster_unsafe_demo.dylib" "/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/ruster_unsafe_demo.o" "-Wl,-force_load,/usr/local/lib/rustlib/x86_64-apple-darwin/lib/libmorestack.a" "/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/ruster_unsafe_demo.metadata.o" "-Wl,-dead_strip" "-nodefaultlibs" "/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps/libruster_unsafe-421b52893b529f99.rlib" "/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps/liblibc-2eda841eb12a3090.rlib" "/usr/local/lib/rustlib/x86_64-apple-darwin/lib/libstd-4e7c5e5c.rlib" "/usr/local/lib/rustlib/x86_64-apple-darwin/lib/libcollections-4e7c5e5c.rlib" "/usr/local/lib/rustlib/x86_64-apple-darwin/lib/libunicode-4e7c5e5c.rlib" "/usr/local/lib/rustlib/x86_64-apple-darwin/lib/librand-4e7c5e5c.rlib" "/usr/local/lib/rustlib/x86_64-apple-darwin/lib/liballoc-4e7c5e5c.rlib" "/usr/local/lib/rustlib/x86_64-apple-darwin/lib/liblibc-4e7c5e5c.rlib" "/usr/local/lib/rustlib/x86_64-apple-darwin/lib/libcore-4e7c5e5c.rlib" "-L" "/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug" "-L" "/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps" "-L" "/usr/local/lib/rustlib/x86_64-apple-darwin/lib" "-L" "/Users/nfiedler/Downloads/ruster_unsafe_demo/.rust/lib/x86_64-apple-darwin" "-L" "/Users/nfiedler/Downloads/ruster_unsafe_demo/lib/x86_64-apple-darwin" "-lc" "-lm" "-lSystem" "-lpthread" "-lc" "-lm" "-dynamiclib" "-Wl,-dylib" "-lcompiler-rt"
note: ld: warning: directory not found for option '-L/Users/nfiedler/Downloads/ruster_unsafe_demo/.rust/lib/x86_64-apple-darwin'
ld: warning: directory not found for option '-L/Users/nfiedler/Downloads/ruster_unsafe_demo/lib/x86_64-apple-darwin'
Undefined symbols for architecture x86_64:
  "_enif_get_tuple", referenced from:
      tuple_add::__rust_abi in ruster_unsafe_demo.o
  "_enif_get_int", referenced from:
      native_add::__rust_abi in ruster_unsafe_demo.o
      tuple_add::__rust_abi in ruster_unsafe_demo.o
  "_enif_make_int", referenced from:
      native_add::__rust_abi in ruster_unsafe_demo.o
      tuple_add::__rust_abi in ruster_unsafe_demo.o
  "_enif_make_badarg", referenced from:
      native_add::__rust_abi in ruster_unsafe_demo.o
      tuple_add::__rust_abi in ruster_unsafe_demo.o
  "_enif_make_atom", referenced from:
      load::__rust_abi in ruster_unsafe_demo.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

error: aborting due to previous error
Could not compile `ruster_unsafe_demo`.

Caused by:
  Process didn't exit successfully: `rustc src/lib.rs --crate-name ruster_unsafe_demo --crate-type dylib -g --out-dir /Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug --emit=dep-info,link -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug -L dependency=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps --extern ruster_unsafe=/Users/nfiedler/Downloads/ruster_unsafe_demo/target/debug/deps/libruster_unsafe-421b52893b529f99.rlib` (exit code: 101)
$ cat /usr/local/lib/erlang/releases/17/OTP_VERSION
17.5
$ rustc --version
rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
$ uname -a
Darwin mac-nfiedler 14.3.0 Darwin Kernel Version 14.3.0: Mon Mar 23 11:59:05 PDT 2015; root:xnu-2782.20.48~5/RELEASE_X86_64 x86_64 i386 MacPro5,1 Darwin

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.

goertzenator commented 9 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.

nlfiedler commented 9 years ago

Found out that building the demo like this works:

$ cargo rustc -- --codegen link-args='-flat_namespace -undefined suppress'
hunterboerner commented 8 years ago

Same problem. @nlfiedler's suggestion fixed it for me. Is there a way to fix this in ruster_unsafe?

goertzenator commented 8 years ago

Is @nlfiedler 's work-around still required on current(1.7) Rust?

nlfiedler commented 8 years ago

Yep, still need it.

hansihe commented 8 years ago

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.

goertzenator commented 8 years ago

I took a quick look at sinking this into the nif_init! macro, but there are a few problems:

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 {}
goertzenator commented 8 years ago

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.

nlfiedler commented 8 years ago

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).

goertzenator commented 8 years ago

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?

hunterboerner commented 8 years ago

@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
hunterboerner commented 8 years ago

Looks like the .dylib isn't being renamed to .so.

goertzenator commented 8 years ago

Thanks. Looks really close now. Do the tests go if you manually rename priv/crates/ruster_unsafe_demo/libruster_unsafe_demo.dylib to .so?

hunterboerner commented 8 years ago

Yes, if I comment out the rm -rf line in plugins.mk and rename the file.

goertzenator commented 8 years ago

Excellent! I just fixed a silly error in the mv. I think it should all go now.

hunterboerner commented 8 years ago

Latest commit works :).

goertzenator commented 8 years ago

Thanks for your help. I will clean that branch up and properly merge it into master when I get a chance.

goertzenator commented 8 years ago

rust.mk will now build for OSX. Closing this.

hansihe commented 8 years ago

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.

hansihe commented 8 years ago

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.

goertzenator commented 8 years ago

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.

hansihe commented 8 years ago

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.

goertzenator commented 8 years ago

Feel free to file bugs against cargo-erlangapp if it can support mix and rustler_mix better. I know little about the elixir ecosystem.