I'm observing different linking behaviour between two machines when compiling a binary.
Each has the same GHC (7.8.3), same code, same flags (-Wall -O2), same libgmp (installed by Homebrew on each):
machine-one$ otool -L my-binary
my-binary:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
machine-two$ otool -L my-binary
my-binary:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
/usr/local/lib/libgmp.10.dylib (compatibility version 13.0.0, current version 13.0.0)
I can't for the life of me figure out why libgmp is linked dynamically on the second machine.
In terms of differences I've been able to recognize: GHC has been installed via the binary distribution for OS X on the first machine and Homebrew on the second. For C compilers, we have:
machine-one$ cc --version
Apple LLVM version 6.0 (clang-600.0.51) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
machine-two$ cc --version
Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
What typically determines the linking behaviour, and how can I enforce one linking method or the other?
EDIT: I've observed the same behaviour happening with zlib on yet another machine, so it's not a GMP-specific issue.
EDIT: I've plucked ghc --info from each of the machines, here they are for machine one and machine two. And here's the diff between the two as well.
EDIT: I've reinstalled ghc on machine two via the distribution binary, and sure enough libgmp is not dynamically linked when I recompile my binary. So it seems like this is related to installing GHC via Homebrew.
Still quite interested in what's going on exactly.
The crucial difference is that machine #2 has /usr/local/lib in the linker path, and is using brew's linker (/usr/local/Library/ENV/4.3/ld). ghc still uses an external linker, even if it isn't using the C backend for code generation, so you can combine Haskell code with code written in other languages (crucial for Haskell's many FFI bindings to third-party libraries). So you should really be asking the brew people why things get linked differently. It's not actually a ghc issue.
Related
I was checking some dependencies with otool -L on a dylib I just built, and got the following system dependencies:
/System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate (compatibility version 1.0.0, current version 4.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.0.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1853.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1200.3.0)
The library is working fine on my system (macOS 12.0.1 on a macbook air m1) but to my great surprise when I tried to check those 4 libraries, they seems to be absent from my system.
/usr/lib does not contain libc++.1.dylib and libSystem.B.dylib, and /System/Library/Frameworks seems to contain mostly empty structures for Accelerate and CoreFoundation frameworks, without the libraries themselves. And yet my dylib is perfectly working, which I cannot explain.
When I check an older system such as macOS 10.14 I can see those 4 libraries and frameworks where expected.
Did something change recently in macOS that somehow hides those system libraries or silently route them elsewhere ? How/where can I see them ?
The reason is explained here: https://developer.apple.com/forums/thread/655588
Since Big Sur, it somehow all became virtual. I still don't understand how it works though, but it works...
This is my first time creating an installer for an application and I need some advice.
This application depends on A.dylib, and A.dylib depends on two other libraries: libstdc++.6.dylib and libgomp.1.dylib which all come from the gcc folder. When I do otool -L on A.dylib, this is what I get :
A.dylib (compatibility version 0.0.0, current version 0.0.0)
/opt/homebrew/opt/gcc/lib/gcc/10/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.28.0)
/opt/homebrew/opt/gcc/lib/gcc/10/libgomp.1.dylib (compatibility version 2.0.0, current version 2.0.0)
Which means that if these two libraries aren't in there, the application won't launch at all. So my problem is with the installer, am I supposed to install libstdc++.6.dylib and libgomp.1.dylib in /opt/homebrew/opt/gcc/lib/gcc/10/ for the user? Even if they don't have a gcc installed there, or at all?
Another option is to install the libraries under say /Library/Application Support/, but then this would mean that the path A.dylib is linked to won't be correct anymore. How do I change the linking path automatically after I install those libraries? What is the best way to go beyond this?
My project is compiled with 10.6SDK and selected 10.5 as Deployment Target. When I run the binary in 10.5 leopard system it gives me
Symbol not found: __ZNKSt13bad_exception4whatEV
Referenced from: ......
Expected in: /usr/lib/libstdc++.6.dylib
Sometimes ago I got the same problem and I closed to use a boost header to make a solution but it was temporary solution. Why this happen? If this symbol is not in 10.5 system, why it compiles without problem?
I can't even find which library call this symbol (probably boost but where?)
Edit:
I found the guilty. thread.o compiled file call __ZNKSt13bad_exception4whatEV this symbol. I had updated boost library from 1.46 to 1.53. Before I had the same problem and I had changed:
#include <boost/thread.hpp>
to
#include <boost/thread/thread.hpp>
and the problem was gone. Now when I updated boost to 1.53, this is calling again.
I compiled boost with macports or with b2.
otool -L bin.v2/libs/thread/build/darwin-4.2.1/release/address-model-32_64/macosx-version-min-10.4/macosx-version-10.8/threading-multi/libboost_thread.dylib
bin.v2/libs/thread/build/darwin-4.2.1/release/address-model-32_64/macosx-version-min-10.4/macosx-version-10.8/threading-multi/libboost_thread.dylib:
libboost_thread.dylib (compatibility version 0.0.0, current version 0.0.0)
libboost_system.dylib (compatibility version 0.0.0, current version 0.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 still see /usr/lib/libstdc++.6.dylib. That means it doesn't compatible with 10.5.
I also looked a solution for static link with libstdc++ but I cound't find it.
I am still looking a solution for it.
Edit2:
I think I give up. I don't have more time for this ridiculous situation. I don't understand why Apple don't supply a updated libstdc++ for 10.5 leopard system. There are so many problem with libstdc++ in 10.5.
The main question why Xcode did NOT tell me this binary is not compatible with 10.5 system?
Windows is much more well about backward compatibility. Now, I can even compile for xp sp3.
I use always staticaly link in Windows but in Apple this is imposible.
At this moment I have learnt that if I want to use c++11 features, I have to compile for 10.7 system. Not even for 10.6 system too. But in Professional Audio so many people use still 10.6 system. I have to wait to use c++11 because of Apple's non static link situation or Aplle's backward compatibility approach.
Yes, I am little bit angry!
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?
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.