静态库缺少 `__imp_` 符号

Static library missing `__imp_` symbols

编辑:找到了解决方案,但还不能接受我自己的答案。

我在静态 link 将库添加到我的程序时遇到了一些问题。我使用 MinGW 工具链和 Code::Blocks 作为 IDE/Build 系统,从 Linux 到 Windows cross-compiling。我还使用与程序相同的工具链自己编译了库。

我对 cross-compiling 和 Windows 的编译都是全新的。

编辑:我刚刚在 Windows XP(使用 Code::Block 捆绑的 MinGW)的虚拟安装上尝试了相同的过程并遇到了同样的问题,所以我想这不是因为cross-compiler.

问题

我将在下面给出所有细节,但本质上问题是 linker 抱怨缺少 _imp__some_symbol 符号。这些符号存在于静态库中,但不是 _imp__some_symbol,而是 _some_symbol。我已经通过搜索 nm libSomeLibrary.a

的输出验证了这一点

详情

库本身是 BearLibTerminal(您可以在 https://bitbucket.org/cfyzium/bearlibterminal/downloads/ 找到源代码)。如前所述,我自己使用与主程序相同的工具链从源代码编译它。

我的主要程序包含代码是 BearLibTerminal 在这里给出的 "Hello world" 示例 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();
}

我完整的 Code::Blocks 构建日志可以在 https://pste.eu/p/VMJp.html 找到。它包含 BearLibTerminal 及其依赖项以及我的程序的构建日志。

相关位(我认为)是这些:

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

在 link 行的末尾,您会看到它应该静态 link BearLibTerminal 依赖项(libPicoPNG.alibFreeType.a)和 BearLibTerminal 本身(libBearLibTerminal.a).

现在用 nm libBearLibTerminal.a | grep -E ' _imp__terminal_(open|print_ext8|refresh|read|close)' 检查 libBearLibTerminal.a 符号给出空输出。

然而 nm libBearLibTerminal.a | grep -E 'terminal_(open|print_ext8|refresh|read|close)' 给出:

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

所以,符号都在那里,只是前缀不同。

这是什么原因造成的,有什么办法可以解决?

工具链

我正在使用 MinGW 工具链和 Code::Blocks 作为 IDE/Build 系统在 Fedora 28 系统上进行编译(全部从 Fedora 官方存储库安装)。如果相关,这里是这些工具的一些版本信息。

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)

编辑:另外,我已经设置 Code::Blocks 使用 cross-compiler 使用此处 http://wiki.codeblocks.org/index.php/Code::Blocks_and_Cross_Compilers

中的稍微修改的说明

原来库 header 包含一个这样的块

#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

在构建库或在项目中分别包含 header 时,它为所有 API 函数加上 __declspec(dllexport/dllimport) 前缀(仅在 Windows 上且仅当 BEARLIBTERMINAL_STATIC_BUILD 未定义)。

直到现在我才看过库代码 - 只是假设在构建库本身时设置这个定义就足够了。

似乎我需要在构建项目时设置它,以防止出现 _declspecs。