Rust and loader paths (#rpath, #loader_path) on OS X - macos

I'm trying to solve a problem with foreign library loading with Rust.
Inputs:
I have an executable rtest and a dylib libcpp2rs.dylib. The library is linked to the executable through FFI:
#[link(name="cpp2rs")]
extern { ... }
My build.rs file (I'm passing an extra argument with libcpp2rs.dylib location):
pub fn main() {
println!("cargo:rustc-link-search=native=./cpplib/bin");
}
And my Cargo.toml file:
[package]
name = "rtest"
version = "0.1.0"
authors = ["astavonin"]
build = "build.rs"
rpath = true
[dependencies]
libc = "0.2.10"
And I use cargo build command for compilation.
Outputs:
otool shows me that library will be loaded by RPATH:
> otool -L rtest
rtest:
#rpath/libcpp2rs.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
But at the same time there is no LC_LPATH section in executable:
> otool -l rtest | grep LC_RPATH
>
And it leads my application to a loading error:
> ./rtest
dyld: Library not loaded: #rpath/libcpp2rs.dylib
Referenced from: /Users/astavonin/projects/Tests/rtest/target/debug/./rtest
Reason: image not found
zsh: trace trap ./rtest
This issue can be fixed by install_name_tool usage, but I prefer do not introduce additional steps into compilation process.
Is it possible (and how) to change loading type from #rpath to #loader_path with cargo configurations/build script?
Is it possible to pass #rpath value to cargo?

After some researches around I've found that the actual problem is libcpp2rs.dylib ID:
> otool -L cpplib/bin/libcpp2rs.dylib
cpplib/bin/libcpp2rs.dylib:
#rpath/libcpp2rs.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.1.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
rustc uses a dylib ID as a reference for linkage type and if you'd like to change linkage type for a library to #loader_path for example, you have to fix dylib ID. It should looks like:
#loader_path/libcpp2rs.dylib (compatibility version 0.0.0, current version 0.0.0)

Related

How to specify rpath for debug builds in meson?

I am trying to port qmake project to meson build system.
Project is a simple Qt GUI application, with no other dependencies.
Application is cross-platform one, it must compile and run on macOS/Linux/Windows.
Right now i'm stuck on mac.
Debug application binary built by ninja/meson unable to load:
mac:~ user$ Projects/qgit/__build__/qgit
dyld: Library not loaded: #rpath/QtCore.framework/Versions/5/QtCore
Referenced from: /Users/eraxillan/Projects/qgit/__build__/qgit
Reason: image not found
Abort trap: 6
Documentation mention two rpath-related parameters:
build_rpath
install_rpath
I've tried both, specifying path to local Qt installation (export DYLD_FRAMEWORK_PATH=/Users/user/Qt/5.12.3/clang_64/lib), but nothing changes:
mac:test user$ otool -L __build__/test
__build__/test:
#rpath/QtCore.framework/Versions/5/QtCore (compatibility version 5.12.0, current version 5.12.3)
#rpath/QtGui.framework/Versions/5/QtGui (compatibility version 5.12.0, current version 5.12.3)
#rpath/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.12.0, current version 5.12.3)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.50.4)
I expected meson changes #rpath to specified, but it don't.
What is my problem, am i doing smth wrong?
P.S. There is a workaround:
export DYLD_FRAMEWORK_PATH=/Users/user/Qt/5.12.3/clang_64/lib
__build__/test
# it now works
P.P.S. meson.build:
project('test', 'cpp', default_options : ['cpp_std=c++11', 'warning_level=3'])
qt5 = import('qt5')
qt5_dep = dependency('qt5', modules : ['Core', 'Gui', 'Widgets'])
incdir = include_directories('src')
prep = qt5.preprocess(
moc_headers : test_headers,
ui_files : test_forms,
qresources : test_resources,
include_directories : incdir,
dependencies: qt5_dep)
...
q5exe = executable('test',
sources : [test_sources, prep],
dependencies : [qt5_dep],
include_directories : incdir,
install : true,
build_rpath : '/Users/user/Qt/5.12.3/clang_64/lib',
#install_rpath : '/Users/user/Qt/5.12.3/clang_64/lib'
)

CMake how to remove the default /usr/lib path when linking a shared library?

This is the current output from the otool -L libtarget.dylib
libA.dylib
libB.dylib
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 307.5.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.60.2)
I was able to remove the libc++.dylib dependence, but I cannot figure out how to remove libSystem.dylib.
Is there a way to remove the default /usr/lib path when linking to a shared library in CMake?
That is gonna be difficult, even the most simple C example links to libSystem.B For instance, if you execute
echo "int main() { return 0; }" | gcc -xc -
followed by
otool -L a.out
it will show you dependency on libSystem.B
a.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.60.2)
An alternative is to use rpath:
install_name_tool -change /usr/lib/libSystem.B.dylib #rpath/libSystem.B.dylib a.out

dynamic library linkining on max mountain-lion

I am trying to link a dynamic library (dylib) on mac mountian-lion. Nothing I try has worked.
$ gcc main.cpp -l/usr/local/lib/libopencv_core.2.4.6.dylib
ld: library not found for -llibopencv_core.2.4.6.dylib
The library exists:
$ ls /usr/local/lib/libopencv_core.2.4.6.dylib
/usr/local/lib/libopencv_core.2.4.6.dylib
I get the same null result using clang.
Using otool to reveal dependencies ...
$ otool -L /usr/local/lib/libopencv_core.2.4.6.dylib
/usr/local/lib/libopencv_core.2.4.6.dylib:
lib/libopencv_core.2.4.dylib (compatibility version 2.4.0, current version 2.4.6)
/System/Library/Frameworks/OpenCL.framework/Versions/A/OpenCL (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 56.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
I am not sure what the problem is, it could be a versioning issue, I do not know.
I am probably missing something simple but essential: can anyone tell me what I am missing?
In order to refer to a library with a filename of:
libMyLib.{a,so,dylib}
using the -l command line option, you use the form:
-lMyLib
So try this:
$ gcc main.cpp -L/usr/local/lib -lopencv_core
(also note that it's normally undesirable to link with a versioned dynamic library most of the time, so I have dropped it from the command line).

How will having a link to libgcc_s.1.dylib from two sources break things?

I am building a binary with MacPorts GCC 4.7.2+universal on a Mac OS X 10.8.3 host running Xcode 4.6.2.
I am targeting the build for Mac OS X 10.5-10.8 hosts by using the compilation flag:
-mmacosx-version-min=10.5
The resulting binary my_first_binary has two links to libgcc_s.1.dylib:
$ otool -L ../bin/my_first_binary
../bin/my_first_binary:
/opt/local/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.17.0)
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1669.0.0)
/opt/local/lib/gcc47/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
The binary is written in C++, is compiled with the MacPorts g++ 4.7.2+universal compiler and has some trouble opening up a file using some C I/O routines.
I make a second binary that targets 10.6-10.8 hosts by changing the compilation flag:
-mmacosx-version-min=10.6
This second binary has only one link to the libgcc_s.1.dylib library:
$ otool -L ../bin/my_second_binary
../bin/my_second_binary:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
/opt/local/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.17.0)
/opt/local/lib/gcc47/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
This second binary works properly and opens files without issues.
My questions are:
What about setting the minimum build version to 10.5 is causing the /usr/lib-variant of libgcc_s.1.dylib to be linked?
Can this cause namespace collisions or other problems with C-based code in my two binaries?
If this is a problem, what can I do to stop or troubleshoot this, while continuing to build to a minimum 10.5 target?

dyld not loaded Reason: image not found libopencv_core.2.4.dylib

I'm still quite new to Objective C and Xcode, but I just finished a small app that uses the openCV libopencv_core.2.4.2.dylib.
When I went to open the final built app on another machine, OS X threw me this error:
Dyld Error Message: Library not loaded: */libopencv_core.2.4.dylib
Referenced from: /Users/USER/Desktop/my
app.app/Contents/MacOS/my app
Reason: image not found
Why is my app looking for 2.4 instead of 2.4.2 here?
What I already checked:
I added a new build phase -> so that libopencv_core.2.4.2.dylib is copied to the app package (via "Copy Bundle Resources" in Xcode) - libopencv_core.2.4.2.dylib now lies in my app.app/Resources
What did I miss? Do I have so set some more library search paths or similar?
What I also did:
install_name_tool -id "#executable_path/../Frameworks/libopencv_core.2.4.2.dylib" libopencv_core.2.4.2.dylib
Copying the dylib to the Frameworks directory doesn't work either:
Library not loaded: #executable_path/../Frameworks/libopencv_core.2.4.2.dylib
Don't know what to do now - the dylib is in the Frameworks directory of my app...
Using otool -L on the binary gives me:
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 19.0.0)
#loader_path/../Frameworks/libopencv_core.2.4.2.dylib (compatibility version 2.4.0, current version 2.4.2)
#loader_path/../Frameworks/libopencv_highgui.2.4.2.dylib (compatibility version 2.4.0, current version 2.4.2)
#loader_path/../Frameworks/libopencv_imgproc.2.4.2.dylib (compatibility version 2.4.0, current version 2.4.2)
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 945.11.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 56.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 744.1.0)
/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData (compatibility version 1.0.0, current version 407.7.0)
/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1187.33.0)
I had the same problem. i keep all .dylib in system root directory usr/lib it working fine. At the run time .o file not get .dylib file path then it gives an error.
I found a better solution: recompiling openCV in Xcode and set the #executable_path/../Frameworks in the build settings, for every .dylib you compile - now the .dylibs themselves always "know where they are".
Since other answers are not clear enough;
Assume your dylib files are located in /usr/local/opt/opencv3/lib
sudo ln -s /usr/local/opt/opencv3/lib/*.dylib /usr/local/lib
will solve this problem. Be aware that /usr/lib is protected by system in MacOS, thus you should use /usr/local/lib.

Resources