【问题标题】:C++ undefined reference to library functionsC++ 对库函数的未定义引用
【发布时间】:2018-07-17 15:15:34
【问题描述】:

我正在构建一个“小型”图形库,但在尝试构建链接到它的测试二进制文件时遇到了这个错误:

al_test.o: In function `test_wave()':
al_test.cpp:(.text+0x1a7): undefined reference to `min::wave::wave(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
...

(以及其他类似的错误,但我们将重点关注这一错误)。该库构建在具有以下规则的 makefile 中:

all: libmgl.a libmgl.so

libmgl.so: $(OBJECTS)
    $(LD) $* $(LDFLAGS) -shared -o $@

libmgl.a: $(OBJECTS)
    $(AR) $(ARFLAGS) libmgl.a $^

%.o: %.cpp
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) -c -o $@ $<

CXXFLAGS 包含一些内容,但最重要的是-std=c++14 -O3 -Wall -Werror 和所有对象都可以正常编译,并且静态和动态库输出时不会出现错误或警告。

现在我有一个文件source/test/al_test.cpp,用于测试库的音频部分,如下所示:

#include <iostream>
#include "twave.h"
int main()
{
    try
    {
        bool out = true;
        out = out && test_wave();
        // out = out && test_ogg();
        // out = out && test_sound_buffer();
        if (out)
        {
            std::cout << "Sound tests passed!" << std::endl;
            return 0;
        }
    }
    catch (std::exception &ex)
    {
        std::cout << ex.what() << std::endl;
    }

    std::cout << "Sound tests failed!" << std::endl;
    return -1;
}

函数test_wavetwave.h中定义如下:

#include <stdexcept>
#include "min/wave.h"
bool test_wave()
{
    bool out = true;

    // Load invention wav file
    {
        const min::wave sound = min::wave("data/sound/invention_no_1.wav");

        // File should not be mono
        out = out && !sound.is_mono();
        if (!out)
        {
            throw std::runtime_error("Failed wave file not is_mono");
        }

        // Other checks that aren't important...
    }

    return out;
}

所以这是我的问题:min::wave::wave() 肯定存在并且肯定应该在库中。这是一个精简的min/wave.h

#ifndef __WAVE__
#define __WAVE__
#include <string>
namespace min {
class wave
{
  private:
    void load(const std::string);
  public:
    wave(const std::string&);
};
}
#endif

min/wave.cpp

#include "wave.h"

min::wave::wave(const std::string &file)
{
    load(file);
}

// Definition of `load` omitted; I don't think it's important,
// but know that it is here

所以文件存在,函数声明和定义都存在,我可以在我的make 输出中看到wave.o 正在构建并链接/归档到libmgl.a/libmgl.so。然而编译器声称它不存在。似乎不是链接顺序问题;这是我构建测试的过程:

g++ -c -Imin/ al_test.cpp -o al_test.o
g++ al_test.o -L. -lmgl -lX11 -lGL -lfreetype -lopenal -lvorbisfile -o bin/al_test

mgl 显然是我的库的名称,而这些是它所依赖的其他内容。我还尝试用-L/absolute/path/to/project/directory/ 替换-L.,但无济于事。

为什么 g++ 认为我的函数未定义?

nm 命令

根据大众需求,这里有一些nm 命令及其输出:

静态库:

nm -C libmgl.a | grep wave
wavefront.o
wave.o:
0000000000000090 T min::wave::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)
0000000000000000 W void min::wave::load<min::mem_file>(min::mem_file const&)
0000000000000000 W void min::wave::load<std::vector<unsigned char, std::allocator<unsigned char> > >(std::vector<unsigned char, std::allocator<unsigned char> > const&)
0000000000000000 T min::wave::clear()
0000000000000880 T min::wave::wave(min::mem_file const&)
0000000000000720 T min::wave::wave(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
0000000000000880 T min::wave::wave(min::mem_file const&)
0000000000000720 T min::wave::wave(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
0000000000000080 T min::wave::get_sample_rate() const
0000000000000060 T min::wave::get_data_samples() const
0000000000000050 T min::wave::get_bits_per_sample() const
0000000000000040 T min::wave::data() const
0000000000000020 T min::wave::is_mono() const
0000000000000030 T min::wave::is_stereo() const
0000000000000550 T min::sound_buffer::add_wave_pcm(min::wave const&)
                 U min::wave::get_sample_rate() const
                 U min::wave::get_bits_per_sample() const
                 U min::wave::data() const
                 U min::wave::is_stereo() const

...动态库:

nm -C libmgl.so
0000000000201020 B __bss_start
0000000000201020 b completed.7631
                 w __cxa_finalize
0000000000000460 t deregister_tm_clones
00000000000004f0 t __do_global_dtors_aux
0000000000200e88 t __do_global_dtors_aux_fini_array_entry
0000000000201018 d __dso_handle
0000000000200e90 d _DYNAMIC
0000000000201020 D _edata
0000000000201028 B _end
000000000000053c T _fini
0000000000000530 t frame_dummy
0000000000200e80 t __frame_dummy_init_array_entry
0000000000000548 r __FRAME_END__
0000000000201000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000000420 T _init
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
00000000000004a0 t register_tm_clones
0000000000201020 d __TMC_END__

...和测试文件:

nm -C al_test.o
                 U __cxa_allocate_exception
                 U __cxa_atexit
                 U __cxa_begin_catch
                 U __cxa_end_catch
                 U __cxa_free_exception
                 U __cxa_throw
                 U __dso_handle
00000000000000e0 t _GLOBAL__sub_I__Z9test_wavev
                 U __gxx_personality_v0
0000000000000000 r .LC1
0000000000000000 T main
                 U __stack_chk_fail
                 U _Unwind_Resume
0000000000000000 T test_wave()
                 U operator delete(void*)
                 U min::wave::wave(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
                 U min::wave::is_mono() const
                 U std::runtime_error::runtime_error(char const*)
                 U std::runtime_error::~runtime_error()
                 U std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long)
                 U std::ios_base::Init::Init()
                 U std::ios_base::Init::~Init()
                 U std::basic_ios<char, std::char_traits<char> >::clear(std::_Ios_Iostate)
                 U std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
                 U std::cout
                 U std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
0000000000000000 b std::__ioinit
                 U typeinfo for std::runtime_error
                 U typeinfo for std::exception

【问题讨论】:

    标签: c++ makefile c++14 gnu-make ld


    【解决方案1】:

    了解更多关于静态库和动态库中可用符号的信息后,我得出的结论是共享库是空的。

    它是空的,因为$* 这里展开为空。

    libmgl.so: $(OBJECTS)
        $(LD) $* $(LDFLAGS) -shared -o $@
    

    GNU make documentation:

    如果显式规则中的目标名称不以可识别的后缀结尾,则将“$*”设置为该规则的空字符串。

    $* 替换为 $^ 就像它用于构建 libmgl.a 一样应该可以解决您的问题。

    【讨论】:

    • 这解决了我的一些问题(我认为),但我现在遇到了不同的错误。我在问题 cmets 中发布了一个示例。
    • 等等,我认为这些可能只是我的源文件的问题(using namespace &lt;any&gt;; 是邪恶的......)。我会浏览它们,看看剩下的。
    • 好的,我能够通过在函数定义上使用显式命名空间名称来清除一些错误。但是,仍然存在一些错误:./libmgl.so: undefined reference to 'min::vec3&lt;float&gt;::cross(min::vec3&lt;float&gt; const&amp;) const'。我没有为float 定义该模板化函数的显式重载,所以我知道这个错误是什么意思。无论如何,如果这个新错误与我的问题中的错误无关,我准备接受这个答案,但我足以说明这是否属实;你认为这可能是相关的,还是一个单独的问题?
    • 好的,经过一番激烈的谷歌搜索后,我确定这是一个单独的问题,与从翻译单元中隐藏模板实现有关。
    【解决方案2】:

    由于nm libmgl.so | grep wave 没有返回任何内容(参见 cmets),我们至少知道该库没有正确链接(构建?)。

    确实,您应该调用g++ 来链接它:

    $(CXX) $* $(LDFLAGS) -shared -o $@
    

    一旦你这样做了,正如用户 UKMonkey 所说:

    链接顺序

    所以,你的二进制文件应该这样构建:

    g++ -L. -lmgl -lX11 -lGL -lfreetype -lopenal -lvorbisfile -o bin/al_test al_test.o
    

    【讨论】:

    • 我认为al_test.o 应该是第一个?我会尝试使用 g++ 而不是 ld 并回复您。
    • @anoneemus 没有。最后很好。这就是自动工具和 CMake 编写 Makefile 的方式;)
    • " 你必须先放置依赖项,然后才是提供函数的库。"与此相矛盾。 al_test 需要库中的函数,并且该声明似乎说这意味着库必须紧随其后。另外,我必须指出我确实链接到我的图书馆,即使不正确。
    • 不管怎样,我是用g++而不是ld构建的,不管我把al_test.o放在哪里,它仍然给我同样的错误。 nm 现在有更多输出,但仍然没有包含“wave”的行。
    • 好吧,肯定英国的报价很奇怪,但肯定你的 .o 应该是最后的。下一个调试步骤是检查 libmgl 究竟包含什么。 $(OBJECTS) 设置为什么?
    猜你喜欢
    • 2011-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 2016-06-14
    • 2021-10-28
    相关资源
    最近更新 更多