Description:
On macOS I am not able to link a C program with libmysqlclient.dylib using rpath. For example:
"main.c":
#include <stdio.h>
#include <mysql.h>
#include <stdlib.h>
int main() {
printf("MySQL client version: %s\n", mysql_get_client_info());
return 0;
}
Before I compile the above program I check in the shell:
$ mysql_config --variable=pkglibdir
/usr/local/mysql-8.0.26-macos11-arm64/lib
$ mysql_config_orig --cflags
-I/usr/local/mysql-8.0.26-macos11-arm64/include
$ mysql_config_orig --libs
-L/usr/local/mysql-8.0.26-macos11-arm64/lib -lmysqlclient -lssl -lcrypto -lresolv
Now I compile main.c like this:
$ libdir=$(mysql_config --variable=pkglibdir); \
cc `mysql_config --cflags --libs` -Wl,-rpath,$libdir main.c -o main
Then I try to run the "main" executable:
$ ./main
dyld: Library not loaded: libssl.1.1.dylib
Referenced from: /Users/hakonhaegland/test/main
Reason: image not found
[1] 9667 abort ./main
I check that the libraries exists:
$ ls /usr/local/mysql-8.0.26-macos11-arm64/lib/lib*dylib
/usr/local/mysql-8.0.26-macos11-arm64/lib/libcrypto.1.1.dylib /usr/local/mysql-8.0.26-macos11-arm64/lib/libprotobuf-lite.dylib
/usr/local/mysql-8.0.26-macos11-arm64/lib/libcrypto.dylib /usr/local/mysql-8.0.26-macos11-arm64/lib/libprotobuf.3.11.4.dylib
/usr/local/mysql-8.0.26-macos11-arm64/lib/libmysqlclient.21.dylib /usr/local/mysql-8.0.26-macos11-arm64/lib/libprotobuf.dylib
/usr/local/mysql-8.0.26-macos11-arm64/lib/libmysqlclient.dylib /usr/local/mysql-8.0.26-macos11-arm64/lib/libssl.1.1.dylib
/usr/local/mysql-8.0.26-macos11-arm64/lib/libprotobuf-lite.3.11.4.dylib /usr/local/mysql-8.0.26-macos11-arm64/lib/libssl.dylib
So the libraries libssl.dylib exists in the libdir, but the problem is that its install name (LC_ID_DYLIB) is not prepended with the magic string `@rpath` that allows the library to be loaded using the `rpath` in the "main" executable. This can be confirmed by using "otool":
$ otool -D /usr/local/mysql-8.0.26-macos11-arm64/lib/libssl.dylib
/usr/local/mysql-8.0.26-macos11-arm64/lib/libssl.dylib:
libssl.1.1.dylib
$ otool -L /usr/local/mysql-8.0.26-macos11-arm64/lib/libssl.dylib
/usr/local/mysql-8.0.26-macos11-arm64/lib/libssl.dylib:
libssl.1.1.dylib (compatibility version 1.1.0, current version 1.1.0)
@loader_path/libcrypto.1.1.dylib (compatibility version 1.1.0, current version 1.1.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
whereas libmysqlclient.dylib has the correct install name to be used with rpath:
$ otool -D /usr/local/mysql-8.0.26-macos11-arm64/lib/libmysqlclient.dylib
/usr/local/mysql-8.0.26-macos11-arm64/lib/libmysqlclient.dylib:
@rpath/libmysqlclient.21.dylib
$ otool -L /usr/local/mysql-8.0.26-macos11-arm64/lib/libmysqlclient.dylib
/usr/local/mysql-8.0.26-macos11-arm64/lib/libmysqlclient.dylib:
@rpath/libmysqlclient.21.dylib (compatibility version 21.0.0, current version 21.0.0)
@loader_path/../lib/libssl.1.1.dylib (compatibility version 1.1.0, current version 1.1.0)
@loader_path/../lib/libcrypto.1.1.dylib (compatibility version 1.1.0, current version 1.1.0)
/usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 904.4.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
We also observe from the above output that libmysqlclient.dylib uses the magic "@loader_path" prefix to load libssl.dylib and libcrypto.dylib.
It means that I do not need to specify "-lssl -lcrypto" when I compile "main.cpp", I only need to specify "-lmysqlclient" and when the dynamic loader loads "libmysqlclient.dylib" it will automatically load libssl.dylib and libcrypto.dylib from the "@loader_path" paths relative to the directory where libmysqlclient.dylib is located. I can verify this by recompiling "main.cpp" like this:
$ libdir=$(mysql_config --variable=pkglibdir); \
cc `mysql_config --cflags` -L$libdir -lmysqlclient -Wl,-rpath,$libdir main.c -o main
If I now run the executable "main" it works fine:
$ ./main
MySQL client version: 8.0.26
How to repeat:
See description for how to repeat.
Suggested fix:
I believe "mysql_config --libs" should be patched so that instead of returning:
-L/usr/local/mysql-8.0.26-macos11-arm64/lib -lmysqlclient -lssl -lcrypto -lresolv
it should simply return:
-L/usr/local/mysql-8.0.26-macos11-arm64/lib -lmysqlclient
Here is a patch for "/usr/local/mysql-8.0.26-macos11-arm64/bin/mysql_config" that works for me:
121c121
< libs="$libs -lmysqlclient -lssl -lcrypto -lresolv"
---
> libs="$libs -lmysqlclient"