目录

1.指定gcc版本编译

1.1.通过CMake参数来实现

1.2.使用 RPATH/RUNPATH 直接指定库路径

1.3.使用符号链接和 LD_LIBRARY_PATH

1.4.使用 wrapper 脚本封装 LD_LIBRARY_PATH

2.交叉编译

2.1.基本用法

2.2.工具链文件关键配置

2.3.多平台工具链示例

2.4.注意事项

2.5.相关资源

相关链接


1.指定gcc版本编译

        背景

        现在项目上碰到一种情况,在麒麟V4系统上正在维护的程序是gcc5.4.0编译出来的,现在增加一个需求需要用到了一个第三方库,第三方库编译需要C++20支持,那么就必须升级gcc到gcc9.3.0,安装完gcc9.3.0,因为程序一直是在gcc5.4.0环境下编译的,代码太多,用gcc9.3.0编译怕出问题,又不想改它。于是在相当一段时间,系统中共存gcc5.4.0和gcc9.3.0两个版本,在CMake编译的时候就需要指定gcc版本,下面就来说说实现方案。

1.1.通过CMake参数来实现

1.通过环境变量指定编译器

临时设置 CC 和 CXX 环境变量,仅对当前终端会话有效:

# 设置环境变量指向 GCC 9.3.0
export CC=/usr/bin/gcc-9.3.0
export CXX=/usr/bin/g++-9.3.0# 运行 CMake
cmake -S . -B build
cmake --build build

如果 GCC 9.3.0 的路径不是 /usr/bin/gcc-9.3.0,可以通过以下命令查找:

find /usr -name "gcc-9.3.0" 2>/dev/null  # 查找 GCC 9.3.0
find /usr -name "g++-9.3.0" 2>/dev/null  # 查找 G++ 9.3.0或whichis gcc
whichis g++

2.在 CMake 命令中直接指定

cmake -S . -B build \-DCMAKE_C_COMPILER=/usr/bin/gcc-9.3.0 \-DCMAKE_CXX_COMPILER=/usr/bin/g++-9.3.0cmake --build build

3.使用工具链文件(推荐)

创建一个工具链文件(如 gcc93.toolchain.cmake),集中管理编译器配置:

# gcc93.toolchain.cmake
set(CMAKE_C_COMPILER /usr/bin/gcc-9.3.0)
set(CMAKE_CXX_COMPILER /usr/bin/g++-9.3.0)# 可选:指定 C/C++ 标准
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

然后在运行 CMake 时指定该工具链文件:

cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=/path/to/gcc93.toolchain.cmake
cmake --build build

验证编译器版本

在 CMake 配置过程中,可以通过打印编译器版本来确认是否使用了正确的 GCC:

cd build
cmake -LA | grep "CMAKE_C.*COMPILER"  # 查看 C/C++ 编译器配置

或者在 CMakeLists.txt 中添加以下代码:

message(STATUS "C 编译器: ${CMAKE_C_COMPILER}")
message(STATUS "C++ 编译器: ${CMAKE_CXX_COMPILER}")# 打印编译器版本
execute_process(COMMAND ${CMAKE_C_COMPILER} --versionOUTPUT_VARIABLE gcc_version
)
message(STATUS "GCC 版本: ${gcc_version}")

1.2.使用 RPATH/RUNPATH 直接指定库路径

通过在编译时设置 RPATH 或 RUNPATH,让可执行程序直接从指定路径加载动态库。

示例步骤:

1.创建版本化的库目录

mkdir -p /opt/libfoo/v1 /opt/libfoo/v2
cp libfoo.so.1.0.0 /opt/libfoo/v1/
cp libfoo.so.2.0.0 /opt/libfoo/v2/

2.编译时指定 RPATH

# 程序 A 链接 v1
g++ -o program_a src/a.cpp -L/opt/libfoo/v1 -lfoo \-Wl,-rpath=/opt/libfoo/v1# 程序 B 链接 v2
g++ -o program_b src/b.cpp -L/opt/libfoo/v2 -lfoo \-Wl,-rpath=/opt/libfoo/v2

3.验证链接的库版本

ldd program_a  # 应显示 /opt/libfoo/v1/libfoo.so.1
ldd program_b  # 应显示 /opt/libfoo/v2/libfoo.so.2

1.3.使用符号链接和 LD_LIBRARY_PATH

通过环境变量 LD_LIBRARY_PATH 临时覆盖系统默认库搜索路径。

示例步骤:

1.创建版本化的库目录

mkdir -p ~/libfoo/v1 ~/libfoo/v2
cp libfoo.so.1.0.0 ~/libfoo/v1/
cp libfoo.so.2.0.0 ~/libfoo/v2/# 创建符号链接
cd ~/libfoo/v1 && ln -s libfoo.so.1.0.0 libfoo.so.1
cd ~/libfoo/v2 && ln -s libfoo.so.2.0.0 libfoo.so.2

2.编译程序(不指定 RPATH)

# 程序 A 链接 v1
g++ -o program_a src/a.cpp -L~/libfoo/v1 -lfoo# 程序 B 链接 v2
g++ -o program_b src/b.cpp -L~/libfoo/v2 -lfoo

3.运行时指定库路径

# 运行程序 A(使用 v1)
LD_LIBRARY_PATH=~/libfoo/v1 ./program_a# 运行程序 B(使用 v2)
LD_LIBRARY_PATH=~/libfoo/v2 ./program_b

1.4.使用 wrapper 脚本封装 LD_LIBRARY_PATH

创建脚本包装程序执行,自动设置正确的库路径。

示例步骤:

1.创建 wrapper 脚本

# program_a_wrapper.sh
#!/bin/bash
LD_LIBRARY_PATH=~/libfoo/v1:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
exec ~/bin/program_a "$@"
# program_b_wrapper.sh
#!/bin/bash
LD_LIBRARY_PATH=~/libfoo/v2:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
exec ~/bin/program_b "$@"

2.添加执行权限

chmod +x program_a_wrapper.sh program_b_wrapper.sh

1.5.使用符号版本控制(高级)

通过修改库的符号版本信息,让不同版本的符号共存于同一库文件中。

示例步骤:

1.创建版本脚本(libfoo.map)

LIBFOO_1.0 {global:func_v1;local:*;
};LIBFOO_2.0 {global:func_v2;local:*;
} LIBFOO_1.0;

2.编译库时指定版本脚本

# 编译 libfoo.so.2 包含两个版本的符号
g++ -shared -fPIC -o libfoo.so.2.0.0 src/foo.cpp \-Wl,--version-script=libfoo.map

3.程序选择性链接特定版本符号

# 程序 A 链接 v1 符号
g++ -o program_a src/a.cpp -L. -lfoo -Wl,-u,func_v1# 程序 B 链接 v2 符号
g++ -o program_b src/b.cpp -L. -lfoo -Wl,-u,func_v2

2.交叉编译

CMAKE_TOOLCHAIN_FILE 是 CMake 中用于配置交叉编译环境的核心变量。通过指定该变量,可覆盖默认的编译器、工具链和系统搜索路径,实现为不同平台(如嵌入式设备、移动平台)构建软件。

2.1.基本用法

1.定义工具链文件

创建一个 .cmake 文件(如 arm_toolchain.cmake),内容示例:

# 指定目标系统
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)# 指定交叉编译工具
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_AR arm-linux-gnueabihf-ar)
set(CMAKE_RANLIB arm-linux-gnueabihf-ranlib)# 指定系统根目录(可选)
set(CMAKE_SYSROOT /path/to/arm-sysroot)# 仅搜索 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)

2.调用 CMake 时指定工具链文件

cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=path/to/arm_toolchain.cmake

2.2.工具链文件关键配置

1.必选配置项

变量名描述
CMAKE_SYSTEM_NAME目标系统名称(如 LinuxWindowsDarwin
CMAKE_SYSTEM_PROCESSOR目标处理器架构(如 armaarch64x86_64
CMAKE_C_COMPILERC 编译器路径
CMAKE_CXX_COMPILERC++ 编译器路径

2.可选配置项

变量名描述
CMAKE_SYSROOT目标系统根目录(包含 includelib 等目录)
CMAKE_FIND_ROOT_PATH自定义搜索路径(覆盖 CMAKE_SYSROOT
CMAKE_AR/CMAKE_RANLIB归档工具和索引工具(用于静态库)
CMAKE_STRIPstrip 工具(用于去除调试信息)
CMAKE_EXE_LINKER_FLAGS链接器选项(如 -static

2.3.多平台工具链示例

1.ARM 嵌入式 Linux 工具链

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)# 编译器路径(根据实际工具链调整)
set(CMAKE_C_COMPILER /opt/gcc-arm-none-eabi/bin/arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER /opt/gcc-arm-none-eabi/bin/arm-none-eabi-g++)# 不使用系统库(裸机开发)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

2.Android NDK 工具链

set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 21)  # API 级别
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)  # 架构# 指定 NDK 路径
set(CMAKE_ANDROID_NDK /path/to/android-ndk)# 使用 NDK 自带的 CMake 工具链
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_ANDROID_NDK}/build/cmake/android.toolchain.cmake)

3.Windows 交叉编译(从 Linux 到 Windows)

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)# 使用 mingw-w64 工具链
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)  # Windows 资源编译器# 生成 .exe 后缀
set(CMAKE_EXECUTABLE_SUFFIX .exe)

2.4.注意事项

1.集中管理工具链文件

将工具链文件放在项目根目录的 cmake/toolchains/ 目录下,便于版本控制。

2.使用环境变量简化调用

export MY_ARM_TOOLCHAIN=/path/to/arm_toolchain.cmake
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$MY_ARM_TOOLCHAIN

3.工具链文件可继承

复杂项目可创建基础工具链文件,再通过 include() 包含特定平台的配置。

4.测试工具链有效性

使用 try_compile() 在工具链文件中验证编译环境是否正常:

try_compile(COMPILER_WORKS ${CMAKE_BINARY_DIR}/test_compileSOURCES ${CMAKE_CURRENT_LIST_DIR}/test.cOUTPUT_VARIABLE COMPILE_OUTPUT)if(NOT COMPILER_WORKS)message(FATAL_ERROR "编译测试失败: ${COMPILE_OUTPUT}")
endif()

2.5.相关资源

  • CMake 官方工具链文档
    cmake-toolchains(7) — CMake 4.0.3 Documentation

  • Android NDK 工具链示例
    https://developer.android.com/ndk/guides/cmake

  • 跨平台工具链集合
    https://github.com/leetal/ios-cmake(iOS 交叉编译)
    https://github.com/lebedevRI/cmake-toolchains(各种平台工具链)

相关链接

  • CMake 官网 CMake - Upgrade Your Software Build System
  • CMake 官方文档:CMake Tutorial — CMake 4.0.3 Documentation
  • CMake 源码:https://github.com/Kitware/CMake
  • CMake 源码:CMake · GitLab
  • 中文版基础介绍:  CMake 入门实战 | HaHack
  • wiki:  Home · Wiki · CMake / Community · GitLab
  • Modern CMake 简体中文版: Introduction · Modern CMake

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87528.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87528.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/87528.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详解鸿蒙Next仓颉开发语言中的全屏模式

大家好,今天跟大家分享一下仓颉开发语言中的全屏模式。 和ArkTS一样,仓颉的新建项目默认是非全屏模式的,如果你的应用颜色比较丰富,就会发现屏幕上方和底部的留白,这是应用自动避让了屏幕上方摄像头区域和底部的导航条…

LoRA 浅析

1. 核心思想 LoRA 是一种参数高效的微调方法,旨在减少微调大型语言模型 (LLMs) 所需的计算资源和存储空间。其核心思想是: 冻结预训练模型权重: 在微调过程中,保持预训练 LLM 的原始权重不变。引入低秩矩阵: 对于 LL…

软件范式正在经历第三次革命

核心主题:软件范式正在经历第三次根本性革命(软件3.0),其核心是“智能体”(Agent),未来十年将是“智能体的十年”。 逻辑模块解析: 软件的三次重生革命 软件1.0: 传统编…

JavaScript 变量与运算符全面解析:从基础到高级应用

昨天学长说可以放缓一下学习进度,刚好最近期末复习也不是很紧张,所以来重新复习一下js的一些知识点。 一:变量 (1)变量声明 来简单看一下变量的一些知识点。首先是变量声明:变量声明尽量使用数组字母下划线 来举几个例子&#x…

移动语义对性能优化的具体示例

前言 本文章对比了&#xff1a;小中大字符串在普通传值、传值移动、传左值引用、传右值引用、模板完美转发、内联版本等多种测试&#xff0c;对比各个方式的性能优异&#xff1a; 测试代码1 #include <iostream> #include <string> #include <chrono> #incl…

C/C++ 和 OpenCV 来制作一个能与人对弈的实体棋盘机器人

项目核心架构 整个系统可以分为四个主要模块&#xff1a; 视觉感知模块 (Vision Perception Module): 任务: 使用摄像头“看懂”棋盘。工具: C, OpenCV。功能: 校准摄像头、检测棋盘边界、进行透视变换、分割 64 个棋盘格、识别每个格子上的棋子、检测人类玩家的走法。 决策模…

SpringBoot扩展——日志管理!

Spring Boot扩展 在Spring Boot中可以集成第三方的框架如MyBatis、MyBatis-Plus和RabbitMQ等统称为扩展。每一个扩展会封装成一个集成&#xff0c;即Spring Boot的starter&#xff08;依赖组件&#xff09;。starter是一种非常重要的机制&#xff0c;不需要烦琐的配置&#xf…

【JSON-To-Video】AI智能体开发:为视频图片元素添加动效(滑入、旋转、滑出),附代码

各位朋友们&#xff0c;大家好&#xff01; 今天要教大家如何在 JSON - To - Video 中为视频内图片元素添加滑入、旋转、滑出的动效。 如果您还不会封装制作自己的【视频工具插件】&#xff0c;欢迎查看之前的教程&#xff01; AI智能体平台&#xff0c;如何封装自定义短视频…

Spring Boot(九十二):Spring Boot实现连接不上数据库就重启服务

场景: 在线上部署时,若服务器因断电等原因意外重启,项目及其依赖的数据库服务通常需要配置为自动启动。此时,如果数据库服务启动较慢或失败,Spring Boot 项目会因无法建立数据库连接而启动失败。 需求: 为确保项目启动成功,需要让 Spring Boot 项目等待数据库服务完全就…

Debian配置Redis主从、哨兵

前言 Redis的下载安装可参考Centos安装配置Redis6.x&#xff0c;Centos和Debian的步骤基本类似&#xff0c;或自行在网上搜索相关资料 注意&#xff1a;远程连接需放开相应端口 主从 搭建一个一主二从的主从模式 处理conf文件 #进入redis所在目录 cd /tools/redis/redis6 …

虚实交融:数字孪生如何重塑交通与公路勘察设计的未来

当每一条道路、每一座桥梁、每一盏信号灯都在数字世界获得“永生副本”&#xff0c;交通系统从被动响应迈入主动预演的纪元 一、数字孪生的核心定义&#xff1a;超越镜像的动态认知引擎 数字孪生&#xff08;Digital Twin&#xff09;并非简单的三维可视化模型&#xff0c;而是…

vector模拟实现中的迭代器失效问题

首先来看一组代码&#xff1a; iterator insert(iterator pos, const T& x) {// 扩容if (_finish _end_of_storage){size_t len pos - _stare;reserve(capacity() 0 ? 4 : capacity() * 2);pos _stare len;}iterator end _finish - 1;while (end > pos){*(end…

java 设计模式_行为型_22模板模式

22.模板模式 模板方法&#xff08;Template Method&#xff09;作为Java的设计模式之一&#xff0c;一个词概括其优势特点那就是&#xff1a;抽象步骤 首先我们应该抽出共通的东西做一个父类&#xff08;Base类&#xff09;&#xff0c;其次具体的蛋糕制作由子类进一步实现&…

随记:在springboot中websocket的使用

我现在有两种方法 第一种&#xff1a;使用java封装的这个包下的javax.websocket.* 先配置这个配置类 import com.alibaba.nacos.common.utils.CollectionUtils; import org.springframework.stereotype.Component;import javax.websocket.HandshakeResponse; import javax.w…

技术文章大纲:SpringBoot自动化部署实战

技术文章大纲&#xff1a;SpringBoot自动化部署实战 概述 自动化部署的背景与意义SpringBoot在现代化部署中的优势常见自动化部署工具与方案概览&#xff08;Jenkins、Docker、K8s等&#xff09; 环境准备 基础工具要求&#xff1a;JDK、Maven/Gradle、Git服务器环境配置&a…

FastAdmin按钮类功能全解析 class 属性定义不同的交互行为

在 FastAdmin 中&#xff0c;超链接的 class 属性用于定义不同的交互行为和样式。以下是常见 class 配置的用途和区别&#xff1a; btn-dialog 用于触发弹出对话框行为。点击带有此 class 的链接或按钮时&#xff0c;FastAdmin 会自动加载指定的 URL 内容并在模态框中显示。通…

python3字典对象实现解析

文章目录 前言Raymond的方案字典结构字典创建字典插入插入空字典PyDictKeysObject的创建设置索引存储entry 插入非空字典调整大小字典查找联合字典插入 字典查询字典删除 前言 本来以为python字典的实现就是一个哈希表的普通实现&#xff0c;所以在学习基本类型时没去仔细研究…

Word2Vec介绍

前言 当今的大语言模型非常智能&#xff0c;但是你有没有想过这些事情&#xff1a; 机器是怎么理解“国王”和“王后”之间的关系&#xff1f; “猫”和“狗”是怎么在 AI 中“相似以及区分”的&#xff1f; 文本又是怎么变成模型能读懂的数字&#xff1f; 这一切&#xf…

Rsync+sersync实现数据实时同步(小白的“升级打怪”成长之路)

目录 一、rsync部署 push推数据 1、编写rsync配置文件 2、备份测试 3、检验结果 二、rsyncsersync 实现数据实时同步 1、安装sersync服务 2、检验结果 pull拉取数据 1、编写rsync配置文件 2、检验结果 三、脚本编写 1、客户端脚本编写 2、服务器脚本编写 一、rsy…

用 python 开发一个可调用工具的 AI Agent,实现电脑配置专业评价

在人工智能时代&#xff0c;AI Agent凭借其强大的任务处理能力&#xff0c;逐渐成为开发人员手中的得力工具。今天&#xff0c;我们就来一起动手&#xff0c;用Python打造一个能够调用工具的AI Agent&#xff0c;实现根据电脑信息对电脑配置进行专业评价的功能。 一、项目创建…