C++20 LNK2019 与 MSVC 错误,而 C++17 可以工作

问题描述 投票:0回答:1

我在使用 CMake 和 Bazel 构建的项目上遇到了 C++20 的问题,其中两者都可以在 linux(GCC 和 Clang)上的 c++17/c++20 上运行,但它们仅在 Windows msvc 上失败c++20.该错误是链接错误(LNK2019),这很奇怪,因为是 CMake(或 Bazel)自己构建了对象,但它们无法链接。 我在 github 上放置了一些可重现的代码,尽管该项目相当大:https://github.com/manydeps/manydeps-cln 我尝试更改MSVC版本(github actions为windows-2022 / windows-latest image提供了4个不同的版本):14.16.27023、14.29.30133、14.35.32215和14.37.32822。 另一个奇怪的事情是,CMake 决定使用 14.35.32215,而 Bazel 使用 14.37.32822(我无法更改它,即使删除文件夹也是如此)。 我正在将其构建为 Windows 上的静态 /MT 库(以及 Linux 上的 .a)。

这是 CLN 项目的奇怪链接错误:

[5 / 6] Linking app_demo_cln.exe; 1s local
ERROR: D:/a/manydeps-cln/manydeps-cln/BUILD.bazel:21:10: Linking app_demo_cln.exe failed: (Exit 1120): link.exe failed: error executing command (from target //:app_demo_cln) C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.35.32215\bin\HostX64\x64\link.exe @bazel-out/x64_windows-fastbuild/bin/app_demo_cln.exe-2.params
cln.lib(cl_prin_globals.obj) : error LNK2019: unresolved external symbol "struct cln::cl_heap_string * __cdecl cl_make_heap_string(char const *)" (?cl_make_heap_string@@YAPEAUcl_heap_string@cln@@PEBD@Z) referenced in function "public: __cdecl cln::cl_string::cl_string(char const *)" (??0cl_string@cln@@QEAA@PEBD@Z)
  Hint on symbols that are defined and could potentially match:
    "struct cln::cl_heap_string * __cdecl cln::cl_make_heap_string(char const *)" (?cl_make_heap_string@cln@@YAPEAUcl_heap_string@1@PEBD@Z)
bazel-out\x64_windows-fastbuild\bin\app_demo_cln.exe : fatal error LNK1120: 1 unresolved externals
Target //:app_demo_cln failed to build

函数

cl_make_heap_string
存在于 CLN 库中,但名称修改看起来很奇怪......类似于
cl_make_heap_string@cln@@YAPEAUcl_heap_string@1@PEBD@Z
cl_make_heap_string@@YAPEAUcl_heap_string@cln@@PEBD@Z
,因此它们不会匹配。

我尝试更改编译器,更改编译器中的标志并在互联网上寻找答案已经很多天了,但没有解决方案。

visual-c++ cmake c++20 bazel lnk2019
1个回答
0
投票

感谢@Tsyvarev 对链接错误性质的精确评论,这表明全局与特定命名空间的命名可能存在问题。我确实检查了代码,这是一个片段:

定义(一些随机的

.cc
文件):

namespace cln { 
cl_heap_string* cl_make_heap_string (const char * s) { ... } } 
}

声明:

namespace cln { 
struct heap_string { 
 // much more stuff here ...
 friend cl_heap_string* cl_make_heap_string(const char* s); 
}; 
}

所以有趣的是,根据 C++17 标准,两者之间的符号匹配,但是对于 C++20 严格 (

/permissive-
) 行为,它们不再匹配(所以需要
/permissive
,但我想要一个真正的修复)。 我看了一下,也许 C++ 上的 bug 缺陷可能是这个 “1477。定义其名称空间之外的朋友”https://cplusplus.github.io/CWG/issues/1477。 html

原文:

命名空间中首先声明的每个名称都是该命名空间的成员。如果非本地类中的友元声明首先声明了一个类或函数,则该友元类或函数是最内层封闭命名空间的成员。在该命名空间范围中提供匹配声明之前,通过非限定查找 (6.5.3 [basic.lookup.unqual]) 或限定查找 (6.5.5 [basic.lookup.qual]) 找不到好友的名称 (在授予友谊的类定义之前或之后)。

2012 年修复文本:

命名空间中首先声明的每个名称都是该命名空间的成员。如果非本地类中的友元声明首先声明了一个类或函数,则该友元类或函数是最内层封闭命名空间的成员。好友声明本身并不使该名称对非限定查找 (6.5.3 [basic.lookup.unqual]) 或限定查找 (6.5.5 [basic.lookup.qual]) 可见)。 [注意:如果在命名空间范围内提供了匹配的声明(在授予友谊的类定义之前或之后),则好友的名称将在其命名空间中可见。 —尾注]如果调用友元函数...

所以,我更改了声明,它在 C++20 严格模式下确实有效!

固定声明:

namespace cln { 
struct heap_string { 
 // much more stuff here ...
 friend cl_heap_string* cl_make_heap_string(const char* s); 
}; 
// ADDED THIS PART HERE, TO ENFORCE THAT METHOD REALLY BELONGS TO cln:: NAMESPACE
cl_heap_string* cl_make_heap_string(const char* s); 
}

所以,非常感谢您的帮助!

© www.soinside.com 2019 - 2024. All rights reserved.