2

使用 Visual Studio C++ 2008 Express:

我正在尝试在编译如下的构建中执行最后的链接步骤:

  • 使用开关静态编译库foo.lib(构建不产生 a .dll) 。/MD构建foo.lib成功。文件和头.lib文件被发送到以下库的项目可以找到它们的目录。foo.lib源代码是用非托管 C++ 编写的。

  • bar.dll被编译为带有/MD /LD开关的动态库。bar.dll取决于foo.lib导出的符号。两者bar.dll和都是使用来自 VS2008 Express 工具链的相同和二进制文件从foo.lib源代码构建的。源代码是用非托管 C++ 编写的。cl.exelink.exebar.dll

  • 构建的所有.obj文件都bar.dll成功,但在最终执行期间link.exe会产生bar.dll,我收到数千个LNK2001关于未定义外部的错误。所有未定义的外部都是我希望在标准 C++ 库中出现的东西:诸如std::basic_string构造函数、std::_Throw类、ostream重载运算符等等。link.exe表示未定义的外部在内部未定义foo.lib

  • 目标是bar.dll在其中包含整个静态链接的代码foo.lib,以及它自己的对象,但动态地取决于运行时的存在/MSVCR90.dll解决MSVCP90.dll

我是想用这个构建设置一个不可能的情况,还是我只是做错了什么?如果这在理论上根本行不通,请告诉我。foo.lib否则,请让我知道我可以尝试哪些诊断程序来确定为什么 C++ 库符号在最后的链接步骤中不可用。

编辑:更具体的信息:foo.libLLVM 3.1 并且bar.dlllibgl-gdi( )从分支llvmpipe构建的Mesamaster(目标是生成opengl32.dll在 上运行的llvmpipe)。我已经满足了所有构建依赖项,如下所示:

  • LLVM 构建依赖于CMake作为构建系统和 Python 2.7。
  • Mesa 构建依赖于SCons作为构建系统、LLVM 2.6 或更高版本、Python 2.7、pywin32、python-libxml2、bison 和 flex。除了上述之外,只有 LLVM 在运行时被运送;其余的只是构建过程中使用的“工具”。

我还根据需要为每个项目定制了构建,以设置环境变量并确保它们始终只使用/MD开关而不是使用/MT其他开关来选择错误的 C 运行时库。

4

3 回答 3

1

MSDN 帮助

定义_MT_DLL以便从标准 .h 文件中选择运行时例程的多线程和 DLL 特定版本。此选项还会导致编译器将库名称 MSVCRT.lib 放入 .obj 文件中。使用此选项编译的应用程序静态链接到 MSVCRT.lib。该库提供了一层代码,允许链接器解析外部引用。实际工作代码包含在 MSVCR71.DLL 中,必须在运行时对与 MSVCRT.lib 链接的应用程序可用。

当 /MD 与定义的 _STATIC_CPPLIB (/D_STATIC_CPPLIB) 一起使用时,它将导致应用程序链接到静态多线程标准 C++ 库 (libcpmt.lib) 而不是动态版本 (msvcprt.lib),同时仍然通过动态链接到主 CRT msvcrt.lib。

更具体地说 - 这段摘录:“使用此选项编译的应用程序静态链接到 MSVCRT.lib

换句话说 - 您需要将您的 foo.lib 链接到 msvcrt.lib。

于 2012-08-03T19:10:56.260 回答
0

这是一个工作示例,可以执行您正在尝试执行的操作。

富.h:

#ifndef FOO_H
#define FOO_H

extern void print_foo();

#endif

foo.cpp:

#include "foo.h"

#include <iostream>

void print_foo() {
  std::cout << "foo" << std::endl;
}

将 foo.cpp 构建到依赖于动态运行时库的静态库中:

cl /c /MD /EHsc foo.cpp
lib foo.obj

酒吧.h:

#ifndef BAR_H
#define BAR_H

#ifdef BAR_DLL
#define BARAPI __declspec(dllexport)
#else
#define BARAPI __declspec(dllimport)
#endif

BARAPI void print_bar();

#endif

bar.cpp:

#include "bar.h"

#include <iostream>
#include "foo.h"

BARAPI void print_bar() {
  std::cout << "bar" << std::endl;
  print_foo();
}

将 bar.cpp 构建到一个 DLL 中,该 DLL 从 foo.lib 中提取代码并依赖于动态运行时库:

cl /c /MD /EHsc /DBAR_DLL bar.cpp
link /DLL bar.obj foo.lib

还有一个简单的 main.cpp 来证明它有效:

#include "bar.h"

int main() {
  print_bar();
  return 0;
}

像这样构建它:

cl /c /MD /EHsc main.cpp
link main.obj bar.lib

(运行时库应该自动进入,因为 /MD 选项应该将目标文件标记为需要动态运行时库。)

main.exe 输出:

bar
foo
于 2012-08-03T20:59:16.427 回答
0

这是视觉工作室项目的常见混淆点。

/MD 不构建静态库。这是一个可以与 Visual Studio 的任何二进制输出(lib、dll、exe)一起使用的标志。它仅仅意味着你告诉你的二进制文件使用静态 CRT(C 运行时)。在常见情况下,这是错误的选择,当链接到不静态链接 CRT(使用动态 CRT)的应用程序或 DLL 时,您会遇到链接问题。

在这里查看更多信息:

http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=vs.71).aspx

在配置属性/常规/配置类型下的项目设置下应该有一个设置。这应该是你用来确定你正在构建什么样的二进制文件

于 2012-08-03T19:10:36.367 回答