前言(maybe废话)

最近正在学习cherno的游戏引擎教程,他使用的是vs进行构建的,后面换了premake。而我用的是vscode+cmake,所以在构建整个项目的时候踩了不少的坑,也找了很多资料去努力解决,比如b站双笙子大佬的cmake教程(强推)。

遂有感而发,写下本篇博客记录一下。

duan20030920@gmail.com 这是我的邮箱,如果有朋友有什么疑问的话,欢迎咨询。当然也可以评论。

CMake是自由的

众所周知的是,CMake是基于你文件系统中的CMakeLists.txt文件的,所以,只要你文件夹里面有个CMakeLists文件,你都可以把该文件夹构建成一个项目。

由此而发,我们很自然地会想,我是否能在一个项目的文件夹中去再构建一个项目呢?

当然是可以的,只要你放CMakeLists,我们就是兄弟(雾)。

扯远了,咳咳。这篇博客主要是用来讲dll的。

说起dll,大家肯定都不陌生,它是windows平台下,用于动态链接的库文件。

什么是动态链接我在此就不多做赘述。

那么,当我们把一个项目编译成dll之后,我们该如何使用它呢?

是不是只要和.lib一样,target_link一下就行了呢?当然不是,win下的动态链接机制较为复杂,大体可以分成两个部分:

  1. 程序知道我可以链接谁(用谁的函数)
  2. 程序真的导入了相应的二进制文件

过程1

你可能会想,为什么我直接把程序链接上dll之后,不能直接使用呢?

如果你是高贵的linux用户,这么做是没问题的(.so)。

但是在window下,你不能直接这么做。

前面我们提到,exe是按需将dll中的函数和数据(以下简称“数据”)链接到其中的,所以我们肯定不能一口气将dll全部复制到程序中,那不就成了lib了。所以我们就需要知道我们要链接哪些数据,以及 我们到哪里链接哪些数据

前者在我们通过引入dll的头文件解决,但问题是如果没有后者,即使我们知道要用谁,也是束手无策的。

所以windows就在它的dll动态链接系统中,提供了下面一种架构,在创建dll的同时,创建一个lib,这个lib负责告知exe,dll里面都有什么数据,相当于一个声明,所以它的size很小,也满足我们灵活性的需求。

(更加细节的部分,请看下方的“为何Windows下链接dll还需要一个.lib?)

过程2

与lib直接将数据复制到exe不同,dll是在运行时,将所需要的数据加载到内存的方式,提供给exe使用,并且实现了多个exe的复用。所以很多大型的项目都趋向于将库做成dll的形式与exe分离,减小exe的大小。

所以,我们的exe能不能找到dll就很关键。

于是我们对构建系统进一步发展,设计出dll的两种链接到exe的方式。它们分别是:隐式链接和显式链接。

所谓隐式与显式之别,就是 是否在程序中指定链接dll

隐式链接

就是我们之前提到的,利用.lib和.h导入我们需要的信息,然后进行dll中的动态链接。

显式链接

在程序中指定,这需要window提供的库函数来实现。

# Dynamic-Link库函数

这是更底层的,线程级对dll加载的控制。

同时,在某种程度上,实现了延时加载和按需加载,也给了我们dll路径更多的选择。

是目前超大型项目的不二之选。

这个我们以后再细聊。

more information...

为何.exe运行时需要.dll在身边

首先要明确的是,dll是在我们的exe运行时动态的链接到程序中的,也就是说,等你要了,我才把我的二进制文件给你。

又因为cmake是作用于项目的构建时,所以它不能设定我们的应用程序去搜索指定目录下的dll。

windows下dll动态链接系统设定要求,在进行动态链接时,运行时程序会搜索如下路径的dll文件:

  • exe路径下
  • 系统变量path路径下
  • system路径,也就是系统目录下

    所以在 默认情况下,我们自己项目的dll文件需要放在exe目录下,那有没有其它的解决方案呢?

使用Window.h库函数动态加载dll

参考:

# c++ 分目录加载dll依赖

# exe与引用的dll不在同一目录下

既然它是运行时加载,那我把它写到我的程序里不就行了吗?

但是这种方案也会带来很多不便,比如说它需要我们修改源代码,而且不能使用模糊搜索,优雅,但没有完全优雅。

不过用于组织我们的项目可以说是绰绰有余了。

为何Windows下链接dll还需要一个.lib?

在 Windows 系统中使用 DLL(动态链接库)时需要一个额外的 .lib 文件作为导入库,主要是由于 Windows 链接模型和 DLL 如何被操作系统和应用程序使用的特定设计决策。以下是一些关键原因和这种设计的详细解释:

1. 链接过程的分隔

在 Windows 上,应用程序通常在编译时静态链接到库,或者在运行时动态链接。DLL 为动态链接提供支持,它们在应用程序启动后或运行中按需加载。然而,为了在编译时让链接器知道哪些函数可用,以及它们在 DLL 中的具体位置,就需要一个额外的导入库(.lib 文件)来作为中介:

  • 导入库包含存根:导入库 .lib 包含了指向 DLL 中函数的跳转存根(stubs)。这些存根提供了必要的信息,以确保在应用程序调用 DLL 中的函数时,能够正确地重定向到相应的函数实现。

2. 解析外部符号

当你的程序使用 DLL 中的函数时,编译器需要解析这些外部函数调用的位置。导入库包含了所有公开函数的符号及其入口点,这些信息在编译时被链接器使用,以确保运行时能够找到并调用正确的代码。

  • 避免编译时直接依赖 DLL:如果没有导入库,编译器在编译时会需要直接访问 DLL,这在多数开发和构建环境中是不可行的。使用导入库简化了构建过程,允许编译器和链接器在没有实际 DLL 文件的情况下完成其工作。

3. 模块化和部署灵活性

使用导入库和 DLL 分离的方式提高了应用程序的模块化和部署灵活性。开发者可以仅重新部署修改过的 DLL 而不需要重新编译整个应用程序,这样可以方便地更新和维护大型应用。

  • 允许不同的语言和工具链开发:DLL 可以由不同的编程语言编写和编译,只要它们遵循相同的调用约定。这样,C#、Visual Basic、C++ 等不同语言编写的组件都可以使用相同的 DLL,而通过导入库与之交互。

4. 运行时加载

DLL 可以在应用程序运行时加载和卸载,提供了高度的灵活性。导入库使得这种动态加载成为可能,因为它把编译时的外部依赖转换为运行时的动态查找和链接。

总的来说,导入库 .lib 在 Windows 系统中的使用提供了一个高效、灵活的机制,使得程序在编译时不必绑定特定的库实现,同时在运行时可以利用 DLL 提供的动态链接和模块化的好处。

CMake 进行多项目中dll的编译和链接的更多相关文章

  1. IDEA的maven项目中 静态文件编译的问题

    IDEA的maven项目中,默认源代码目录下的xml等资源文件并不会在编译的时候一块打包进classes文件夹,而是直接舍弃掉. 如果使用的是Eclipse,Eclipse的src目录下的xml等资源 ...

  2. Java之——Web项目中DLL文件动态加载方法

    本文转自:https://blog.csdn.net/l1028386804/article/details/53903557 在Java Web项目中,我们经常会用到通过JNI调用dll动态库文件来 ...

  3. IDEA的maven项目中静态文件编译的路径问题(未测试)

    转自:http://www.cnblogs.com/signheart/p/6625126.html IDEA的maven项目中,默认源代码目录下的xml等资源文件并不会在编译的时候一块打包进clas ...

  4. DelphiXE10.1项目中增加预编译的方法

    操作: 菜单选择Proceject->Options->Delphi Compilerz在Conditional Defines(第一行)中添加预编译标识.例:VCL代码:uses{$IF ...

  5. 在CLion项目中指定不同版本的链接库

    在项目中, 需要使用到libevent-2.1.x, 但是Ubuntu16.04自带的libevent版本为2.0.5, 需要另外编译安装新版的libevent, 安装过程很简单 -stable.ta ...

  6. Linux中程序的编译和链接过程

    1.从源码到可执行程序的步骤:预编译.编译.链接.strip 预编译:预编译器执行.譬如C中的宏定义就是由预编译器处理,注释等也是由预编译器处理的. 编译: 编译器来执行.把源码.c .S编程机器码. ...

  7. 怎么向Xcode6 IOS8之后向项目中添加预编译文件

    苹果的XCode在6版本之后新建项目时取消了自动创建预编译头文件pch,该文件里存放的工程中一些不常被修改的代码,比如常用的框架头文件,这样做的目的提高编译器编译速度.我们可以往里面加入一些项目中都要 ...

  8. vue项目中跳转到外部链接方法

    当我们在文件中,如果是vue页面中的内部跳转,可以用this.$router.push()实现,但是如果我们还用这种方法跳到外部链接,就会报错,我们一看链接的路径,原来是我们的外部链接前面加上了htt ...

  9. 解决cuvid中的sample编译和链接问题

    unzip Video_Codec_SDK_9.0.20.zip cd Video_Codec_SDK_9.0.20/Samples/AppDecode/AppDecImageProvider vi ...

  10. iOS项目中常见的文件

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

随机推荐

  1. 【郑州轻工业大学】HarmonyOS宠物健康系统的开发分享

    原文:https://mp.weixin.qq.com/s/upcS6PcMS7UBR5jgoP7eow,点击链接查看更多技术内容. 本期我们给大家带来的是家庭宠物健康监测系统开发者杨光的分享,希望能 ...

  2. C语言专业课复试整理

    C复试专业基础测试整理 运行C程序的步骤和方法 编辑.编译.连接和运行 . 编辑是用户把编写好的C语言源程序输入计算机,以文本文件的形式存放在磁盘上.其标识为:"文件名.c". 编 ...

  3. 我用这10招,能减少了80%的BUG

    前言 对于大部分程序员来说,主要的工作时间是在开发和修复BUG. 有可能修改了一个BUG,会导致几个新BUG的产生,不断循环. 那么,有没有办法能够减少BUG,保证代码质量,提升工作效率? 答案是肯定 ...

  4. 力扣442(java)-数组中重复的数据(中等)

    题目: 给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 .请你找出所有出现 两次 的整数,并以数组形式返回. 你必须设 ...

  5. 技术门槛高?来看 Intel 机密计算技术在龙蜥社区的实践 | 龙蜥技术

    简介: 数据可用不可见是怎么做到的? 编者按:龙蜥社区云原生机密计算 SIG 定位于云原生机密计算底层基础设施,专注于机密计算底层技术.在阿里巴巴开源开放周中, 龙蜥社区机密计算 SIG Mainta ...

  6. 阿里云 ACK One 多集群管理全面升级:多集群服务、多集群监控、两地三中心应用容灾

    简介: 本文介绍了 ACK One 近期发布的 3 个主要特性,覆盖了多集群管理的 3 个主要场景,跨集群服务发现与访问.多集群全局监控.应用容灾.除多集群管理外,ACK One 更是支持连接并管理任 ...

  7. 阿里云 EMR Delta Lake 在流利说数据接入中的架构和实践

    简介: 为了消灭数据孤岛,企业往往会把各个组织的数据都接入到数据湖以提供统一的查询或分析.本文将介绍流利说当前数据接入的整个过程,期间遇到的挑战,以及delta在数据接入中产生的价值. 背景 流利说目 ...

  8. Spring Cloud Gateway 突发高危漏洞,下一代云原生网关恰逢其时?

    ​简介:Log4j2 的漏洞刚告一段落,Spring 官方在 2022 年 3 月 1 日发布了 Spring Cloud Gateway 的两个 CVE 漏洞:分别为 CVE-2022-22946( ...

  9. 各位 PHPer,Serverless 正当时

    ​简介:PHP 作为一个开发群体的很大的语言其应用范围相当广泛,Serverless 的理念和 PHP 语言的理念都是让开发者最大精力集中在自己的业务价值.那么 PHP 遇见 Serverless 会 ...

  10. [Blockchain] 开发完真实的 DApp 后才能得出的结论与看法

    1. 最近经常看到地方新闻有关 区块链在追踪溯源方面被实际应用,但是我本人认为这很大程度上可能是伪命题. 因为,是不是区块链.或者说有没有办法更改数据,这都很难说,本质上这个链还是由机构控制,所以对此 ...