【问题标题】:CMake throws exception because of undefined reference in CryptoPP由于 CryptoPP 中未定义的引用,CMake 引发异常
【发布时间】:2017-10-04 09:47:05
【问题描述】:

我收到此错误:

CMakeFiles/Athena.dir/Startup/main.cpp.o: In function `CryptoPP::ClonableImpl<CryptoPP::BlockCipherFinal<(CryptoPP::CipherDir)0, CryptoPP::Rijndael::Enc>, CryptoPP::Rijndael::Enc>::ClonableImpl()':
/home/dev/workspace/Athena/lib/cryptopp/simple.h:26: undefined reference to `CryptoPP::Rijndael::Enc::Enc()'
collect2: error: ld returned 1 exit status
CMakeFiles/Athena.dir/build.make:434: recipe for target 'Athena'

当我尝试将 CryptoPP 链接到我的程序时。

这是我的 CMakeLists.txt:

cmake_minimum_required(VERSION 3.8)
project(Athena)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -fpermissive -Wno-deprecated -Wno-int-to-pointer-cast -Wno-deprecated-declarations")

include_directories(lib/SQLiteCpp/include)
add_subdirectory(lib/SQLiteCpp)

include_directories(lib/cryptopp)
add_subdirectory(lib/cryptopp)

include_directories(lib/json/src)
add_subdirectory(lib/json)

set(SOURCE_FILES
    Startup/main.cpp)

add_executable(Athena ${SOURCE_FILES})
target_link_libraries(Athena SQLiteCpp sqlite3 pthread dl cryptopp)

这是我的内容:

#include "modes.h" // For CTR_Mode
#include "filters.h" //For StringSource
#include "aes.h" // For AES

我已经尝试通过 find_package、find_library 链接cryptopp,甚至尝试编写脚本来手动下载和制作cryptopp。我真的没有想法,我也很确定这不是我的代码(我粘贴了来自 cryptopp wiki 的示例)。

【问题讨论】:

  • 我们围绕Rijndael::Enc 构造函数重新编写了代码。 ctor 不再存在于 Rijndael 类中。现在将使用默认的、编译器生成的 ctor。您需要从 Master 那里获取最新的资源。另请参阅Commit 01e46aa474f6

标签: c++ cmake linker crypto++


【解决方案1】:

您的 CMakeLists.txt 看起来不正确。你应该做两件事。首先,您应该复制GNUmakefile 用于目标的源文件的确切列表。其次,您应该使用GNUmakefile 使用的相同标志。您必须运行项目的 makefile 或 msbuild 文件才能获得这些文件。

您还应该考虑使用ExternalProject_Add;并停止尝试让 Cmake 构建库。该库已经提供了一个 Makefile 和 MSBuild 文件来在它支持的所有平台上构建该库,因此 Cmake 是多余的并且不需要。没有理由让 Cmake 创建带有不正确选项和标志的构建文件,因为我们已经提供了正确的选项。另请参阅 Stack Overflow 上的 How to use CMake ExternalProject_Add or alternatives in a cross platform way?

在尝试在 Crypto++ 中支持 Cmake 一年之后,我说这话有很多经验。另请参阅 Crypto++ wiki 上的 Cmake


CMakeFiles/Athena.dir/Startup/main.cpp.o: In function `CryptoPP::ClonableImpl<CryptoPP::BlockCipherFinal<(CryptoPP::CipherDir)0, CryptoPP::Rijndael::Enc>, CryptoPP::Rijndael::Enc>::ClonableImpl()':
/home/dev/workspace/Athena/lib/cryptopp/simple.h:26: undefined reference to `CryptoPP::Rijndael::Enc::Enc()'
collect2: error: ld returned 1 exit status
CMakeFiles/Athena.dir/build.make:434: recipe for target 'Athena'

您应该显示用于构建库的命令行。这是 Crypto++ 取消对 Cmake 支持的另一个原因 - 它隐藏了用于故障排除的必要信息,例如用于构建源文件的命令行。它导致了像这样可怕的错误报告。

Rijndael::Enc::Enc() 用于在未对齐的数据访问生效时启用代码以抵御侧通道攻击。不使用构造函数本身;但它需要用于代码路径,因为其中设置了一些值。

如果您查看rijndael.h,您将看到当平台为 IA-32、ARM 或 PowerPC 时启用了构造函数。但感兴趣的源文件确实是rijndael.cpp,大约在第 1070 行:

#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86

static inline bool AliasedWithTable(const byte *begin, const byte *end)
{
    ptrdiff_t s0 = uintptr_t(begin)%4096, s1 = uintptr_t(end)%4096;
    ptrdiff_t t0 = uintptr_t(Te)%4096, t1 = (uintptr_t(Te)+sizeof(Te))%4096;
    if (t1 > t0)
        return (s0 >= t0 && s0 < t1) || (s1 > t0 && s1 <= t1);
    else
        return (s0 < t1 || s1 <= t1) || (s0 >= t0 || s1 > t0);
}

struct Locals
{
    word32 subkeys[4*12], workspace[8];
    const byte *inBlocks, *inXorBlocks, *outXorBlocks;
    byte *outBlocks;
    size_t inIncrement, inXorIncrement, outXorIncrement, outIncrement;
    size_t regSpill, lengthAndCounterFlag, keysBegin;
};

const size_t s_aliasPageSize = 4096;
const size_t s_aliasBlockSize = 256;
const size_t s_sizeToAllocate = s_aliasPageSize + s_aliasBlockSize + sizeof(Locals);

Rijndael::Enc::Enc() : m_aliasBlock(s_sizeToAllocate) { }

#endif  // CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86

#if CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
// Do nothing
Rijndael::Enc::Enc() { }
#endif

您需要弄清楚为什么 Cmake 与 CRYPTOPP_BOOL_X86CRYPTOPP_BOOL_X64 和朋友的定义混为一谈。为此,您需要查看命令行,但 Cmake 对您隐藏了它。


相关,我们确实测试了 C++17,你应该可以接受这个标志。但是,根据经验,这可能会导致问题:set(CMAKE_CXX_STANDARD 17)。 Cmake 没有很好的 C++ 支持。我们无法执行简单的project(cryptopp, CXX)。另见Tell CMake to use C++ compiler for C files coming from CMake?


我将考虑删除所有构建的构造函数;并在UncheckedSetKey 中设置m_aliasBlock。这可能有助于解决这个问题。但这只是解决更大工程问题的创可贴。 Cmake 造成的更大的工程问题是我们撤回对它的支持的原因。

【讨论】:

    【解决方案2】:

    尝试

    target_link_libraries(Athena SQLiteCpp sqlite3 cryptopp pthread ${CMAKE_DL_LIBS})
    

    我想更改库排序可能会有所帮助。使用 ${CMAKE_DL_LIBS} 代替 dl 不是强制性的,但使用可移植 CMake 定义是一种很好的做法。

    【讨论】:

    • 不幸的是我得到了同样的例外:(但感谢 ${CMAKE_DL_LIBS} 的提示!
    猜你喜欢
    • 1970-01-01
    • 2012-07-20
    • 2015-09-09
    • 2020-10-29
    • 1970-01-01
    • 1970-01-01
    • 2016-08-21
    • 1970-01-01
    相关资源
    最近更新 更多