library linking between c and cpp

关于c c++ libraries互相linking的问题。

undefined reference

有几次在link libraries的时候会出现 undefined reference 的问题,明明已经把.so文件放到了命令后面,但还是有问题。除了网上找的到的常见原因,还有一个比较容易忽略的就是name mangling的问题。比如使用nm命令进行查看,注意调用方和被调用方都需要查看一下。

1
2
3
-bash-4.2$ nm CMakeFiles/main.dir/main.cpp.o
0000000000000000 T main
U _Z3foov

这个是main生成的.o文件中的symbol

这个是目标library的symbol

1
2
3
4
5
-bash-4.2$ nm libfoo.so 
...
00000000000006a4 T _fini
0000000000000685 T foo
...

可以看到里面的symbol是不一样的,究其原因就是编译main文件的时候采用的是cpp的compiler(main.cpp文件),而编译libfoo的时候采用的是c的compiler(foo.c)。具体fix的手段一种是采用相同的compiler,比如都使用cpp的,或者是都使用c的。或者是按照stackoverflow这里的解释,采用extern C的关键字来强制地按照c的方式进行编译。

具体使用CMake的时候,由于它会根据后缀自动选择,因此最好显示地指定compiler或者使用的语言。在一些完全用c写的library中,通常会加上如下的预编译命令来规避这个问题。

比如在.h 文件中进行如下定义

1
2
3
4
5
6
7
8
9
#ifdef __cplusplus
extern "C" {
#endif

//the content of the .h file

#ifdef __cplusplus
}
#endif

这个例子说的内容比较详细,由于主要影响的是link阶段而不是compile阶段,因此在.h文件中加上相关的操作即可。

引用多个.h文件

本质上来说,这里的.h 相当于一个adaptor,cpp 文件本身会include这个.h 文件,调用方的.c文件在link相对应的cpp部分的时候(实际上具体执行link的是编译之后的.so文件),就会通过这个adaptor来找到对应的cpp部分。如果.h 文件中又include了多个其他的.h文件,这个时候其他的.h文件内也要使用extern c的操作。注意不要将include的声明放在extern的block中。

命名不规范引起的冲突

有一次遇到类似这个帖子中说的问题。

在完全使用c compiler的时候正常工作的code在使用了cpp的compiler的时候遇到了问题,这问题猛然一看不知到是什么原因,其实是很简单的事情。主要是因为一些old header file使用了macro来定义max min 这个就和cpp的使用max min 的方式产生了conflict,比如参数的个数这些。因为pure c 的code不带有namespace,也不会使用std::这样的方式,所以容易出现问题。即使是纯c的code,也要有一些前瞻性,这个code可能会被cpp调用,所以macro命名的时候也应该小心谨慎,加上一些特别的prefix。

reference

https://stackoverflow.com/questions/18877437/undefined-reference-to-errors-when-linking-static-c-library-with-c-code

https://stackoverflow.com/questions/3789340/combining-c-and-c-how-does-ifdef-cplusplus-work

https://stackoverflow.com/questions/43602910/extern-c-causing-an-error-expected-before-string-constant

推荐文章