Repository: rust
Issue: rustc OSX LC_LOAD_DYLIB paths are broken
Labels: A-linkage,O-macos,C-bug

I've noticed that the `/usr/local/bin/rustc` has several dylib load commands for various rust libraries which have incorrect/nonexistent paths prefixed to them.

There are two points I'd like to bring up, the first being much more serious.
## Bad Paths

In my setup various tools all report that `/usr/local/bin/rustc` loads/requires the following dynamic libraries:

```
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_driver-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_trans-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_privacy-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_borrowck-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_resolve-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_lint-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_typeck-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libflate-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_data_structures-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libarena-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libgraphviz-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libgetopts-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librbml-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_back-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libsyntax-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libserialize-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libterm-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/liblog-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libfmt_macros-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_llvm-198068b3.dylib
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libstd-198068b3.dylib
/usr/lib/libSystem.B.dylib
/usr/lib/libedit.3.dylib
/usr/lib/libc++.1.dylib
```

However, most of these (the rust libs) appear to be an artifact from the initial compilation build (on a side note, non-absolute paths in OSX typically should have an `@rpath` or `@install_path` prefixed to the path, etc.) .  If you run:

`DYLD_PRINT_LIBRARIES=true /usr/local/bin/rustc --version`

you will notice all of the libraries actually get bound to `/usr/local/lib/<name of dylib>`.  This only accidentally works, because `dyld`'s default library search path(s) are:

```
$(HOME)/lib:/usr/local/lib:/lib:/usr/lib
```

and when interpreting a binary if `dyld` fails to find a library at the specified `LC_LOAD_DYLIB` path, it then takes the basename of the library with the bad path, e.g.:

```
x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libstd-198068b3.dylib -> libstd-198068b3.dylib
```

and looks for that dynamic library in the default path list; in our case it just so happens the libraries were installed to `/usr/local/lib`, so it finds them and runs as normal.  If they were installed to a nonstandard path, `/usr/local/bin/rustc` would fail to run with something like:

```
dyld: Library not loaded: x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libstd-198068b3.dylib
  Referenced from: /usr/local/bin/rustc
  Reason: image not found
Trace/BPT trap: 5
```

You can verify this by moving `/usr/local/lib/libstd-198068b3.dylib` somewhere else (don't do this unless you know how to undue it), or by manually editing the basename of the imported libraries in the `rustc` binary (don't do this either unless you know how to undo it); either case will fail with an error similar to the above.

Therefore `/usr/local/bin/rustc` is only accidentally running correctly on OSX as of this writing.

If `/usr/local/lib/` is the preferred location for rust libraries (and why not), then I _highly_ suggest outputting `LC_LOAD_DYLIB` paths like `/usr/local/lib/libstd-198068b3.dylib`, etc.

If you want this dynamic or configurable, then I suggest using `@rpath` although this adds more complexity; more information can be found [at the Apple official documentation](https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/RunpathDependentLibraries.html).
## Too Many Libraries

This is a less serious issue, but I believe most of the libraries printed above are actually not required to run `rustc` on OSX.  Please correct me if I'm wrong, but it looks like the only imports in `rustc` are:

```
2038 __ZN4main20h62bf81b281987584efdE (8) ~> x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/librustc_driver-198068b3.dylib
2040 __ZN2rt10lang_start20hd654f015947477d622wE (8) ~> x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libstd-198068b3.dylib
2048 _rust_stack_exhausted (8) ~> x86_64-apple-darwin/stage1/lib/rustlib/x86_64-apple-darwin/lib/libstd-198068b3.dylib
2050 _exit (8) ~> /usr/lib/libSystem.B.dylib
2028 dyld_stub_binder (8) -> /usr/lib/libSystem.B.dylib
```

Hence, the minimal set of dynamic libraries required is:

```
/usr/local/lib/librustc_driver-198068b3.dylib
/usr/local/lib/libstd-198068b3.dylib
/usr/lib/libSystem.B.dylib
```

which I believe closely matches the library dependencies for the GNU/Linux `rustc` distribution.