google / benchmark

A microbenchmark support library
Apache License 2.0
8.69k stars 1.59k forks source link

Link errors in cross compilation #1586

Open 24bit-xjkp opened 1 year ago

24bit-xjkp commented 1 year ago

Describe the bug I tried to cross compile benchmark to x86_64-w64-mingw32. When I set "-DBUILD_SHARED_LIBS=ON", no error generated. When I set "-DBUILD_SHARED_LIBS=OFF", the libbenchmark could be built. But when I tried to run the test, link errors generated. The test code:

void BM_empty(benchmark::State& state) {
              for (auto _ : state) {
                      benchmark::DoNotOptimize(state.iterations());
              }
}
BENCHMARK(BM_empty);

The command:

x86_64-w64-mingw32-g++ test.cpp -std=c++20 -isystem ./include -L./lib -lbenchmark

The errors:

/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text+0x106): undefined reference to `__imp__ZN9benchmark5State16StartKeepRunningEv'
/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text.startup+0x44): undefined reference to `__imp__ZN9benchmark16PrintDefaultHelpEv'
/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text.startup+0x52): undefined reference to `__imp__ZN9benchmark10InitializeEPiPPcPFvvE'
/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text.startup+0x5f): undefined reference to `__imp__ZN9benchmark27ReportUnrecognizedArgumentsEiPPc'
/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text.startup+0x70): undefined reference to `__imp__ZN9benchmark22RunSpecifiedBenchmarksEv'
/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text.startup+0x76): undefined reference to `__imp__ZN9benchmark8ShutdownEv'
/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text.startup+0x9a): undefined reference to `__imp__ZN9benchmark8internal17InitializeStreamsEv'
/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text.startup+0xab): undefined reference to `__imp__ZN9benchmark8internal9BenchmarkC2EPKc'
/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text.startup+0xc1): undefined reference to `__imp__ZTVN9benchmark8internal17FunctionBenchmarkE'
/home/luo/x86_64-w64-mingw32/lib/gcc/x86_64-w64-mingw32/13.0.0/../../../../x86_64-w64-mingw32/bin/ld: /tmp/cciXACO6.o:test.cpp:(.text.startup+0xcb): undefined reference to `__imp__ZN9benchmark8internal25RegisterBenchmarkInternalEPNS0_9BenchmarkE'

It seemed that the linker couldn't find functions with "imp". The amazing thing is that when I added "-DBENCHMARK_ENABLE_LTO=ON" and compiled the test with lto, it worked correctly again. The successful command:

x86_64-w64-mingw32-g++ test.cpp -std=c++20 -isystem ./include -L./lib -lbenchmark -flto

System

To reproduce Steps to reproduce the behavior:

  1. download the release v1.7.1
  2. ccmake -B build --toolchain toolchain.cmake --install-prefix=/home/luo/benchmark/install -DBUILD_SHARED_LIBS=OFF toolchain.cmake:
    set(CMAKE_SYSTEM_NAME Windows)
    set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
    set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
  3. cd build && make install -j
  4. See error

Expected behavior The benchmark for static links should also work.

LebedevRI commented 1 year ago

I suspect the cause is symbol visibility. https://github.com/google/benchmark/blob/1b507cbf104f7226ade1dd23abe92630e818d54b/CMakeLists.txt#L44-L46 Perhaps this either is not working on windows at all, or does not correctly handle using non-MSVC compilers: https://github.com/google/benchmark/blob/1b507cbf104f7226ade1dd23abe92630e818d54b/include/benchmark/export.h#L4-L14

24bit-xjkp commented 1 year ago

I tried to build benchmark on windows. Clang with "-DBUILD_SHARED_LIBS=OFF" generated some other errors.

lld-link: error: undefined symbol: __declspec(dllimport) int __cdecl benchmark::internal::InitializeStreams(void)
>>> referenced by C:\Users\ADMINI~1.SKY\AppData\Local\Temp\.xmake\230416\_19FB25C6824C4B00894B9FB808826310.o:(void __cdecl `dynamic initializer for 'benchmark::internal::stream_init_anchor''(void))
lld-link: error: undefined symbol: __declspec(dllimport) private: void __cdecl benchmark::State::StartKeepRunning(void)
>>> referenced by C:\Users\ADMINI~1.SKY\AppData\Local\Temp\.xmake\230416\_19FB25C6824C4B00894B9FB808826310.o:(void __cdecl BM_empty(class benchmark::State &))
lld-link: error: undefined symbol: __declspec(dllimport) private: void __cdecl benchmark::State::FinishKeepRunning(void)
>>> referenced by C:\Users\ADMINI~1.SKY\AppData\Local\Temp\.xmake\230416\_19FB25C6824C4B00894B9FB808826310.o:(void __cdecl BM_empty(class benchmark::State &))
lld-link: error: undefined symbol: __declspec(dllimport) public: __cdecl benchmark::internal::FunctionBenchmark::FunctionBenchmark(char const *, void (__cdecl *)(class benchmark::State &))
>>> referenced by C:\Users\ADMINI~1.SKY\AppData\Local\Temp\.xmake\230416\_19FB25C6824C4B00894B9FB808826310.o:(void __cdecl `dynamic initializer for 'benchmark_uniq_2_benchmark_''(void))
lld-link: error: undefined symbol: __declspec(dllimport) class benchmark::internal::Benchmark * __cdecl benchmark::internal::RegisterBenchmarkInternal(class benchmark::internal::Benchmark *)
>>> referenced by C:\Users\ADMINI~1.SKY\AppData\Local\Temp\.xmake\230416\_19FB25C6824C4B00894B9FB808826310.o:(void __cdecl `dynamic initializer for 'benchmark_uniq_2_benchmark_''(void))

But it works correctly when it is built with "-DBUILD_SHARED_LIBS=ON".