Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forcing symbol export with MSVC

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).

like image 304
torque Avatar asked Jan 14 '09 19:01

torque


4 Answers

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.

like image 186
Judge Maygarden Avatar answered Nov 14 '22 18:11

Judge Maygarden


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;
};
like image 29
Greg Domjan Avatar answered Nov 14 '22 20:11

Greg Domjan


What I tried out to solve this was this:

  1. build a static library with function void afunction( int ).
  2. build a dll, linked to static lib, exporting afunction.
  3. 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!

like image 21
xtofl Avatar answered Nov 14 '22 20:11

xtofl


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.

like image 2
James Hugard Avatar answered Nov 14 '22 19:11

James Hugard