I'm building qt 5 from source. I'm wondering what is the easiest way to copy-paste qt binaries under MacOS. If you run otool on any of the qt frameworks you'll see that all the dependencies are using absolute paths:
bash-3.2$ otool -L QtWidgets
QtWidgets:
/Users/../Qt/qt5/qtbase/lib/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.1.0, current version 5.1.1)
/Users/../Qt/qt5/qtbase/lib/QtGui.framework/Versions/5/QtGui (compatibility version 5.1.0, current version 5.1.1)
/Users/../Qt/qt5/qtbase/lib/QtCore.framework/Versions/5/QtCore (compatibility version 5.1.0, current version 5.1.1)
/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 155.0.0)
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 19.0.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5)
/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 65.1.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.18.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 945.16.0)
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 45.0.0)
/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1187.37.0)
When I copy qt binaries and link my application against that copy, it works but some dependent frameworks are taken from the old place. The things become even worse when I try to move the binaries to another machine. I know that the problems can be fixed using install_name_tool but it's a lot of error-prone manual work. I'm wondering if there is a script which could help me in that?
After a long search on the Internet. I discovered that Qt Installer Framework has necessary code to patch relocated Qt binaries under Mac OSX. There was small problem to run that code, it's written in C++ that was not that easy to compile since it depends on Qt4 while I'm using Qt5.1. Fortunately, it turned out that all the operations are available via command line.
To use that commands you need any installer created with Qt Installer Framework (Qt binary installer for Mac OSX is good enough) and to use the command below:
./qt-mac-opensource-5.1.0-clang-offline.app/Contents/MacOS/qt-mac-opensource-5.1.0-clang-offline --runoperation "QtPatch" "mac"
"/Path/to/Qt/binaries/which/need/to/be/patched" "qt5"
========================================
Operation was successfully performed.
In case you get an error message which says "qmake is not a program" or something like that try to chmod qmake:
chmod 777 qmake
Note: this works with any QtIFW installer. Play around with prebuilt version of QtIFW
OK, that's it, that's the most straight forward way I found so far.
If you are building QT5 from source anyways then static linking will solve some of your headaches.
The original link listed broke.
To build QT statically add -static to the arguments when you run ./configure e.g.
./configure -prefix /Developer/qt -qt-zlib -qt-libpng -qt-libjpeg -universal -sdk /Developer/SDKs/MacOSX10.4u.sdk -static -release
Compile with: make sub-src
Install with: sudo make install
Related
I built an audio plugin. I target .app and .component.
I dynamically link against a brew-installed library, libfluidsynth.
I copied libfluidsynth into the .app / .component.
I used install_name_tool to re-link the binary to point to the bundled libfluidsynth.
libfluidsynth depends on glib, gthread, intl.
I copied those libraries into the bundle, re-linked libfluidsynth to prefer the bundled copy.
I also did the same for those libraries and their dependencies.
Here's a quick peek at what that looks like:
ls /Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks
libfluidsynth.1.7.1.dylib
libglib-2.0.0.dylib
libgthread-2.0.0.dylib
libintl.8.dylib
libpcre.1.dylib
otool -L \
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/MacOS/juicysfplugin \
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/* \
| grep -vE '\t(/System/Library|/usr/lib)'
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/MacOS/juicysfplugin:
#executable_path/../Frameworks/libfluidsynth.1.7.1.dylib (compatibility version 1.0.0, current version 1.7.1)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libfluidsynth.1.7.1.dylib:
#loader_path/../Frameworks/libfluidsynth.1.dylib (compatibility version 1.0.0, current version 1.7.1)
#loader_path/../Frameworks/libgthread-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libglib-2.0.0.dylib:
#loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
#loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libgthread-2.0.0.dylib:
#loader_path/../Frameworks/libgthread-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
#loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libintl.8.dylib:
#loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/git/juicysfplugin/Builds/MacOSX/build/Release/juicysfplugin.app/Contents/Frameworks/libpcre.1.dylib:
#loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
This worked perfectly for .app. Here, look at the file opens (opensnoop | grep 'dylib'):
EXECNAME PATH
juicysfplugin juicysfplugin.app/Contents/MacOS/../Frameworks/libfluidsynth.1.7.1.dylib
juicysfplugin juicysfplugin.app/Contents/MacOS/../Frameworks/../Frameworks/libgthread-2.0.0.dylib
juicysfplugin juicysfplugin.app/Contents/MacOS/../Frameworks/../Frameworks/libglib-2.0.0.dylib
juicysfplugin juicysfplugin.app/Contents/MacOS/../Frameworks/../Frameworks/libintl.8.dylib
juicysfplugin juicysfplugin.app/Contents/MacOS/../Frameworks/../Frameworks/../Frameworks/libpcre.1.dylib
The .app only looks for dylibs inside its bundled Frameworks folder. Perfect.
Then I did the same copies and re-links upon my .component target. This did not work.
I load the .component into an audio plugin host, and check the file opens:
EXECNAME PATH
Plugin Host /Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/MacOS/juicysfplugin
Plugin Host /usr/local/lib/libfluidsynth.1.7.1.dylib
Plugin Host /usr/local/opt/glib/lib/libgthread-2.0.0.dylib
Plugin Host /usr/local/opt/glib/lib/libglib-2.0.0.dylib
Plugin Host /usr/local/opt/gettext/lib/libintl.8.dylib
Plugin Host /usr/local/opt/pcre/lib/libpcre.1.dylib
It's looking for libraries under /usr/local. Why? As a sanity-check, I used otool to confirm that I had indeed linked correctly:
otool -L \
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/MacOS/juicysfplugin \
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/* \
| grep -vE '\t(/System/Library|/usr/lib)'
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/MacOS/juicysfplugin:
#executable_path/../Frameworks/libfluidsynth.1.7.1.dylib (compatibility version 1.0.0, current version 1.7.1)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libfluidsynth.1.7.1.dylib:
#loader_path/../Frameworks/libfluidsynth.1.dylib (compatibility version 1.0.0, current version 1.7.1)
#loader_path/../Frameworks/libgthread-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libglib-2.0.0.dylib:
#loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
#loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libgthread-2.0.0.dylib:
#loader_path/../Frameworks/libgthread-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libglib-2.0.0.dylib (compatibility version 5401.0.0, current version 5401.3.0)
#loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
#loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libintl.8.dylib:
#loader_path/../Frameworks/libintl.8.dylib (compatibility version 10.0.0, current version 10.5.0)
/Users/me/Library/Audio/Plug-Ins/Components/juicysfplugin.component/Contents/Frameworks/libpcre.1.dylib:
#loader_path/../Frameworks/libpcre.1.dylib (compatibility version 4.0.0, current version 4.9.0)
I thought I linked it correctly. I used exactly the same script (it's automated and parameterised). What am I doing wrong? How did the audio plugin host know to lookup dependencies under /usr/local? Why were my library links ignored?
I've released the binaries to: https://github.com/Birch-san/juicysfplugin/releases/tag/1.0.1
My relinking script is here: https://github.com/Birch-san/juicysfplugin/blob/master/Builds/MacOSX/relink-build-for-distribution.sh
The main difference between how the .app and .component targets are used is:
.app is standalone
.component is an Audio Unit plugin, that you load into a DAW / audio plugin host.
So, perhaps the runtime dependency resolution is different when a parent process is responsible for loading our executable?
Okay, I got it working.
macOS load-time linking is documented at man dyld.
The problem is that I told my binary to look for libraries relative to #executable_path.
This works fine for .app, because the .app's binary is the executable.
But for my .vst and .component plugins, the binary is loaded into a different executable: the audio plugin host.
So, if we want to lookup a library relative to our binary (juicysfplugin.component/Contents/MacOS/juicysfplugin), we need to use #loader_path, not #executable_path.
Now, onto the other mysteries… why did the load-time linker ignore my install path (#executable_path/../Frameworks/libfluidsynth.1.7.1.dylib), and instead look for find fluidsynth under /usr/local/lib/libfluidsynth.1.7.1.dylib?
It's because of DYLD_FALLBACK_LIBRARY_PATH!
It is used as the default location for libraries not found in their install path. By default, it is set to $(HOME)/lib:/usr/local/lib:/lib:/usr/lib.
I believe that it failed to find the library in the install path. It then looked for that leaf file name — libfluidsynth.1.7.1.dylib — under a few directories, including /usr/local/lib (which succeded).
Why didn't I see the failed file lookups in opensnoop? Probably it uses a different syscall than open/open_nocancel/open_extended. For example, running stat on a file does not show up in opensnoop.
It's also possible that the load-time linking is done by a dyld process. SIP would disallow attaching DTrace to this process.
I am trying to build a minimal easily transportable Ruby without relying on external projects, just for my own learning process.
I am using otool -L ruby to determine what libraries the Ruby binary is dynamically linking against as I am trying to minimize it.
Yesterday when i built Ruby it only dynamically linked against 3 libraries, however today when i build Ruby it is linking against 13. I have no idea what has changed between yesterday and today but I am thoroughly confused -- especially as many of the libraries it is linking against existed prior to yesterday's compilation.
On Yesterday's Ruby executable the result of otool -L was:
otool -L ruby
ruby:
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1349.8.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.60.2)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 489.0.0)
But today it is:
otool -L ./ruby
./ruby:
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1349.8.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.60.2)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/opt/openssl/lib/libssl.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.8)
/usr/lib/libffi.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/opt/gdbm/lib/libgdbm.4.dylib (compatibility version 5.0.0, current version 5.0.0)
/usr/lib/libutil.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libedit.3.dylib (compatibility version 2.0.0, current version 3.0.0)
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 489.0.0)
Does anyone know what is going on?
I am compiling Ruby 2.4.2 like so:
X="-arch i386 -mmacosx-version-min=10.5"
CFLAGS="$X" CXXFLAGS="$X" LDFLAGS="$X" ./configure --prefix=/tmp/ruby-deploy --with-openssl-dir=$(brew --prefix openssl) --disable-install-doc --without-gmp
The answer to this was that I had also run:
CFLAGS="$X" CXXFLAGS="$X" LDFLAGS="$X" ./configure --prefix=/tmp/ruby-deploy --with-openssl-dir=$(brew --prefix openssl) --with-static-linked-ext --disable-install-doc --without-gmp
at one point -- note the --with-static-linked-ext. This resulted in the other dynamically linked libs.
However because i had subsequently run ./configure again WITHOUT that option i assumed it would have reset the configuration, but it didn't.
I discovered the problem by wiping out the Ruby source folder and re-fetching from github. Running the initial ./configure (excluding the --with-static-linked-ext resolved the issue!
I'm building an application using Qt5.1.1 on a Mac. I'm using packages to create an installer. I have it set up so that the installer installs the .app file and all of the libraries into a folder in /Applications/. The problem is when I install the application it is not looking where I want it to look for the libraries.
An otool -L shows this:
esu:
libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)
/Users/ken/Qt5.1.1/5.1.1/clang_64/lib/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.1.0, current version 5.1.1)
/Users/ken/Qt5.1.1/5.1.1/clang_64/lib/QtGui.framework/Versions/5/QtGui (compatibility version 5.1.0, current version 5.1.1)
/Users/ken/Qt5.1.1/5.1.1/clang_64/lib/QtCore.framework/Versions/5/QtCore (compatibility version 5.1.0, current version 5.1.1)
/Users/ken/Qt5.1.1/5.1.1/clang_64/lib/QtSerialPort.framework/Versions/5/QtSerialPort (compatibility version 5.1.0, current version 5.1.1)
/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 744.1.0)
/Users/ken/Qt5.1.1/5.1.1/clang_64/lib/QtNetwork.framework/Versions/5/QtNetwork (compatibility version 5.1.0, current version 5.1.1)
/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/AGL.framework/Versions/A/AGL (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)
How can I change where the application is looking for these libraries?
If you run macdeployqt it will change some of them automaticaly (thoses used by Qt) for the other ones, you can do it with install_name_tool
install_name_tool -change oldpath newpath target
I ended up going to where my release esu.app file was and I just used the macdeployqt. Trying to manually set up lib dependencies with install_name_tool was too much of a pain.
This is the command I used:
macdeployqt esu.app -verbose=2 -dmg
So I have a project that I have been working on. Currently I am able to build it in Linux and Windows without too much trouble. I am having some issues on Mac, however.
I'm using Mac OS X 10.7.5, with Qt 4.8.1.
I installed the libraries for QSerialPort since those are not included in Qt4. It looks like they installed correctly. My /qt/4.8.1/gcc/lib folder now includes:
libQtSerialPort_debug.1.0.0.dylib
libQtSerialPort_debug.1.0.dylib
libQtSerialPort_debug.1.dylib
libQtSerialPort_debug.dylib
libQtSerialPort_debug.prl
When I try to build the project this is what I get:
Starting /Users/ken/esu_2.x/esu/esu.app/Contents/MacOS/esu...
dyld: Library not loaded: libQtSerialPort_debug.1.dylib
Referenced from: /Users/ken/esu_2.x/esu/esu.app/Contents/MacOS/esu
Reason: image not found
The program has unexpectedly finished.
/Users/ken/esu_2.x/esu/esu.app/Contents/MacOS/esu exited with code 0
Edit:
apples-MacBook-Pro:macOs ken$ otool -L esu
esu:
libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)
libQtSerialPort_debug.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/Users/ken/QtSDK/Desktop/Qt/4.8.1/gcc/lib/QtGui.framework/Versions/4/QtGui (compatibility version 4.8.0, current version 4.8.1)
/Users/ken/QtSDK/Desktop/Qt/4.8.1/gcc/lib/QtCore.framework/Versions/4/QtCore (compatibility version 4.8.0, current version 4.8.1)
/Users/ken/QtSDK/Desktop/Qt/4.8.1/gcc/lib/QtNetwork.framework/Versions/4/QtNetwork (compatibility version 4.8.0, current version 4.8.1)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1094.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
Moved QtSerialPort libraries to /usr/lib. It works now.
I'm trying to compile a version of convert (one of the ImageMagick tools) for distribution with a Cocoa app I'm writing, and I've mistakenly bundled a version that relies on shared libraries my users don't have (twice, already). Thus, I'm trying to pare down the list. After stripping out everything I didn't need, running otool -L convert gives me the following list:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.4)
/usr/lib/libbz2.1.0.dylib (compatibility version 1.0.0, current version 1.0.5)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.3)
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
and for another tool bundled with the same app, I'm also using:
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.4.0)
Is it safe to assume that any out-of-the-box installation of Leopard or above will have these libraries on board? (More generally, my google-fu has failed me, so if anyone can point me to a resource that would answer these questions for me, I'd be eternally grateful!)
If the library path is /usr/lib, it should be available on a vanilla OS X of the level you're running on (and presumably above). Third-party apps and installers should not be installing into /usr/lib.
Yes, on my Snow Leopard box that has no changes to /usr/lib, all of these libraries exist