Кросс-компиляция библиотеки линейной алгебры Armadillo

Мне нравится пользоваться библиотекой линейной алгебры Armadillo. Это становится чрезвычайно удобным при переносе файлов octave .m на C++, особенно когда вам приходится использовать собственные методы.

Однако я столкнулся с проблемами, когда мне пришлось взять свою программу из моего родного ванильного G++ и сбросить ее на мой процессор ARM. Поскольку я потратил несколько часов на то, чтобы разобраться в этом, я хотел поделиться, чтобы другие могли избежать некоторого разочарования.

Если бы кто-то еще мог добавить что-нибудь еще, я был бы рад. Это был процесс, который я использовал для решения этой проблемы, и, конечно, это не единственный или лучший подход.


person Matt    schedule 21.01.2014    source источник


Ответы (2)


Во-первых, я использую Code Sourcery. как мой кросс-компилятор. Я знаю, что есть и другие, но я еще не собирался перестраивать для другого компилятора, несмотря на то, что это должно быть применимо к любому компилятору.

Информация:

Для библиотеки Armadillo требуются LAPACK и BLAS, но у Code Sourcery нет компилятора Fortran. Это привело меня к f2c-версии LAPACK и BLAS.

1. Получить исходники:

Прежде всего, возьмите исходники.

2. Кросс-компиляция CLAPACK

Как только у нас есть исходники, следующее, что нужно сделать, это кросс-компилировать их для нашего конечного оборудования. В моем случае ARM7 с использованием CodeSourcery. Это ДЕЙСТВИТЕЛЬНО хорошая идея прочитать README здесь, вы действительно можете сделать все это, просто потратив время и прочитав их.

  1. Первое, что нужно сделать, это изменить файл make.inc, чтобы он смотрел на наш кросс-компилятор вместо обычного GCC. Обычно вы бы использовали $export, но мне было проще отслеживать изменения, изменяя make-файлы.

    Отредактируйте clapack-3.2.1-CMAKE/make.inc из:

    CC = GCC
    LOADER = GCC
    

    to:

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

    Отредактируйте clapack-3.2.1-CMAKE/F2CLIBS/libf2c/Makefile из:

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

    to:

    [CROSS-COMPILER-LD location] -r -x -o $*.xxx $*.o
    
  2. Скомпилируйте библиотеки f2c:

    $make f2clib
    

    Когда я делаю библиотеки f2c, я получаю сообщение об ошибке в самом конце:

    ./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
    

    Здесь нет реальной проблемы. Конечно, у него будут проблемы с выполнением, он был кросс-компилирован!

  3. Скомпилируйте БЛАС:

    $make blaslib
    

    Как только это будет сделано, вы заметите, что у вас есть новый "blas_XXXXX.a". Это ваша кросс-компилированная библиотека BLAS.

  4. Скомпилируйте LAPACK:

    make.inc укажет вам на использование $make lapacklib, но это приведет к повторным попыткам выполнения кросс-компилированных элементов. Вместо этого $cd в каталог SRC и:

    $make
    

    Это должно сгенерировать ваш новый «lapack_XXXXX.a». Теперь, когда у нас есть F2C, LAPACK и BLAS, я рекомендую разместить их где-нибудь, чтобы вы могли найти их позже. В моем случае я разместил их там, где храню компилятор Code Sourcery /CodeSourcery/arm-none-linux-gnueabi/usr/lib. Не забудьте переименовать эти файлы:

    $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
    

    Помните, что они должны иметь «lib», чтобы быть распознанными позже. Снова продолжайте и сохраните их в расположении кросс-компилированной библиотеки. Я настроил его с помощью своей цепочки инструментов, чтобы упростить отделение от обычного gcc/g++.

3. Кросс-компиляция ARMADILLO

Прежде всего прочтите README, это всегда лучшее место для начала.
Продолжайте и запустите:

    $cmake .

Это подготовит все и сгенерирует все, что cmake понадобится для создания нашей общей библиотеки броненосцев. Я действовал здесь не так, как я думаю, вы должны, но, поскольку я не волшебник с make-файлами в целом, я подумал, что было бы полезно показать, что я сделал, чтобы заставить его кросс-компилироваться. Я изменил сгенерированные строки CMakeCache.txt следующим образом:

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

Я знаю, что где-то в этом файле CMakeCache.txt можно указать путь к расположению наших BLAS и LAPACK, но я изо всех сил пытался понять это. Вместо того, чтобы ломать голову над этой проблемой, я просто изменил «CMakeFiles/armadillo.dir/link.txt» и вручную добавил «-L [кросс-компилируемый каталог BLAS/LAPACK]. Кто-то, кто более знаком с тем, как это сделать, может указать в комментарии? Далее, так как мы хотим вручную связать библиотеки BLAS и LAPACK, когда мы будем компилировать нашу программу позже (как сказано в README), измените «include/armadillo_bits/config.hpp» и убедитесь, что строка, определяющая использование оболочки arma, закомментирован:

    //  #define ARMA_USE_WRAPPER

Осталось только $cd вернуться в корень каталога броненосца и

    $make

После завершения сборки вы сможете использовать Armadillo в своих программах.

4. Использование ARMADILLO в вашей программе

Чтобы использовать Armadillo в своей программе, добавьте включение #include <armadillo> и пространство имен using namespace arma;. Теперь вы сможете использовать все vec и mat, которые пожелаете. Обычно при использовании arma все, что вам нужно сделать во время компиляции, это связать библиотеку libarmadillo.so, но, как я уже говорил ранее, вместо этого нам нужно напрямую связать BLAS и LAPACK. Итак, вот мой синтаксис компилятора GCC C++:

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

и мой компоновщик:

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

Также обратите внимание, что порядок, в котором вы связываете библиотеки, имеет значение! Сначала должен идти lapack, потом f2c, потом blas.

На самом деле все, что вам нужно сделать, это убедиться, что каталог кросс-компилированного броненосца включен при компиляции, и ваша ссылка настроена правильно, как указано выше.

Опять же, больше информации лучше, пожалуйста, не стесняйтесь добавлять больше комментариев. Что сработало для вас, отличается от того, что я сделал, что я сделал неправильно, что можно было бы сделать, чтобы улучшить.

Спасибо.

person Matt    schedule 21.01.2014
comment
В пункте 3 вместо $make . (с точкой в ​​конце) вы имели в виду cmake . ? - person mtall; 22.01.2014
comment
Вы правы, отредактировано, чтобы изменить $make . на $cmake .. Спасибо! - person Matt; 22.01.2014
comment
@Matt, правильный способ перекрестной компиляции с CMake — использовать файл цепочки инструментов. Если бы вы использовали Buildroot, у вас уже был бы настроен файл цепочки инструментов. - person yegorich; 11.04.2014
comment
В качестве еще одной точки данных, мне удалось пройти через кучу обручей, чтобы собрать libopenblas с помощью кросс-компилятора Fortran, затем связать с ним Armadillo и собрать его с помощью файла цепочки инструментов из github.com/taka-no-me/android-cmake . Это немного менее хакерский IMO, и, надеюсь, я смогу почистить и опубликовать инструкции в ближайшее время. Но, по крайней мере, использование файла набора инструментов должно быть проще, чем изменение пути компилятора вручную. - person Ibrahim; 08.07.2015

Моя конкретная установка - это кросс-компиляция OSX (IDE Eclipse) в Beaglebone Black. Однако эти инструкции должны работать для аналогичных настроек.

Необязательный:

Для компиляции я использовал Mac OS X ARM GNU Linux G++ Lite 2013.11-33 Набор инструментов. В частности, расширенный двоичный файл ARM GNU/Linux G++ Lite 2013.11-33.

1. Скачать:

Как и написал Мэтт, кросс-компилятор GCC не поддерживает Fortran, поэтому, если вы хотите скомпилировать LAPACK и BLAS, используйте модифицированную версию, найденную здесь. Я использую clapack-3.2.1-CMAKE.tgz

2. Создайте файл cmake для кросс-компиляции:

Вы можете использовать конструктор цепочек инструментов или просто написать его. Я написал один.

Пример:

# http://www.cmake.org/Wiki/CMake_Cross_Compiling#The_toolchain_file

# REQUIRED
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1)
SET(CMAKE_SYSTEM_PROCESSOR arm)

# Added for the beaglebone
SET(FLOAT_ABI_SUFFIX "")

# specify the cross compiler
SET(CMAKE_C_COMPILER   /usr/local/arm-2013.11/bin/arm-none-linux-gnueabi-gcc)
SET(CMAKE_CXX_COMPILER /usr/local/arm-2013.11/bin/arm-none-linux-gnueabi-c++)

# where is the target environment 
SET(CMAKE_FIND_ROOT_PATH  /usr/local/arm-2013.11)

# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Примечание. Это мой первый опыт создания файла cmake. Не гарантируется правильность.

Вы захотите заменить /usr/local/arm-2013.11/bin/arm-none-linux-gnueabi-gcc на путь к выбранному вами компилятору, а также /usr/local/arm-2013.11/bin/arm- нет-linux-gnueabi-С++ и /usr/local/arm-2013.11

Я решил сохранить этот файл cmake как beaglebone.cmake.

3. Скомпилируйте:

Извлеките clapack-3.2.1-CMAKE.tgz и компакт-диск

скомпилировать: cmake -DCMAKE_TOOLCHAIN_FILE=~/Dropbox/workspaces/beaglebone/beaglebone.cmake
где ~/Dropbox/workspaces/beaglebone/beaglebone.cmake — это путь к вашему файлу cmake.

делать

По какой-то причине я получаю:

ds-mac-pro:clapack-3.2.1-CMAKE bunny$ make
Scanning dependencies of target arithchk
[  0%] Building C object F2CLIBS/libf2c/CMakeFiles/arithchk.dir/arithchk.c.o
Linking C executable arithchk
[  0%] Built target arithchk
[  0%] Generating arith.h
/bin/sh: arithchk: command not found
make[2]: *** [F2CLIBS/libf2c/arith.h] Error 127
make[1]: *** [F2CLIBS/libf2c/CMakeFiles/f2c.dir/all] Error 2
make: *** [all] Error 2

Как ни странно, запуск make снова компилируется нормально:

ds-mac-pro:clapack-3.2.1-CMAKE bunny$ make
[  0%] Built target arithchk
Scanning dependencies of target f2c
[  0%] Building C object F2CLIBS/libf2c/CMakeFiles/f2c.dir/f77vers.c.o
[  0%] Building C object F2CLIBS/libf2c/CMakeFiles/f2c.dir/i77vers.c.o
[  0%] Building C object F2CLIBS/libf2c/CMakeFiles/f2c.dir/main.c.o
[  0%] Building C object F2CLIBS/libf2c/CMakeFiles/f2c.dir/s_rnge.c.o

...

[100%] Building C object TESTING/EIG/CMakeFiles/xeigtstz.dir/xerbla.c.o
[100%] Building C object TESTING/EIG/CMakeFiles/xeigtstz.dir/xlaenv.c.o
[100%] Building C object TESTING/EIG/CMakeFiles/xeigtstz.dir/chkxer.c.o
[100%] Building C object TESTING/EIG/CMakeFiles/xeigtstz.dir/__/__/INSTALL/dsecnd.c.o
Linking C executable xeigtstz
[100%] Built target xeigtstz

4. Скопируйте (установите):

find . | grep \.a$

возвращается

./BLAS/SRC/libblas.a
./F2CLIBS/libf2c/libf2c.a
./SRC/liblapack.a
./TESTING/MATGEN/libtmglib.a

скопируйте libblas.a libf2c.a и libblapack.a в папку вашей любимой библиотеки. Я сделал /usr/local/armadillo-4.300.3/lib

Необходимый:

1. Копия включает:

Armadillo не нужно компилировать. Я не запускал какие-либо тесты для проверки, но похоже, что использование LAPACK и BLAS прекрасно работает с нескомпилированной копией Armadillo с использованием #define в коде. Примеры кода позже.

экстракт броненосец-4.300.3.tar.gz

(необязательно) cp armadillo-4.300.3/include/ /usr/local/armadillo-4.300.3/include
и, конечно же, замените /usr/local/armadillo-4.300.3/include на выбранный вами путь

2. Настройте GCC для использования Armadillo:

Я использую Eclipse с надстройкой поддержки кросс-компилятора C/C++ (меню «Справка» -> «Установить новое программное обеспечение...»), но инструкции легко преобразовать в cli или другие IDE.

В окне свойств проекта: C/C++ Build -> Settings

Компилятор Cross G++ -> Включает -> Включает пути (-I)

Нажмите +, чтобы добавить включение. Мой путь включения: /usr/local/armadillo-4.300.3/include

3. НЕОБЯЗАТЕЛЬНО — настройте GCC для использования скомпилированных библиотек:

Cross G++ Linker -> Библиотеки ->

Библиотеки (-l)

lapack
f2c
blas

Путь поиска библиотеки (-L)

Нажмите +, чтобы добавить путь. Мой путь: /usr/local/armadillo-4.300.3/lib

3. Пример кода:

В файле cpp попробуйте:

#include <armadillo>
using namespace arma;

mat A = randu<mat>(4,5);
mat B = randu<mat>(4,5);

std::cout << A*B.t() << std::endl;

Успех! :D

Некоторые функции Armadillo не поддерживаются напрямую и будут работать только с скомпилированными библиотеками. Вы можете проверить, что библиотеки скомпилированы и работают правильно, запустив простой тест, например:

#define ARMA_DONT_USE_WRAPPER
#define ARMA_USE_LAPACK
#define ARMA_USE_BLAS
#include <armadillo>
using namespace arma;

mat    A = randu<mat>(5,5);
double x = det(A);

std::cout << x << std::endl;
person Danielle    schedule 12.06.2014