使用 cmake 在 windows 上编译 c++ 数据库时出错

Posted

技术标签:

【中文标题】使用 cmake 在 windows 上编译 c++ 数据库时出错【英文标题】:Error compiling a c++ database on windows with cmake 【发布时间】:2019-10-21 12:32:45 【问题描述】:

对于我的硕士学位,我需要在一个名为 daddb 的数据库上工作(它在 git hub 上)。通常在 Linux 上,您可以简单地克隆它并“制作”它来安装。

安装 CMake 和 Cygwin 后,我在 Windows 上也感到厌烦。

但是编译到一半就报错了

'DUCKDB~2/duckdb/THIRD_~1/catch/catch.hpp:1445:96: 错误:ISO C++ 禁止指针和整数比较[-fpermissive]

 auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool  return static_cast<bool>(lhs != rhs); '

由于我怀疑duckdb 的创建者确实把这件事搞砸了,我认为尝试将C 文件编译为C++ 文件时可能会出现编译器错误。

我的主要问题是:如何在 windows 上配置 make 命令以阻止它产生此错误?

我在安装了 gcc 5.1 和当前 cmake 的 Windows 7 和 10 系统上都尝试过,但都产生了这个错误。

编辑:这是完整的错误文本

[ 87%] 构建 CXX 对象 test/sql/capi/CMakeFiles/test_sql_capi.dir/ub_test_sql_capi.cpp.obj 在 C:/duckdb/test/sql/capi/test_capi.cpp:1:0 包含的文件中, 来自 test_capi.cpp:0:

C:/DUCKDB~2/duckdb/THIRD_~1/catch/catch.hpp: 在 'bool >Catch::compareNotEqual(const LhsT&, RhsT&&) [with LhsT = void*; RhsT = const >long long int&]':

C:/DB/DUCKDB~2/duckdb/THIRD_~1/catch/catch.hpp:1471:37: 需要来自 'const >Catch::BinaryExpr Catch::ExprLhs::operator!=(const >RhsT& ) [with RhsT = long long int; LhsT = void* const&]'

C:/DB/duckdb/test/sql/capi/test_capi.cpp:332:2:从这里需要 C:/DB/DUCKDB~2/duckdb/THIRD_~1/catch/catch.hpp:1445:96:错误:ISO C++禁止比较>指针和整数[-fpermissive] auto compareNotEqual(LhsT const& lhs, RhsT&& rhs) -> bool return >static_cast(lhs != rhs);

我只在路径等中编辑了我的用户名。

【问题讨论】:

错误消息(C++ 禁止在指针和整数之间进行比较)似乎很清楚C++ 的规则已被破坏。 CC++ 是不同的语言,具有不同的规则。 如何在 Windows 上配置 make 命令以阻止它产生此错误? 使违规代码符合 C++ :) 有问题的文件似乎是 Catch2 克隆的一部分,并且似乎仅用于库中的测试。您应该能够在没有测试的情况下构建它。或者,错误消息应该告诉您是哪个测试.cpp 文件导致了错误。 (你不是把所有的行都复制了吗?)然后你可以看看有没有问题。有问题的代码显然是 C++,而不是 C。所以这不是问题。 @uneven_mark 我认为这不是问题所在。错误消息只是不完整。它看起来像是来自项目其他部分实例化的 catch 库中的模板 @PeterT 我并不是说 Catch2 有问题,只是它是错误表现的地方。 @nada 这是一个错误,而不是警告。而且我不会在标志中添加-fpermissive 【参考方案1】:

我不知道图书馆,所以我不能给出肯定的答案。我将使用https://github.com/cwida/duckdb 的代码。

根据问题代码中的错误信息在test/sql/capi/test_capi.cpp的第332行,即:

REQUIRE(stmt != NULL);

REQUIRE 是来自单元测试库 Catch2 的宏,它在解析给它的表达式时做了一些魔术。重要的部分是stmt != NULL实际上不会立即执行,而只能通过函数间接执行。

stmt 在第 324 行声明为

duckdb_prepared_statement stmt = nullptr;

duckdb_prepared_statementsrc/include/duckdb.h 的第94 行中的typedef:

typedef void *duckdb_prepared_statement;

因此问题行的意图是检查stmt在一些中间操作后是否仍然是nullptr

通常stmt != NULL 会很好。但是,由于 Catch2 宏引入了中间函数调用,而不是直接评估此表达式,因此不应用特定于文字的隐式转换。

根据标准,NULLstd::nullptr_t 类型的纯右值或值为 0 的整数文字。其中哪一个(以及哪个整数类型)是实现定义的。

通常禁止比较整数和指针,但是值为零的整数文字有一个特殊的例外,允许它们被隐式转换为任何指针类型的空指针。如果直接评估 stmt != NULL 会发生这种情况。

但是由于 Catch2 的插入,NULL 首先被传递,然后通过变量与stmt 进行比较,这使得特殊的零字面规则不再适用。因此,如果 NULL 在当前实现中是整数文字,则 NULLNULLREQUIRE 的比较将失败。

Catch2 确实考虑了这个问题,并且 third_party/catch/catch.hpp 中的 compareNotEqual 有重载,可以处理 NULLintlong 类型的零整数文字的情况,但由于某种原因不考虑long long 的情况。不知道是Catch2的问题还是只有duckdb中包含的克隆版本。

因此,如果实现对NULL 使用long long 类型的零字面量,那么您观察到的错误将会发生。

真的duckdb应该使用nullptr而不是NULL(就像它在初始化时那样),它没有这些问题,正是因为这些问题才被添加到语言中。

我想您可以简单地尝试通过将NULL 替换为nullptr 来解决此问题(也许在其他测试用例中也是如此)。

但是,有问题的代码仅存在于文件中,这些文件本身就是对实际库代码的单元测试。所以应该有一些 cmake 或 make 选项将禁用构建单元测试,这样你就可以忽略这个特定的错误,希望它不会出现在实际库代码的任何地方。

如果我的评估是正确的,那么您可能需要考虑向 Dukedb 提交一份错误报告,假设他们首先支持您的平台。

【讨论】:

【参考方案2】:

与使用 Cygwin 相比,使用 CMake 结合 Visual Studio 编译项目可能更容易。这是作者自己在 Windows 上编译和测试 DuckDB 的方式。

使用 CMake,生成一组 Visual Studio 项目文件。然后在 Visual Studio 中打开这些项目文件(我们使用 Visual Studio Community 2019),编译并运行测试套件(unittest)。可以通过将测试名称添加为命令行参数来运行单个测试。

【讨论】:

【参考方案3】:

DuckDB 目前似乎没有发布版本。所以不要以为创作者没有留下任何错误......

您可以添加编译器标志-fpermissive 以忽略错误(例如make CXX="g++ -fpermissive")。

但忽略此类错误并不总是安全的。

所以我尝试解决这个问题,并且能够在 Windows 上构建一个版本。请参阅https://github.com/cwida/duckdb/issues/361 了解我的解决方案。

【讨论】:

我注意到您的回答和问题的链接。只是让您知道您在此处发布的差异会破坏其他输入类型的功能(它应该适用于所有类型,而不仅仅是可转换为uintptr_t 的类型)。正确的解决方法是使用nullptr 而不是NULL,正如我在回答中提到的那样,或者添加一个额外的重载template&lt;typename T&gt; auto compareNotEqual( T* const&amp; lhs, long long rhs ) -&gt; bool return lhs != reinterpret_cast&lt;void const*&gt;( rhs ); ,类似于已经存在的重载(只是long long 而不是long)和类似物compareEqual. 如果我错了并且不能解决问题,如果您让我知道以便我改进答案,我将不胜感激。我自己没有测试过。 github.com/cwida/duckdb/commit/… 的补丁给了我这个结果:R:/x86_64-7.2.0-release-posix-seh-rt_v6-rev0/duckdb-0.1.1/src/common/types/value.cpp:481:10: error: converting to 'bool' from 'std::nullptr_t' requires direct-initialization [-fpermissive] 这似乎与该文件中的 NULL -> nullptr 替换有关。你确定你正确地应用了补丁吗?第 481 行是右大括号,nullptr 仅与 s 进行比较,std::nullptr_t 未在其他任何地方使用,无处(尝试)将其转换为 bool。 (同样我没有测试过自己。)见github.com/cwida/duckdb/blob/…

以上是关于使用 cmake 在 windows 上编译 c++ 数据库时出错的主要内容,如果未能解决你的问题,请参考以下文章

在Windows上编译和调试CoreCLR

在 Windows 上编译时出现 Apache thrift 错误

如何在 Windows 上编译 libevent2?

我无法使用 CMake 在 Mac 上编译 gtkmm

C++/LapackE 代码在 Windows 上编译良好,但相同的代码在 Linux 上编译失败

无法在 Windows 10 上编译 Cairo C 代码