views:

128

answers:

2

I am trying to create a shared library on Windows. I am able to create this shared library on linux but on windows I get linker errors. I am using the MinGW G++ 4.5 compiler. I will first present the source code to the example on linux , and then present the file which I tried to change on windows.

/home/nxd/Progs/C++/shared-lib>cat lib_interface.h 

#ifndef LIBINTERFACE_H
#define LIBINTERFACE_H

int func(int a);

#endif /* LIBINTERFACE_H */
/home/nxd/Progs/C++/shared-lib>cat sh_lib.cpp 
extern int b;

int func(int a)
{
 return a+b;
}
/home/nxd/Progs/C++/shared-lib>cat main.cpp 
#include <iostream>
#include "lib_interface.h"

int b;

int main()
{
 b=10;
 std::cout << func(20) << std::endl;
}

/home/nxd/Progs/C++/shared-lib>cat Makefile 
OBJS = main.o sh_lib.o

test: main.o libshared.so
 g++ -L. -o$@ main.o -lshared

main.o: main.cpp lib_interface.h
 g++ -c -Wall -fPIC $<

sh_lib.o: sh_lib.cpp lib_interface.h
 g++ -c -Wall -fPIC $<

libshared.so: sh_lib.o
 ld -shared -soname=libshared.so -o libshared.so.1 $<
 ln -s libshared.so.1 libshared.so

.PHONY: clean

clean:
 rm *.o *.so *.so.1
/home/nxd/Progs/C++/shared-lib>make
g++ -c -Wall -fPIC main.cpp
g++ -c -Wall -fPIC sh_lib.cpp
ld -shared -soname=libshared.so -o libshared.so.1 sh_lib.o
ln -s libshared.so.1 libshared.so
g++ -L. -otest main.o -lshared
/home/nxd/Progs/C++/shared-lib>LD_LIBRARY_PATH=. ./test
30

I tried to make a shared library out of sh_lib.cpp using MinGW g++ on Windows. The reason there are so many comments is because of the many things I tried before I decided to post this.

/home/nxd>cat sh_lib.cpp 
//extern "C" __declspec(dllimport) int b;
//#ifdef __cplusplus 
//extern "C" { 
//#endif 

__declspec(dllimport) extern int b;
//__declspec(dllimport) int b;
//extern int b;

//#ifdef __cplusplus 
//} 
//#endif 

int func(int a)
{
 return a+b;
}

Here is the relevant portion of the Makefile with various tweaks. The options passed to the linker that you see below were added one by one to try to get rid of the link error. The ld command below was just to be sure that the linker was indeed getting the options. The preceding hyphen tells make to run the next command even if the current one had errors.

sh_lib.o: sh_lib.cpp lib_interface.h
 g++ -c -Wall -fPIC $<

libshared.so: sh_lib.o
 -ld -shared --enable-auto-import --unresolved-symbols=ignore-in-shared-libs   -soname=libshared.so --allow-shlib-undefined -o libshared.so.1 $<
 g++ -shared  -Wl,--unresolved-symbols=ignore-in-shared-libs  -Wl,--enable-auto-import -Wl,--allow-shlib-undefined -Wl,-soname,libshared.so -o libshared.so.1 $<

My Question: how can I compile sh_lib.cpp into a dll using the extern variable like the way it works in linux?. I did read the stackoverflow article : http://stackoverflow.com/questions/56500/cant-access-variable-in-c-dll-from-a-c-app , but "I think" there is a subtle difference here between the 2 cases. There he was trying to link with a file, here I am trying to create a shared library, using a variable for which storage has not been allocated (extern), and I want to tell the linker to ignore this variable's storage when creating the library - it will be resolved when I am linking with an exe. I am currently managing this problem with static linking.

Many thanks for your help in advance.

A: 

you don't say what error(s) you are getting, but I see at least two things in the source that may cause havoc:

  • __declspec(dllimport) int b: with this statement, you are saying b has to be imported (from an import library for a dll) library, but that will not work since you want to use the 'b' from your exe. (edit starts here) At first I thought 'extern int b' would do it, but that won't work as well: the linker needs to know where b is in order to be able to create the dll, that is just how this works on Windows (to my understanding, please someone correct me if I'm wrong). Saying 'extern int' to the compiler is like saying 'hey there's an int somewhere but it's not in this compilation unit, don't worry the linker will figure it out'. And there's the problem: the linker does not find it. I see no other option than to rewrite a to take b as an argument, or get rid of the 'extern' so that 'b' is in the dll.

  • int func(int a): has basically the same problem, this must be exported from the dll and imported into the main executable;

example header:

#ifdef BUILD_DLL
  #define MYDLL __declspec( dllexport )
#else
  #define MYDLL __declspec( dllimport )
#endif

MYDLL int func( int a );

When building the dll, you define BUILD_DLL (pass -DBUILD_DLL to gcc) and have the linker create an import library (pass -Wl,--out-implib,libmylib.a).

When building the executable, define nothing extra and the macro resolves to dllimport so the linker knows it has to find func somewhere else, namely in the import library for the dll (pass -lmylib, and eventually -L/path/to/dir/where/lib/is)

stijn
I started "sh_lib.cpp" with extern int b; But when I try to create a shared library i get the error "undefined reference to b". I do not get this error on linux. >Still the question remains whether an extern global makes sense, >there might be better options.Well the original example is a compiler I'm developing - http://sourceforge.net/projects/xtcc source code in qscript-0.7.tar.gz the global variable is a "question list" required in the runtime and compiletime environments.
Neil
I didn't really think this through, edited answer: I'm not sure this can ever work with a dll.. hopefully someone else can provide some more insight?
stijn
+1  A: 

I provided my answer in email (because the original poster repeated his question in email to a list I follow) complete with modified sample source that works as he wanted. See http://mingw-users.1079350.n2.nabble.com/using-an-external-variable-in-C-in-a-shared-library-tp5521039p5521149.html . I won't bother repeating the whole thing here. Just some key points:

  • declspec(dllimport/dllexport) is required for variables, yes
  • to import a variable from the .exe, you need to treat the exe as a dll in the sense that you generate an import library for it to link the shared library with
  • but actually, you don't want to import variables from the exe as that means only an exe with that name can use the shared library in question
  • instead, redesign the software to not have variables in the API boundaries. Just have the an API in the library a function to "register" data in the main (or wherever) needed by subsequent calls to the library instead
  • and actually, just as an advice, don't use variables in the API of libraries either, a pure function-based API is much nicer
  • note that the original poster uses MinGW, so don't bother commenting if you have experience only of MSVC. They might well differ in some key aspects here
  • finally, I am not really a C++ guy, so I talk from a pure C aspect above, sorry. C++ classes etc will definitely make the situation more complex, and cause even more annoying differences between gcc on Linux / gcc on Windows (MinGW) / MSVC / and others
tml