dynamic library linkining on max mountain-lion - macos

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

Related

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

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

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)

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?

Cannot create dylib for distribution that works on OS X 10.5 (building in 10.6 environment)

I'm trying to distribute cairo (1.10.2) with my application. I can create the necessarily dylibs using Homebrew but they are dependent on versions of other dynamic libraries that aren't present in OS X 10.5 (libfontconfig, libfreetype, and others located primarily in /usr/X11/lib).
I assume to solve this I want it to be using the dylibs in /Developer/SDKs/MacOSX10.5.sdk/usr/X11/lib rather than the libraries in /usr/X11/lib. I've tried anything I could find for targeting cairo against the 10.5 SDK.
Setting MACOSX_DEPLOYMENT_TARGET environment variable to 10.5 (before calling brew or using Homebrew's ENV)
Setting SDKROOT environment variable to "/Developer/SDKs/MacOSX10.5.sdk" (before calling brew or using Homebrew's ENV)
Adding -mmacosx-version-min=10.5 to the CFLAGS, CXXFLAGS, and LDFLAGS in the Homebrew formula for cairo.
Adding -sysroot/-isysroot /Developer/SDKs/MacOSX10.5.sdk to the CFLAGS, CXXFLAGS, and LDFLAGS in the Homebrew formula for cairo.
Adding -I$(SDKROOT)/usr/X11/include and -I$(SDKROOT)/usr/X11R6/include to the CFLAGS and CXXFLAGS in the Homebrew formula for cairo.
Adding -L$(SDKROOT)/usr/X11/lib and -L$(SDKROOT)/usr/X11R6/lib to the LDFLAGS in the Homebrew formula for cairo.
While building cairo it has -I/usr/X11/lib on the gcc commands (with my options tacked on the end) so I imagine it's hitting that first. I'm not sure how to get rid of that so it uses my options. I thought isysroot would make it so the include and library paths were rerooted in the SDK but -isysroot doesn't seem to have any effect.
You should be able to use install_name_tool to change where cairo looks for its libraries. (I have no idea what cairo is. I'm assuming it's a dylib. If not, my confidence in this solution goes down considerably.)
Here's a made-up example that you should be able to adapt.
First, use otool -L to see which libraries cairo is using. In this example I'm working with libopencv_imgproc.2.3.1.dylib, but you'll use your cairo library's file name instead:
$ otool -L libopencv_imgproc.2.3.1.dylib
libopencv_imgproc.2.3.1.dylib:
lib/libopencv_imgproc.2.3.dylib (compatibility version 2.3.0, current version 2.3.1)
lib/libopencv_core.2.3.dylib (compatibility version 2.3.0, current version 2.3.1)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.3)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.11)
Then use install_name_tool -change to change whichever paths you need to change. The first parameter is the current library path, the second is the desired library path, and the third is the library file. I'm telling it to look for libz.1.dylib in /Developer/SDKs/MacOSX10.5.sdk/usr/X11/lib/ instead of /usr/lib:
$ install_name_tool -change /usr/lib/libz.1.dylib /Developer/SDKs/MacOSX10.5.sdk/usr/X11/lib/libz.1.dylib libopencv_imgproc.2.3.1.dylib
Repeat this for every library whose path you need to change. otool -L shows us that the change was made:
$ otool -L libopencv_imgproc.2.3.1.dylib
libopencv_imgproc.2.3.1.dylib:
lib/libopencv_imgproc.2.3.dylib (compatibility version 2.3.0, current version 2.3.1)
lib/libopencv_core.2.3.dylib (compatibility version 2.3.0, current version 2.3.1)
/Developer/SDKs/MacOSX10.5.sdk/usr/X11/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.3)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.11)
In my example (and perhaps in your application) my library expects to find itself somewhere other than my application bundle, so I need to change that as well with install_name_tool -id. I'm copying the library to my application bundle's Frameworks folder so I'm telling it to look there:
$install_name_tool -id #executable_path/../Frameworks/libopencv_imgproc.2.3.1.dylib libopencv_imgproc.2.3.1.dylib
You can put the install_name_tool invocations in a Run Script build phase. If you are copying the library into your application bundle's Frameworks folder, you should prepend the library name with $BUILT_PRODUCTS_DIR/$FRAMEWORKS_FOLDER_PATH/ to ensure that the script can find the library.

Linking to a dynamic library on a Mac with full path

I am linking a (Python extension) library that embeds the Matlab engine with the following command (generated using cmake)
c++ -mmacosx-version-min=10.6 -bundle -headerpad_max_install_names -o library.so library.o /Applications/MATLAB_R2009b.app/bin/maci64/libeng.dylib /Applications/MATLAB_R2009b.app/bin/maci64/libmx.dylib -framework Python
resulting in
$ otool -L library.so
library.so:
#loader_path/libeng.dylib (compatibility version 0.0.0, current version 0.0.0)
#loader_path/libmx.dylib (compatibility version 0.0.0, current version 0.0.0)
/System/Library/Frameworks/Python.framework/Versions/2.6/Python (compatibility version 2.6.0, current version 2.6.1)
/opt/local/lib/gcc44/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.13.0)
/opt/local/lib/gcc44/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 125.0.0)
However, when I try to use the library, I get an error message:
ImportError: dlopen(./library.so, 2): Library not loaded: #loader_path/libmex.dylib
Referenced from: ./library.so
Reason: image not found
I believe the problem stems from the fact that the linker includes the matlab dylib files in the form #loader_path/libeng.dylib rather than using the full path, even though I give the full path to g++. How can I force the linker to use the full path?
I know one solution is to use
export DYLD_LIBRARY_PATH=/Applications/MATLAB_R2009b.app/bin/maci64:$DYLD_LIBRARY_PATH
which is where those library files reside, but I'd like to avoid that as it causes some other problems.
Manually changing the files using install_name_tool
install_name_tool -change "#loader_path/libeng.dylib" "/Applications/MATLAB_R2009b.app/bin/maci64/libeng.dylib" library.so
install_name_tool -change "#loader_path/libmx.dylib" "/Applications/MATLAB_R2009b.app/bin/maci64/libmx.dylib" library.so
I could use this as a temporary fix, but I wonder if there isn't a better solution where the linker is given a setting to use the full paths.
Note that some of the problems with DYLD_LIBRARY_PATH can be prevented by using DYLD_FALLBACK_LIBRARY_PATH instead. This will only be used if the lib cannot be found in the default paths.
Look into the -rpath option to the ld command to control this. You might also be interested in the contents of https://github.com/bimargulies/jni-origin-testbed, which is a demonstration of some relevant technology.
The critical technique here is:
install_name_tool -change libsl2.so "#loader_path/libsl2.so" libsl1.so
You can also use symbolic link !

Resources