views:

97

answers:

4

I have a C++ project that due to its directory structure is set up as a static library A, which is linked into shared library B, which is linked into executable C. (This is a cross-platform project using CMake, so on Windows we get A.lib, B.dll, and C.exe, and on Linux we get libA.a, libB.so, and C.) Library A has an init function (A_init, defined in A/initA.cpp), that is called from library B's init function (B_init, defined in B/initB.cpp), which is called from C's main. Thus, when linking B, A_init (and all symbols defined in initA.cpp) is linked into B (which is our desired behavior).

The problem comes in that the A library also defines a function (Af, defined in A/Afort.f) that is intended to by dynamically loaded (i.e. LoadLibrary/GetProcAddress on Windows and dlopen/dlsym on Linux). Since there are no references to Af from library B, symbols from A/Afort.o are not included into B. On Windows, we can artifically create a reference by using the pragma:

#pragma comment (linker, "/export:_Af")

Since this is a pragma, it only works on Windows (using Visual Studio 2008). To get it working on Linux, we've tried adding the following to A/initA.cpp:

extern void Af(void);
static void (*Af_fp)(void) = &Af;

This does not cause the symbol Af to be included in the final link of B. How can we force the symbol Af to be linked into B?

A: 

You can use the --undefined option when you build B:

g++ -Wl,--undefined,Af -o libB.so ...
R Samuel Klatchko
A: 

Try putting those lines into B/initB.cpp so that they're (hopefully) forced into the libB.so library at link time.

But why do you have to do it in this way at all? Can't you set it up so that the executable references that function (or a caller of it), causing the linker to do the right thing automatically?

Mark B
C is actually a scripting language frontend, B is the language engine, and A is a set of native code methods for the engine to use. We're implementing a pre-existing language that has a well-defined foreign function interface. A and B are produced by separate teams; we'd prefer to keep everything that the A-team writes in the A directory.
Brian Bassett
A: 

If you can use C++0x features of gcc (-std=c++0x), then the function default template arguments may do the trick. As of the current c++ standard, default arguments are not allowed for function templates. With these enabled in c++0x, you can do something like :-

In some header file of static library ...

template< class T = int >
void Af()
{
}

Then in its corresponding cpp file use explicit template instantiation...

template void Af();

This will generate the symbols for the function Af though it is not yet called/referenced. This won't affect the callers due to the fact that because of the default template argument, you need not specify a type. Just add the template <class T = int > before the function declaration and explicitly instantiate it in its implementation file.

HTH,

Abhay
Unfortunately, this won't work because Af is actually a Fortran procedure.
Brian Bassett
Well then, make a 'C' wrapper that calls Af_(...) [u can call fortran functions from 'C' i.e. function name appended by underscore; google nitty gritty details for arguments, i donno abt C++ calling fortran]. Call this 'C' wrapper from C++. BTW, thats how one of the leading financial company that i worked for, managed its antique/crappy code :-)
Abhay
+2  A: 

It turns out my original attempt was mostly there. The following works:

extern "C" void Af(void);
void (*Af_fp)(void) = &Af;

For those that want a self-contained preprocessor macro to encapsulate this:

#if defined(_WIN32)
# if defined(_WIN64)
#  define FORCE_UNDEFINED_SYMBOL(x) __pragma(comment (linker, "/export:" #x))
# else
#  define FORCE_UNDEFINED_SYMBOL(x) __pragma(comment (linker, "/export:_" #x))
# endif
#else
# define FORCE_UNDEFINED_SYMBOL(x) extern "C" void x(void); void (*__ ## x ## _fp)(void)=&x;
#endif

Which is used thusly:

FORCE_UNDEFINED_SYMBOL(Af)
Brian Bassett