Неопределенная ссылка для Crypto++, хотя она связана и работает в других проектах

Поэтому я пытаюсь создать функцию-оболочку для генерации хеша с использованием Cryptop++. Я создал эту тестовую функцию:

#include <cryptopp/sha.h>
#include <cryptopp/hex.h>
#include <cryptopp/cryptlib.h>

#include <vector>
#include <cstdint>

#include <string>

#include <iostream>

void test2()
{
    CryptoPP::SHA1 hash;
    CryptoPP::byte digest[CryptoPP::SHA1::DIGESTSIZE];

    std::vector<uint8_t> v;
    for (uint32_t i = 0; i < 1000; ++i)
    {
        v.push_back(i % 9);
    }

    hash.CalculateDigest(digest, v.data(), v.size());

    CryptoPP::HexEncoder encoder;

    std::string output;

    encoder.Attach(new CryptoPP::StringSink(output));
    encoder.Put(digest, sizeof(digest));
    encoder.MessageEnd();

    std::cout << output << std::endl;
}

И скомпилировал его с помощью следующей строки clang ++: clang++ main2.cpp -lcryptopp, Тем не менее, когда я использую его в своем проекте, где функция определяется следующим образом:

template<typename Hash>
std::string get_hash(std::vector<uint8_t> data)
{
Hash hash;

// Intialise a byte "array" with space enough for the result
CryptoPP::byte digest[Hash::DIGESTSIZE];

// Create hash for the data
hash.CalculateDigest(digest, data.data(), data.size());

CryptoPP::HexEncoder encoder;
// result will hold the hex representation of the hash
std::string result;

// Tell the Hex encoder that result is the destination
// for its operations
encoder.Attach(new CryptoPP::StringSink(result));
encoder.Put(digest, sizeof(digest));
// As we will not put more in the message we end it
encoder.MessageEnd();

return result;
}

И назовите это так: hash::get_hash<CryptoPP::SHA1>(pair.pivot); с помощью следующей команды компилятора: clang++ -std=c++17 -Wall -Werror -Wextra -pthread -pthread -lpqxx -lpq -lcryptopp examples/sql_index_example/sql_index_example.cpp.1.o -o/home/tools/git/alexandria/build/examples/sql_index_example/sql_index_example -Wl-Bstatic -L. -lalexandria -Wl-Bdynamic

Я получаю массу неопределенных ссылок на Crypto ++, таких как:

examples/sql_index_example/sql_index_example.cpp.1.o: In function `alexandria::data::hash::GetHash[abi:cxx11](std::vector<unsigned char, std::allocator<unsigned char> >)':
sql_index_example.cpp:(.text+0x197): undefined reference to `CryptoPP::StringSinkTemplate<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::StringSinkTemplate(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'

и я совершенно заблудился относительно того, что на самом деле происходит, когда работает простой тест. Надеюсь, кто-то может помочь.

РЕДАКТИРОВАТЬ: уже пробовал: неопределенная ссылка на символ, хотя библиотека связана

1 ответ

Решение
clang++ -std=c++17 -Wall -Werror -Wextra -pthread -pthread -lpqxx -lpq -lcryptopp \
examples/sql_index_example/sql_index_example.cpp.1.o -o/home/tools/git/alexandria/
build/examples/sql_index_example/sql_index_example -Wl-Bstatic -L. -lalexandria -Wl-Bdynamic

А также:

examples/sql_index_example/sql_index_example.cpp.1.o: In function `alexandria::data::hash::
GetHash[abi:cxx11](std::vector<unsigned char, std::allocator<unsigned char> >)':
sql_index_example.cpp:(.text+0x197): undefined reference to ...

Чтобы повторить то, что сказал @HolyBlackCat, -lcryptopp должен следовать sql_index_example.cpp.o потому что объектному файлу sql нужен материал из архива Crypto++. Поэтому команда compile and link должна выглядеть примерно так:

clang++ -std=c++17 -Wall -Werror -Wextra -pthread -pthread \
  examples/sql_index_example/sql_index_example.cpp.1.o \
  -o /home/tools/git/.../sql_index_example \
  -lpqxx -lpq -lcryptopp -Wl-Bstatic -L. -lalexandria -Wl-Bdynamic

Я бы даже рекомендовал статическую линковку в этом случае, чтобы избежать (1) глупых проблем с Linux; и (2) пути посадки / инъекции. Так что может быть что-то вроде:

clang++ -std=c++17 -Wall -Werror -Wextra -pthread -pthread \
  examples/sql_index_example/sql_index_example.cpp.1.o \
  /usr/local/lib/libcryptopp.a \
  -o /home/tools/git/.../sql_index_example \
  -lpqxx -lpq -Wl-Bstatic -L. -lalexandria -Wl-Bdynamic

Также см. Почему порядок, в котором связаны библиотеки, иногда вызывает ошибки в GCC?


Вы можете изменить эту подпись, чтобы получить постоянную ссылку:

std::string get_hash(const std::vector<uint8_t>& data);

Здесь нет необходимости в глубоких копиях. Ссылка или указатель будет делать. Ссылки не могут быть NULL поэтому с ними немного легче работать.

Также см. Когда использовать const и ссылку на const в аргументах функции? Как передать объекты в функции в C++? имеет более современную информацию, в том числе C++11.


В соответствии с этим:

HexEncoder encoder;
// result will hold the hex representation of the hash
std::string result;
// Tell the Hex encoder that result is the destination
// for its operations
encoder.Attach(new StringSink(result));

Вы можете сжать это немного, чтобы:

std::string result;
HexEncoder encoder(new StringSink(result));

Поскольку вы печатаете std::cout Вы могли бы даже:

std::string result;
HexEncoder encoder(new FileSink(std::cout));

И если вы хотите стать действительно гладким, вы можете распечатать и вернуть его:

ChannelSwitch channels;
channels.AddRoute(new FileSink(std::cout));
channels.AddRoute(new StringSink(result));

HexEncoder encoder(new Redirector(channels));

Теперь, когда вы вставляете данные в encoder, он будет закодирован в шестнадцатеричном формате и затем отправлен std::cout и std::string,


И относительно:

std::vector<uint8_t> data;
...

HexEncoder encoder;
encoder.Attach(new CryptoPP::StringSink(result));
encoder.Put(digest, sizeof(digest));
// As we will not put more in the message we end it
encoder.MessageEnd();

Crypto++ 8.0 будет иметь VectorSource а также VectorSink, Вы сможете:

VectorSource(data, true, new HashFilter(hash, 
    new HexEncoder(new StringSink(result))));
return result;

Также см. Запрос на извлечение 730.

Другие вопросы по тегам