What's the proper way to link against an executable on Windows?

后端 未结 2 474
你的背包
你的背包 2021-01-21 12:10

I need to use some symbols from the main executable in a plugin.

Linking against the executable causes the following linker errors:

i686-w64-mingw32-g++          


        
相关标签:
2条回答
  • 2021-01-21 12:13

    This is a case where you probably do want to qualify the callback symbols, in the .exe, with the __declspec(dllexport) attribute. Cross-compiling on my Linux Mint Debian box, the following minimal example works for me:

    $ cat foo.c
    #include <stdio.h>
    
    int __declspec(dllexport) foo( int bar ){ return bar << 2; }
    int main(){ printf( "%d\n", foo( 4 ) ); return 0; }
    
    $ mingw32-gcc -o ~/src/exp/foo.exe -Wl,--out-implib=libfoo.dll.a foo.c
    

    This produces both a working executable, and an import library to map its exported symbols, for use when linking plug-ins, with just one invocation of the linker in the preceding commands, (as seen when running the executable under wine, and listing the import library using the native linux nm tool):

    $ ~/src/exp/foo.exe
    16
    
    $ nm -A libfoo.dll.a
    libfoo.dll.a:d000002.o:00000000 I _foo_exe_iname
    libfoo.dll.a:d000002.o:00000000 i .idata$4
    libfoo.dll.a:d000002.o:00000000 i .idata$5
    libfoo.dll.a:d000002.o:00000000 i .idata$7
    libfoo.dll.a:d000000.o:         U _foo_exe_iname
    libfoo.dll.a:d000000.o:00000000 I __head_foo_exe
    libfoo.dll.a:d000000.o:00000000 i .idata$2
    libfoo.dll.a:d000000.o:00000000 i .idata$4
    libfoo.dll.a:d000000.o:00000000 i .idata$5
    libfoo.dll.a:d000001.o:00000001 a @feat.00
    libfoo.dll.a:d000001.o:00000000 T _foo
    libfoo.dll.a:d000001.o:         U __head_foo_exe
    libfoo.dll.a:d000001.o:00000000 i .idata$4
    libfoo.dll.a:d000001.o:00000000 i .idata$5
    libfoo.dll.a:d000001.o:00000000 i .idata$6
    libfoo.dll.a:d000001.o:00000000 i .idata$7
    libfoo.dll.a:d000001.o:00000000 I __imp__foo
    libfoo.dll.a:d000001.o:00000000 t .text
    

    Likewise, the executable runs just fine in WinXP, (running within VirtualBox on the LMDE box, with ~/src/exp mapped as drive E: in the WinXP VM, and invoked from the MSYS shell):

    $ /e/foo.exe
    16
    

    FWIW, I can reproduce your failure to create a runnable executable, when adding the -shared attribute to the linker invocation; as you note, that is intended for creating DLLs, (which differ from executables in format only in having a different magic number embedded in the header; otherwise they are fundamentally the same).

    In summary:

    • Don't specify -shared when linking the executable.

    • Do qualify symbols to be exported from the executable with the __declspec(dllexport) attribute.

    • Do specify the -Wl,--out-implib=lib<exename>.dll.a attribute, when linking the executable.

    0 讨论(0)
  • 2021-01-21 12:19

    Like Keith Marshall stated in the comments, -Wl,--out-implib indeed works in combination with either:

    • -Wl,--export-all-symbols

    • by declaring symbols with __declspec(dllexport)

    • or by providing a .def file

    I went with the third option and wrote a bash script to generate a def file / version scripts on-the-fly to avoid exporting a lot of unneeded symbols.

    The script can be found here.

    Use it like:

    export SYMBOLS_TO_EXPORT="*tools* *network* _Z8compressPvRjPKvjib ..." # use mangled names and skip leading underscores on i686
    export HOSTPREFIX=i686-w64-mingw32 # unneeded on Windows
    i686-w64-mingw32-g++ $(OBJS) `./gen_export_file $(OBJS)` -Wl,--out-implib=foo.exe.a -o foo.exe
    
    0 讨论(0)
提交回复
热议问题