在测试protobuf-c编码时,由于已编译安装好protobuf-c相关的库,简单写了一个例子进行测试。
直接使用gcc命令进行编译时,报出如下错误:
gcc `pkg-config --cflags --libs libprotobuf-c` -o test *.c ../test.pb-c.c -I..
/usr/bin/ld: /tmp/cc2Zocqz.o: in function `main':
test-generated-code.c:(.text+0xe7): undefined reference to `protobuf_c_buffer_simple_append'
...
从错误日志中可以明显看出,错误是由ld报出,也就是link时发生了搜寻不到相关定义,也就是没能够成功链接到protobuf-c相关的库。
直接运行pkg-config--cflags --libs libprotobuf-c,返回-I/usr/local/include -L/usr/local/lib -lprotobuf-c,表明pkg-config工具能够能够正确返回配置信息。
那么问题应该还是出在ld命令上,键入manld,获取帮助信息。
查看-I、-L、-l、-o等参数的介绍,发现了如下解释:
-l namespec
--library=namespec
Add the archive or object file specified by namespec to the list of files to link. This option may be used any number
of times. If namespec is of the form :filename, ld will search the
library path for a file called filename, otherwise it will search the library path for a file called libnamespec.a.
On systems which support shared libraries, ld may also search for files other than libnamespec.a. Specifically, on ELF
and SunOS systems, ld will search a directory for a library called libnamespec.so before searching for one called
libnamespec.a. (By convention, a ".so" extension indicates a shared library.) Note that this behavior does not apply
to :filename, which always specifies a file called filename.
The linker will search an archive only once, at the location where it is specified on the command line. If the archive
defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker
will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the
command line will not cause the linker to search the archive again.
See the -( option for a way to force the linker to search archives multiple times.
You may list the same archive multiple times on the command line.
This type of archive searching is standard for Unix linkers. However, if you are using ld on AIX, note that it is
different from the behaviour of the AIX linker.
Google翻译就是:
-l名称规范
--library = namespec
将namespec指定的归档文件或目标文件添加到要链接的文件列表中。此选项可以使用多次。如果namespec的格式为:filename,则ld将在库路径中搜索
名为filename的文件,否则将在库路径中搜索名为libnamespec.a的文件。
在支持共享库的系统上,ld可能还会搜索libnamespec.a以外的文件。具体来说,在ELF和SunOS系统上,ld将在目录中搜索名为libnamespec.so的库,
然后再搜索一个名为libnamespec.a的库。 (按照惯例,扩展名“ .so”表示共享库。)请注意,此行为不适用于:filename,它始终指定一个名为
filename的文件。
链接器仅在命令行上指定的位置搜索一次存档。如果归档文件定义了在命令行上归档文件之前出现的某个对象中未定义的符号,则链接器将包含归档文件中
的相应文件。但是,稍后出现在命令行中的对象中未定义的符号将不会导致链接程序再次搜索档案。
请参阅-(选项,以强制链接程序多次搜索存档。
您可以在命令行上多次列出同一档案。
这种类型的档案搜索是Unix链接器的标准配置。但是,如果在AIX上使用ld,请注意它与AIX链接器的行为不同。
重点信息,我已下划线标出,意思就是ld链接符号时仅搜寻一次,且仅链接-l前面的代码中的符号。
知道问题产生的原因,那么修正就容易多了,我们只需要将pkg-config--cflags --libs libprotobuf-c放在命令的后面就可以了。
执行下面的命令,能够顺利编译成果物。
gcc -o test *.c ../test.pb-c.c -I.. `pkg-config --cflags --libs libprotobuf-c`
想了解更多链接器与库的知识,可以看看此文件Oracle® Solaris 11.1 Linkers and Libraries Guide。