CMake + MSys2 对所有内容(包括 C++ 运行时)的未定义引用

mik*_*rry 1 c++ mingw cmake mingw-w64

我正在开发一个跨平台的 C++ 项目。在 Linux 上一切正常,但在 Windows (10) + MSys2 上我遇到了一个奇怪的问题。编译工作正常(获取我的包含目录等),但链接失败,并出现对我拥有的静态导入库甚至 C++ 运行时的各种未定义引用错误。

我尝试设置 CMAKE_C[XX]_COMPILER、CMAKE_MAKE_PROGRAM,但配置步骤的输出始终相同:

$ cmake ..
-- The C compiler identification is GNU 10.2.0
-- The CXX compiler identification is GNU 10.2.0
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19041 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
-- Detecting C compiler ABI info
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19041 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19041 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /mingw64/bin/CC.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: <....>
Run Code Online (Sandbox Code Playgroud)

正如前面提到的,编译可以工作,但是链接可执行文件却严重失败。这是我的最小工作示例:

$ cat ../CMakeLists.txt
project(example)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

add_executable(example
        main.cpp
)
Run Code Online (Sandbox Code Playgroud)

以下是输出示例(为简洁起见,省略了其余部分):

C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/example.dir/main.cpp.obj:main.cpp:(.text+0x51): undefined reference to `std::ios_base::Init::~Init()'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/example.dir/main.cpp.obj:main.cpp:(.text+0x81): undefined reference to `std::ios_base::Init::Init()'
Run Code Online (Sandbox Code Playgroud)

将 -v 添加到 cmake 会生成以下命令。

编译:

/mingw64/bin/CC.exe   -std=gnu++17 -o CMakeFiles/example.dir/main.cpp.obj -c /home/.../Development/minex/main.cpp
Run Code Online (Sandbox Code Playgroud)

关联:

/mingw64/bin/CC.exe CMakeFiles/example.dir/main.cpp.obj -o example
Run Code Online (Sandbox Code Playgroud)

CC.exe 似乎已关闭...如果我设置了 CXX 编译器标志或未设置 CXX 编译器标志,它就会被使用...

我还尝试生成“MSYS2 Makefiles”,但也失败了(不知道生成器)。

我可以通过运行来重现输出

$ CC main.cpp -o example
Run Code Online (Sandbox Code Playgroud)

尽管

$ g++ main.cpp -o example
Run Code Online (Sandbox Code Playgroud)

工作正常。

CMake 版本是 3.18.4。

编辑:这是运行的整个输出make VERBOSE=1(使用mingw64-cmake似乎产生相同的输出,除了“进入目录”和“离开目录”路径是绝对Windows路径):

    $ cat log
/usr/bin/cmake.exe -S/home/<...>/Development/minex -B/home/<...>/Development/minex/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake.exe -E cmake_progress_start /home/<...>/Development/minex/build/CMakeFiles /home/<...>/Development/minex/build//CMakeFiles/progress.marks
make  -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/<...>/Development/minex/build'
make  -f CMakeFiles/example.dir/build.make CMakeFiles/example.dir/depend
make[2]: Entering directory '/home/<...>/Development/minex/build'
cd /home/<...>/Development/minex/build && /usr/bin/cmake.exe -E cmake_depends "Unix Makefiles" /home/<...>/Development/minex /home/<...>/Development/minex /home/<...>/Development/minex/build /home/<...>/Development/minex/build /home/<...>/Development/minex/build/CMakeFiles/example.dir/DependInfo.cmake --color=
Dependee "/home/<...>/Development/minex/build/CMakeFiles/example.dir/DependInfo.cmake" is newer than depender "/home/<...>/Development/minex/build/CMakeFiles/example.dir/depend.internal".
Dependee "/home/<...>/Development/minex/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/<...>/Development/minex/build/CMakeFiles/example.dir/depend.internal".
Scanning dependencies of target example
make[2]: Leaving directory '/home/<...>/Development/minex/build'
make  -f CMakeFiles/example.dir/build.make CMakeFiles/example.dir/build
make[2]: Entering directory '/home/<...>/Development/minex/build'
[ 50%] Building CXX object CMakeFiles/example.dir/main.obj
/mingw64/bin/CC.exe   -std=gnu++17 -o CMakeFiles/example.dir/main.obj -c /home/<...>/Development/minex/main.cpp
[100%] Linking CXX executable example
/usr/bin/cmake.exe -E cmake_link_script CMakeFiles/example.dir/link.txt --verbose=1
/mingw64/bin/CC.exe CMakeFiles/example.dir/main.obj -o example
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/example.dir/main.obj:main.cpp:(.text+0x23): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/example.dir/main.obj:main.cpp:(.text+0x32): undefined reference to `std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/example.dir/main.obj:main.cpp:(.text+0x51): undefined reference to `std::ios_base::Init::~Init()'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/example.dir/main.obj:main.cpp:(.text+0x81): undefined reference to `std::ios_base::Init::Init()'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/example.dir/main.obj:main.cpp:(.rdata$.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_[.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_]+0x0): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/example.dir/main.obj:main.cpp:(.rdata$.refptr._ZSt4cout[.refptr._ZSt4cout]+0x0): undefined reference to `std::cout'
collect2.exe: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/example.dir/build.make:103: example] Error 1
make[2]: Leaving directory '/home/<...>/Development/minex/build'
make[1]: *** [CMakeFiles/Makefile2:95: CMakeFiles/example.dir/all] Error 2
make[1]: Leaving directory '/home/<...>/Development/minex/build'
make: *** [Makefile:103: all] Error 2
Run Code Online (Sandbox Code Playgroud)

解决方案:

我设置了 CMAKE_CXX_COMPILER 错误:/。我是凭记忆做的,而且我就是这么做的

CMAKE_CXX_COMPILER=... cmake ..
Run Code Online (Sandbox Code Playgroud)

不是

cmake .. -DCMAKE_CXX_COMPILER=...
Run Code Online (Sandbox Code Playgroud)

然而!还是很奇怪,用CC成功编译了cpp文件,却无法链接目标文件。

olo*_*uki 6

如果您使用mingw64编译器,MSYS2请确保您也使用 的mingw64版本cmake

使用与 gcc 不匹配的 cmake 例如:

MINGW64
# which gcc
/mingw64/bin/gcc

MINGW64
# which cmake
/usr/bin/cmake
Run Code Online (Sandbox Code Playgroud)

运行cmake时会导致以下错误:

...
-- The CXX compiler identification is GNU 10.2.0
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19041 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
...
Run Code Online (Sandbox Code Playgroud)

和构建步骤中的链接器错误。

因此,请确保安装 mingw64 版本的 cmake:

MINGW64
pacman -S mingw-w64-x86_64-cmake
Run Code Online (Sandbox Code Playgroud)

安装cmake后需要关闭终端并再次打开。然后确保安装了 gcc 和 cmake 的一致版本:

MINGW64
# which gcc
/mingw64/bin/gcc

MINGW64
# which cmake
/mingw64/bin/cmake
Run Code Online (Sandbox Code Playgroud)

现在 cmake 应该可以正常工作了。