Static library missing `__imp_` symbols
Asked Answered
O

1

7

Edit: Found a solution but can't accept my own answer yet.

I am having some trouble statically linking a library to my program. I am cross-compiling from Linux to Windows using the MinGW toolchain and Code::Blocks as an IDE/Build System. I've also compiled the library myself with the same toolchain as the program.

I am completely new to both cross-compiling and compiling for Windows.

Edit: I just tried the same procedure on a virtual installation of Windows XP (with Code::Block's bundled MinGW) and get the same problem, so I guess it's not because of the cross-compiler.

The problem

I'll give all details below, but in essence the problem is that the linker is complaining about missing _imp__some_symbol symbols. The symbols are present in the static library, but not as _imp__some_symbol, rather as just _some_symbol. I've verified this by grepping the output of nm libSomeLibrary.a

Details

The library itself is BearLibTerminal (You can find the sources at https://bitbucket.org/cfyzium/bearlibterminal/downloads/). As said before, I've compiled it from source myself with the same toolchain as my main program.

My main program consists code is the "Hello world" example given by BearLibTerminal here http://foo.wyrd.name/en:bearlibterminal#simple_examplec_c:

#include "BearLibTerminal.h"

int main()
{
    terminal_open();

    // Printing text
    terminal_print(1, 1, "Hello, world!");
    terminal_refresh();

    // Wait until user close the window
    while (terminal_read() != TK_CLOSE);

    terminal_close();
}

My complete Code::Blocks build log can be found at https://pste.eu/p/VMJp.html. It contains the build log for BearLibTerminal and its dependencies, as well as my program.

The relevant bits (I think) are these:

i686-w64-mingw32-g++ -Wall -fexceptions -O2 -DWINVER=0x0400 -D__WIN95__ -D__GNUWIN32__ -DSTRICT -DHAVE_W32API_H -D__WXMSW__ -D__WINDOWS__ -IBearLibTerminal -I/usr/i686-w64-mingw32/sys-root/mingw/include -I/home/laleksic/Desktop/Roguelike -I/home/laleksic/Desktop/Roguelike/ -c /home/laleksic/Desktop/Roguelike/main.cpp -o /home/laleksic/Desktop/Roguelike/.objs/main.o
i686-w64-mingw32-g++ -L/usr/i686-w64-mingw32/sys-root/mingw/lib -o build/Roguelike /home/laleksic/Desktop/Roguelike/.objs/main.o -s -lstdc++ -lgcc -lodbc32 -lwsock32 -lwinspool -lwinmm -lshell32 -lcomctl32 -lctl3d32 -lodbc32 -ladvapi32 -lodbc32 -lwsock32 -lopengl32 -lglu32 -lole32 -loleaut32 -luuid BearLibTerminal/Dependencies/PicoPNG/libPicoPNG.a BearLibTerminal/Dependencies/FreeType/libFreeType.a BearLibTerminal/libBearLibTerminal.a
/home/laleksic/Desktop/Roguelike/.objs/main.o:main.cpp:(.text.startup+0x11): undefined reference to "_imp__terminal_open'
/home/laleksic/Desktop/Roguelike/.objs/main.o:main.cpp:(.text.startup+0x56): undefined reference to "_imp__terminal_print_ext8'
/home/laleksic/Desktop/Roguelike/.objs/main.o:main.cpp:(.text.startup+0x5c): undefined reference to "_imp__terminal_refresh'
/home/laleksic/Desktop/Roguelike/.objs/main.o:main.cpp:(.text.startup+0x62): undefined reference to "_imp__terminal_read'
/home/laleksic/Desktop/Roguelike/.objs/main.o:main.cpp:(.text.startup+0x7b): undefined reference to "_imp__terminal_close'
collect2: error: ld returned 1 exit status

At the end of the link line you see it's supposed to statically link the BearLibTerminal dependencies (libPicoPNG.a and libFreeType.a) and BearLibTerminal itself (libBearLibTerminal.a).

Now checking the libBearLibTerminal.a symbols with nm libBearLibTerminal.a | grep -E ' _imp__terminal_(open|print_ext8|refresh|read|close)' gives empty output.

However nm libBearLibTerminal.a | grep -E 'terminal_(open|print_ext8|refresh|read|close)' gives:

00000000 t __GLOBAL__sub_I_terminal_open
00000690 T _terminal_close
000032b0 T _terminal_open
000015b0 T _terminal_print_ext8
000024c0 T _terminal_read
00003240 T _terminal_read_str16
000031f0 T _terminal_read_str32
000031a0 T _terminal_read_str8
00000cd0 T _terminal_refresh
         U _terminal_close
         U _terminal_open
         U _terminal_print_ext8
         U _terminal_read
         U _terminal_read_str8
         U _terminal_refresh
00000220 T __Z16luaterminal_openP9lua_State
000010f0 T __Z16luaterminal_readP9lua_State
00000250 T __Z17luaterminal_closeP9lua_State
000002b0 T __Z19luaterminal_refreshP9lua_State
00001410 T __Z20luaterminal_read_strP9lua_State

So, the symbols are there, just with a different prefix.

What is the cause of this, and what would be the way to fix it?

Toolchain

I'm compiling on a Fedora 28 system with the MinGW toolchain and Code::Blocks as an IDE/Build System (all installed from Fedora official repos). If relevant, here is some version info for these tools.

Code::Blocks version info

Output of i686-w64-mingw32-g++ -v:

Using built-in specs.
COLLECT_GCC=i686-w64-mingw32-g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-w64-mingw32/7.3.0/lto-wrapper
Target: i686-w64-mingw32
Configured with: ../configure --prefix=/usr --bindir=/usr/bin --includedir=/usr/include --mandir=/usr/share/man --infodir=/usr/share/info --datadir=/usr/share --build=x86_64-redhat-linux-gnu --host=x86_64-redhat-linux-gnu --with-gnu-as --with-gnu-ld --verbose --without-newlib --disable-multilib --disable-plugin --with-system-zlib --disable-nls --without-included-gettext --disable-win32-registry --enable-languages=c,c++,objc,obj-c++,fortran --with-bugurl=http://bugzilla.redhat.com/bugzilla --with-cloog --enable-threads=posix --enable-libgomp --target=i686-w64-mingw32 --with-sysroot=/usr/i686-w64-mingw32/sys-root --with-gxx-include-dir=/usr/i686-w64-mingw32/sys-root/mingw/include/c++
Thread model: posix
gcc version 7.3.0 20180125 (Fedora MinGW 7.3.0-1.fc28) (GCC)

Edit: Additionaly, I've set up Code::Blocks to work with the cross-compiler using slightly modified instructions from here http://wiki.codeblocks.org/index.php/Code::Blocks_and_Cross_Compilers

Ownership answered 6/9, 2018 at 13:5 Comment(0)
O
4

It turns out the library header contained a block that goes like this

#if defined(BEARLIBTERMINAL_STATIC_BUILD)
#  define TERMINAL_API
#elif defined(_WIN32)
#  if defined(BEARLIBTERMINAL_BUILDING_LIBRARY)
#    define TERMINAL_API __declspec(dllexport)
#  else
#    define TERMINAL_API __declspec(dllimport)
#  endif
#else
#  if defined(BEARLIBTERMINAL_BUILDING_LIBRARY) && __GNUC__ >= 4
#    define TERMINAL_API __attribute__ ((visibility ("default")))
#  else
#    define TERMINAL_API
#  endif
#endif

It prefixes all of the API functions with __declspec(dllexport/dllimport) when building the library or including the header in the project respectively (on Windows only and only if BEARLIBTERMINAL_STATIC_BUILD isn't defined).

I hadn't looked at the library code until now- and just assumed that setting this define was enough when building the library itself.

It seems I need to set it when building my project as well to prevent the _declspecs from appearing.

Ownership answered 6/9, 2018 at 19:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.