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.pswp.cn/bicheng/79852.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/79852.shtml
英文地址,請注明出處:http://en.pswp.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…