Reputation: 1569
Using Visual Studio C++ 2008 Express:
I am trying to perform the final link step in a build compiled as follows:
A library foo.lib
is statically compiled (the build does not produce a .dll
) with the /MD
switch. The build for foo.lib
succeeds. The .lib
file and headers are shipped to a directory where the project for the below library can find them. foo.lib
sources are written in unmanaged C++.
A library bar.dll
is compiled as a dynamic library with the /MD /LD
switches. bar.dll
depends on foo.lib
exported symbols. Both bar.dll
and foo.lib
are built form source using the same cl.exe
and link.exe
binaries from the VS2008 Express toolchain. bar.dll
sources are written in unmanaged C++.
All the .obj
files of bar.dll
build successfully, but during the final execution of link.exe
that would produce bar.dll
, I receive thousands of LNK2001
errors about undefined externals. All of the undefined externals are things that I would expect to be in a standard C++ library: things like std::basic_string
constructors, the std::_Throw
class, ostream
overloaded operators, and on and on. link.exe
says that the undefined externals are undefined within foo.lib
!
The goal is for bar.dll
to contain the entire statically linked code of foo.lib
within it, as well as its own objects, but dynamically depend on the existence/resolution of MSVCR90.dll
and MSVCP90.dll
at runtime.
Am I trying to set up an impossible situation with this build, or am I just doing something wrong? If this can't work at all in theory, let me know. Otherwise, please let me know what diagnostics I could try to determine why the C++ library symbols are not available to foo.lib
during the final link step.
Edit: More specific information: foo.lib
is LLVM 3.1 and bar.dll
is the libgl-gdi
(llvmpipe
) build of Mesa from the master
branch (the goal is to produce opengl32.dll
that runs on llvmpipe
). I have satisfied all the build dependencies as follows:
I have also customized the build for each project as appropriate to set environment variables and ensure that they are consistently using only the /MD
switch and not /MT
or some other switch for selecting a wrong C runtime library.
Upvotes: 2
Views: 1000
Reputation: 48019
Here's a working sample that does what you're trying to do.
foo.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;
}
Build foo.cpp into a static library that will depend on the dynamic run-time libraries:
cl /c /MD /EHsc foo.cpp
lib foo.obj
bar.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();
}
Build bar.cpp into a DLL that pulls in code from foo.lib and depends in the dynamic runtime libraries:
cl /c /MD /EHsc /DBAR_DLL bar.cpp
link /DLL bar.obj foo.lib
And a simple main.cpp to show that it works:
#include "bar.h"
int main() {
print_bar();
return 0;
}
Build it like this:
cl /c /MD /EHsc main.cpp
link main.obj bar.lib
(The runtime libraries should come in automatically because the /MD options should have tagged the object files as needing the dynamic runtime libraries.)
main.exe output:
bar
foo
Upvotes: 0
Reputation: 5866
From the MSDN help:
Defines _MT and _DLL so that both multithread- and DLL-specific versions of the run-time routines are selected from the standard .h files. This option also causes the compiler to place the library name MSVCRT.lib into the .obj file. Applications compiled with this option are statically linked to MSVCRT.lib. This library provides a layer of code that allows the linker to resolve external references. The actual working code is contained in MSVCR71.DLL, which must be available at run time to applications linked with MSVCRT.lib.
When /MD is used with _STATIC_CPPLIB defined (/D_STATIC_CPPLIB) it will cause the application to link with the static multithread Standard C++ Library (libcpmt.lib) instead of the dynamic version (msvcprt.lib) while still dynamically linking to the main CRT via msvcrt.lib.
More specifically - this excerpt: "Applications compiled with this option are statically linked to MSVCRT.lib"
In other words - you need to link your foo.lib to msvcrt.lib.
Upvotes: 1
Reputation: 3713
This is a common point of confusion with visual studio projects.
/MD doesn't build a static library. That is a flag that can be used with any binary output from visual studio (lib, dll, exe). It merely means you're telling your binary to use the static CRT (C runtime). This is, in the common case, the wrong choice and you will get link issues when linking into applications or DLL's that do NOT statically link the CRT (using the DYNAMIC CRT).
Have a look here for more information:
http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=vs.71).aspx
There should be a setting under the project settings under Configuration Properties/General/Configuration type. That should be what you're using to determine what kind of binary you're building
Upvotes: 0