Building a project for iOS or OSX with Armadillo in Xcode
Armadillo is a superb linear algebra library for C++, that makes doing things which are easy in MATLAB, almost as easy in C++ . I recently had to port a fairly complex curve fitting algorithm from MATLAB to an Xcode library, to use in an iPad Unity app. Setting the environment up requires a little care. Armadillo is from the C++ world, and it's not as simple as copying a .framework. There are two different ways of getting Armadillo to work:
- Use armadillo simply as a template library, and link directly to LAPACK and BLAS (sounds complicated but isn't)
- Build the runtime library as suggested in the README.md
Armadillo mainly consists of headers which 'wrap' the more complicated and verbose commands of whichever library that is actually used for doing matrix calculations. For both iOS and OSX, this is Accelerate.framework, which contains optimised versions of LAPACK and BLAS, the components for doing the linear algebra fast.
Armadillo: To build or not to build
You do not have to build the Armadillo run-time library (e.g. using the installation instructions included), but you can if you wish. This includes which ever libraries the installation routine finds into a package, and conveniently for your purposes copies the headers to a sensible location. Alternatively you can just run Armadillo as a pure template library. This way, you include the headers, but don't need to include the library. This is probably the easiest way and just requires a simple preprocessor directive before you include armadillo. I repeat: you do not have to build the Armadillo run-time library to get it to work on iOS.
If you try to include the run-time library you made on OSX in an iOS project it will not work! Really the only reason you would want to build this library is if you are not using Accelerate.framework for some reason.
Wait what?
Dylib files are dynamic libraries, which you can essential think of as precompiled code that is loaded at runtime, as opposed to code you compile yourself. In order to write code with the .dylib, you need header files, which tell you (and your compiler) what names to call the functions in the library. Libraries that you use in C++ generally come in this form, with both the library, and the header files. Frameworks are in fact just a neat package of dynamic libraries and headers. Armadillo is special - it's not really a library per se, but is really just some very clever headers that sit on top of other dynamic libraries, which do the work. Since iOS and OSX come with the Accelerate framework as standard, you can just use Armadillo with that - and not bother creating the run-time library, which essentially is just a repackaging of existing libraries.
Problem with BLAS symbols on iOS store
For iOS, one problem that arises when you submit the app store is you will get a rejection unless you tell the armadillo library to NOT use BLAS. The first time I submitted an app I got the following rejection note:
ITMS-90338: Non-public API usage - The app references non-public symbols...ddot, dgemm, dgemv, dsyrk.
You might also get the same for any of these symbols:
_sasum_ _dasum_ _snrm2_ _dnrm2_ _sdot_ _ddot_ _sgemv_
_dgemv_ _cgemv_ _zgemv_ _sgemm_ _dgemm_ _cgemm_ _zgemm_
_ssyrk_ _dsyrk_ _cherk_ _zherk_
These are all used by BLAS for doing faster matrix calculation, but are in fact not necessary for basic functionality. To turn off BLAS go to the armadillo_bits/config.hpp wherever you are linking to armadillo and comment out line 26:
#if !defined(ARMA_USE_BLAS)
//#define ARMA_USE_BLAS
//// Comment out the above line if you don't have BLAS or a high-speed replacement for BLAS,
//// such as OpenBLAS, GotoBLAS, Intel MKL, AMD ACML, or the Accelerate framework.
//// BLAS is used for matrix multiplication.
//// Without BLAS, matrix multiplication will still work, but might be slower.
#endif
This will now mean you can use armadillo without BLAS and the app store will not reject the binary. If you WANT to use BLAS, you could have a look in wrapper_blas.h and def_blas.h and do some replacement with the provided public API (eg. cblas_dgemm) - but this was not necessary for my project and I didn't have time to check if it would all work (and I have to admit I have more interesting free time projects...)
Recipe for iOS and OSX (without run-time library_:
- Copy the armadillo headers to your project, or install globally to your usr/local/include directory.
- If you have installed globally, add the header's path (e.g. usr/local/include) to your 'Header Search Paths' entry in the target's build settings.
- Add Accelerate.framework (included with Xcode) to your linked frameworks and libraries.
- Comment out the #define ARMA_USE_BLAS line in config.hpp if you are submitting on the app store
- Add #define ARMA_DONT_USE_WRAPPER to the top of your code.Add #include
afterwards - Thats it!
- If you get an 'armadillo' file not found error (highlighting the #include
this is because the preprocessor cannot find the headers, so you need to check your 'Header Search Paths'
Happy linear algebra fun in Xcode!