OSX Xcode - Packaging dependencies libmysqlclient.18.dylib - xcode

This may well have been asked before I just couldn't figure out the right term to search.
I'm writing a client-server application to run on an OSX desktop which will talk to a MySQL server on the local network. It seems long-winded to implement a web-services API when basically a bunch of SQL statements will be perfect internally.
I've wrestled with the install procedure for MySQL server on my development machine, ad had to resort to symlinking libmysqlclient.18.dylib into /usr/lib even though i'd put the include path in header search paths.
What I need to know is how do I create a .app file I can send to other machines that will have access to the libmysqlclient.18.dylib file?
I'm used to Windows having installers to do this and a bit new to OSX programming although i've been doing Obj-c for iDevices for 2 years.
Is there a setting which allows the library to be copied into the .app file or do I need to install the mysql connector on each machine - if so, how do I get around the symlink issue, ideally I need it to work from the stock folders.
If this has been answered somewhere else, please point me in the right direction.

At build time the static linker on OS X, ld, writes the shared library identifier of each library that your application links against in to the application binary. At run time the dynamic linker, dyld, attempts to load each shared library from the paths specified in the application binary. You can see this information using otool -L YourApp.app/Contents/MacOS/YourApp.
The fact you needed to symlink libmysqlclient.18.dylib in to /usr/lib suggests that the shared library identifier of libmysqlclient.18.dylib is something like /usr/lib/libmysqlclient.18.dylib. To include the library in your .app bundle in a way that your application will use it rather than looking in /usr/lib you need to:
Change the shared library identifier of libmysqlclient.18.dylib so that dyld will look for the binary relative to your application binary. This is typically done by running install_name_tool -id #executable_path/../Frameworks/libmysqlclient.18.dylib libmysqlclient.18.dylib.
Copy the modified libmysqlclient.18.dylib in to the Frameworks subdirectroy in your application bundle. This is typically done using a Copy Files build phase in your Xcode project.
You should then be able to verify that the install name written in to your application binary is #executable_path/../Frameworks/libmysqlclient.18.dylib rather than /usr/lib/libmysqlclient.18.dylib (using otool -L YourApp.app/Contents/MacOS/YourApp again). If the install name isn't correct then you'll need to ensure that your linker search path is set up to find your modified version of libmysqlclient.18.dylib ahead of any other versions you may have.

Related

Issues with codesigning and notarization for Mac M1

I'm working to correctly distribute a software bundle for Mac ARMS (M1, M2...) which consists in a zip containing a bunch of command line utilities and dynamic libraries built using the command line tools (cc, c++ etc).
So far I've been able to sign all my executable files and my dynamic libraries with codesign using my company Developer ID certificate and to successfully notarize the zip.
Unfortunately when I download the zip using the browser my command line tools show a strange behavior: if I double click on of them from finder I get an error message saying that the identity of the developer can't be confirmed but if I run from the terminal most of the utilities work. I've noticed that if I download the last jdk as .tar.gz the behavior with the java executable is the same so I'm wondering if it's the expected behavior for command line utilities.
Still one of the utilities is not working because it is supposed to load the dynamic libraries I get an error saying that relative paths are not allowed in hardened programs.
My questions are:
Is the behavior described above for command line executable files expected?
Is there a way to allow my program that loads dynamic library to work by loading dynamic libraries as it used to do with our unsigned bundles for Intel Macs?
Does anyone knows if it's possible to notarize and distribute such a bundle in .tar.gz format rather than zip?
Thanks!
For macOS notarized software that means the executable is going to have the hard-coded path to the library and won’t work with a relative path. Usually that means setting RPATH to the hardpath
/Applications/myapp.app/Contents/Frameworks/
and aliasing your binaries from
/Applications/myapp.app/Contents/MacOS
But that is just the most common arrangement.
The hard-coded path is part of the “hardened runtime” which is a requirement to pass apple notary, an anti-malware scanner. Changing the assigned RPATH with otool is possible but invalidates the code signature, blocking execution on machines with default security without code signing at least ad hoc.
See
https://wiki.lazarus.freepascal.org/Code_Signing_for_macOS
Launching the executable directly from terminal does not run thru launchservices the way it does when you launch in finder. Launchservices begins by checking the signature against the ticket and checking the ticket, so a bare executable will be missing that info.
Thanks to the suggestions of Richard Barber I've finally understood how to correctly code-sing, notarize and deploy our bundles on Mac with hardened runtimes.
I'm leaving the steps I've taken below for future reference.
Here are the steps I needed to run:
Made sure all the dynamic executable files and libraries have referenced their dependencies without using relative paths. The relative paths may be substituted with macros like #rpath using install_name_tool
Code-singed all executable files and all the dynamic libraries suing the codesign tool with a valid Apple Distribution certificate and developer/organization key
Once signed put everything in a ZIP and sent for notarization using xcrun notarytool submit command
If the notarization succeeds the contents of the ZIP can be extracted and put in a .tar.gz without losing the validity
Once the tar.gz is downloaded on a testing machine our command line tools can be correctly used by the terminal. As suggested by Richard Barber they can't be run from Finder, but even the JDK in tar.gz format shows the same behavior, so happy with that.

OSX: start app with runtime-dependent dylibs

OSX 10.10 Yosemite.
My application depends on Intel IPP.
At compile time it depends on 2 dylibs, but these depend from other dylibs, which are loaded at runtime (and not displayed in otool -L) . When starting my application does not find these libraries.
I do not understand how can I specify for my app (or for the compile time dependent dylibs) a folder to search a path for runtime dylibs.
As far as I can understand, it is necessary to use rpath. But what exactly should be done? How to set runtime search path? Do I need to set a 'rpath' for the executable file or for the dylibs?
I think you will have to use install_name_tool command to add the dylib.
Don't think you can setup a folder that can magically load all the dylib in it. It's against the purpose of code signing and security.

mac app requires newer version of sqlite but uses the old one

Trying to run / debug an app on mac (Mavericks), that has to use sqlite 3.8.6.
I have the .h and .c files in the project. I have the dylib added as a build resource
LIBS += sqlite3/libsqlite3.0.dylib
But I also must place the dylib somewhere and tell the program at run-time to use this version.
There is a SQLite version 3.7.13 installed on the system (in /usr/lib). It seems to be used preferentially. If I had admin rights (which I don't) I could move it to a different location... But the user system may have it in the default location so that would be useless.
I have tried to place MY sqlite3 in a place that will be used preferentially - like in myapp.app/Contents/Frameworks or myapp.app/Contents/MacOs... also tried to change the dependency with install_name_tool... no success.
Checking the dependencies with otool -L shows a dependency on sqlite3.0.dylib in /usr/local/lib (which does not contain any sqlite3)... even after running install_name_tool it still shows the same. Perhaps I am doing it wrong...
install_name_tool -id #executable_path/Frameworks/libsqlite3.0.dylib myapp.app/Contents/Frameworks/libsqlite3.0.dylib
install_name_tool -change myapp.app/Contents/Frameworks/libsqlite3.0.dylib #executable_path/Frameworks/libsqlite3.0.dylib myapp.app/Contents/Frameworks/mylib.dylib
install_name_tool -change myapp.app/Contents/Frameworks/libsqlite3.0.dylib #executable_path/Frameworks/libsqlite3.0.dylib myapp.app/Contents/MacOs/myapp
I am getting an SQL error that is caused by having the wrong (older) version of sqlite3, which does not support certain required features.
How can I force the app to see the version I added ?
Update: I added the c file and removed the dylib as a dependency...
I got the error no such module: fts4
I added the following in the .c file (from http://www.sqlite.org/fts3.html) - as suggested in comments below
#define SQLITE_ENABLE_FTS4
#define SQLITE_ENABLE_FTS4_PARENTHESIS
Adding the same in windows and linux, the effect is double the size of the library + sqlite3. And queries on a database run significantly slower (I actually thought they were not even performed).
If this is the only option I have on mac, I will have to use it... I am either stuck with very slow build, very large libs, and VERY SLOW QUERIES, or ... there must still be an option to use the sqlite3.dylib without building it into the lib I am creating.
You can just add the original (Amalgamation) files sqlite3.c and sqlite3.h (look for version 3.8.6) to your Xcode project. That's basically it.
If you need to change/add some compile options
you can do that at the top in sqlite3.c.
Here an example to activate FTS3/FTS4:
#define SQLITE_ENABLE_FTS4
All the compile options are here: http://www.sqlite.org/compile.html

Trace dylib loading on Mac OSX

I'm trying to build a Qt-based application on Mac OSX, and something in my application bundle is pulling in a Qt library from /Library rather than from the application bundle.
I've done this successfully in the past, so I know about using install_name_tool to link applications and libraries to the bundle versions of libraries. I've done this, but I must be missing something. I've tried setting DYLD_PRINT_LIBRARIES, but I'm not really sure how this helps: I can see which Qt library is being pulled in from /Library first (QtXml), but I don't know which file in the bundle is pulling in this library.
Is there some trick to tracing back which file is loading a particular library?
Use otool utility to see what libraries are used by your app and where the app expects to find them:
otool -L yourApp.app/Contents/MacOS/yourApp

USB GCC Development Environment with Libraries

I'm trying to get something of an environment on a usb stick to develop C++ code in. I plan to use other computers, most of the time linux, to work on this from a command line using g++ and make.
The problem is I need to use some libraries, like Lua and OpenGL, which the computers don't have. I cannot add them to the normal directories, I do not have root on these computers. Most of the solutions I've found involve putting things in /usr/lib/ and the like, but I cannot do that. I've also attempted adding options like '-L/media//lib', which is where they are kept, and it didn't work. When compiling, I get the same errors I got when first switching to an OS with the libraries not installed.
Is there somewhere on the computer outside of /usr/ I can put them, or a way to make gcc 'see' them?
You need more than the libraries to be able to compile code utilizing those libraries. (I'm assuming Linux here, things might be slightly different on e.g. OSX,BSDs,Cygwin,Mingw..)
Libraries
For development you need these 3 things when your code uses a library:
The library header files, .h files
The library development files, libXXX.so or libXXX.a typically
The library runtime files , libXXX.so.Y where Y is a version number. These are not needed if you statically link in the library.
You seem to be missing the header files (?) Add them to your usb stick, say under /media/include
Development
Use (e.g.) the compiler flag -I/media/include when compiling source code to refer to a non-standard location of header files.
Use the compiler/linker flag -L/media/lib to refer to non-standard location of libraries.
You might be missing the first step.
Running
For dynamically linked libraries, the system will load those only from default locations, typically /lib/ , /usr/lib/
Learn the ldd tool to help debug this step.
You need to tell the system where to load additional libraries when you're running a program, here's 3 alternatives:
Systemwide: Edit /etc/ld.so.conf and add /media/libs there. Run ldconfig -a afterwards.
Local, to the current shell only. set the LD_LIBRARY_PATH environment variable to refer to /media/lib, run export LD_LIBRARY_PATH=/media/lib
Executable: Hardcode the non-standard library path in the executable. You add this to the linking step when creating your executable: -Wl,-rpath,/media/lib
Etc.
There could be other reasons things are not working out, if so,
show us the output of ls -l /media/libs , and where you put the library header files, the command line you use to compile/link, and the exact errors you get.
Missing the headers and/or development libraries (for dynamic libraries there is usually a symlink from a libXXX.so to a libXXX.so.Y , the linker needs the libXXX.so , it will not look directly at libXXX.so.Y)
using libraries not compatible with your current OS/architecture. (libraries compiled on one linux distro is often not compatible with another distro, or even another minor version of the same distro)
using an usb stick with a FAT32 filesystem, you'll get in trouble with symlinks..

Resources