cmake编译项目

需求:

想要实现一键编译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即配置好的专门为交叉编译配置的编译环境

效果:

在这里插入图片描述
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值