编写交叉编译链文件

交叉编译工具链文件toolchain.cmake或者cross.cmake文件名都可以

# cross.cmake文件
# 设置为1则表示交叉编译,设置为0则表示x86 gcc编译
SET(CROSS_COMPILE 1)

IF(CROSS_COMPILE)
SET(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR loongarch64)
SET(TOOLCHAIN_DIR "/usr/local/loongson-gnu-toolchain-13.2")
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/bin/loongarch64-unknown-linux-gnu-g++)
set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/bin/loongarch64-unknown-linux-gnu-gcc)

# 指定 Buildroot 的 sysroot 路径
set(BUILDROOT_SYSROOT "/home/robot/tspi/ABI2.0/buildroot/output/host/loongarch64-buildroot-linux-gnu/sysroot")
set(CMAKE_SYSROOT ${BUILDROOT_SYSROOT})

# 告诉 CMake 在 sysroot 中查找库和头文件
set(CMAKE_FIND_ROOT_PATH ${BUILDROOT_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

ENDIF(CROSS_COMPILE)

第6行:目标系统类型

SET(CMAKE_SYSTEM_NAME Linux)
  • 作用:指定目标平台的操作系统是 Linux。

  • 为什么重要:这是 CMake 识别开始交叉编译的最关键变量之一。设置这个变量会告诉 CMake:"现在开始交叉编译,目标系统不是当前主机系统"。

第7行:目标处理器架构

set(CMAKE_SYSTEM_PROCESSOR loongarch64)
  • 作用:指定目标平台的 CPU 架构是龙芯 LoongArch 64 位。

  • 为什么重要:帮助 CMake 了解目标硬件架构,某些自动检测的功能可能会基于此做出决策。

第8-10行:编译器路径设置

SET(TOOLCHAIN_DIR "/usr/local/loongson-gnu-toolchain-13.2")
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/bin/loongarch64-unknown-linux-gnu-g++)
set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/bin/loongarch64-unknown-linux-gnu-gcc)
  • 作用:明确指定交叉编译器的完整路径

  • 设计思路:避免依赖系统 PATH 环境变量,确保使用正确的工具链。

  • 为什么重要:这是交叉编译的核心,告诉 CMake 使用哪个编译器来生成目标平台的代码。

第13-14行:Sysroot 设置

set(BUILDROOT_SYSROOT "/home/robot/tspi/ABI2.0/buildroot/output/host/loongarch64-buildroot-linux-gnu/sysroot")
set(CMAKE_SYSROOT ${BUILDROOT_SYSROOT})
  • 作用:指定目标系统的根文件系统在开发主机上的位置。

  • 设计思路:创建一个"虚拟的目标系统环境",所有库和头文件都从这里获取。

  • 为什么重要:这是最关键的设置!它确保:

    • 编译时找到的是目标平台的库文件(龙架构的 .so 文件),不是主机平台的(x86_64 的 .so 文件)

    • 头文件来自目标系统的版本,避免因版本不一致导致的编译错误

第17-21行:查找路径控制

set(CMAKE_FIND_ROOT_PATH ${BUILDROOT_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
  • 作用:精细控制 CMake 在哪些位置查找各种资源。

  • 设计思路:实施严格的隔离策略,防止意外找到主机系统的资源。

详细解释每个模式:
模式 设置 含义 为什么这样设置
PROGRAM NEVER 永远不要在 sysroot 中查找可执行程序 因为目标平台的程序无法在主机上运行,我们需要使用主机上的交叉编译工具
LIBRARY ONLY 只在 sysroot 中查找库文件 确保链接的是目标平台的库,避免链接到错误架构的主机库
INCLUDE ONLY 只在 sysroot 中查找头文件 确保使用目标平台兼容的头文件
PACKAGE ONLY 只在 sysroot 中查找包配置 确保 find_package() 找到的是目标平台的

编写CMakeLists.txt文件

# 包含交叉编译工具链
include(cross.cmake)

# 设置CMake的最低版本要求
cmake_minimum_required(VERSION 3.5.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -pthread -Wall -lrt -lpthread") # 对于 C++ 编译器
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall -lrt -lpthread" ) # 对于 C 编译器

# 获取当前 CMakeLists.txt 文件所在目录的完整路径
set(CURRENT_DIR ${CMAKE_CURRENT_LIST_DIR})

# 获取上上级目录的完整路径
get_filename_component(PARENT_PARENT_DIR ${CURRENT_DIR}/.. ABSOLUTE)

# 从完整路径中提取文件夹名称
get_filename_component(PARENT_PARENT_FOLDER_NAME ${PARENT_PARENT_DIR} NAME)

# 打印上上级文件夹名称
message("Parent parent folder name: ${PARENT_PARENT_FOLDER_NAME}")

# 定义项目名称和版本,并指定使用C和C++语言
project(${PARENT_PARENT_FOLDER_NAME} VERSION 0.1.0 LANGUAGES C CXX)

# 设置OpenCV的安装路径(用于本地编译而非交叉编译时指明路径)
# set(CMAKE_PREFIX_PATH "/opt/opencv_4_10_build") 

# 查找OpenCV库,确保安装了所需的依赖
find_package(OpenCV REQUIRED)

# 包含OpenCV的头文件路径
include_directories(${OpenCV_INCLUDE_DIRS})
message(STATUS "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
message(STATUS "OpenCV_LIBS: ${OpenCV_LIBS}")

# 包含项目的自定义库路径
include_directories(../user)
include_directories(../code)

# 从目录下查找C/C++文件
aux_source_directory(../user DIR_SRCS)
aux_source_directory(../code DIR_SRCS)


# 创建可执行文件,使用项目名称作为目标名称
add_executable(${PROJECT_NAME} ${DIR_SRCS})

# 链接OpenCV库到可执行文件
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})

编写build.sh文件

将上面两个文件放在user文件夹下,在user同级文件夹out下编写build.sh文件内容:

cd ../out

# 检查 cd 命令是否执行成功
if [ $? -ne 0 ]; then
    echo "无法进入 ./project/out 目录,请检查目录是否存在。"
    exit 1
fi

find . -mindepth 1 ! -name "本文件夹作用.txt" -exec rm -rf {} +
# 检查 cd 命令是否执行成功
if [ $? -ne 0 ]; then
    echo "无法进入 ./project/out 目录,请检查目录是否存在。"
    exit 1
fi

cmake ../user
# 检查 cmake 命令是否执行成功
if [ $? -ne 0 ]; then
    echo "cmake 命令执行失败。"
    exit 1
fi

echo "cmake 命令执行成功。"
make -j4

echo "生成可执行文件"

# cmake --build .

# 获取上级目录的名称
# parent_dir_name=$(basename $(dirname $(pwd)))

# 使用获取到的上级目录名称进行 scp 操作
# scp -O $parent_dir_name root@192.168.2.61:/home/root/

# echo "传输完成"

第1行:Shebang

#!/bin/bash
  • 作用:指定这个脚本使用 Bash shell 来执行。

第3行:切换目录

cd ../out
  • 作用:切换到上级目录下的 out 目录。

  • 设计意图:通常 out 或 build 目录用于存放编译生成的文件,与源代码分离。

第5-9行:检查目录切换是否成功

if [ $? -ne 0 ]; then
    echo "无法进入 ./project/out 目录,请检查目录是否存在。"
    exit 1
fi
  • 作用:检查上一条 cd 命令的返回值($?),如果非零(表示失败),则输出错误信息并退出脚本。

  • 设计意图:增加脚本的健壮性,避免在错误目录中执行后续命令。

第11行:清理目录(核心命令)

find . -mindepth 1 ! -name "本文件夹作用.txt" -exec rm -rf {} +
  • 作用:删除当前目录(out)下的所有文件和子目录,但保留名为"本文件夹作用.txt"的文件。

  • 分解说明

    • find .:在当前目录查找

    • -mindepth 1:不包括当前目录本身(.

    • ! -name "本文件夹作用.txt":排除名为"本文件夹作用.txt"的文件

    • -exec rm -rf {} +:对找到的所有文件执行 rm -rf(强制删除)

第13-17行:再次检查目录状态

if [ $? -ne 0 ]; then
    echo "无法进入 ./project/out 目录,请检查目录是否存在。"
    exit 1
fi
  • 注意:这里的检查逻辑上有问题,因为它检查的是上一条 find 命令的返回值,而不是 cd 命令。应该是多余的代码。

第19行:运行 CMake

cmake ../user
  • 作用:在 out 目录中运行 CMake,指定源代码目录为 ../user

  • 设计意图:执行"外部构建",在单独的目录中生成构建文件。

第21-25行:检查 CMake 是否成功

if [ $? -ne 0 ]; then
    echo "cmake 命令执行失败。"
    exit 1
fi
  • 作用:检查 CMake 命令是否执行成功,失败则退出。

第27行:输出成功信息

echo "cmake 命令执行成功。"

第28行:执行编译

make -j4
  • 作用:使用 4 个并行任务(-j4)执行编译,加速构建过程。

cmake --build . 统一的参数接口

cmake --build . 提供标准化的参数,无论底层是什么构建工具:

# 指定并行编译(所有平台通用)
cmake --build . --parallel 4
cmake --build . -j 4

# 指定构建目标
cmake --build . --target my_app

# 清理构建
cmake --build . --target clean

# 详细输出
cmake --build . --verbose

# 只编译不链接
cmake --build . --target my_app_obj

现代方式(跨平台)

# 所有平台使用相同的命令
cmake --build . --parallel 4

# 如果需要指定构建类型
cmake --build . --config Release --parallel 4
Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐