C++ C++;对库函数的未定义引用

C++ C++;对库函数的未定义引用,c++,makefile,c++14,gnu-make,ld,C++,Makefile,C++14,Gnu Make,Ld,我正在构建一个“小”图形库,当我试图构建一个与之链接的测试二进制文件时,遇到了这个错误: 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> > co

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

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&)'
...
函数
test\u wave
twave.h
中定义如下:

#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;
}
#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;
}
g++ -L. -lmgl -lX11 -lGL -lfreetype -lopenal -lvorbisfile -o bin/al_test al_test.o
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.
替换为
-L/absolute/path/to/project/directory/
,但没有成功

为什么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
nm-C铝合金试验
U\U\U cxa\U分配\U异常
退欧
你开始接球
U_uuucxa_uend_ucatch
U\uuuuucxa\uFree\U例外
U___cxa_投掷
U(U)dso(U)手柄
00000000000000 E0 t_全球___子_I__Z9;测试_wavev
你的个性
0000000000000000卢比LC1
0000000000000000吨干管
U(U)堆栈(U)chk(U)失败
你(放松)你(恢复)
0000000000000000吨测试_波()
U运算符删除(无效*)
U min::wave::wave(标准:uuuCXX11::基本字符串常量&)
U min::wave::is_mono()常量
U std::运行时错误::运行时错误(字符常量*)
U std::runtime_error::~runtime_error()
U std::uu cxx11::基本字符串::_M_创建(无符号长-,无符号长)
U std::ios_base::Init::Init()
U std::ios_base::Init::~Init()
U std::basic_ios::clear(std:_ios\U Iostate)
U std::basic_ostream&std::_ostream_insert(std::basic_ostream&,char const*,long)
U std::cout
U std::basic_ostream&std::endl(std::basic_ostream&)
0000000000000000 b标准::uu ioinit
std::runtime\U错误的U typeinfo
std::exception的U类型信息

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

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

$(CXX) $* $(LDFLAGS) -shared -o $@
完成后,如用户UKMonkey所述:

联系事项的顺序

因此,二进制文件的构建应如下所示:

#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;
}
#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;
}
g++ -L. -lmgl -lX11 -lGL -lfreetype -lopenal -lvorbisfile -o bin/al_test al_test.o

由于
nm libmgl.so | grep wave
不返回任何内容(请参阅注释),我们至少知道库没有正确链接(构建?)

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

$(CXX) $* $(LDFLAGS) -shared -o $@
完成后,如用户UKMonkey所述:

联系事项的顺序

因此,二进制文件的构建应如下所示:

#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;
}
#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;
}
g++ -L. -lmgl -lX11 -lGL -lfreetype -lopenal -lvorbisfile -o bin/al_test al_test.o

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

它是空的,因为这里扩展为空

见:

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


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

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

它是空的,因为这里扩展为空

见:

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


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

我认为
al_test.o
应该是第一个?我将尝试使用
g++
而不是
ld
,然后返回给你。@anonemus没有。最后一切都很好。这就是autotools和CMake编写Makefiles;)“您必须先放置依赖项,然后再放置提供函数的LIB。”这与此相矛盾。al_测试需要库中的函数,该语句似乎表示这意味着库必须在后面。另外,我必须指出,我确实链接到了我的库,即使链接不正确。无论如何,我是用
g++
而不是
ld
构建的,无论我把
al_test.o
放在哪里,它仍然会给我同样的错误
nm
现在有了更多的输出,但仍然没有包含“
wave
”的行。当然,英国的报价很奇怪,但你的.o应该是最后一个。下一个调试步骤是检查libmgl到底包含什么。
$(OBJECTS)
设置为什么?我认为
al_test.o
应该是第一个?我将尝试使用
g++
而不是
ld
,然后返回给你。@anonemus没有。最后一切都很好。这就是autotools和CMake编写Makefiles;)“您必须先放置依赖项,然后再放置提供函数的LIB。”这与此相矛盾。al_测试需要库中的函数,该语句似乎表示这意味着库必须在后面。另外,我必须指出,我确实链接到了我的库,即使链接不正确。无论如何,我是用
g++
而不是
ld
构建的,无论我把
al_test.o
放在哪里,它仍然会给我同样的错误
nm
现在有了更多的输出,但仍然没有包含“
wave
”的行