交叉编译犰狳线性代数库

Posted

技术标签:

【中文标题】交叉编译犰狳线性代数库【英文标题】:Cross-Compiling Armadillo Linear Algebra Library 【发布时间】:2014-01-21 16:14:05 【问题描述】:

我喜欢使用Armadillo Linear Algebra Library。当将 octave .m 文件移植到 C++ 时,它变得非常好,尤其是当您必须使用 eigen 方法时。

但是,当我不得不从我的原生 vanilla G++ 中获取我的程序并将其转储到我的 ARM 处理器时,我遇到了问题。因为我花了几个小时搞混了,虽然我想分享,所以其他人可能会避免一些挫折。

如果其他人可以添加任何其他内容,我会喜欢的。这是我用来解决这个问题的过程,当然不是唯一或最好的方法。

【问题讨论】:

【参考方案1】:

首先我使用Code Sourcery 作为我的交叉编译器。我知道那里还有其他人,但我还没有开始为另一个编译器重建,不管这应该适用于任何编译器。

信息:

Armadillo 库需要 LAPACK 和 BLAS,但 Code Sourcery 没有 Fortran 编译器。这让我想到了 LAPACK 和 BLAS 的 f2c 版本。

1。获取来源:

首先去获取资源。

Armadillo LAPACK & BLAS

2。交叉编译 CLAPACK

一旦我们获得了源代码,接下来要做的就是为我们的最终硬件交叉编译它们。在我的例子中,一个使用 CodeSourcery 的 ARM7。在这里阅读自述文件是一个真的好主意,您真的可以通过花时间阅读它们来完成所有这些工作。

    首先要做的是更改 make.inc 文件以查看我们的交叉编译器而不是普通的 GCC。通常你会使用 $export,但我发现通过修改 makefile 更容易跟踪。

    从以下位置编辑 clapack-3.2.1-CMAKE/make.inc:

    CC = GCC
    LOADER = GCC
    

    到:

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

    从以下位置编辑 clapack-3.2.1-CMAKE/F2CLIBS/libf2c/Makefile:

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

    到:

    [CROSS-COMPILER-LD location] -r -x -o $*.xxx $*.o
    

    编译 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
    

    这里没有实际问题。当然它执行起来会有问题,它是交叉编译的!

    编译 BLAS:

    $make blaslib
    

    完成此操作后,您会注意到您有一个新的“blas_XXXXX.a”。这是您的交叉编译的 BLAS 库。

    编译 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。交叉编译犰狳

首先阅读自述文件,始终是最好的起点。 继续跑吧:

    $cmake .

这将使一切准备就绪并生成 cmake 创建我们共享的犰狳库所需的一切。我在这里进行的方式不是我认为您应该采取的方式,但由于我不是一般的 makefile 向导,我认为展示我为使其交叉编译所做的工作会有所帮助。 我用以下内容修改了生成的 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;。现在您应该可以使用您喜欢的所有vecmat。 通常在使用 arma 时,您在编译时需要做的就是链接 libarmadillo.so 库,但正如我之前所说,我们需要直接链接 BLAS 和 LAPACK。所以这是我的 GCC C++ 编译器 synatx:

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

和我的链接器:

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

还要注意链接库的顺序很重要! lapack 必须先来,然后是 f2c,然后是 blas。

真正需要确保的是,编译时包含交叉编译的犰狳目录,并且如上所述正确设置了链接。

再次提供更多信息会更好,请随时添加更多 cmets。对你有用的东西与我所做的不同,我做错了什么,可以做些什么来改进。

谢谢。

【讨论】:

在第 3 点中,您的意思不是 $make . (末尾有一个点)是指 cmake . 吗? 你是对的,编辑将$make .更改为$cmake .。谢谢! @Matt 使用 CMake 进行交叉编译的正确方法是使用 toolchain file。如果您使用的是Buildroot,则您已经设置了工具链文件。 作为另一个数据点,我已经成功地跳过了一堆障碍,使用 Fortran 交叉编译器构建 libopenblas,然后将 Armadillo 链接到它并使用来自 github.com/taka-no-me/android-cmake 的工具链文件构建它。 IMO 有点不那么 hacky,希望有一天我能够清理并发布说明。但至少使用工具链文件应该比手动更改编译器路径更容易。【参考方案2】:

我的具体设置是 OSX (IDE Eclipse) 交叉编译为 Beaglebone Black。但是,这些说明应该适用于类似的设置。

可选:

为了编译,我使用了Mac OS X ARM GNU Linux G++ Lite 2013.11-33 Toolchain。具体来说,ARM GNU/Linux G++ Lite 2013.11-33 Advanced Binary。

1。下载:

正如 Matt 发布的那样,GCC 交叉编译器不支持 Fortran,因此如果您想编译 LAPACK 和 BLAS,请使用找到的修改版本 here。我使用的是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-none-linux-gnueabi-c++ 和 /usr/local/arm-2013.11

我选择将这个 cmake 文件保存为 beaglebone.cmake

3。编译:

提取 clapack-3.2.1-CMAKE.tgz 和 cd

编译: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

cp libblas.a libf2c.a 和 liblapack.a 到您最喜欢的库文件夹。我做了 /usr/local/armadillo-4.300.3/lib

必填:

1。文案包括:

犰狳不需要编译。我没有运行任何基准测试来验证,但似乎使用 LAPACK 和 BLAS 通过在代码中使用 #define 可以很好地处理未编译的犰狳副本。稍后编写代码示例。

提取 armadillo-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:

我正在使用带有 C/C++ 交叉编译器支持插件的 Eclipse(帮助菜单 -> 安装新软件...),但说明很容易转换为 cli 或其他 IDE。

在项目属性窗口中:C/C++ Build -> Settings

Cross G++ 编译器 -> 包含 -> 包含路径 (-I)

单击 + 以添加包含。我的包含路径是:/usr/local/armadillo-4.300.3/include

3。可选 - 设置 GCC 以使用已编译的库:

Cross G++ 链接器 -> 库 ->

库 (-l)

拉包 f2c 废话

库搜索路径 (-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

犰狳不直接支持某些功能,仅适用于已编译的库。您可以通过运行以下简单测试来测试库是否已编译并正常工作:

#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;

【讨论】:

以上是关于交叉编译犰狳线性代数库的主要内容,如果未能解决你的问题,请参考以下文章

在犰狳中对立方体切片进行操作

调用 conv 没有匹配的函数(犰狳库)

在犰狳库中引用向量的最快方法

犰狳 C++ 矩阵线程安全吗

使用文件路径 c++ Linux OS 访问 Armadillo 库

如何将 lapack 和 BLAS 库链接到 C++ 代码