最近,我试图构建一个应用程序,它使用一些以共享对象文件形式提供的库。我在编制CPP代码时浪费了很多时间,但它没有用。
以下是命令,之前我正在尝试编译代码 -
g++ -I/opt/ros/indigo/include/ -I/usr/include/eigen3/ -L/opt/ros/indigo/lib/ -lorocos-kdl -lkdl_parser test.cpp -o test
上述命令始终显示许多undefined references
错误。只是为了好奇,我改变了参数的顺序。下面是命令,它正在工作 -
g++ -L/opt/ros/indigo/lib -I/opt/ros/indigo/include -I/usr/include/eigen3 test.cpp -lorocos-kdl -lkdl_parser -o test
我发布了完整的代码和解决方案here。
我的问题是为什么将参数传递给g ++的顺序很重要?有没有其他方法可以避免将来出现这类问题?
答案 0 :(得分:9)
一般来说,参数的顺序并不重要,但当然有例外。例如,如果您提供多个-O
标志,它将是最后一个使用的标志,对于其他标志也是如此。
但是,图书馆有点不同,因为对他们而言,订单很重要。如果对象文件或库A
依赖于库B
,那么A
必须在命令行上B
之前。这是因为链接器扫描符号的方式:当您使用库时,链接器将检查是否存在可以解析的符号。扫描完成后,库将被丢弃,不会再次搜索。
这意味着当您有-lorocos-kdl -lkdl_parser test.cpp
时,链接器将首先扫描库orocos-kdl
和kdl_parser
,注意这些库没有依赖关系,不需要库中的符号,并继续使用源文件生成的目标文件。
当您将订单更改为test.cpp -lorocos-kdl -lkdl_parser
时,链接器将能够解析test.cpp
引用的未定义符号。
答案 1 :(得分:1)
如果您不想关心订单,您可以(至少在某些版本的gcc中)使用库周围的括号。
请参阅:
Why does the order in which libraries are linked sometimes cause errors in GCC?
具体做法是:
如果静态库依赖于另一个库,而另一个库则依赖于另一个库 再取决于前库,有一个循环。你可以解决 这可以通过 - (和 - )括起循环依赖库来实现 as - (-la -lb - )(你可能需要逃避parens,例如 - (和 - ))。然后,链接器会多次搜索这些封闭的lib,以确保解析循环依赖关系。