DEV Community

Pavel Evstigneev
Pavel Evstigneev

Posted on

Making portable binary for MacOS

Let’s say we want to take some binary and prepare it for distribution (unsigned), here is how we can make it portable with example of psql

Copy executable file

# cp /Applications/Postgres.app/Contents/Versions/latest/bin/psql .

Check linked libraries

# otool -L psql
psql:
/Applications/Postgres.app/Contents/Versions/13/lib/libpq.5.dylib (compatibility version 5.0.0, current version 5.13.0)
/usr/lib/libedit.3.dylib (compatibility version 2.0.0, current version 3.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.0.0)

We can see psql has dependency on libpq.5.dylib

Copy required dylib’s

# cp /Applications/Postgres.app/Contents/Versions/latest/lib/libpq.5.13.dylib .

Check dependencies of libpq.5.13.dylib

# otool -L libpq.5.13.dylib
libpq.5.13.dylib:
/Applications/Postgres.app/Contents/Versions/13/lib/libpq.5.dylib (compatibility version 5.0.0, current version 5.13.0)
/Applications/Postgres.app/Contents/Versions/13/lib/libssl.1.1.dylib (compatibility version 1.1.0, current version 1.1.0)
/Applications/Postgres.app/Contents/Versions/13/lib/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 1281.0.0)

Copy libssl.1.1.dylib, libcrypto.1.1.dylib and their dependencies (if any)

# ls
libcrypto.1.1.dylib
libssl.1.1.dylib
libpq.5.13.dylib
psql

Use install_name_tool to change dependencies paths to @loader_path/....

More details about @loader_path

install_name_tool -change /Applications/Postgres.app/Contents/Versions/13/lib/libssl.1.1.dylib @loader_path/libssl.1.1.dylib ./libpq.5.13.dylib

install_name_tool -change /Applications/Postgres.app/Contents/Versions/13/lib/libcrypto.1.1.dylib @loader_path/libcrypto.1.1.dylib ./libpq.5.13.dylib

install_name_tool -change /Applications/Postgres.app/Contents/Versions/13/lib/libcrypto.1.1.dylib @loader_path/libcrypto.1.1.dylib ./libssl.1.1.dylib

install_name_tool -change /Applications/Postgres.app/Contents/Versions/13/lib/libpq.5.dylib @loader_path/libpq.5.13.dylib ./psql

Try to run psql

If you run this on Macos Catalina, it will be killed by system

# ./psql
[1]    2490 killed     ./psql

It happens because those binaries was signed but modified them, and signature check started to fail

Let’s remove code signing

codesign --remove-signature *

If binary is not signed we may need to remove quarantine flag

xattr -d com.apple.quarantine *

Try again

# ./psql
psql (13.0, server 10.14)
Type "help" for help.
myname=#

It works 👏


I use this technique in Postbird.app - Free Cross-platform Desktop Client for PostgreSQL

Discussion (0)