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 . 
Enter fullscreen mode Exit fullscreen mode

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) 
Enter fullscreen mode Exit fullscreen mode

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 . 
Enter fullscreen mode Exit fullscreen mode

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) 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

Try to run psql

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

# ./psql [1] 2490 killed ./psql 
Enter fullscreen mode Exit fullscreen mode

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

Let’s remove code signing

codesign --remove-signature * 
Enter fullscreen mode Exit fullscreen mode

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

xattr -d com.apple.quarantine * 
Enter fullscreen mode Exit fullscreen mode

Try again

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

It works 👏


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

Top comments (0)