C++ Windows 打包exe运行方案(cmake)

文章目录

  • 背景
  • 动态库梳理
  • 打包方案
    • 一、使用 Vcpkg 安装静态库(关键基础配置)
      • 1. 初始化 Vcpkg
      • 2. 安装静态库(注意 `x64-windows-static` 后缀)
    • 二、CMakeLists.txt 关键配置
    • 三、编译
    • 四、验证
  • 不同平台代码兼容
    • \_\_attribute\_\_((packed)) 兼容
    • #include \<arpa/inet.h> 兼容
    • time兼容
    • timezone兼容

背景

使用C++编写的一个小项目,需要打包成windows下的可执行文件(免安装版本),方便分发给其他windows执行,需要把项目的动态库都打在软件包中,分发之后可以直接运行,而不需要再重复安装。

动态库梳理

经过依赖精简和梳理,项目最终必须依赖的动态库包括:pcl, bzip2, lz4, yaml, rosbag(用于读取rosbag包,后续会有专门的文章会提到如何做到不依赖ros环境)

打包方案

yaml动态库在前面的文章中已经转成了静态库代码的形式包含在了项目里。对于其他动态库,简单调研了一下,发现可以使用 vcpkg 工具 将所有动态库以静态库的形式来安装,那就尝试用这个方案。

一、使用 Vcpkg 安装静态库(关键基础配置)

1. 初始化 Vcpkg

# 克隆 vcpkg 仓库
git clone https://github.com/microsoft/vcpkg
# 构建 vcpkg
.\vcpkg\bootstrap-vcpkg.bat

2. 安装静态库(注意 x64-windows-static 后缀)

# 安装核心依赖
.\vcpkg.exe install bzip2:x64-windows-static lz4:x64-windows-static# 安装 PCL 及其全套依赖(耗时约 30-60 分钟),可能需要科学上网
.\vcpkg.exe install pcl:x64-windows-static

二、CMakeLists.txt 关键配置

cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_TOOLCHAIN_FILE "your_path/vcpkg/scripts/buildsystems/vcpkg.cmake")
project(project_name)# 1. 强制使用静态运行时库
if(MSVC)# 静态链接运行时(/MT 或 /MTd)set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")# 删除所有可能存在的动态运行时选项, 防止依赖冲突报错string(REGEX REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})string(REGEX REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})string(REGEX REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})add_compile_options(/MP)  # 启用多核编译(可选)add_definitions(-DNOMINMAX)  # Avoid conflicts with min/max macros like error C2589: “(”:“::”右边的非法标记
endif()...
# 添加子目录编译 yaml-cpp 库
add_subdirectory(thirdparty/yaml-cpp)find_package(BZip2 REQUIRED)
find_package(LZ4 REQUIRED)# 这里只依赖了 io 这一个components,其他组件可以按需添加
find_package(PCL REQUIRED COMPONENTS io)
if(PCL_FOUND)message("PCL FOUND")include_directories(${PCL_INCLUDE_DIRS})
else()message(WARNING "can not find PCL")
endif()add_executable(MyApp ...)
target_include_directories(MyApp PUBLIC ${PCL_INCLUDE_DIRS}${CMAKE_SOURCE_DIR}/thirdparty/yaml-cpp/include...
)# 链接库
target_link_libraries(MyApp PUBLIC yaml-cppBZip2::BZip2LZ4::lz4_static${PCL_LIBRARIES}ws2_32
)

三、编译

# 1. 生成构建系统
cmake -B build -DCMAKE_BUILD_TYPE=Release -DVCPKG_TARGET_TRIPLET=x64-windows-static -DCMAKE_TOOLCHAIN_FILE="your_path/vcpkg/scripts/buildsystems/vcpkg.cmake"
# 2. 编译项目
cmake --build build --config Release --parallel 8

四、验证

# 验证依赖项, 需要
dumpbin /dependents build/Release/MyApp.exe

预期输出应该只包含以下系统库:

KERNEL32.dll
USER32.dll
...
不会有其他第三方 DLL(如 boost_*.dll, pcl_*.dll 等)

注意:dumpbin 命令为VisualStudio的工具:

在这里插入图片描述

不同平台代码兼容

__attribute__((packed)) 兼容

以下代码中的__attribute__((packed)) 与编译平台Unix/Linux强相关:

typedef struct MyStruct_s
{int a;char b;
}__attribute__((packed)) MyStruct;

需要做出针对windows的兼容性修改:

// 根据编译器类型选择内存对齐语法,建议在 common.h 中定义
#if defined(_MSC_VER)#define PACKED_BEGIN __pragma(pack(push, 1))#define PACKED_END   __pragma(pack(pop))#define PACKED_STRUCT  /* MSVC 下无需额外关键字 */
#elif defined(__GNUC__) || defined(__clang__)#define PACKED_BEGIN#define PACKED_END#define PACKED_STRUCT  __attribute__((packed))
#endif// 使用方式:
PACKED_BEGIN
struct MyStruct {int a;char b;
} PACKED_STRUCT;
PACKED_END

#include <arpa/inet.h> 兼容

arpa/inet.h 是Unix/Linux特有的头文件 ,而Windows平台没有这个头文件。

看代码中需要用到的只有ntohs ,windows上对应的头文件为<winsock2.h>

#if defined(_WIN32) || defined(_WIN64)#include <winsock2.h>
#else#include <arpa/inet.h>
#endif

依赖的库为ws2_32.lib,需要在CMakeLists.txt中显式链接,否则编译会报错:error LNK2001: 无法解析的外部符号 __imp_ntohs, 参考 https://www.cnblogs.com/chai51/p/16931965.html

target_link_libraries(MyApp PUBLIC ...ws2_32
)

time兼容

<time.h> 为Unix/Linux 平台下独有,比如 clock_gettime(CLOCK_MONOTONIC, &time) ,在windows上兼容方案如下:

#if defined(_WIN32) || defined(_WIN64)#include <windows.h>
#else#include <time.h>
#endif
unsigned int GetMicroTickCount() {unsigned int ret = 0;#if defined(_WIN32) || defined(_WIN64)// Windows implementation using QueryPerformanceCounterstatic LARGE_INTEGER frequency;static BOOL frequencyInitialized = QueryPerformanceFrequency(&frequency);if (!frequencyInitialized) {return 0; // If the frequency cannot be initialized, return 0}LARGE_INTEGER counter;if (QueryPerformanceCounter(&counter)) {ret = static_cast<unsigned int>((counter.QuadPart * 1000000) / frequency.QuadPart);}#elsetimespec time;memset(&time, 0, sizeof(time));if (clock_gettime(CLOCK_MONOTONIC, &time) == 0) {ret = time.tv_nsec / 1000 + time.tv_sec * 1000000;}#endifreturn ret;
}

timezone兼容

同上, timezone关键词也是 Unix/Linux 独有,兼容方案如下:

#ifdef _WIN32// Windows: Use _get_timezone with a temporary long variablelong temp_offset = 0;_get_timezone(&temp_offset);time_offset = static_cast<int64_t>(temp_offset);
#else// Linux: Use timezone global variableextern long timezone;time_offset = timezone;
#endif
return (raw_time - time_offset) * 1000000 + GetTimestamp();

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

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

相关文章

Java学习手册:Hibernate/JPA 使用指南

一、Hibernate 和 JPA 的核心概念 实体&#xff08;Entity&#xff09; &#xff1a;实体是 JPA 中用于表示数据库表的 Java 对象。通过在实体类上添加 Entity 注解&#xff0c;JPA 可以将实体类映射到数据库表。例如&#xff0c;定义一个 User 实体类&#xff1a; import ja…

字符串匹配 之 拓展 KMP算法(Z算法)

文章目录 习题2223.构造字符串的总得分和3031.将单词恢复初始状态所需的最短时间 II 灵神代码模版 区别与KMP算法 KMP算法可用于求解在线性时间复杂度0(n)内求解模式串p在主串s中匹配的未知当然&#xff0c;由于在KMP算法中&#xff0c;预处理求解出了next数组&#xff0c;也就…

安全为上,在系统威胁建模中使用量化分析

*注&#xff1a;Open FAIR™ 知识体系是一种开放和独立的信息风险分析方法。它为理解、分析和度量信息风险提供了分类和方法。Open FAIR作为领先的风险分析方法论&#xff0c;已得到越来越多的大型组织认可。 在数字化风险与日俱增的今天&#xff0c;企业安全决策正面临双重挑战…

游戏引擎学习第259天:OpenGL和软件渲染器清理

回顾并为今天的内容做好铺垫 今天&#xff0c;我们将对游戏的分析器进行升级。在之前的修复中&#xff0c;我们解决了分析器的一些敏感问题&#xff0c;例如它无法跨代码重新加载进行分析&#xff0c;以及一些复杂的小问题。现在&#xff0c;我们的分析器看起来已经很稳定了。…

讯睿CMS模版常用标签参数汇总

一、模板调用标签 1、首页 网站名称&#xff1a;{SITE_NAME} 标题&#xff1a;{$meta_title}&#xff08;列表页通用&#xff09; Keywords&#xff1a;{$meta_keywords} Description&#xff1a;{$meta_description}2、列表页 迅睿cms调用本栏目基础信息标签代码 当前栏目…

【C#】Buffer.BlockCopy的使用

Buffer.BlockCopy 是 C# 中的一个方法&#xff0c;用于在数组之间高效地复制字节块。它主要用于操作字节数组&#xff08;byte[]&#xff09;&#xff0c;但也可以用于其他类型的数组&#xff0c;因为它直接基于内存操作。 以下是关于 Buffer.BlockCopy 的详细说明和使用示例&…

记一次pdf转Word的技术经历

一、发现问题 前几天在打开一个pdf文件时&#xff0c;遇到了一些问题&#xff0c;在Win10下使用WPS PDF、万兴PDF、Adobe Acrobat、Chrome浏览器打开都是正常显示的&#xff1b;但是在macOS 10.13中使用系统自带的预览程序和Chrome浏览器&#xff08;由于macOS版本比较老了&am…

在Laravel 12中实现4A日志审计

以下是在Laravel 12中实现4A&#xff08;认证、授权、账户管理、审计&#xff09;日志审计并将日志存储到MongoDB的完整方案&#xff08;包含性能优化和安全增强措施&#xff09;&#xff1a; 一、环境配置 安装MongoDB扩展包 composer require jenssegers/mongodb配置.env …

链表高级操作与算法

链表是数据结构中的基础&#xff0c;但也是面试和实际开发中的重点考察对象。今天我们将深入探讨链表的高级操作和常见算法&#xff0c;让你能够轻松应对各种链表问题。 1. 链表翻转 - 最经典的链表问题 链表翻转是面试中的常见题目&#xff0c;也是理解链表指针操作的绝佳练…

架构思维:构建高并发读服务_使用懒加载架构实现高性能读服务

文章目录 一、引言二、读服务的功能性需求三、两大基本设计原则1. 架构尽量不要分层2. 代码尽可能简单 四、实战方案&#xff1a;懒加载架构及其四大挑战五、改进思路六、总结与思考题 一、引言 在任何后台系统设计中&#xff0c;「读多写少」的业务场景占据主流&#xff1a;浏…

在运行 Hadoop 作业时,遇到“No such file or directory”,如何在windows里打包在虚拟机里运行

最近在学习Hadoop集群map reduce分布运算过程中&#xff0c;经多方面排查可能是电脑本身配置的原因导致每次运行都会报“No such file or directory”的错误&#xff0c;最后我是通过打包文件到虚拟机里运行得到结果&#xff0c;具体步骤如下&#xff1a; 前提是要保证maven已经…

软考-软件设计师中级备考 11、计算机网络

1、计算机网络的分类 按分布范围分类 局域网&#xff08;LAN&#xff09;&#xff1a;覆盖范围通常在几百米到几千米以内&#xff0c;一般用于连接一个建筑物内或一个园区内的计算机设备&#xff0c;如学校的校园网、企业的办公楼网络等。其特点是传输速率高、延迟低、误码率低…

【C#】.net core6.0无法访问到控制器方法,直接404。由于自己的不仔细,出现个低级错误,这让DeepSeek看出来了,是什么错误呢,来瞧瞧

&#x1f339;欢迎来到《小5讲堂》&#x1f339; &#x1f339;这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。&#x1f339; &#x1f339;温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01;&#…

当LLM遇上Agent:AI三大流派的“复仇者联盟”

你一定听说过ChatGPT和DeepSeek&#xff0c;也知道它们背后的LLM&#xff08;大语言模型&#xff09;有多牛——能写诗、写代码、甚至假装人类。但如果你以为这就是AI的极限&#xff0c;那你就too young too simple了&#xff01; 最近&#xff0c;**Agent&#xff08;智能体&a…

Spring Boot多模块划分设计

在Spring Boot多模块项目中&#xff0c;模块划分主要有两种思路&#xff1a;​​技术分层划分​​和​​业务功能划分​​。两种方式各有优缺点&#xff0c;需要根据项目规模、团队结构和业务特点来选择。 ​​1. 技术分层划分&#xff08;横向拆分&#xff09;​​ 结构示例&…

两次解析格式化字符串 + 使用SQLAlchemy的relationship执行任意命令 -- link-shortener b01lersCTF 2025

题目描述: A fast and reliable link shortener service, with a new feature to add private links! 我们走一遍逻辑 注册 app.route("/register", methods[GET, POST]) def register(): """ 用户注册路由&#xff0c;处理用户注册请求&#xff…

后端id类型为long类型时,返回给前端浏览器四舍五入,导致id精度缺失问题

背景 今天在代码里&#xff0c;掉了别人写的接口&#xff0c;有个id的字段是long类型的&#xff0c;我这边加点参数返回给前端&#xff0c;然后前端根据id修改&#xff0c;结果修改的数据记录有&#xff0c;但是没起作用&#xff0c;后来发现根据他传给我的id在后台数据库查不…

Scartch038(四季变换)

知识回顾 1.了解和简单使用音乐和视频侦测模块 2.使用克隆体做出波纹特效 3.取色器妙用侦测背景颜色 前言 我国幅员辽阔,不同地方的四季会有不同的美丽景色,这节课我带你使用程序做一个体现北方四季变化的程序 之前的程序基本都是好玩的,这节课做一个能够赏心悦目的程序。…

JVM happens-before 原则有哪些?

理解Java Memory Model (JMM) 中的 happens-before 原则对于编写并发程序有很大帮助。 Happens-before 关系是 JMM 用来描述两个操作之间的内存可见性以及执行顺序的抽象概念。如果一个操作 A happens-before 另一个操作 B (记作 A hb B)&#xff0c;那么 JMM 向你保证&#x…

从 Eclipse Papyrus / XText 转向.NET —— SCADE MBD技术的演化

从KPN[1]的萌芽开始&#xff0c;到SCADE的推出[2]&#xff0c;再到Scade 6的技术更迭[3]&#xff0c;SCADE 基于模型的开发技术已经历许多。现在&#xff0c;Scade One 已开启全新的探索 —— 从 Eclipse Papyrus / XText 转向.NET 8跨平台应用。 [1]: KPN, Kahn进程网络 (197…