交叉编译 SystemC 库并链接到它们

Cross-compiling SystemC libraries and linking to them

我从头开始,并遵循以下主要步骤:

1.构建并安装交叉编译器工具链(主机Linux,目标Win64):

获取此 MXE version,仅将 plugins/gcc6/gcc6-overlay.mk 更改为:

$(PKG)_VERSION  := 6.3.0
$(PKG)_CHECKSUM := f06ae7f3f790fbf0f018f6d40e844451e6bc3b7bc96e128e63b09825c1f8b29f

那就简单了(只需要一些时间,用make --jobs=X JOBS=Y加速):

setenv MXE_SRC /path/to/where/you/extracted/mxe

cd $MXE_SRC
make MXE_TARGETS='x86_64-w64-mingw32.shared x86_64-w64-mingw32.static' MXE_PLUGIN_DIRS=plugins/gcc6 pthreads
setenv PATH $MXE_SRC/usr/bin:$PATH

2。交叉编译安装 SystemC 2.3.3 libraries

这同样简单(但要快得多!):

setenv SYSTEMC_SRC                  /path/to/where/you/extracted/systemc/
setenv SYSTEMC_STATICTOOLCHAIN_DEST /this/is/your/choice

cd $SYSTEMC_SRC
./configure --prefix=$SYSTEMC_STATICTOOLCHAIN_DEST --host=x86_64-w64-mingw32.static
make install

3。构建一个简单的可执行文件

sc_main.cpp中写几行代码:

#include "systemc.h"

int sc_main (int argc, char* argv[])
{
  sc_clock clk("CLOCK", 1, SC_NS, 0.5);
  sc_start();
  return 0;
}

现在进行最后一步构建:

x86_64-w64-mingw32.static-g++ sc_main.cpp -I$SYSTEMC_STATICTOOLCHAIN_DEST/include -L$SYSTEMC_STATICTOOLCHAIN_DEST/lib-mingw64 -lsystemc

我得到了一大堆

libsystemc.a(sc_prim_channel.o):sc_prim_channel.cpp:(.text+0x44): undefined reference to `__imp_pthread_mutex_unlock'

(及其变体)。

任何人都可以重现并解释发生了什么事吗?

当 SystemC configure 完成时,它清楚地表明它不会使用 Posix 线程,而是使用 WinFiber,所以我有点惊讶地看到这些未解决的 phread 依赖关系(对于记录,在命令行末尾添加 -lpthread 仍然产生相同的结果)

4.以不同方式构建 SystemC 库的额外实验

如果我使用 a native Win64 toolchain 构建 SystemC 库,然后使用相同的命令行构建我的可执行文件:

 setenv SYSTEMC_NATIVETOOLCHAIN_DEST /path/to/systemc/libraries/built/with/native/toolchain
 x86_64-w64-mingw32.static-g++ sc_main.cpp -I$SYSTEMC_NATIVETOOLCHAIN_DEST/include -L$SYSTEMC_NATIVETOOLCHAIN_DEST/lib-mingw64 -lsystemc

然后一切正常,正如预期的那样。

此外,如果我使用 cmake 而不是 configure 交叉编译和安装 SystemC 库:

cd $SYSTEMC_SRC
mkdir build && cd build && x86_64-w64-mingw32.static-cmake .. -DBUILD_SHARED_LIBS=OFF -DCMAKE_CXX_STANDARD=14 -DINSTALL_TO_LIB_TARGET_ARCH_DIR=ON -DCMAKE_INSTALL_PREFIX=$SYSTEMC_STATICTOOLCHAIN_DEST
make install

x86_64-w64-mingw32.static-g++ sc_main.cpp -I$SYSTEMC_STATICTOOLCHAIN_DEST/include -L$SYSTEMC_STATICTOOLCHAIN_DEST/lib-mingw64 -lsystemc

然后,一切正常,正如预期的那样。

我怀疑 SystemC 库在交叉编译时没有正确生成。任何人都可以 confirm/deny?

这不是一个正确的答案,但至少我可以描述导致问题的 end-to-end 机制。 我对 MingW、winpthread 等的所有错综复杂之处还不够熟悉……无法真正准确地说出谁做错了什么,但我会把它留给专家 ;-)

所以这一切都从 SystemC 的 configure 开始,它生成定义 DLL_EXPORT 的 Makefile 配方。乍一看,定义 DLL_EXPORT 似乎很合理,因为目标是构建一个库。

但在实践中,DLL_EXPORT 并未在 SystemC 代码中的任何地方被引用,因此其意图不是很清楚(事实上,SystemC 的基于 cmake 的流程并没有定义它)。不过,如果我相信 configure 中的评论,那么这是一种有充分理由相信的黑客行为。

接下来,随着 SystemC 源文件的编译,mingw-w64-libraries/winpthreads/include/pthread.h 会在某个时候被包含(通过 sc_host_mutex.h<mutex>)。

此时编译器看到以下内容:

#if defined DLL_EXPORT
#      ifdef IN_WINPTHREAD
#            define WINPTHREAD_API __declspec(dllexport)
#      else
#            define WINPTHREAD_API __declspec(dllimport)
#      endif
#else
#      define WINPTHREAD_API
#endif

注意 mingw-w64-libraries/winpthreads/include/sched.hmingw-w64-libraries/winpthreads/include/semaphore.h

中有类似的代码

假设未定义 IN_WINPTHREAD(我猜这总是正确的,除非在构建 ​​libwinpthread.dll 时),从 SystemC 库调用 pthread API 被声明为 'dllimport' 最终导致臭名昭著的:

libsystemc.a(sc_prim_channel.o):sc_prim_channel.cpp:(.text+0x44): undefined reference to `__imp_pthread_mutex_unlock'
  

我想知道 mingw-w64 header 的意图是否有点不同,也许是这样的:

#ifdef IN_WINPTHREAD
#    if defined DLL_EXPORT
#        define WINPTHREAD_API __declspec(dllexport)
#    else
#        define WINPTHREAD_API __declspec(dllimport)
#    endif
#else
#    define WINPTHREAD_API
#endif 

甚至

#if defined DLL_EXPORT
#      ifdef IN_WINPTHREAD
#            define WINPTHREAD_API __declspec(dllexport)
#      else
#            define WINPTHREAD_API
#      endif
#else
#      define WINPTHREAD_API
#endif

最终我无法在以下两者之间做出决定:

  • SystemC 是罪魁祸首,configure 不应该定义 DLL_EXPORT
  • MinGW-w64 是罪魁祸首,pthread.h 应该提供一种不同的机制,以便对 pthread API 的调用不会自动转换为 'dllimport',而是默认为正常的静态链接也许(也可以引入 DLL_IMPORT 的显式机制)。
  • 以上两者
  • 其他

在过去的几天里,我学到了很多关于 libtool 和 how DLLEXPORT is meant to be used in a consistent manner 的知识。

这让我意识到问题的根本原因是最终用户(我自己),一如既往...

公平地说,SystemC 附带的 configure 脚本中存在一些不一致的地方。以下:

./configure --host=x86_64-w64-mingw32.static
  • 将按预期构建静态库 (libsystemc.a)
  • 但默认情况下它会很乐意使用共享库的设置(假设--enable-shared

它让最终用户相信一切都很好......但事实并非如此。

一旦您理解了这一点并明确指定了与构建静态库一致的设置:

./configure --host=x86_64-w64-mingw32.static --disable-shared

然后一切正常。

SystemC cmake 流程更健壮。如果您尝试使用默认设置定位 Windows,它会抛出一个错误,这让您别无选择,只能在命令行上指定 -DBUILD_SHARED_LIBS=OFF