首页 > 编程语言 >msvc C++编译链接

msvc C++编译链接

时间:2023-07-19 18:26:48浏览次数:112  
标签:函数 lib 静态 C++ dll 编译 msvc 链接

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库文件。大多数是没有这个问题的。

标签:函数,lib,静态,C++,dll,编译,msvc,链接
From: https://www.cnblogs.com/zijian-yang/p/17566414.html

相关文章

  • C / C++ Data Structure
    用低劣的水平描述数据结构的东西,后续考研还要细学目前主要加深对数据结构的理解,大体过一遍,如果你质疑我的文章,那一定是我错了,我会忽略一些专业术语,更偏向于自己的理解思考对于初学者来说可能会有一定的帮助前置一堆概念数据:客观事物的符号描述数据元素:数据的基本单位......
  • Embedding into a shared library fails-- c++ import numpy异常
    rb reportatbugs.python.orgWedNov2610:13:39CET2008 Previousmessage: [New-bugs-announce][issue4433]_ctypes.COMErrorcrashNextmessage: [New-bugs-announce][issue4435]SphinxdoesnotshowfaileddoctestsinquietmodeMessagessortedby: [da......
  • (GCC) gcc编译选项 -Wl, -start-group,whole-archive,-Wl, Bstatic
    1.start-group编译选项假设程序x依赖三个静态库:libX1.a、libX2.a和libX3.a,而libX2.a又依赖libX1.a,libX3.a依赖libX2.a和libX1.a,正常情况下的CMakeLists.txt格式如下target_link_libraries(xlibX1.alibX2.alibX3.a)但也可以偷懒,不关心静态库的顺序问题,ld......
  • C/C++以太网布网及故障检测模拟[2023-07-19]
    C/C++以太网布网及故障检测模拟[2023-07-19]“数据结构与算法综合设计”任务书专业:计算机与软件工程学院所有专业年级:2021一、 设计题目以太网布网及故障检测模拟二、 设计内容【问题描述】某个以太网内有n台计算机,由于搭建以太网时工作人员的疏忽,现......
  • Android编译报错Caused by: java.lang.RuntimeException: Manifest merger failed wit
    Android编译报错Causedby:java.lang.RuntimeException:Manifestmergerfailedwithmultiple这种异常一般是引用了aar,如果项目中的manifestapplication配置和aar中不一样就会报错,比如android:icon和aar中不一致,则添加tools:replace="android:icon"配置即可。......
  • C/C++数据结构课程设计题目[2023-07-19]
    C/C++数据结构课程设计题目[2023-07-19]数据结构课程设计题目基本要求:1、每人1题,如果系统具有界面以及功能复杂,可以2人合作一题。2、可以自拟题目,难度不低于给定题目,且自拟的题目需要经过老师审核通过。3、要求实现一个界面美观、功能完整、具有实用性的系统。4、不限制......
  • lua环境配置与编译
    1.背景2.安装lua官方下载地址:https://joedf.ahkscript.org/LuaBuilds/下载后解压即可 解压后: 配置环境变量: 检查是否安装成功: 如果能输出版本号,则表示配置成功.3.执行lua文件4.编译lua文件完美!......
  • 编译安装redis6.2.13集群-哨兵模式
    下载并编译Redis虽然使用SLES15进行编译,但是理论上在其它系统上也是可行的,我们把编译所需要的依赖包安装即可。Redis我们选择6.2.13这个版本,我们先随便找个节点进行编译产生二进制文件#首先安装依赖包zypperref&&zypperinstallgccmakesystemd-devel#SLES/SUSEyu......
  • 编译安装最新的Pluto compiler,以及遇到的一些坑
    好久不见!这段时间在鼓捣一些奇奇怪怪的东西。PlutoCompiler是一款非常优秀的Polyhedral编译器。这玩意拿来优化循环和程序局部性啥的是相当好的。其安装过程涉及到整个llvm的编译过程,如果之前并没能够了解llvm的话估计会够呛,我也是基本上把坑踩了一个遍。所以干脆写篇博客给之......
  • 从哪里找到、下载已经预编译好的二进制openjdk文件?
    openjdk在官网上都是源码,在实际使用中,需要直接用到二进制文件 尤其是基于alpine构建openjdk的基础镜像,发现...... 将linux版本的openjdk17的二进制tar.gz包,在alpine中进行解压,是无法运行的,安装glibc之后,也会有问题,很多的时候,会出现版本不匹配的问题,然后,这个问题就真的很难......