惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Simon Willison's Weblog
Simon Willison's Weblog
P
Privacy International News Feed
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Troy Hunt's Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
Attack and Defense Labs
Attack and Defense Labs
S
Secure Thoughts
V2EX - 技术
V2EX - 技术
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
O
OpenAI News
Cloudbric
Cloudbric
Google Online Security Blog
Google Online Security Blog
Schneier on Security
Schneier on Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Help Net Security
Help Net Security
Cyberwarzone
Cyberwarzone
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Spread Privacy
Spread Privacy
NISL@THU
NISL@THU
N
News and Events Feed by Topic
T
Tenable Blog
S
Security @ Cisco Blogs
N
News and Events Feed by Topic
The Hacker News
The Hacker News
C
CXSECURITY Database RSS Feed - CXSecurity.com
宝玉的分享
宝玉的分享
月光博客
月光博客
酷 壳 – CoolShell
酷 壳 – CoolShell
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
V
Visual Studio Blog
P
Proofpoint News Feed
Webroot Blog
Webroot Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 三生石上(FineUI控件)
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Jina AI
Jina AI
雷峰网
雷峰网
T
The Blog of Author Tim Ferriss
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
L
LangChain Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东

博客园 - BackSword

unity ui canvas shader texcoord.zw is not used for ui particle 问题记录,unity shaderlab 模版写入问题 textmeshpro 放大缩小出现黑色边框问题,修改shader FXAA 在桌面平台更高效的原因,MSAA在手机端更高效 glados优惠码 C# Array.Fill 值类型优化。 git 设置github代理 unity physics bug win10 ctrl+space 快捷键冲突问题 切线空间 c++局部静态变量是线程安全的 c++函数参数和返回值 c++返回值不能是右值对象 状态同步 分享mkgmttime自实现功能。 关于socket通信中大小端转换问题 wpf clickonece 坑 [修复] 启动期间超频失败的错误信息 template return value error C2440: “初始化”: 无法从“const T”转换为“const Player *&”
msvc C++编译链接
BackSword · 2023-07-19 · via 博客园 - BackSword

C++编译链接

静态库编译

C RunTimeLibrary

C++是C的超集,C RunTimeLibrary 是 C 标准库,在编译期安装的时候,或者下载vc运行时库安装到电脑中。

msvc中/mt /mtd /md /mdd 是决定当前程序用哪个C RunTimeLibrary. 不同的实现不同。

链接过程

静态库链接过程是需要所有的lib文件。比如 A 静态库有 Hello 函数。 B 静态库使用 A 项目的 Hello 函数编译成 Hello World 函数,C 执行程序调用 B 的Hello World函数。

A.lib 会包含Hello函数的信息。

B.lib 会包含HelloWorld函数的信息。但没有Hello的函数。

C.exe 要链接exe的时候,需要 A.lib B.lib 才能真正链接成功。

当然还有一些默认的,比如 C RunTimeLibrary 的链接,也会参与进来。

当A.lib的 C RunTimeLibrary 与 B.lib 中C RunTimeLibrary的版本不匹配的时候,会报 error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MTd_StaticDebug”。 (如果没有调用 C 的函数,则不会报这个错,最常见的 #include ... 但是基本函数,只要有一个包含了,就会报错,所以必然出错)

原因是 在链接的过程中,C的函数有多种实现导致。所以同一个函数,无法定位真正是哪个RunTimeLibrary中的函数参与进来。

动态库编译

动态库编译成dll,是跟exe一样需要链接,链接一个可加载的动态库。所以一个dll中,包含所有引用的函数信息。

A.lib 静态库 b.lib b.dll 动态库(动态库项目也会生成一个lib符号文件,但没有实现,因为c++会在编译期间,把函数和类改名。)

b.dll 中就包含 Hello 函数的信息,当链接的时候,只需要链接 b.lib 即可。

c.exe 就只需要b.lib 和 b.dll 即可。

场景问题加深理解

下面场景都是使用了 RuntimeLibrary 库的情景(基本没有不用的)

  1. 因为exe必用 c 标准库的东西,所以链接的时候如果 /MD /MDD /MT /MTD 如果不匹配,都会报 RuntimeLibrary 不一致

  2. 3rd_release.lib -> engine.lib -> app.exe 3rd_release.lib 如果是静态库,并且是release,没有debug版本, 那 engine.lib 必须也是release版本的lib,否则在 app.exe 生成的时候会报 RuntimeLibrary 不一致。

  3. debug 是可以链接 release 版本的代码库的,但是 debug A.exe 不能调用 额外的 debug B 库,B 调用 release.lib 会报 A.exe 的RuntimeLibrary和 release.lib 的不一致。

  4. stl 不同debug release 的 许多变量的长度不一致,运行时会溢出闪退。

  5. *.lib 库对应的宏和头文件使用应保持一致,因为编译时,已经根据宏 导出函数内容到 .lib 中,如果头文件声明跟 lib 中函数不一致,会导致 函数 link 不上。

  6. class 的头文件函数(实现在头文件中), lib 中不会定义,基本大部分编译期,会直接把头文件函数变为内联函数,而且不用dllexport。

  7. 如果想使用 3rd_release.lib -> engine.lib -> app.exe engine 是debug库,可以用 engine.dll ,这样会在dll时候,就链接完成。

  8. 静态库函数保持一致,全局变量,静态变量都是一份。动态库会在链接的时候,把静态库的内容链接到dll中,两个dll链接一个静态库,则这个静态库中的全局变量和静态变量都是两份。如果宏定义不一致,则会爆炸。(可以想象,一个库改了静态变量,而另一个库的函数中没有改,导致实现有时好,有时坏。 心态爆炸)

  9. vs 中如果不填 /md ... 等,填空,会默认 /mt /mtd (不一定,我测试是这样)

  10. cpp中使用宏,头文件不使用的库,已经生成的lib 文件,链接的主体(exe)再怎么改 宏定义,也不会影响函数的实现(在编译的过程已经确定了,链接方再怎么改,也无济于事)

  11. 网上查的dll使用准则是,dll中的对象,不能传递到dll外,如果传出来,可能会调用到跟dll中预想不同的函数(因为dll的宏定义是在dll生成的时候,但是使用的人的dll和stl等标准库的实现不一致),导致整体流程损坏而查不到原因。 dll的对象是在dll中运转(减少错误发生率)

总结

如果没有想好的话,最好是不要使用dll,静态库只是编译慢,但会减少很多问题。 如果想要使用dll,则一定要注意项目链接和宏,还有对象的流转,还有dll链接的问题。

最好是,如果一个dll链接了一个静态库,则不导出这个静态库的任何头文件,所有想要操作这个静态库的,都需要通过dll的接口来调用。

gcc clang 等编译器,有些没有_DEBUG 宏,当跨编译器链接的时候,也可能会出现额外的问题。

而有些cmake工具会重写宏定义,如果通过vs创建项目,有些会定义默认的宏定义,但是cmake等工具,是直接写文件。导致不一定会跟vs等IDE一样生成默认的宏定义。则会导致编译的问题。

目前C++项目第三方都是开源的,或者会给debug版本,所以大部分都是自己公司的某个人写的(或者哪里编译出来的)才会导致只有release库文件。大多数是没有这个问题的。