将C编译的静态库链接到C++程序中。
将C编译的静态库链接到C++程序中。
我尝试将一个使用gcc编译的静态库链接到一个C++程序中,但是出现了“未定义的引用”的错误。我在一个Ubuntu 12.04服务器上使用gcc和g++版本4.6.3。例如,这是一个简单的用于阶乘方法的库文件:
mylib.h
#ifndef __MYLIB_H_ #define __MYLIB_H_ int factorial(int n); #endif
mylib.c
#include "mylib.h" int factorial(int n) { return ((n>=1)?(n*factorial(n-1)):1); }
我使用gcc为这个mylib.c文件创建了一个对象:
gcc -o mylib.o -c mylib.c
然后使用AR工具从对象文件创建了静态库:
ar -cvq libfact.a mylib.o
我用一个C程序(test.c)和一个C++程序(test.cpp)来测试这个库
C和C++程序的主体相同:
#include "mylib.h" int main() { int fact = factorial(5); return 0; }
假设静态库libfact.a位于/home/test目录中,我编译C程序没有任何问题:
gcc test.c -L/home/test -lfact
然而,在测试C++程序时,出现了链接错误:
g++ test.cpp -L/home/test -lfact test.cpp:(.text+0x2f): undefined reference to `factorial(int)' collect2: ld returned 1 exit status
我甚至尝试在test.cpp中添加extern命令:
extern int factorial(int n) //added just before the main () function
仍然是同样的错误。
- 有人能告诉我我在哪里出错了吗?
- 在创建静态库时我有什么遗漏吗?
- 我需要在我的test.cpp中添加什么才能使它工作?
问题出现的原因是一些编辑器在处理开/闭括号时会出现问题,会对头文件中的整个extern "C"范围进行缩进。为了解决这个问题,可以使用预处理指令来定义宏,根据是否是C++程序来决定是否需要添加extern "C"。
解决方法如下:
1. 在mylib.h头文件中,根据是否是C++程序来定义宏_MYLIB_INIT_DECL和_MYLIB_FINI_DECL,如果是C++程序则定义为extern "C",否则为空。
2. 在其他mylib库的头文件中,例如mylib_aux.h,在包含mylib.h之前,使用#ifndef指令来判断该头文件是否已经被包含过,如果没有则定义宏_MYLIB_INIT_DECL为extern "C",否则为空。在头文件内容的末尾使用宏_MYLIB_FINI_DECL来结束extern "C"范围。
这种方法可以解决编辑器在处理extern "C"时的缩进问题,使得多个库头文件可以正常链接。
问题的原因是你没有告诉你的C++程序factorial是用C语言编写的。你需要更改你的test.h头文件,像这样:
#ifndef __MYLIB_H_ #define __MYLIB_H_ #ifdef __cplusplus extern "C" { #endif int factorial(int n); #ifdef __cplusplus } #endif #endif
现在你的头文件应该适用于C和C++程序。详情请参见这里。
顺便说一下,双下划线命名的名称是保留给编译器的(以及以下划线和大写字母开头的名称),所以#ifndef __MYLIB_H_
严格来说是不合法的。我会改为#ifndef MYLIB_H #define MYLIB_H
。
是的,用这个方法很好用。感谢你提供的链接。感谢你添加关于双下划线的信息。
很好的解释。+1