c++dllcross-compilingmingw-w64dllexport

Symbols not exported when creating Windows DLL using MingW


I'm trying to debug this issue with DuckDB.


For the Windows build cross-compiled on Linux using the MingW toolchain, newer versions of the DuckDB library does not export any of the C-API symbols in the final shared library file.
This is the first bad commit.

To build:

cmake -B build \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_TOOLCHAIN_FILE=mingw-w64-x86_64.cmake \
      -DBUILD_EXTENSIONS='autocomplete;icu;parquet;json;fts;tpcds;tpch' \
      -DENABLE_EXTENSION_AUTOLOADING=1 \
      -DENABLE_EXTENSION_AUTOINSTALL=1 \
      -DBUILD_UNITTESTS=FALSE \
      -DBUILD_SHELL=TRUE \
      -DDUCKDB_EXPLICIT_PLATFORM=x86_64-w64-mingw32-cxx11 .
cmake --build build

The toolchain file:

set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)

# cross compilers to use for C, C++ and Fortran
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)

# target environment on the build host system
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})

# modify default behavior of FIND_XXX() commands
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

The shared library (build/src/libduckdb.dll) exports the C-API symbols, which you can test with winedump like this:

$ winedump -j export libduckdb.dll | grep duckdb_vector_size
  009F42F0   365  duckdb_vector_size # see this if symbols are present, empty otherwise

The above is empty for the library built after the bad commit.

I went through the build commands, this is the relevant bit (during the build, it runs in build/src):

/usr/bin/cmake -E rm -f CMakeFiles/duckdb.dir/objects.a
/usr/bin/x86_64-w64-mingw32-ar qc CMakeFiles/duckdb.dir/objects.a @CMakeFiles/duckdb.dir/objects1.rsp
/usr/lib64/ccache/x86_64-w64-mingw32-g++ -O3 -DNDEBUG -O3 -DNDEBUG   -shared -o libduckdb.dll \
    -Wl,--out-implib,libduckdb.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -Wl,--whole-archive \
    CMakeFiles/duckdb.dir/objects.a -Wl,--no-whole-archive @CMakeFiles/duckdb.dir/linkLibs.rsp

So I tried to follow the symbols starting from the object file (in build/src).

# find the C-API object file
$ tr ' ' '\n' <CMakeFiles/duckdb.dir/objects1.rsp | grep capi.cpp
main/capi/CMakeFiles/duckdb_main_capi.dir/ub_duckdb_main_capi.cpp.obj
# check for symbols
$ nm -C main/capi/CMakeFiles/duckdb_main_capi.dir/ub_duckdb_main_capi.cpp.obj | grep duckdb_vector_size
0000000000004f60 T duckdb_vector_size
# check for the C-API object file in the objects archive
$ /usr/bin/x86_64-w64-mingw32-ar t CMakeFiles/duckdb.dir/objects.a | grep capi.cpp
ub_duckdb_main_capi.cpp.obj
# check for C-API symbols in the objects archive
$ nm -C CMakeFiles/duckdb.dir/objects.a | grep duckdb_vector_size
0000000000004f60 T duckdb_vector_size
# check if the C-API symbols are public
$ winedump -j export CMakeFiles/duckdb.dir/objects.a | grep duckdb_vector_size
 31a0ae4 duckdb_vector_size
# create the shared library
$ /usr/lib64/ccache/x86_64-w64-mingw32-g++ -O3 -DNDEBUG -O3 -DNDEBUG   -shared -o libduckdb.dll \
    -Wl,--out-implib,libduckdb.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -Wl,--whole-archive \
    CMakeFiles/duckdb.dir/objects.a -Wl,--no-whole-archive @CMakeFiles/duckdb.dir/linkLibs.rsp
# the C-API symbols exist
$ nm -C libduckdb.dll | grep duckdb_vector_size
00000001f3d116e0 T duckdb_vector_size
# but they are not exported
$ winedump -j export libduckdb.dll | grep duckdb_vector_size # no match

For the previous commit (d1ea1538c9~), the symbols are exported as expected. The "bad" commit doesn't do anything other than add 11 new symbols. I really have no idea what is causing this. Anyone any thoughts?


Solution

  • This has now been fixed in duckdb/duckdb#16397. Release version 1.2.1 includes the fix. The issue was two identically named macros were conflicting. The solution was to rename one of them.