Is it possible to "link" a static library, instead of just combining its .obj files into the .lib?
I have static library (A) which depends on Version 1 of static library B (B.1). I link A into my Executable. The executable itself depends on Version 2 of static library B (B.2). When the executable is created, the Linker complains about multiple defined symbols coming from B.1 (via A) and B.2. It is not desirable to solve this by setting /FORCE:MULTIPLE.
Why is it not possible in this case to basically "treat a static library like a DLL" in some sense?
If A would be a DLL, and linked into the executable by using its Import-Lib, everything would work out. In the resulting process, and after the Loader loaded DLL A into the process space, the definitions of B.1 (coming via the DLL) and B.2 (coming from the Image file of the Executable) would coexist just fine.
Why can the static library A not be "linked" so it would allow this coexistence as well? -Resolving all references and make them fixed in A. Or maybe marking everything what A imports from B.1 somehow as "private", so the Linker, which creates the Executable, treats all B.1 parts as internals of A, which he has nothing to do with? Hench, "embedding" A (compiled as a DLL) into the Executable?
Why can the static library A not be "linked" ... ?
because libraries are not executables (a DLL is).
So generally you cannot combine two versions of a library into one executable when there are conflicting names in both of them.
To circumvent this you could use namespaces with optionally an inline namespace for the prefered version (which can be controlled by conditional compilation ,one condition for the executable and one for the depending library). But be carefull with such strategy !
namespace libB
{
// "forward" declare namespaces
#ifdef LIB_A
inline namespace v1 {}
namespace v2 {} // not really necessary here
#else
namespace v1 {} // not really necessary here
inline namespace v2 {}
#endif
namespace v1
{ // implementation of version1
}
namespace v2
{ // implementation of version2
}
}
Related
I'm looking to make a set of libraries that a developer can use, and they can decide if they want to use them as dynamic libraries, or static libraries. Of course, this brings up several issues of complexity, the current of which is symbol resolution. In my test code, I have 3 projects: The executable project, the static project, and the dynamic project. As the name implies, the static project is compiled to a .lib, and the dynamic project is compiled to a .dll.
The static project includes the header for the dynamic project's code, and calls the function DynamicFunction, which means it will try to link to this function at compile time. However, the dynamic project being compiled to a shared library, it's not available, and it doesn't link. Is there a way for me to define the function, in any of the three projects, to resolve this issue?
My test code is as follows:
main.cpp - compiles to the executable
#include <Windows.h>
#include "../static/static.h"
using proc = void(*)();
proc p = 0;
// I tried using this to force there to be a DynamicFunction function to link with,
// But since they're in different compilation units, it doesn't quite work.
void DynamicFunction() {
if (p) {
p();
}
}
int main(int argc, char** argv) {
HMODULE dll = LoadLibrary("dynamic");
proc p = (proc)GetProcAddress(dll, "DynamicFunction");
UseDynamic();
}
Static.h
#pragma once
void UseDynamic();
Static.cpp
#include "../dynamic/dynamic.h"
#include "static.h"
void UseDynamic() {
DynamicFunction();
}
dynamic.h
#pragma once
extern "C" __declspec(dllexport) void DynamicFunction();
dynamic.cpp
#include "dynamic.h"
void DynamicFunction() {}
I recognize the error is stemming from UseDynamic's assumption that the function is also defined statically, but I'm not aware of any way to have it be aware of whether or not the function is static or dynamic without having knowledge of how another library is being used, and even it would probably involve some ugly preprocessor conditionals.
Is is possible to do what I'm looking to do, or would I need to decide on either static or dynamic libraries (or at the least, not allow mixing the two)
Edit: I'm working with Visual Studio 2017
When you build a DLL project in Visual Studio, it will build a static import library along with the DLL. This library contains shim definitions of the functions your DLL exports that will take care of loading them from the DLL. Linking your test executable to your DLL's import library should get things working.
I'm in DLL hell. I have 2 DLLs let's say A.dll and B.dll which have a name collision - the same C++ class name is used in each, etc. Both DLLs are available as static libs.
Can I create a 'wrappe' DLL, say Aprime.dll which exports a similar class, methods, etc. as in A.dll, and delegates the functionality to the class in A.lib, but statically linked into the Aprime.dll? Wouldn't that avoid the name collision?
I've been trying this, but not sure I have the MSVS project set up correctly. Aprime.dll is being produced, but according to Dependency Walker Aprime.dll is still loading A.dll.
I've been searching, but most stuff I find applies only to statically linking in the CRT or MFC, which have their own switches.
I added A.lib under Linker -> Input -> Additional Dependencies.
Am I missing some magic linker command line switch or something?
Yes that method should work. The key though is to ensure that you do not include any of the original A.dll header files in the Aprime.dll header file. Otherwise if someone includes Aprime.h/pp then it will include A.h/pp and you will then have a clash again.
So you want something like:
A.h
// Library A includes
class test
{
};
B.h
// Library B includes
class test
{
}
Aprime.h
// Proxy class
class myTest
{
}
Aprime.cpp
#include "A.h"
#include "Aprime.h"
...
main.cpp
#include "Aprime.h"
#include "B.h"
...
Note that main never includes both A and B. In only includes Aprime and B. B is still static lib and Aprime is a DLL.
Yes, you can, and it's supported at a very low level by Windows. Aprime.DLL is effectively empty except for a bunch of references to A.DLL.
I'm building a DLL from a group of static libraries and I'm having a problem where only parts of classes are exported.
What I'm doing is declaring all symbols I want to export with a preprocessor definition like:
#if defined(MYPROJ_BUILD_DLL)
//Build as a DLL
# define MY_API __declspec(dllexport)
#elif defined(MYPROJ_USE_DLL)
//Use as a DLL
# define MY_API __declspec(dllimport)
#else
//Build or use as a static lib
# define MY_API
#endif
For example:
class MY_API Foo{
...
}
I then build static library with MYPROJ_BUILD_DLL & MYPROJ_USE_DLL undefined causing a static library to be built.
In another build I create a DLL from these static libraries. So I define MYPROJ_BUILD_DLL causing all symbols I want to export to be attributed with __declspec(dllexport) (this is done by including all static library headers in the DLL-project source file).
Edit:
Note on unrefenced symbols: Linker options Keep Unreferenced Data (/OPT:NOREF) and Do Not Remove Redundant COMDATs (/OPT:NOICF) is set so that no unreferenced symbols will be removed.
Ok, so now to the problem. When I use this new DLL I get unresolved externals because not all symbols of a class is exported. For example in a class like this:
class MY_API Foo{
public:
Foo(char const* );
int bar();
private:
Foo( char const*, char const* );
};
Only Foo::Foo( char const*, char const*); and int Foo::bar(); is exported. How can that be? I can understand if the entire class was missing, due to e.g. I forgot to include the header in the DLL-build. But it's only partial missing.
Also, say if Foo::Foo( char const*) was not implemented; then the DLL build would have unresolved external errors. But the build is fine (I also double checked for declarations without implementation).
Note: The combined size of the static libraries I'm combining is in the region of 30MB, and the resulting DLL is 1.2MB.
I'm using Visual Studio 9.0 (2008) to build everything. And Depends to check for exported symbols.
Edit:
For the ones who wonder why I don't just build a DLL from each of the static libraries: I can't because they cross-reference each other (that's why I need to group them together in one a single DLL). I know, it's horrible I can't really understand the logic behind it.
Remember that when you link against a static LIB, by default the linker is only pulling in the functions, classes, and data that the client (which in this case is your DLL) actually references.
So what happens is this:
You build your static LIB, and that's fine. This LIB is 100% valid.
You now build your static DLL around the original binary LIB. It pulls in only the stuff that it actually references. It doesn't pull in the entire class definition which is what it needs to do. This DLL, though it builds, is invalid.
A client then uses the DLL, and expects to see a complete binary definition for the exported class, because that's what the client sees in the accompanying header file.
However the class has only been partially imported, and this is why you're getting those link errors.
To fix:
If you're able to, don't build your DLL off your static LIB. Build your DLL off the original source code. And build your static LIB off the original source code.
Otherwise you can possibly fiddle with linker settings but I strongly recommend option 1 above. Note that OPT:NOREF won't work here as OPT:NOREF has no effect on static LIBs.
What wont't fix it:
High-level linker tweaks like OPT:NOREF, anything involving COMDATs, etc. If you want those functions present, you have to make sure they're referenced, either by referencing them, or by telling the linker explicitly, "hey, this Symbol X is referenced".
As a side note:
Anytime I build a DLL or LIB, I build both a DLL and a LIB, using exactly the technique you're using. Having a single code base that can generate either a DLL or a LIB by toggling a setting is ideal. But building a DLL off of a (binary) static LIB when you own the source code for both... I'm having a hard time imagining when such a scenario would be necessary.
The problem is surely that you use the already-built static .lib in your DLL project. That cannot work, you have to rebuild the .lib so that the functions get the __declspec(dllexport) declarator and will be exported by the linker.
At that point, it just isn't all that useful anymore to create the DLL compatible version of the .lib in the first place. Just create two projects, one that creates the static .lib, another that creates the DLL. Technically it is possible to still use the static .lib in your DLL project but you'll have to export the functions with a .def file. That can be high maintenance if the library has a lot of exports.
This is probably years too late, but OP's complaint was that a private method (the destructor) was not exported from a dllexport'd class. Isn't that normal? No external user is allowed to call a private method.
Been a while since I have programmed in C++, so the whole export/import idea slipped off my mind.
Can you explain me why to use __declspec(dllexport) & import thingy if it looks like I can use classes from other libraries without those.
I have created a solution in VC++ 2005, added the console applicaiton project and two dll libraries projects. Then create ClassA in a LibA, ClassB in LibB project.
Once I have included ClassA.h & ClassB.h into my console app source code, and has linked it with a LibA.lib and LibB.lib I was able to create and use instances of ClassA and ClassB in a console applicaiton. So basically I was able to use classes without exporting/importing them using __declspec.
Can you explain me - what I am missing here.
Once I have included ClassA.h & ClassB.h into my console app source code, and has linked it with a LibA.lib and LibB.lib I was able to create and use instances of ClassA and ClassB in a console applicaiton.
This sounds like you have used static linking. This works without the __declspec(dllexport) in the same way as linking with the object files of your classes directly.
If you want to use dynamic (run-time) linking with a DLL, you have to use either the mentioned declaration or a DEF-file specifying the exported functions. DLLs contain an exports table listing the functions exposed to other executables. All other functions remain internal to your DLL.
Perhaps you are confused coming from the Linux world, where the situation is the other way round: All symbols are visible externally by default.
You would use __declspec(dllexport) if you wanted to provide symbols in your dll for other dlls/exes to access.
You would use __declspec(dllimport) if you wanted to access symbols in your dll/exe provided by another dll.
Not necessary if you are linking against a static .lib.
If you are including .h files and linking to .lib files then you can drop the DLL declarations. Why do you need a dynamic link library if you only need static linking?
The export declaration marks the function as available for exporting. The declaration you are using may be a macro for "extern" and "pascal" It's been years since I've done this but I think DLLs function calls have a different ordering of pushing params on the stack and the allocation of the return result is done differently (the pascal flag). The extern declaration helps the linker make the function available when you link the library.
You may have missed the step of linking the DLL - the linker will take classA.lib and turn it into classA.dll ( you may need to setup a setupA.def file to define the DLL library). Same applies to ClassB
I have a application and several plugins in DLL files. The plugins use symbols from the
application via a export library. The application links in several static libraries and this is where most of the symbols come from. This works fine as long as the application uses a symbol. If the symbol is not used there, I get linker errors when compiling the DLL.
How can I force the export of the symbols only used in the plugins?
In order to trigger the export I've tried something like this:
class MyClassExporter
{
MyClass mInstance;
public:
MyClassExporter() {}
};
static MyClassExporter TheMyClassExporter;
in one of the static libs the application is made of to force the export, which didn't work.
In response to Greg (thanks for the answer) and to clarify: The class I want to force the export for is MyClass (which has __declspec(...) defined, depending on wether I want to export or import). MyClassExport was my attempt to force the inclusion of unused (in terms of the application) symbols into the app. I want to 'touch' the symbols so that the linker recognizes them as used and includes them into the application so that it can in turn export these to my plugins. Linking the static libs into the plugins is not an option, since they contain singletons which would be duplicated (app and DLLs each have their own copy of static variables).
The /INCLUDE directive can be used to force the MSVC linker to include a symbol. Alternatively, /OPT:NOREF can be used to disable removal of unused symbols in general.
A common approach is to create a single unused function that references all objects exported for your plugins. Then you only need a single /INCLUDE directive for that function.
You probably want to look at __declspec(export/import)
#ifdef DLL_EXPORTING
#define WHDLL __declspec(dllexport)
#else
#define WHDLL __declspec(dllimport)
#endif
When linking static module into a dll it will only bring in the code that is used. I've never imported stuff from a static lib to simply re export it.
Perhaps you just need to mark it as exportable in the dll when compiling the static lib.
But that reminds me of putting std containers into exported classes and using some trickery in msvc to export the 'instance' of the specialised container. the template code is similar to your static code (in my thinking)
for instance without the template you get warnings the template code is not exported to support the class - this is MSVC specific from my understanding
template class DLL_EXPORTING std::auto_ptr<wxCursor>;
class DLL_EXPORTING imageButton : public wxWindow
{
std::auto_ptr<wxCursor> m_Cursor;
};
What I tried out to solve this was this:
build a static library with function void afunction( int ).
build a dll, linked to static lib, exporting afunction.
build an exe, using the afunction symbol.
How? Since the linker can be told to export functions using the __declspec(dllexport) directive, a dll needs no more than declare a to-be-exported symbol thusly.
The lib has a header "afunction.h" and an accompanying cpp file containing the function body:
// stat/afunction.h
namespace static_lib { void afunction(int); }
// stat/afunction.cpp
#include "afunction.h"
namespace static_lib { void afunction(int){ } }
The dll has an include file "indirect.h", containing the declaration of the function to be exported. The dll has a link-time dependency to the static lib. (Linker options: Input/Additional Dependencies: "static_library.lib")
// dll/indirect.h
namespace static_lib {
__declspec( dllexport ) void afunction(int);
}
The executable has only the indirectly included file:
#include <dll/indirect.h>
int main() { static_lib::afunction(1); }
And guess what? It compiles, links and even runs!
The "Use Library Dependency Inputs" option does the trick in VS2005!
This option can be found under Configuration Properties -> Linker -> General -> Use Library Dependency Inputs. Set to "true" to force linking in ALL symbols & code declared in every LIB specified as input to the project.
You can do the following to get the symbol to export from the DLL: define LIB_EXPORTS in the library project and nothing in either the DLL project or the DLL client project.
#ifdef LIB_EXPORTS
#define DLLAPI __declspec(dllexport)
#else
#define DLLAPI __declspec(dllimport)
#endif
Turns out there is no need #include any headers from the LIB project when compiling the DLL project; just specify the LIB as a linker input. However, if you need to make use of the LIB code from within the DLL, you will need to #define DLLAPI as an empty macro; setting the symbol(s) to either dllexport or dllimport will generate an error or a warning, respectively.
There is some discussion of this problem on MSDN which was pretty useful. As it turns out, /OPT:NOREF is not particularly helpful in this case. /INCLUDE can work but it can be hard to automatically figure out what needs to be /INCLUDEd. There's unfortunately no silver bullet.
http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/2aa2e1b7-6677-4986-99cc-62f463c94ef3