How to deploy Qt application on MacOS – part II

In first part of this article I introduced a manual way how to deploy MacOS application. Because doing all these stuff manually was a lot of hand work, Qt introduced small tool called macdeployqt.

This utility looks very good, but also have some drawbacks. As first I will show you how utility works:

macdeployqt Application.app

That’s all ;-). This command should do all the hard work for you. But in some cases it didn’t.

ERROR: no file at "/usr/lib/libboost_iostreams.dylib"
ERROR: no file at "/usr/lib/libboost_filesystem.dylib"
ERROR: no file at "/usr/lib/libboost_system.dylib"
ERROR: no file at "/usr/lib/libboost_thread.dylib"
ERROR: no file at "/usr/lib/libboost_date_time.dylib"
ERROR: no file at "/usr/lib/libboost_regex.dylib"
ERROR: no file at "/usr/lib/libboost_chrono.dylib"
ERROR: no file at "/usr/lib/libyaml-cpp.0.2.dylib"

The problem is that libraries mentioned in the previous list doesn’t has included absolute path. If you inspecit this library, you will se this:

otool -L libboost_regex.dylib
libboost_regex.dylib:
	libboost_regex.dylib (compatibility version 0.0.0, current version 0.0.0)
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)

And this is the problem. Inner path in library is only filename without full path, so when we link library with our executable, our executable also has only relative path. And when macdeployqt try to find this library, automatically try to search in /usr/lib.

One possible solution is copy libraries to /usr/lib. Second solution is update paths in libraries to absolute paths. The third way is fix library linker to include full paths in libraries.

I found out that the simplies way how to fix it is call install_name_tool after library compilation and fix the path (don’t forget to update library paths inside other library paths!)

  install_name_tool -id "$SHL_PATH/boost/lib/libboost_chrono.dylib" $SHL_PATH/boost/lib/libboost_chrono.dylib
  install_name_tool -id "$SHL_PATH/boost/lib/libboost_date_time.dylib" $SHL_PATH/boost/lib/libboost_date_time.dylib
  ...
  install_name_tool -change "libboost_system.dylib" "$SHL_PATH/boost/lib/libboost_system.dylib" $SHL_PATH/boost/lib/libboost_chrono.dylib
  install_name_tool -change "libboost_system.dylib" "$SHL_PATH/boost/lib/libboost_system.dylib" $SHL_PATH/boost/lib/libboost_filesystem.dylib

So, now when we have updated all libraries, we can try to create application bundle again

macdeployqt AtomixDevelopment.app/

And if we did everything correctly, now we should have a working app ;-).

Troubleshooting

In some cases you can get error “Permission defined”, “Bad file descriptor” or other similar errors when using macdeployqt.

ERROR: "install_name_tool: can't open input file: OrmDesigner2.app/Contents/Frameworks//libssl.1.0.0.dylib for writing (Permission denied)
install_name_tool: can't lseek to offset: 0 in file: OrmDesigner2.app/Contents/Frameworks//libssl.1.0.0.dylib for writing (Bad file descriptor)
install_name_tool: can't write new headers in file: OrmDesigner2.app/Contents/Frameworks//libssl.1.0.0.dylib (Bad file descriptor)
install_name_tool: can't close written on input file: OrmDesigner2.app/Contents/Frameworks//libssl.1.0.0.dylib (Bad file descriptor)

The reason is insufficient permissions for modifying copied libraries. Simple execute

sudo macdeployqt

and everything should work ok. Another workaround for this issue is using newer version of Qt. I figured out that on MacOS I wrongly use Qt 4.7.4. When I correct this to version Qt 4.8.2 this issue was solved.

DMG file

If you want to create simply DMG file, simply call macdeployqt with param –dmg. But this dmg doesn’t look so good:

This will need more investigation how to make DMG files nicer ;-).

Notes

  • Everytime you run macdeployqt run it on clean folder. The best way is to call rm -rf Application, compile app and than run macdeployqt

Notes to bug in macdeployqt

The problem is caused by invalid permissions. Copied libraries have the same permissions like in the source location. There are three different solutions:

  1. Use sudo and execute macdeployqt with root permissions
  2. Update external libraries permissions to rw, so also copies will have a correct permissions
  3. Update macdeployqt script. In file shared.cpp on line 91 is method copyFilePrintStatus. Here is a necessary to update copied files permissions to correct rw

In my case the problem was in file liblzma.5.dylib

Frameworks/liblzma.5.dylib is not writable (Permission denied)

Orinal library is located in path:

/usr/local/Cellar/xz/5.0.4/lib

2 comments

Leave a Reply

Your email address will not be published. Required fields are marked *