带有 clang 的 CMake 显示未定义的符号,并且 cl 链接正确

CMake with clang shows undefined symbol, and with cl links correctly

TLDR

我正在构建静态库并将其链接到可执行文件。我正在用 cmake 生成 makefile。当我为 cl 生成 makefile 时(来自 visual studio 的编译器)我没有问题,但是当我为 clang 生成 makefile 时我得到一个未定义的符号。

版本:

最小示例

我的项目结构如下:

Proyect Root
│   CMakeLists.txt
│   foo.cpp
│   foo.hpp
│   main.cpp
│
└───bin

这是文件的内容:

foo.hpp

namespace foo {
    void do_stuff(void);
}

foo.cpp

#include <foo.hpp>

namespace foo {

void do_stuff(void) {}

}

main.cpp

#include <foo.hpp>

int main(void) {
    foo::do_stuff();
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.0.0)
project(CompileAndLinkLib)

include_directories(".")

file(GLOB FOO_SRC "foo.cpp")
add_library(foo STATIC ${FOO_SRC})

add_executable(main "main.cpp")
target_link_libraries(main foo)

正确链接

首先我打电话给vcvarsall.bat。我使用以下命令生成一个 nmake 文件:

cmake .. -G "NMake Makefiles"

并编译:

nmake

项目编译和链接正确

未定义符号

我使用以下命令生成 make 文件:

cmake .. -G "Unix Makefiles" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++

当我用 make 编译时,我得到以下输出:

Scanning dependencies of target foo
[ 25%] Building CXX object CMakeFiles/foo.dir/foo.cpp.obj
[ 50%] Linking CXX static library foo.lib
[ 50%] Built target foo
Scanning dependencies of target main
[ 75%] Building CXX object CMakeFiles/main.dir/main.cpp.obj
[100%] Linking CXX executable main.exe
lld-link: error: undefined symbol: void __cdecl foo::do_stuff(void)
>>> referenced by C:\Users\pabsa\temp\main.cpp:4
>>>               CMakeFiles/main.dir/main.cpp.obj:(main)
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [main.exe] Error 1
make[1]: *** [CMakeFiles/main.dir/all] Error 2
make: *** [all] Error 2

我不确定我是否做错了什么,比如我是否遗漏了什么,或者这是 cmake 生成的 makefile 的错误。

我再次测试了:

  • clang 版本 12.0.0
    • 目标:x86_64-pc-windows-msvc
    • 线程模型:posix

它工作正常。好像是 clang 11

的问题

我遇到了同样的问题,但使用的是 Clang 13。可以通过在 CMakeLists 中将 clang 指定为编译器来解决,而不是让 CMake 自动确定它。

set(CMAKE_CXX_COMPILER "clang++")

(是的,我读了你原来的问题是正确的,使用这个:

-DCMAKE_CXX_COMPILER=clang++

作为 cmake 的附加参数对我也不起作用,即使它看起来应该与 CMakeLists.txt)

中的设置相同