需求:
想要实现一键编译x86 和 arm64 架构可以运行的项目可执行文件(编译环境为x86 ubantu)
分析:
cmake 管理项目编译要比常规Makefile管理项目要更加方便,所以采用cmake + 脚本的方式编译项目
实现:

项目架构如上,其中request文件夹下的动态库为arm64架构,编译环境为x86 ubantu
EquipCtrl/CMakeLists.txt:
# 指定CMake的最低版本要求,确保兼容性
cmake_minimum_required(VERSION 3.10)
# 定义项目名称
project(EquipCtrl)
# 设置C语言标准为C11
set(CMAKE_C_STANDARD 11)
# 要求必须支持C11标准
set(CMAKE_C_STANDARD_REQUIRED ON)
# 默认构建类型为Debug,如果用户没有指定的话
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
# 设置全局编译选项
# -Wall: 开启所有警告
# -g: 生成调试信息
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -g")
# ============================================================================
# 交叉编译检测逻辑
# ============================================================================
# 检测是否处于交叉编译环境
if(CMAKE_CROSSCOMPILING)
# 如果是交叉编译,检查目标架构是否为ARM64
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
set(ARM64_CROSS_COMPILE TRUE)
message(STATUS "检测到ARM64交叉编译环境")
else()
set(ARM64_CROSS_COMPILE FALSE)
endif()
else()
# 如果是本地编译,检查主机架构
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "i386")
set(ARM64_CROSS_COMPILE FALSE)
message(STATUS "检测到x86本地编译环境")
else()
set(ARM64_CROSS_COMPILE TRUE)
message(STATUS "检测到ARM64本地编译环境")
endif()
endif()
# ============================================================================
# 输出目录设置
# ============================================================================
# 根据架构设置不同的构建目录,避免x86和ARM64构建文件混淆
if(ARM64_CROSS_COMPILE)
set(OUTPUT_DIR "build-aarch64")
else()
set(OUTPUT_DIR "build")
endif()
# 设置各类输出文件的目录
# CMAKE_ARCHIVE_OUTPUT_DIRECTORY: 静态库文件(.a)输出目录
# CMAKE_LIBRARY_OUTPUT_DIRECTORY: 动态库文件(.so)输出目录
# CMAKE_RUNTIME_OUTPUT_DIRECTORY: 可执行文件输出目录
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# ============================================================================
# 构建子项目
# ============================================================================
# 添加Server子目录,CMake会执行该目录下的CMakeLists.txt
add_subdirectory(Server)
# 添加Requester子目录
add_subdirectory(Requester)
# ============================================================================
# 自定义构建后操作
# ============================================================================
# 创建一个自定义目标,在构建完成后将可执行文件复制到项目根目录
add_custom_target(copy_binaries ALL
# 复制server可执行文件到项目根目录
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/server ${CMAKE_SOURCE_DIR}/
# 复制ctl可执行文件到项目根目录
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_BINARY_DIR}/ctl ${CMAKE_SOURCE_DIR}/
# 指定依赖关系,确保server和ctl目标先构建完成
DEPENDS server ctl
COMMENT "正在复制可执行文件到项目根目录..."
)
# ============================================================================
# 配置信息显示
# ============================================================================
message(STATUS "构建类型: ${CMAKE_BUILD_TYPE}")
message(STATUS "目标系统处理器: ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS "主机系统处理器: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
message(STATUS "ARM64交叉编译: ${ARM64_CROSS_COMPILE}")
message(STATUS "输出目录: ${OUTPUT_DIR}")
此cmake用于创建编译环境并进入对应文件中做编译操作
EquipCtrl/toolchain-arm64.cmake:
# ============================================================================
# ARM64交叉编译工具链配置文件
# 文件名: toolchain-arm64.cmake
# 用途: 告诉CMake如何为ARM64架构进行交叉编译
# ============================================================================
# ============================================================================
# 基本系统配置
# ============================================================================
# 设置目标系统名称 - 告诉CMake我们要编译到哪个系统
# Linux: 表示目标平台是Linux操作系统
set(CMAKE_SYSTEM_NAME Linux)
# 设置目标处理器架构 - 告诉CMake目标CPU架构
# aarch64: ARM64架构的另一种称呼
set(CMAKE_SYSTEM_PROCESSOR aarch64)
# ============================================================================
# 交叉编译工具链路径配置
# ============================================================================
# 设置交叉编译工具链的安装路径
# 这是你本地机器上ARM64交叉编译器的安装位置
set(TOOLCHAIN_PATH "/home/saisi/NtArea/gcc-arm/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu")
# 设置C编译器路径
# 使用ARM64架构的GCC编译器来编译C代码
# 命名规则: aarch64-rockchip1031-linux-gnu-gcc
# - aarch64: 目标架构
# - rockchip1031: 芯片平台特定标识
# - linux-gnu: 目标系统
# - gcc: GNU C编译器
set(CMAKE_C_COMPILER "${TOOLCHAIN_PATH}/bin/aarch64-rockchip1031-linux-gnu-gcc")
# 设置C++编译器路径
# 使用ARM64架构的G++编译器来编译C++代码
set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PATH}/bin/aarch64-rockchip1031-linux-gnu-g++")
# 设置汇编器路径
# 使用相同的GCC来编译汇编代码(GCC也包含汇编功能)
set(CMAKE_ASM_COMPILER "${TOOLCHAIN_PATH}/bin/aarch64-rockchip1031-linux-gnu-gcc")
# ============================================================================
# 查找路径配置 - 控制CMake在哪里查找依赖项
# ============================================================================
# 设置根文件系统路径
# 告诉CMake在交叉编译工具链目录中查找目标系统的库和头文件
set(CMAKE_FIND_ROOT_PATH "${TOOLCHAIN_PATH}")
# ============================================================================
# 查找模式配置 - 控制CMake的搜索行为
# ============================================================================
# 程序查找模式: NEVER - 不在目标系统中查找可执行程序
# 这意味着编译期间需要运行的程序(如代码生成器)会在主机系统上查找
# 因为目标系统的程序不能在主机上运行
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# 库文件查找模式: ONLY - 只在目标系统中查找库文件
# 确保链接的是ARM64架构的库,而不是x86的库
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
# 头文件查找模式: ONLY - 只在目标系统中查找头文件
# 确保包含的是ARM64架构对应的头文件
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# 包查找模式: ONLY - 只在目标系统中查找CMake包
# 确保找到的CMake包配置是针对ARM64架构的
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# ============================================================================
# 自定义变量 - 用于在CMakeLists.txt中识别交叉编译状态
# ============================================================================
# 设置一个标志变量,表示正在进行ARM64交叉编译
# 这个变量可以在项目的CMakeLists.txt中用于条件判断
set(CROSS_COMPILE_ARM64 TRUE)
此模块用于配置交叉编译环境,当选择arm64架构的时候就会用此配置环境做为临时配置,例如告诉cmake 交叉编译工具位置,动态库位置
EquipCtrl/Requester/CMakeLists.txt:
# 定义Requester子项目
project(Requester)
# ============================================================================
# 源文件配置
# ============================================================================
# 设置请求器源文件列表
set(REQUESTER_SOURCES
requester.c # 请求器主程序
)
# ============================================================================
# 头文件包含路径设置
# ============================================================================
# 添加当前目录的include子目录(用于readline头文件)
include_directories(./include)
# 添加Server目录(用于serve_pri.h)
include_directories(../Server)
# ============================================================================
# 目标构建
# ============================================================================
# 创建可执行文件目标:ctl
# 使用requester.c源文件
add_executable(ctl requester.c)
# ============================================================================
# 交叉编译链接策略
# ============================================================================
# 根据架构选择不同的链接方式
if(ARM64_CROSS_COMPILE)
message(STATUS "ARM64交叉编译: 使用项目自带的ARM64库文件")
# ARM64交叉编译时,直接链接项目内预编译的ARM64库文件
target_link_libraries(ctl
servr # Server模块的静态库
# 直接指定库文件路径,避免使用系统库
"${CMAKE_CURRENT_SOURCE_DIR}/lib/libreadline.so"
"${CMAKE_CURRENT_SOURCE_DIR}/lib/libncurses.so"
)
else()
message(STATUS "x86编译: 使用系统库")
# x86本地编译时,使用系统的readline和ncurses库
target_link_libraries(ctl
servr # Server模块的静态库
readline # 系统readline库
ncurses # 系统ncurses库
)
endif()
# ============================================================================
# 目标属性设置
# ============================================================================
# 设置ctl可执行文件的属性
set_target_properties(ctl PROPERTIES
OUTPUT_NAME "ctl" # 输出文件名为ctl
# 设置运行时输出目录为构建目录
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
)
主要用于做链接作用,如果是交叉编译则直接用request/lib目录下的动态库做为链接对象,否者不是交叉编译则直接使用系统中的动态库即可
EquipCtrl/Server/CMakeLists.txt:
# 定义Server子项目
project(Server)
# ============================================================================
# 源文件配置
# ============================================================================
# 设置服务器源文件列表
set(SERVER_SOURCES
serve_lib.c # 服务器库文件
server.c # 服务器主程序
)
# ============================================================================
# 头文件包含路径设置
# ============================================================================
# 添加当前目录到头文件搜索路径(用于serve_pri.h)
include_directories(.)
# 添加Requester的include目录(用于request_api.h)
include_directories(../Requester/include)
# ============================================================================
# 目标构建
# ============================================================================
# 创建静态库目标:servr
# STATIC表示构建静态库(.a文件),使用serve_lib.c源文件
add_library(servr STATIC serve_lib.c)
# 创建可执行文件目标:server
# 使用server.c源文件
add_executable(server server.c)
# ============================================================================
# 链接配置
# ============================================================================
# 将server可执行文件链接到以下库:
# servr: 上面创建的静态库
# pthread: POSIX线程库
# rt: 实时扩展库(用于时钟、定时器等)
target_link_libraries(server servr pthread rt)
# ============================================================================
# 目标属性设置
# ============================================================================
# 设置servr库的输出名称
set_target_properties(servr PROPERTIES
OUTPUT_NAME "servr" # 确保输出文件名为libservr.a
)
# 设置server可执行文件的输出名称
set_target_properties(server PROPERTIES
OUTPUT_NAME "server" # 确保输出文件名为server
)
EquipCtrl/build.sh :
#!/bin/bash
# ============================================================================
# 构建脚本:EquipCtrl项目多架构构建管理器
# 功能:支持x86本地编译、ARM64交叉编译、清理和全架构构建
# ============================================================================
# 清理构建产物的函数
clean_build() {
echo "正在清理构建目录和生成文件..."
# 删除构建目录
rm -rf build build-aarch64
# 删除项目根目录下的可执行文件和库文件
rm -f server ctl libservr.a
echo "清理完成!"
}
# 显示脚本使用说明
usage() {
echo "用法: $0 [x86|arm64|clean|all]"
echo " x86 - 为x86架构构建(使用系统库)"
echo " arm64 - 为ARM64架构构建(使用项目自带的ARM64库)"
echo " clean - 清理所有构建目录和生成文件"
echo " all - 为所有架构构建"
exit 1 # 退出并返回错误码1
}
# ============================================================================
# x86架构构建函数
# ============================================================================
build_x86() {
echo "开始为x86架构构建(使用系统库)..."
# 创建并进入构建目录
mkdir -p build && cd build
# 配置CMake项目
# -DCMAKE_BUILD_TYPE=Release: 设置构建类型为发布模式
# .. : CMakeLists.txt在上级目录
cmake .. -DCMAKE_BUILD_TYPE=Release
# 检查CMake配置是否成功
# $? 获取上一条命令的退出状态,0表示成功,非0表示失败
if [ $? -ne 0 ]; then
echo "CMake配置失败!"
cd .. # 返回上级目录
return 1 # 函数返回错误码
fi
# 开始编译
# -j$(nproc): 使用所有CPU核心并行编译,nproc命令返回CPU核心数
# copy_binaries: 构建完成后执行复制目标
make -j$(nproc) copy_binaries
# 检查编译是否成功
if [ $? -ne 0 ]; then
echo "编译失败!"
cd ..
return 1
fi
# 返回项目根目录
cd ..
echo "x86架构构建成功完成!"
echo "生成的可执行文件: ./server 和 ./ctl"
}
# ============================================================================
# ARM64架构构建函数
# ============================================================================
build_arm64() {
echo "开始为ARM64架构构建(使用项目自带的ARM64库)..."
# 创建并进入ARM64专用构建目录
mkdir -p build-aarch64 && cd build-aarch64
# 配置CMake项目,使用交叉编译工具链
# -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm64.cmake: 指定交叉编译工具链文件
cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm64.cmake -DCMAKE_BUILD_TYPE=Release
# 检查CMake配置是否成功
if [ $? -ne 0 ]; then
echo "CMake配置失败!"
cd ..
return 1
fi
# 开始交叉编译
make -j$(nproc) copy_binaries
# 检查编译是否成功
if [ $? -ne 0 ]; then
echo "交叉编译失败!"
cd ..
return 1
fi
# 返回项目根目录
cd ..
echo "ARM64架构构建成功完成!"
echo "生成的可执行文件: ./server 和 ./ctl"
}
# ============================================================================
# 主程序逻辑 - 命令行参数处理
# ============================================================================
# 使用case语句处理命令行参数
case "$1" in
"x86")
# 构建x86版本
build_x86
;;
"arm64")
# 构建ARM64版本
build_arm64
;;
"clean")
# 执行清理操作
clean_build
;;
"all")
# 构建所有架构版本
echo "开始为所有架构构建..."
build_x86 # 先构建x86版本
build_arm64 # 再构建ARM64版本
echo "全架构构建完成!"
;;
*)
# 如果参数不匹配任何已知选项,显示使用说明
usage
;;
esac
# 脚本正常结束
主要是脚本文件,如果选择了x86则使用系统默认编译环境,如果使用了arm64配置则使用toolchain-arm64.cmake即配置好的专门为交叉编译配置的编译环境
效果:



8586

被折叠的 条评论
为什么被折叠?



