gpt4 book ai didi

c++ - 将静态库封装在动态链接库 (DLL) 中

转载 作者:太空狗 更新时间:2023-10-29 19:58:30 24 4
gpt4 key购买 nike

我试图增加我对基本库链接、依赖关系等的理解。我创建了一个包含三个项目的 Visual Studio 解决方案

  1. 静态 lib使用 /MTd有一个类( Foo ),一个方法 int GetNum() { return 5; }

  2. 共享 dll使用 /MDd有一个类( Bar ),一个方法 int GetNum() { Foo f; return f.GetNum(); }

  3. Win32 控制台应用程序。那叫Bar b; std::cout << b.GetNum() << std::endl

当我尝试构建它时,它提示找不到我的 dll 的关联库。做了一点研究,发现我需要添加 __declspec(dllexport)到我的GetNum()方法,我会得到一个 .lib .很酷。

下一个障碍是控制台应用程序说它找不到 Foo 的静态库.我将它添加到我的引用资料中,并且一切都正常运行。

我的问题是 - 为什么我的 exe 需要知道关于 Foo 的任何信息? ?我想有效地将​​我所有的依赖项“烘焙”到 dll 中,这样我就可以共享它,链接到它,然后就可以开始了。

这不是语言的工作方式还是我缺少的设置/模式?我的最终目标是能够构建一个 dll 来封装第三方 .lib 的使用,而不是让客户端应用程序需要担心添加对所有这些的引用。

更新

这里是大部分代码。

    // ---------------------- Lib (e.g. Foo)
#pragma once
class MathLib
{
public:
MathLib(void);
~MathLib(void);
int GetNum() { return 83; }
};

// ---------------------- DLL (e.g. Bar)
#pragma once

#ifdef CONSOLETEST_EXPORT
#define CONSOLETEST_API __declspec(dllexport)
#else
#define CONSOLETEST_API __declspec(dllimport)
#endif

#include "MathLib.h"

class MathDll
{
public:
__declspec(dllexport) MathDll(void);
__declspec(dllexport) ~MathDll(void);
__declspec(dllexport) int GetNumFromDyn()
{
MathLib m;
return m.GetNum();
}

};


// ---------------------- exe
int _tmain(int argc, _TCHAR* argv[])
{
MathDll m;
std::cout << "num is " << m.GetNumFromDyn() << std::endl;
return 0;
}

最佳答案

对于 C/C++,在 headers(例如 hhpphxxh++ 等)和翻译单元(通常称为 sources,例如 ccppcxxc++ 等)。当您设计一个库时,您应该不断思考什么属于它的接口(interface)(即应该被消费者看到)以及什么属于它的实现(即不应该被消费者看到)。

记住经验法则 - 任何 header 中出现的所有符号都会被消费者看到(如果包含的话),因此消费者需要稍后在链接阶段解决!

这基本上就是您在玩具示例中发生的情况。因此,让我们使用一个您应该牢记的简单规则来解决它:尽可能多地放入翻译单元,即保持标题最少。现在让我们使用您的示例来说明它是如何工作的:

MathLib.hpp:

#pragma once

class MathLib {
public:
MathLib();
~MathLib();
int GetNum();
};

MathLib.cpp:

#include "MathLib.hpp"

MathLib::MathLib() {}

MathLib::~MathLib() {}

int MathLib::GetNum() { return 83; }

现在构建 MathLib.cpp 作为静态库

MathDll.hpp:

#pragma once

#ifdef CONSOLETEST_EXPORT
# define CONSOLETEST_API __declspec(dllexport)
#else
# define CONSOLETEST_API __declspec(dllimport)
#endif

class CONSOLETEST_API MathDll {
public:
MathDll();
~MathDll();
int GetNumFromDyn();
};

MathDll.cpp:

#include "MathDll.hpp"
#include "MathLib.hpp"

MathDll::MathDll() {}

MathDll::~MathDll() {}

int MathDll::GetNumFromDyn() {
MathLib m;
return m.GetNum();
}

现在将 MathDll.cpp 构建为动态链接库 (DLL),不要忘记在其构建过程中添加定义 CONSOLETEST_EXPORT,以便 CONSOLETEST_API__declspec(dllexport),因此,一个带有导出符号的导入库(即 MathDll 类及其方法) 是为 DLL 生成的。在 MSVC 上,您可以通过将 /DCONSOLETEST_API 添加到编译器调用来实现此目的。最后,在构建这个 DLL 时,一定要将它与之前构建的静态库 MathLib.lib 链接起来。

注意:最好像我上面对 class CONSOLETEST_API MathDll 那样导出整个类,而不是单独导出所有方法。

main.cpp:

#include "MathDll.hpp"

#include <iostream>

int _tmain(int argc, _TCHAR* argv[]) {
MathDll m;
std::cout << "num is " << m.GetNumFromDyn() << std::endl;
return 0;
}

现在构建 main.cpp 作为控制台应用程序 并且将它与之前构建的 DLL 导入库链接,MathDll.lib

请注意问题是如何解决的,因为我已经摆脱了 main.cppMathLib 的传递依赖(通过 MathDll.hpp) >,因为现在 #include "MathLib.hpp" 包含在翻译单元 MathDll.cpp 中完成(因为根据上述规则实际上只需要在那里),并且因此内置于二进制工件(在本例中为 DLL)中,而不存在于其界面中。

了解所有这些对于使用 C/C++ 进行适当的 native 软件开发非常重要,因此您最好事先提出这个问题。我经常遇到不知道/不理解这一点的人,这对他们(业余爱好者)和我们来说是一场噩梦,当我们不得不处理他们编写的糟糕软件时......

关于c++ - 将静态库封装在动态链接库 (DLL) 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20925478/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com