Creating a shared library using gcc for Linux and MinGW on Windows

I am having problems generating the assembly, which allows me to create shared libraries on Linux and Windows using gcc and MinGW, respectively. On Linux, a shared library does not have to allow all dependencies at compile time; then how it looks on windows. Here is the problem setting:


$ cat foo.h #ifndef FOO_H #define FOO_H void printme(); #endif 

 $ cat foo.c #include "foo.h" #include <stdio.h> void printme() { printf("Hello World!\n"); } 

 $ cat bar.h #ifndef BAR_H #define BAR_H void printme2(); #endif 

 $ cat bar.c #include "bar.h" #include "foo.h" void printme2() { printme(); printme(); } 

 $ cat main.c #include "bar.h" int main(){ printme2(); } 

 $ cat Makefile .co: gcc -fPIC -c $< all: foo.o bar.o main.o gcc -shared foo.o -o libfoo.so gcc -shared bar.o -o libbar.so gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main 

Now on Linux this compiles and runs fine:

 $ make gcc -fPIC -c foo.c gcc -fPIC -c bar.c gcc -fPIC -c main.c gcc -shared foo.o -o libfoo.so gcc -shared bar.o -o libbar.so gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main $ ./main Hello World! Hello World! 

On Windows, we need to change this to a dll, which is insignificant and accurate:

 $ cat Makefile .co: gcc -fPIC -c $< all: foo.o bar.o main.o gcc -shared foo.o -o libfoo.dll gcc -shared bar.o -o libbar.dll gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main 

However, when we try to build, we get the following error:

 $ make gcc -fPIC -c foo.c foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] gcc -fPIC -c bar.c bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] gcc -fPIC -c main.c main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] gcc -shared foo.o -o libfoo.dll gcc -shared bar.o -o libbar.dll bar.o:bar.c:(.text+0x7): undefined reference to `printme' bar.o:bar.c:(.text+0xc): undefined reference to `printme' collect2.exe: error: ld returned 1 exit status make: *** [all] Error 1 

Now we can fix the error by simply including the objects from foo.o in libbar.dll:

 $ cat Makefile .co: gcc -fPIC -c $< all: foo.o bar.o main.o gcc -shared foo.o -o libfoo.dll gcc -shared bar.o foo.o -o libbar.dll gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main $ make gcc -fPIC -c foo.c foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] gcc -fPIC -c bar.c bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] gcc -fPIC -c main.c main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default] gcc -shared foo.o -o libfoo.dll gcc -shared bar.o foo.o -o libbar.dll gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main $ ./main Hello World! Hello World! 

However, I do not like this approach, since libbar.dll now contains characters for both foo and bar. On Linux, it contains only bar symbols. This separation is important in situations where the library depends on some standard number library, such as BLAS. I would like to be able to deploy the shared library and depend on the optimized version of the number library on the user's machine, and not on mine.

In any case, what is the correct procedure to create a shared library where not all characters are present at compile time?

In case it matters, I compiled these examples with gcc 4.6.3 on Linux and mingw-get-inst-20120426.exe with gcc 4.7.2 on Windows.

+6
source share
1 answer

On Windows, you need to create an import library for the DLL. The import library looks like a static library, because it defines all the necessary characters, but it does not have actual function implementations, it just has stubs. The import library will fix "undefined reference" errors by avoiding static binding.

To create an import library using MinGW, follow the instructions here . The key is that when creating the DLL, you must pass the -Wl,--out-implib,libexample_dll.a linker to create the libexample_dll.a import libexample_dll.a .

Then, when you compile your main executable, you use the -lexample_dll option (along with -L. ) To link to the import library. So with your code, I think this should work:

 all: foo.o bar.o main.o gcc -shared foo.o -o libfoo.dll -Wl,--out-implib,libfoo.a gcc -shared bar.o foo.o -o libbar.dll -Wl,--out-implib,libbar.a gcc main.o -Wl,-rpath=. -L. -lbar -lfoo -o main 

Also note that on Windows, the calling convention for exported functions in a DLL is almost always __stdcall , not the default __cdecl , so if you want your DLL files to be used by other software, I would recommend making them __cdecl . But this is not strictly required, since both the codes in the DLL and the header files are consistent with what is the calling convention.

+8
source

Source: https://habr.com/ru/post/949264/


All Articles