Some previously compiled wallets were removed due to being completely outdated... and I only compile them when I really need them.
Still if you're running into serious troubles, feel free to contact me at maciej(no-spam-please)taranienko(dot)pl and we can discuss the terms.
Please note this article is a draft. It may still contain both spellings and syntax/grammar errors. I only pre-release it because a close friend asked me for precise directions.
You have been warned.
As many of you have probably already discovered, compiling an alt-currency wallet on Mac OSX is quite of task.
Even if you come from Linux or other UNIX/UNIX-clone world, you will still likely get caught in a couple traps during the process.
Dependencies first
This one sounds quite obvious, but... it may also be painful. Why? There are couple different package managers which again may provide quite some different results.
My manager of choice will be Homebrew and the rest of this article will simply cover usage of it.
First and foremost I would strongly encourage you to updage all installed packages and Homebrew itself. Things change quite often in Apple's world; and often they change in a very nasty way.
brew update brew upgrade
When this is done, make sure you have the development version of Qt framework installed:
brew install qt
Due to quite some changes Apple made in their C++ compiler (clang vs gcc), if you're building a 64bit binary (and I bet 99% of readers are), it may help you avoid some caveats if you enforce Homebrew to compile few things from source. Why? I'll explain later:
brew install boost --build-from-source brew install berkeley-db4 --build-from-source
Going further
When you have this sort of env, and you cloned the source code of your wallet - you are pretty much free to prepare the basic Makefile:
cd /where/you/got/the/source qmake
Editing the Makefile
Of course trying to build the thing now with make will most likely fail, so you need to edit the qmake-generated Makefile yourself. It is likely that the real Makefile you'd want to edit is called Makefile.Release. Tips and tricks on doing so will vary greatly depending on which wallet you're trying to compile, but here are few common tips that would probably suit most cases:
Give it a shot
Try to run make and see what happens. Most likely the compilation process will fail sooner or later. The errors here really depend on the wallet you're trying to compile but they all share one thing - a really messy and poor written code. Few common problems I've came across when playing with quite some wallets were:
Some other of the unknown function usage errors may happen, but they're most often solved by changing the include names in .h files.
Installing
If you went through fixing all the errors, and the compilation process finished - the rest is quite obvious. You should now have an extra .app directory in your current path. Simply copy that directory to either /Applications/ or ~/Applications/ and you should have your wallet visible in Launchpad, QuickSilver or whatever else launcher you use.
Be aware that the very first launch may actually crash with an error. This again is caused by poor coding as some wallets are trying to access the freshly created hash database... and failing there. Second launch should work like a charm though.
Going static and building release
Building a typical static release on Apple isn't as easy as it would seem. This is because the -Bstatic flag does pretty much nothing and if you enforce $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) -static $(LIBS), your linker will fail with ld: library not found for -lcrt0.o error. This is because Apple does not really provide a "typical" way of static linking and does not want us to use it. Luckily there are few tricks that can help us here greatly.
First of all, let's see what exactly is our binary linking against. To do this, we can use the otool command. I will use the Netcoin wallet as an example:
$ otool -L netcoin-qt.app/Contents/MacOS/netcoin-qt netcoin-qt.app/Contents/MacOS/netcoin-qt: /usr/local/lib/libminiupnpc.9.dylib (compatibility version 0.0.0, current version 0.0.0) /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1056.13.0) /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 48.0.0) /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1265.21.0) /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 59.0.0) /usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) /usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) /usr/local/opt/berkeley-db4/lib/libdb_cxx-4.8.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/local/lib/libboost_system-mt.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/local/lib/libboost_filesystem-mt.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/local/lib/libboost_program_options-mt.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/local/lib/libboost_thread-mt.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/local/lib/QtGui.framework/Versions/4/QtGui (compatibility version 4.8.0, current version 4.8.6) /usr/local/lib/QtCore.framework/Versions/4/QtCore (compatibility version 4.8.0, current version 4.8.6) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0) /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 855.17.0)
Here comes the tricky part. As you can see, some of the linked libraries point to global /System/ ones, while others link against our /usr/local/ Homebrew environment. The binary we created will have a very weak chance to run on other OSX computer, even if the system version alone is identical... and I believe I don't even have to explain why.
There are two different approaches used commonly in such cases; and I'd say using a mixture of the two is a way to go. Please note you'd really need to *think* here which libraries would be common for your target OSX version, and which may vary. My approach is just an educational example of how this *may* be solved.
First of all, let's link the smaller libraries statically. In order to do so, you need to edit the Makefile.Release file again and play around the LIBS variable. The idea is quite simple; dynamic linking will use something like -lminiupnpc, while static one will simply point to the .a (archive) library using a full path: /usr/local/lib/libminiupnpc.a. Please note there's no -l prefix used. What you need to do here, is really analysing each and every -llib precisely, removing it and replacing with an absolute path to the .a library instead (if you have one, that is). The end result may look similar to this (using Netcoin wallet as an example again):
LIBS = $(SUBLIBS) -F/usr/local/Cellar/qt/4.8.6/lib -L/usr/local/Cellar/qt/4.8.6/lib -L/usr/local/Cellar/berkeley-db4/4.8.30/lib -L/usr/local/Cellar/qt/4.8.6/lib -F/usr/local/Cellar/qt/4.8.6/lib -L/usr/local/lib \ -framework Foundation -framework ApplicationServices -framework AppKit -framework CoreServices -framework QtGui -framework QtCore \ /usr/local/lib/libminiupnpc.a /usr/local/lib/libdb_cxx.a /usr/local/lib/libboost_system-mt.a /usr/local/lib/libboost_filesystem-mt.a /usr/local/lib/libboost_program_options-mt.a /usr/local/lib/libboost_thread-mt.a /usr/local/lib/libboost_chrono-mt.a \ -lssl -lcrypto
At this point you don't really have to make clean and recompile everything. Removing the .app directory and re-running make should be enough:
rm -rf netcoin-qt.app/ && make
And let's see what we got:
$ otool -L netcoin-qt.app/Contents/MacOS/netcoin-qt netcoin-qt.app/Contents/MacOS/netcoin-qt: /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1056.13.0) /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 48.0.0) /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1265.21.0) /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 59.0.0) /usr/local/lib/QtGui.framework/Versions/4/QtGui (compatibility version 4.8.0, current version 4.8.6) /usr/local/lib/QtCore.framework/Versions/4/QtCore (compatibility version 4.8.0, current version 4.8.6) /usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) /usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 855.17.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
Better? Better! We still have some of the /usr/local/ though... And I wouldn't trust those SSL versions either. Even though they're OSX provided ones, they're quite old... and who knows when will Apple decide to replace them with newer ones completely? Luckily we can somewhat bind and provide those library files together with our .app here.
In order to do so, create an extra subdirectory in our .app/Contents/ and name it Frameworks (for example). Then just copy there the untrusted libraries and library directories (parts of Qt):
$ mkdir netcoin-qt.app/Contents/Frameworks $ cp -r /usr/local/Cellar/qt/4.8.6/Frameworks/QtGui.framework netcoin-qt.app/Contents/Frameworks/ $ cp -r /usr/local/Cellar/qt/4.8.6/Frameworks/QtCore.framework netcoin-qt.app/Contents/Frameworks/ $ cp /usr/lib/libssl.0.9.8.dylib netcoin-qt.app/Contents/Frameworks/ $ cp /usr/lib/libcrypto.0.9.8.dylib netcoin-qt.app/Contents/Frameworks/ $ ls -l netcoin-qt.app/Contents/Frameworks/ total 6240 drwxr-xr-x 8 Kyeno staff 272 Aug 29 05:45 QtCore.framework drwxr-xr-x 9 Kyeno staff 306 Aug 29 05:44 QtGui.framework -rwxr-xr-x 1 Kyeno staff 2590960 Aug 29 05:46 libcrypto.0.9.8.dylib -rwxr-xr-x 1 Kyeno staff 600288 Aug 29 05:45 libssl.0.9.8.dylib
Then just change working directory to the one where our binary is and modify the linking paths using the install_name_tool and the @executable_path variable available in OSX' linker. Make sure you enter full library paths as first argument; ones previously provided by otool:
$ cd netcoin-qt.app/Contents/MacOS/ $ install_name_tool -change /usr/local/lib/QtGui.framework/Versions/4/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/4/QtGui netcoin-qt $ install_name_tool -change /usr/local/lib/QtCore.framework/Versions/4/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore netcoin-qt $ install_name_tool -change /usr/lib/libssl.0.9.8.dylib @executable_path/../Frameworks/libssl.0.9.8.dylib netcoin-qt $ install_name_tool -change /usr/lib/libcrypto.0.9.8.dylib @executable_path/../Frameworks/libcrypto.0.9.8.dylib netcoin-qt
Our final result should be a fully portable OSX 10.9 app:
$ otool -L netcoin-qt netcoin-qt: /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1056.13.0) /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 48.0.0) /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1265.21.0) /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 59.0.0) @executable_path/../Frameworks/QtGui.framework/Versions/4/QtGui (compatibility version 4.8.0, current version 4.8.6) @executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore (compatibility version 4.8.0, current version 4.8.6) @executable_path/../Frameworks/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) @executable_path/../Frameworks/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 855.17.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
You now should be able to compress the .app directory and distribute it to other people safely.
If you like my compiles and advices - please donate my work so it can evolve. Thank you!
BitCoin: 1LmCoXUpaf7fsqZMWAkp16u9EkDL5RaPKP
MERGE: MMjafiEwQV9PUVgjb65YcHpCHtfyJjNkxc
© 2014 Maciej 'Kyeno' Taranienko