未定义符号的链接问题通用解决方法
在linux下做c/c++开发时,经常遇到一个问题,就是如果代码引用了大量的第三方库,链接的时候常忘记或者根本就不知道具体要链接哪个库,导致
链接的时候报未定义的引用,特别是一些库你不太熟悉时,甚至都不知道该链接谁。
/usr/bin/ld: CMakeFiles/gstdemo.dir/main.c.o: in function `main':
/home/a/test/gstdemo/main.c:178: undefined reference to `gst_audio_info_set_format'
/usr/bin/ld: /home/a/test/gstdemo/main.c:179: undefined reference to `gst_audio_info_to_caps'
如何解决这个问题?以往我只能靠网络上搜索,但是全得凭运气,万一搜索不到呢?其实在对应的动态库文件里面的符号表就会包含里面定义的函数或者调
用的函数。所以用grep进行搜索就找得到相关的库文件。例如对于上面未定义的引用,
grep -snr "gst_audio_info_set_format" /usr/lib/x86_64-linux-gnu/
Binary file /usr/lib/x86_64-linux-gnu/libgstaudio-1.0.so.0.1603.0 matches
Binary file /usr/lib/x86_64-linux-gnu/libgstbadaudio-1.0.so.0.1603.0 matches
Binary file /usr/lib/x86_64-linux-gnu/girepository-1.0/GstAudio-1.0.typelib matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstdecklink.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstvorbis.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstwavpack.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstalaw.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmpg123.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstspeex.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstinterleave.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstrawparse.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmulaw.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstopus.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstadpcmdec.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstdv.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstdtsdec.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstlibav.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstmxf.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstsiren.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstsbc.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstgsm.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstfaad.so matches
Binary file /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstflac.so matches
这么多库中,一般来说只会有一个地方是真正定义函数的,其他都是调用它,这时候可以通过readelf工具查看谁定义了它,readelf的-s选项可以查看符
号表信息,
readelf -s gstreamer-1.0/libgstopus.so
Symbol table '.dynsym' contains 155 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_tag_list_new_empty
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND g_free
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_decoder_set_lat
....
....
....
readelf -s
会输出多列内容,其中Ndx
这一列如果是UND
表示此elf文件(这里是动态库)没定义这个符号,是引用的一个外部符号(这里是函数),
也就是说当前这个库会调用一个其他库定义的函数,当Ndx
为一个具体数字时,表示此符号是这个elf文件内部定义的,也就是说我们要链接的就是这个动态库。
grep -snr "gst_audio_info_set_format" /usr/lib/x86_64-linux-gnu/ | awk '{print $3}' | xargs readelf -s | grep "gst_audio_info_set_format"
502: 000000000001b1a0 518 FUNC GLOBAL DEFAULT 14 gst_audio_info_set_format
137: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
66: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
152: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
114: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
38: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
66: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
135: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
142: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
104: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
41: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
69: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
37: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
166: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
68: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
213: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
256: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
26: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
57: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
46: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
55: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
229: 0000000000000000 0 FUNC GLOBAL DEFAULT UND gst_audio_info_set_format
可以看出来第一个grep出来的so文件定义了gst_audio_info_set_format
这个函数。so文件为/usr/lib/x86_64-linux-gnu/libgstaudio-1.0.so.0.1603.0
。
直接通过-l指定连接路径就行了,但是又可能头文件位置不知道,又得-I来指定,实在麻烦。其实在linux下可以通过pkg-config命令来获取这些信息。
pkg-config命令工作原理是搜索指定路径里面的.pc文件,而pc文件里面就描述了库的详细信息,包括头文件,库的路径,它的依赖库。例如此处,输出需要的链接信息
pkg-config --libs gstreamer-audio-1.0
-lgstaudio-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0
输出需要的CFLAGS信息,
pkg-config --cflags gstreamer-audio-1.0
-I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -pthread -I/usr/include/orc-0.4
通常会指定这2个选项
gcc main.c -o main `pkg-config --libs --cflags gstreamer-audio-1.0`
此处有个问题,怎么通过so文件找到对于的pc文件?我暂时至能通过看名字,两者的关联不知道怎么查看。
此外,查看当前系统pc文件的搜索目录的方式:
pkg-config --variable pc_path pkg-config