Bug #105370 mysql_config --libs should not return -lssl and -lcrypto
Submitted: 28 Oct 2021 21:03 Modified: 16 Mar 2022 15:26
Reporter: Håkon Hægland Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S3 (Non-critical)
Version:8.0.26 OS:MacOS
Assigned to: CPU Architecture:Any

[28 Oct 2021 21:03] Håkon Hægland
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"
[16 Mar 2022 15:26] MySQL Verification Team
Hello,

Thank you for the report .
This is not our bug, since the system can not find a function from the standard C library hence, nothing to do with MySQL.
Also, you are using non-standard invocation of C compiler. Please use either clang or llvm. Thanks.

Regards,
Ashwini Patil