【问题标题】:Custom library compiles fine, but fails with undefined refences when linked against自定义库编译正常,但在链接时失败并出现未定义的引用
【发布时间】:2022-12-07 06:16:58
【问题描述】:

我目前正在使用 cmake 和 crypto++ 构建一个库。虽然库编译得很好,但引用它的代码却没有。

库的cmake:

add_library(MYCrypto Crypto.cpp)
target_link_libraries(MYCrypto libcrypto++.a)
set_target_properties(MYCrypto PROPERTIES PUBLIC_HEADER "includes/MYCrypto.hpp")
install(TARGETS File MYCrypto ARCHIVE DESTINATION ~/.local/dev-bin/bin PUBLIC_HEADER DESTINATION ~/.local/dev-bin/includes)

我的密码.hpp

#ifndef MYCrypto
#define MYCrypto
#include <string>
namespace MYCrypto
{
    std::string hashSha256(std::string);
    std::string hashMd5(std::string);
}
#endif

密码.cpp

#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include <cryptopp/iterhash.h>
#include <cryptopp/cryptlib.h>
#include <cryptopp/sha.h>
#include <cryptopp/md5.h>
#include <sstream>
#include <iomanip>
#include "MYCrypto.hpp"

using namespace std;

template<typename T>
string encrypt(string data, T hasher)
{
    stringstream output;
    CryptoPP::byte* digest;

    hasher.Update((const CryptoPP::byte*)data.c_str(),data.size());
    digest = new CryptoPP::byte[hasher.DigestSize()];
    hasher.Final(digest);

    for (int i=0; i < hasher.DigestSize(); i++) output << hex << setw(2) << setfill('0') << (int)digest[i];
    delete[] digest;

    return output.str();
}

string MYCrypto::hashSha256(string data)
{
    return encrypt(data, CryptoPP::SHA256());
}

string MYCrypto::hashMd5(string data)
{
    return encrypt(data, CryptoPP::Weak1::MD5());
}

用于消费应用程序的 CMake

cmake_minimum_required(VERSION 3.0.0)
project(TEST VERSION 0.1.0)

include(CTest)

include_directories(~/.local/dev-bin/includes)
link_directories(~/.local/dev-bin/bin)

add_library(Archive Archive.cpp)
target_link_libraries(Archive MYCrypto)

存档.hpp

#ifndef Archive
#define Archive
#include <string>
#include <unordered_set>
namespace Archive
{
   std::string getImportPath(std::string);
   bool fileExistsInDatabase(std::string, std::string);
}
#endif

存档.cpp

#include "MYCrypto.hpp"
#include "Archive.hpp"

using namespace std;

string Archive::getImportPath(string path)
{
    return MYCrypto::hashSha256(Path);
}

当我尝试编译我的第二个 cmake progject 时,出现这样的错误

[build] /usr/bin/ld: /home/user/.local/dev-bin/bin/libMYCrypto.a(Crypto.cpp.o):(.data.rel.ro._ZTVN8CryptoPP5Weak13MD5E[_ZTVN8CryptoPP5Weak13MD5E]+0x38): undefined reference to `CryptoPP::IteratedHashBase<unsigned int, CryptoPP::HashTransformation>::Update(unsigned char const*, unsigned long)'

我不明白如何解决这个错误。我静态链接所以第二个项目应该只知道在公共头文件上声明的函数,我应该不再需要 crypto++。

我如何编译第二个项目?

【问题讨论】:

  • encrypt在命名空间MYCrypto中声明,然后在全局命名空间中定义了encrypt
  • @463035818_is_not_a_number 恐怕我不明白你在说什么。 encrypt 未在声明命名空间的 MYCrypto.hpp 中的任何位置定义。我只在全球范围内声明过encrypt。是否需要放入 MYCrypto 命名空间才能看到?
  • 你在链接cryptopp吗?在第二个项目中,我的意思是。 cryptopp 不是仅包含标头的库,因此您甚至需要在第二个项目上链接它。您的第一个项目不会包含任何关于 cryptopp 代码的内容(内联代码除外)。这两个项目必须使用相同版本的 cryptopp obv 否则你会看到地狱
  • 静态链接仅对应用程序有意义。语言中有“一个定义规则”,如果您链​​接 libalibb 库都定义了 foo (即使它是相同的并且通过过渡依赖定义),您仍然应该从链接器收到多重定义警告 -通常不提供符号隔离(Windows 上的 DLL 需要完全解析所有依赖关系,但 Linux 上不需要,静态库只是目标文件的存档)。通常有特定于链接器的方法来强制合并静态库,但它会导致多次链接库的麻烦。
  • 是的。此外,您可以通过 cmake export 您的库,它会在使用时自动链接依赖项,例如通过 find_package

标签: c++ cmake static-libraries static-linking crypto++


【解决方案1】:

静态链接仅适用于应用程序而非库。

该语言中有“一个定义规则”,它适用于整个可执行文件。如果你链接 libalibb 库都提供 foo (即使它是相同的并且通过过渡依赖定义)你很可能会从链接器收到多重定义警告 - 通常不提供符号隔离。存在特定于平台的例外情况:Windows 上的 DLL 需要完全解析和链接所有依赖项并仅导出明确导出的符号,但情况并非如此,例如对于 Linux 上的共享库,静态库只是目标文件的存档,无法在所有主要平台上链接任何内容。

因此,您将静态库链接到可执行文件,而不是其他静态库。

通常有链接器特定的方法来强制合并静态库,但它会再次引起麻烦,因为库符号被多次链接。

但如果你有

target_link_libraries(MYCrypto libcrypto++.a)
...
target_link_libraries(Application MyCrypto)

在单个 cmake 文件中,它可以看到依赖项并自动链接依赖项。

如果你想单独分发库并想简化它的使用,你可以export 它,如果可执行文件也是用 cmake 构建的,那么用户可以使用 find_package 导入你的库,这将链接所需的依赖项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-03
    • 2017-05-07
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多