Different crypto-currency wallets compiled for Mac OSX

Downloads

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.

Notes on compiling yourself

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:

  1. Append -Wno-deprecated at the end of CXXFLAGS
    Most wallets' code is really messy and native OSX compilers are very strict. Deprecated warnings will flood the hell out of you and make your further debugging really painful
  2. Set -mmacosx-version-min= to 10.9 in both CFLAGS and CXXFLAGS
    Going any lower will most likely cause pain when linking, since Mac OS 10.9 introduced a brand new standard C++ library - libc++ vs old good libstdc++
  3. Make sure all of your -stdlib= point to libc++ instead of libstdc++
    Not doing so will again cause problems when linking. That is unless you're really compiling with GCC/G++ and aiming for lower OSX' version compatibility; but that's an entirely different story and this article does not cover such cases. We compile with CLANG and CLANG++
  4. Make sure you have local library directories included in INCPATH, f.e. -I/usr/local/include, -F/usr/local/Cellar/qt/4.8.6/lib
  5. Make sure you have the right Berkeley DB set in LIBS, f.e. -L/usr/local/Cellar/berkeley-db4/4.8.30/lib
    This is often the case when you have multiple versions of Berkely DB installed in your system. Most wallets want the version 4 explicitly.
  6. Search for MACOSX_DEPLOYMENT_TARGET variable and set it to 10.9
    I believe existence of this variable strictly depends on particular wallet, but I might be wrong.

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.

Support

If you like my compiles and advices - please donate my work so it can evolve. Thank you!

BitCoin: 1LmCoXUpaf7fsqZMWAkp16u9EkDL5RaPKP
Feathercoin: 6hnR73kP6p6YAKg7XXrMg3eQdSitCWcjTh
Netcoin: nPkw3h2cyEV4s2gM8SVkeyfd3yM7ZLZB8p


© 2014 Maciej 'Kyeno' Taranienko