C++ 未定义对库函数的引用
C++ undefined reference to library functions
我有一个正在构建的 "small" 图形库,在尝试构建一个 link 反对它的测试二进制文件时,我 运行 遇到了这个错误:
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_wave
在 twave.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
并且 linked/archived 进入 libmgl.a
/libmgl.so
。然而编译器声称它不存在。这似乎不是 link 订单问题;这是我构建测试的过程:
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
由于 nm libmgl.so | grep wave
returns 什么都没有(见评论),我们至少知道库没有 link 编辑(构建?)正确。
确实,您应该调用 g++
到 link 它:
$(CXX) $* $(LDFLAGS) -shared -o $@
完成后,如用户 UKMonkey 所述:
order of linking matters
因此,您的二进制文件应该像这样构建:
g++ -L. -lmgl -lX11 -lGL -lfreetype -lopenal -lvorbisfile -o bin/al_test al_test.o
根据有关静态库和动态库中可用符号的更多信息,我得出的结论是共享库是空的。
它是空的,因为$*
这里展开为空。
libmgl.so: $(OBJECTS)
$(LD) $* $(LDFLAGS) -shared -o $@
If the target name in an explicit rule does not end with a recognized suffix, ‘$*’ is set to the empty string for that rule.
将 $*
替换为 $^
就像它用于构建 libmgl.a 应该可以解决您的问题。
我有一个正在构建的 "small" 图形库,在尝试构建一个 link 反对它的测试二进制文件时,我 运行 遇到了这个错误:
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_wave
在 twave.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
并且 linked/archived 进入 libmgl.a
/libmgl.so
。然而编译器声称它不存在。这似乎不是 link 订单问题;这是我构建测试的过程:
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
由于 nm libmgl.so | grep wave
returns 什么都没有(见评论),我们至少知道库没有 link 编辑(构建?)正确。
确实,您应该调用 g++
到 link 它:
$(CXX) $* $(LDFLAGS) -shared -o $@
完成后,如用户 UKMonkey 所述:
order of linking matters
因此,您的二进制文件应该像这样构建:
g++ -L. -lmgl -lX11 -lGL -lfreetype -lopenal -lvorbisfile -o bin/al_test al_test.o
根据有关静态库和动态库中可用符号的更多信息,我得出的结论是共享库是空的。
它是空的,因为$*
这里展开为空。
libmgl.so: $(OBJECTS) $(LD) $* $(LDFLAGS) -shared -o $@
If the target name in an explicit rule does not end with a recognized suffix, ‘$*’ is set to the empty string for that rule.
将 $*
替换为 $^
就像它用于构建 libmgl.a 应该可以解决您的问题。