用Sysroots实现对AArch64的现代CMake交叉编译

deikduxw  于 2023-01-30  发布在  其他
关注(0)|答案(1)|浏览(488)

考虑下面的示例project_(CMakeLists.txt):

cmake_minimum_required(VERSION 3.1)

project(CCL LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)

find_library(MATH_LIBRARY m)
add_executable(main main.cpp)
if (MATH_LIBRARY)
  target_link_libraries(main PUBLIC ${MATH_LIBRARIES})
endif()

#include <iostream>
#include <cmath>

Main.cpp:

int main(void)
{
    std::cout << "Hello, sin()" << std::sin(30) << std::endl;
    return 0;
}

我想用下面的CMake工具链(aarch 64-toolchain.cmake)编译这个项目:

# Cross-compilation system information.
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

# The sysroot contains all the libraries we might need to link against and
# possibly headers we need for compilation.
set(CMAKE_SYSROOT /var/lib/schroot/chroots/ubuntu-focal-arm64)
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_LIBRARY_ARCHITECTURE aarch64-linux-gnu)

# Install path when SYSROOT is read-only.
# set(CMAKE_STAGING_PREFIX aarch64-staging)

# Set the compilers for C, C++ and Fortran.
set(GCC_TRIPLE "aarch64-linux-gnu")
set(CMAKE_C_COMPILER ${GCC_TRIPLE}-gcc-10 CACHE FILEPATH "C compiler")
set(CMAKE_CXX_COMPILER ${GCC_TRIPLE}-g++-10 CACHE FILEPATH "C++ compiler")
set(CMAKE_Fortran_COMPILER ${GCC_TRIPLE}-gfortran CACHE FILEPATH "Fortran compiler")

# Automatically use the cross-wrapper for pkg-config when available.
set(PKG_CONFIG_EXECUTABLE aarch64-linux-gnu-pkg-config CACHE FILEPATH "pkg-config executable")

# Set the architecture-specific compiler flags.
set(ARCH_FLAGS "-mcpu=cortex-a53+crc+simd")
set(CMAKE_C_FLAGS_INIT ${ARCH_FLAGS})
set(CMAKE_CXX_FLAGS_INIT ${ARCH_FLAGS})
set(CMAKE_Fortran_FLAGS_INIT ${ARCH_FLAGS})

# Don't look for programs in the sysroot (these are ARM programs, they won't run
# on the build machine).
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# Only look for libraries, headers and packages in the sysroot, don't look on
# the build machine.
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE arm64)

其中系统根目录(/var/lib/schroot/chroots/ubuntu-focal-arm 64)是使用以下命令设置的:

name=ubuntu-focal
mk-sbuild --arch=arm64 --skip-proposed --skip-updates --skip-security --name=${name} focal
su - $USER
mk-sbuild --arch=arm64 --skip-proposed --skip-updates --skip-security --name=${name} focal

配置方面,这工作得很好,但是当我尝试“正确地”构建这个项目find_library时,发现错误的libm.so库:

$ cmake -DCMAKE_TOOLCHAIN_FILE=../aarch-toolchain.cmake ..
$ make
Scanning dependencies of target main
[ 50%] Building CXX object CMakeFiles/main.dir/main.cpp.o
make[2]: *** No rule to make target '/var/lib/schroot/chroots/ubuntu-focal-arm64/usr/lib/aarch64-linux-gnu/libm.so', needed by 'main'.  Stop.
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/main.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

查看sysroot本身,可以正确找到库,但很明显,它是指向sysroot本地文件的符号链接,而不是指向主机:

$ ls -hal /var/lib/schroot/chroots/ubuntu-focal-arm64/usr/lib/aarch64-linux-gnu/
lrwxrwxrwx  1 root root   32 Apr 14  2020 libm.so -> /lib/aarch64-linux-gnu/libm.so.6

在我看来,CMake选择了错误的库(find_library实际上应该先使用编译器库),所以我猜我的工具链文件写得不正确。应该如何修改它以正确地找到数学库,而不改变sysroot或项目本身?
(Also,请注意,这是一个示例项目来说明问题。我仍然需要能够搜索sysroot中的包。)

编辑

正如注解中所要求的,结束状态应该是一个正确的aarch 64二进制文件(“main”),本质上,下面的构建命令无论有没有工具链都应该成功,并且应该产生一个功能性的二进制文件(尽管aarch 64二进制文件自然只能在sysroot中工作)。

$ mkdir -p host-build && cd host-build && cmake .. && make 
$ mkdir -p device-build && cd device-build && cmake -DCMAKE_TOOLCHAIN_FILE=../aarch64-toolchain.cmake .. && make
lp0sw83n

lp0sw83n1#

TLDR:据我所知,没有简单的方法。

你的工具链文件是好的,它的符号链接是坏的,他们应该是理想的相对的,而不是绝对的,如果你想用它来构建。下面我提到了一些选项,并解释了这个问题。这都是基于我的经验与交叉编译。也许有人知道更多。
你的工具链文件没有任何问题。从我的Angular 来看,它配置正确。这是一个问题,正如你所指出的,符号链接是相对于你创建的rootfs,而不是绝对的主机**,但他们是作为绝对**。
IIRC在这里你能做的不多。
我会给你几个选项,我知道从个人经验:
1.忘记交叉编译和使用QEMUchroot到环境中并在那里构建,这是最简单的选择。
1.在主机上获取所有需要的库(在sysroot之外)并使用它们进行编译-您只需确保您拥有与目标机器完全相同的库。然后您的工具链文件将被重新配置以在此处的库中查找库。
1.另一种选择是修复您的项目CMakeList以更好地适应交叉编译。这将要求您指定正确库的绝对路径。有一个缺点,因为您需要始终"指向"最新库。例如,您可以创建另一个.cmake文件来帮助您配置正确的路径,因为target_link_libraries()允许您指定绝对路径,您可以使用新创建的自定义目标。
1.最后一个选项是修复符号链接**(理想情况下是使它们成为相对的).在我看来这是首选的方法.最后你将用于构建的rootfs将只是这样,即用于构建.**
据我所知(我可能是错的)但是mks-build只是一个debian工具,它最初是用来打包.deb文件的,因此并不是作为CMake的补充,如果是的话,那么debian团队可能有你正在寻找的工具链文件(也就是说,我会寻找关于.deb软件包的交叉编译和软件包指南--如果存在的话,它们会被包含在内)。
CMAKE_SYSROOTCMAKE_FIND_ROOT_PATH只为特定的find_命令/函数添加前缀。它们几乎不能更改任何有关目标系统或链接器行为(这是这里的问题所在)的内容。这意味着它们配置正确。配置错误的是fake system

相关问题