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?
Related
I built a simple app using Crystal on a Mac, and it appears to depend upon two libraries (.dylib).
What is the simplest way to distribute that app (would zipping the .dylib(s) along with the executable in a given directory work), or do I have to use a tool like install_name_tool to rewrite the path to the libraries?
In other words, if the required libraries are in the same directory than the executable, will the executable find them or is the path to libraries hard-coded in a Mac application?
otool -L ./bin/hello: yields:
./bin/hello:
/opt/homebrew/opt/bdw-gc/lib/libgc.1.dylib (compatibility version 7.0.0, current version 7.1.0)
/opt/homebrew/opt/libevent/lib/libevent-2.1.7.dylib (compatibility version 8.0.0, current version 8.1.0)
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
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...
I am trying to create a macOS application using Crystal and libui. I am able to compile a crystal executable with all of the required libraries statically, so it can run on any mac (partially static). For some reason, the shard I am using which is called "hedron" (the crystal bindings for libui), I am unable to compile the program using libui.a, like I am compiling my program with libevent.a and libgc.a. I am only able to build successfully with libui.A.dylib.
I have changed the top of bindings file of the shard to #[Link(ldflags: "#{__DIR__}/../../../../vendor/libui.A.dylib")], and I am compiling my program using shards build --release --link-flags="-Lpwd/vendor". In the vendor folder of my project, I have libevent.a, libssl.a, libgc.a, libcrypto.a, and libui.A.dylib. The project compiles ok. Then I run otool -L ./bin/CrystalDistroTest and I get the following output:
./bin/CrystalDistroTest:
#rpath/libui.A.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libpcre.0.dylib (compatibility version 1.0.0, current version 1.1.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
Even when I copy libui.A.dylib into the ./bin directory, it does not start up on other computers. It starts on mine because I have libui.A.dylib in my /usr/local/lib directory. My end goal is to package this into a .app folder for only macOS distribution. Where should I put the libui.A.dylib so my executable can find it?
Figured it out by compiling with shards build --release --link-flags="-rpath #executable_path/../Frameworks -Lpwd/vendor". I just needed to add the -rpath #executable_path/../Frameworks to the linker.
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.
I have the library libmysqlclient.16.dylib, which I need to have on the computer where my application is running, or I will get the following error:
Dyld Error Message: Library not
loaded:
/usr/local/mysql/lib/libmysqlclient_r.16.dylib
Referenced from: /Users/alex/snow
server 3.app/Contents/MacOS/snow
server Reason: image not found
This is very strange, because I linked the binary with this library.
If the same dylib exists on the target computer, but in a different version (for example, Snow Leopard Server), I get an error like the following:
Dyld Error Message: Library not
loaded:
/usr/local/mysql/lib/libmysqlclient_r.16.dylib
Referenced from: /Users/alex/snow
server 3.app/Contents/MacOS/snow
server Reason: no suitable image
found. Did find:
/usr/local/mysql/lib/libmysqlclient_r.16.dylib:
mach-o, but wrong architecture
I'd like to link against this library, but not have to use the local copy of it. Is this possible?
UPDATE - when i try to using install_name_tool i don't have any changes:
bash-3.2# otool -L
libmysqlclient.16.dylib
libmysqlclient.16.dylib:
libmysqlclient.16.dylib
(compatibility version 16.0.0, current
version 16.0.0)
/usr/lib/libSystem.B.dylib
(compatibility version 1.0.0, current
version 123.0.0)
/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) bash-3.2#
install_name_tool -change
libmysqlclient.16.dylib
#executable_path/../Frameworks/libmysqlclient.16.dylib
Usage: install_name_tool [-change old
new] ... [-rpath old new] ...
[-add_rpath new] ... [-delete_rpath
old] ... [-id name] input bash-3.2#
install_name_tool -change
libmysqlclient.16.dylib
#executable_path/../Frameworks/libmysqlclient.16.dylib
libmysqlclient.16.dylib bash-3.2#
otool -L libmysqlclient.16.dylib
libmysqlclient.16.dylib:
libmysqlclient.16.dylib
(compatibility version 16.0.0, current
version 16.0.0)
/usr/lib/libSystem.B.dylib
(compatibility version 1.0.0, current
version 123.0.0)
/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)
SOLUTION
i was add a script into build phase:
install_name_tool -change libmysqlclient.16.dylib #executable_path/../Frameworks/libmysqlclient.16.dylib $CONFIGURATION_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME
this was fixed a libpath for executive product and working fine with lib in bundle.
First, you'll want to make sure that you're copying this library into your application bundle so that it will be available on the user's machine. To do this, add a new Copy Files build phase for your application to copy bundled frameworks. Within the properties of that build phase, make sure that the destination is Frameworks. Drag your library from your project into that build phase to make sure that it is packaged with your application.
You may also need to modify the library itself so that it points to the correct location within the application bundle. In the past, I've done this by making a copy of the library within my project's directory, then using the following command to modify where the library expects to find itself:
install_name_tool -id #executable_path/../Frameworks/libftd2xx.0.1.0.dylib libftd2xx.0.1.0.dylib
In this case, the library being modified was called libftd2xx.0.1.0.dylib.
You can use the command
otool -L [library filename]
to see the path where the library expects itself to be found and determine if this change needs to be made.
Make sure that you change the path on the library within your Xcode project so that you will be linking against this new, modified version of the library residing within your project directory.