由于 CryptoPP 中未定义的引用,CMake 抛出异常

CMake throws exception because of undefined reference in CryptoPP

我收到这个错误:

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'

当我尝试 link 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 尝试了 linking cryptopp,我什至尝试编写一个脚本来手动下载和制作 cryptopp。我真的没有想法,我也很确定这不是我的代码(我粘贴了 cryptopp wiki 中的示例)。

尝试

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

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

您的 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 you will see the constructor is enabled when the platform is IA-32, ARM or PowerPC. But the source file of interest is really 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)。另见 .


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