Search code examples
cross-compilinglapackblasarmadillocodesourcery

Cross-Compiling Armadillo Linear Algebra Library


I enjoy using the Armadillo Linear Algebra Library. It becomes extremely nice when porting octave .m files over to C++, especially when you have to use the eigen methods.

However I ran into issues when I had to take my program from my native vanilla G++ and dump it onto my ARM processor. Since I spent a few hours muddling my way though it I wanted to share so others might avoid some frustration.

If anyone else could add anything else I would love it. This was the process I used to tackle this and surely isn't the only or best approach.


Solution

  • First off I use Code Sourcery as my cross-compiler. I know there others out there, but I haven't gotten around to rebuilding for another compiler yet, regardless this should be applicable to any compiler.

    Information:

    The Armadillo library requires LAPACK and BLAS, but Code Sourcery has no Fortran compiler. This led me to a f2c'ed version of LAPACK and BLAS.

    1. Get the sources:

    First off go grab the sources.

    2. Cross-Compile CLAPACK

    Once we've got the sources the next thing to do is cross-compile them for our end hardware. In my case an ARM7 using CodeSourcery. Its a REALLY good idea to read the READMEs here, you really can do all of this by just taking the time and reading them.

    1. First thing to do is change the make.inc file to look at our cross-compiler instead of the normal GCC. Normally you would $export, but I found it easier to keep track by modifying the makefiles.

      Edit clapack-3.2.1-CMAKE/make.inc from:

      CC = GCC
      LOADER = GCC
      

      to:

      CC = [CROSS-COMPILER-GCC location]
      LOADER = [CROSS-COMPILER-GCC location]
      

      Edit clapack-3.2.1-CMAKE/F2CLIBS/libf2c/Makefile from:

      ld -r -x -o $*.xxx $*.o
      

      to:

      [CROSS-COMPILER-LD location] -r -x -o $*.xxx $*.o
      
    2. Compile the f2c libraries:

      $make f2clib
      

      When I make the f2c libraries I get an error at the very end:

      ./a.out > arith.h
      /bin/sh: ./a.out: cannot execute binary file
      make[1]: *** [arith.h] Error 126
      make[1]: Leaving directory `/home/matt/clapack-3.2.1-CMAKE/F2CLIBS/libf2c'
      make: *** [f2clib] Error 2
      

      No actual problem here. Of course it will have trouble executing, it was cross-compiled!

    3. Compile BLAS:

      $make blaslib
      

      Once this is done you will notice you have a new "blas_XXXXX.a". This is your cross-compiled BLAS library.

    4. Compile LAPACK:

      The make.inc will point you to use $make lapacklib, but this will lead it to attempt more execution of cross-compiled items. Instead $cd into the SRC directory and:

      $make
      

      That should generate your new "lapack_XXXXX.a". Now that we have our F2C, LAPACK and BLAS I recommend placing them somewhere that makes sense so you can find them later. In my case I placed them where I keep my Code Sourcery compiler /CodeSourcery/arm-none-linux-gnueabi/usr/lib. Remember to rename these files:

      $cp libf2c.a [CROSS-COMPILE LIBRARY PATH]/libf2c.a
      $cp blas_XXXXX.a [CROSS-COMPILE LIBRARY PATH]/libblas.a
      $cp lapack_XXXXX.a [CROSS-COMPILE LIBRARY PATH]/liblapack.a
      

      Remember they have to have the "lib" to be recognized later. Again go ahead and store these in your cross-compiled library location. I have it setup with my tool-chain to make it easier to separate from normal gcc/g++.

    3. Cross-Compile ARMADILLO

    First off read the README, always the best place to start.
    Go ahead and run:

        $cmake .
    

    This will get everything ready and generate everything cmake will need for creating our shared armadillo library. The way I proceeded here is not how I think you are supposed to, but as I am no wizard with makefiles in general I thought it would be helpful to show what I did to get it to cross-compile. I modified the generated CMakeCache.txt lines with the following:

        //CXX compiler.
        CMAKE_CXX_COMPILER:FILEPATH=[CROSS-COMPILER-G++ location]
    

    I know there is somewhere in that CMakeCache.txt file where you can specify the path to the location of our BLAS and LAPACK, but I struggled to figure it out. Instead of bashing my head against this issue I just modified the "CMakeFiles/armadillo.dir/link.txt" and manually added "-L [Cross-Compiled BLAS/LAPACK directory]. Someone more familiar with how to do this could specify in the comments? Next since we want to manually link the BLAS and LAPACK libraries when we compile our program later (like the README says) modify "include/armadillo_bits/config.hpp" and make sure the line defining the use of the arma wrapper is commented out:

        //  #define ARMA_USE_WRAPPER
    

    The only thing left to do is $cd back to the root of the armadillo directory and

        $make
    

    Once the make completes you should be able to use Armadillo in your programs.

    4. Using ARMADILLO in your program

    To use Armadillo in your program add the include #include <armadillo> and the namespace using namespace arma;. Now you should be able to use all of the vec and mat you feel like. Normally when using arma all you need to do at compile time is to link libarmadillo.so library, but as I stated earlier we will need to link BLAS and LAPACK directly instead. So here is my GCC C++ Compiler synatx:

        [CROSS-COMPILER-G++] -I [CROSS-COMPILED ARMADILLO DIRECTORY]/include ...
    

    and my linker:

        [CROSS-COMPILER-G++] -L [CROSS-COMPILED LIBRARY] -o ... -llapack -lf2c -lblas
    

    Also note that the order in which you link libraries does matter! lapack must come first, then f2c, then blas.

    Really all you need to make sure happens is that the cross-compiled armadillo directory is included when you compile and your linking is setup correctly as above.

    Again more information is better, please feel free to add more comments. What worked for you different that what I did, what I did wrong, what could be done to improve.

    Thanks.