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

CMake + MSys2 undefined references to everything (including c++ runtime)

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

我尝试设置 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: <....>

如前所述,编译工作正常,但 link 编译可执行文件却失败了。这是我的最小工作示例:

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

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

add_executable(example
        main.cpp
)

这是一个输出示例(为简洁起见省略了其余部分):

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()'

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

编译:

/mingw64/bin/CC.exe   -std=gnu++17 -o CMakeFiles/example.dir/main.cpp.obj -c /home/.../Development/minex/main.cpp

Link:

/mingw64/bin/CC.exe CMakeFiles/example.dir/main.cpp.obj -o example

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

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

我可以通过 运行ning

重现输出
$ CC main.cpp -o example

$ g++ main.cpp -o example

工作正常。

CMake 版本为 3.18.4.

编辑:这是 运行ning make VERBOSE=1 的全部输出(使用 mingw64-cmake 似乎产生相同的输出,除了 'entering directory' 和 'leaving directory' 路径是绝对 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

解法:

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

CMAKE_CXX_COMPILER=... cmake ..

没有

cmake .. -DCMAKE_CXX_COMPILER=...

不过!还是很奇怪,用CC编译cpp文件成功了,但是不能link目标文件

您遇到这些错误是因为您正尝试 compile/link 使用 c 编译器编写 c++ 程序。例如,您提到的两个未定义引用是 libstdc++ 的一部分。使用 g++ 时默认使用它,但不使用 CC。如果要使用 CC,则必须手动添加 -lstdc++.

最简单的方法是使用 g++ 编译和 link c++ 程序。

出于某种原因,/mingw64/bin/CC.exe 被视为 CXX 编译器,工作检测被跳过。为避免跳过工作检测,您可以添加 set(CMAKE_CXX_COMPILER_WORKS 1)。要自行修改编译器,您可以按照 CMAKE_CXX_COMPILER or set CXX as explained in CXX 中的说明设置 CMAKE_CXX_COMPILER 。注意清理缓存。

如果您在 MSYS2 中使用 mingw64 编译器,请确保您也在使用 cmakemingw64 版本。 使用不与 gcc 对齐的 cmake 例如:

MINGW64
# which gcc
/mingw64/bin/gcc

MINGW64
# which cmake
/usr/bin/cmake

当运行 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
...

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

所以一定要安装mingw64版本的cmake:

MINGW64
pacman -S mingw-w64-x86_64-cmake

安装cmake后需要关闭terminal再打开。然后确保安装了 gcc 和 cmake 的对齐版本:

MINGW64
# which gcc
/mingw64/bin/gcc

MINGW64
# which cmake
/mingw64/bin/cmake

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