【问题标题】:Reference not found during library linkage [duplicate]库链接期间未找到参考[重复]
【发布时间】:2020-10-24 10:01:35
【问题描述】:

我在 C++ 中创建了一个名为 libparse 的库,该代码被另一个名为 libitcmpmsg.so 的库使用。

我一直在尝试在 test.cpp 中测试 libitcmpmsg,但是当我尝试构建它时,编译器会返回以下消息:

$libpath/libitcmpmsg.so: reference not found to "void MSG_PARSER::WriteBigEndian<unsigned char>(std::vector<unsigned char, std::allocator<unsigned char> &, unsingned char)"
$libpath/libitcmpmsg.so: reference not found to "unsigned char* MSG_PARSER::ReadBigEndian<unsigned char>(unsigned char&, unsigned char*, unsigned int&)"
$libpath/libitcmpmsg.so: reference not found to "MSG_PARSER::ReadFixedLengthString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned char*, int, unsigned int&)"
$libpath/libitcmpmsg.so: reference not found to "MSG_PARSER::WriteFixedLengthString(std::vector<unsigned char, std::allocator<unsigned char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)"

libpath 只代表库的路径。 MSG_PARSER 是来自 libparser 的命名空间。

从错误消息来看,msg_parser.h 中函数的作用域是:

    template <class T>
    void WriteBigEndian(std::vector<uint8_t>& target, T source);

    template <class T>
    uint8_t* ReadBigEndian(T &target, uint8_t* source, uint32_t &available);

    uint8_t* ReadFixedLengthString(string& target, uint8_t *source, int size, uint32_t &available);

    void WriteFixedLengthString(std::vector<uint8_t> &target, const string& source, uint32_t size);

似乎 libitcmpmsg 将错误类型的参数传递给 libparser.so。 下面是一个代码 sn-p,其中 libparer.so 被 libitcmpmsg.so 使用

#include "ptcinteraction.h"
#include "msg_parser.h"
#include <stdint.h>

using namespace PTC_INTERACTION;
using namespace MSG_PARSER;


PtcInteraction::PtcInteraction( std::vector<uint8_t> &data )
{
    m_msgBuffer.clear();
    uint32_t tavailable = static_cast<uint32_t>(data.size());
    uint8_t *tsource = &data[0];
    uint8_t value = 0;

    tsource = ReadFixedLengthString(m_message.railScac, tsource,  SCAC_SIZE, tavailable);
    tsource = ReadBigEndian<uint8_t>(m_message.sizeOfPromptTxt, tsource, tavailable );
    tsource = ReadFixedLengthString(m_message.promptTxt, tsource,  m_message.sizeOfPromptTxt, tavailable);
    tsource = ReadBigEndian<uint8_t>(m_message.sizeOfKeyPressedTxt, tsource, tavailable );
    tsource = ReadFixedLengthString(m_message.keyPressedTxt, tsource,  m_message.sizeOfKeyPressedTxt, tavailable);

    if((&data[0] + data.size()) == tsource)
    {
        m_msgBuffer = data;
    }
    else
    {
        m_msgBuffer = {};
    }
}

PtcInteraction::PtcInteraction( OCCPTCMSG::PtcInteractionT &ptcInteraction)
{
    m_msgBuffer.clear();
    m_message = ptcInteraction;

    WriteFixedLengthString(m_msgBuffer, ptcInteraction.railScac, SCAC_SIZE);
    WriteBigEndian<uint8_t>(m_msgBuffer, ptcInteraction.sizeOfPromptTxt );
    .
    .
    .

PTCInteraction 是一个来自 libitcmpmsg.so 的类,而 PtcInteractionT 是一个同样由 libitcmpmsg 定义的结构。

测试代码如下:

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include "ptcinteraction.h"
#include "occptcmessages_generated.h"
#include "msg_parser.h"
#include <cstdio>

using namespace PTC_INTERACTION;

int main(void)
{
    OCCPTCMSG::PtcInteractionT teste;


    teste.railScac = "abcd";
    teste.promptTxt = "message test";
    teste.sizeOfPromptTxt = teste.promptTxt.size();
    teste.keyPressedTxt = "test";
    teste.sizeOfKeyPressedTxt = teste.keyPressedTxt.size();

    PTC_INTERACTION::PtcInteraction ptcInter(teste);

    PTC_INTERACTION::PtcInteraction ptcInter2(ptcInter.m_msgBuffer);

    if ( (ptcInter.m_message.railScac == ptcInter2.m_message.railScac) &&
       (ptcInter.m_message.promptTxt == ptcInter2.m_message.promptTxt) &&
       (ptcInter.m_message.sizeOfPromptTxt == ptcInter2.m_message.sizeOfPromptTxt) &&
       (ptcInter.m_message.keyPressedTxt == ptcInter2.m_message.keyPressedTxt) &&
       (ptcInter.m_message.sizeOfKeyPressedTxt == ptcInter2.m_message.sizeOfKeyPressedTxt) )
    {
        std::cout << "Serialization and deserialization succeeded" << std::endl;
    }

}

代码开发中使用了 3 个 CMakeList:

  • libparser 生成器;
  • libitcmpmsg 生成器;
  • 测试生成器。

有谁知道为什么编译器会返回问题开头描述的 4 条错误消息?

我该如何解决这些问题?

如果您需要 CMakeLists 代码来更好地理解问题,请告诉我。

【问题讨论】:

  • 您的模板函数(函数的主体)是在头文件(h)还是主体(cpp)文件中定义的?
  • 它们在 cpp 文件中定义。
  • this question模板函数。 ReadFixedLengthStringWriteFixedLengthString 在哪里定义? This 可能会有所帮助。
  • ReadFixedLengthString 和 WriteFixedLengthString 在 msg_parser.cpp 中定义。我将模板函数的位置重新定位到头文件,关于它们的错误已经消失。不使用模板的函数我也将它们移到标题和编译的代码中。为什么我还要移动非模板函数?
  • "为什么我还要移动非模板函数?" - 您不必在头文件中定义非模板函数。您对函数ReadFixedLengthStringWriteFixedLengthString 的定义可能有其他问题。但是由于您没有显示此定义(不是声明),我们只能猜测推理。

标签: c++ cmake shared-libraries


【解决方案1】:

您必须在 cpp 中实例化专门的模板类,或者将模板类的主体放在标题中:https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl

【讨论】:

  • 我把模板函数的主体改成了头部,还是不行。但是,作为一种尝试,我也尝试将正常功能更改为标题,并且它起作用了。为什么我还要把正常的函数替换到header中?
  • @AndréMachoski 除了琐碎的错误(忘记保存文件等),我建议您没有使用正确的命令来链接(可能缺少指定所有所需文件的参数),所以添加他们到标题删除了链接的需要。
猜你喜欢
  • 1970-01-01
  • 2017-05-14
  • 1970-01-01
  • 1970-01-01
  • 2018-02-07
  • 2013-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多