Связывание скомпилированной статической библиотеки C с программой С++
Я попытался связать статическую библиотеку (скомпилированную с gcc) в программу С++, и я получил ссылку undefined. Я использовал gcc и g++ версию 4.6.3 на серверной машине ubuntu 12.04. Например, вот простой файл библиотеки для факториала:
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);
}
Я создал объект для этого mylib.c, используя gcc:
gcc -o mylib.o -c mylib.c
Снова статическая библиотека была создана из объектного файла с помощью утилиты AR:
ar -cvq libfact.a mylib.o
Я протестировал эту библиотеку с помощью программы C (test.c) и программы на С++ (test.cpp)
Обе программы C и С++ имеют одно и то же тело:
#include "mylib.h"
int main()
{
int fact = factorial(5);
return 0;
}
Предполагая, что статическая библиотека libfact.a доступна в каталоге /home/test, я скомпилировал свою программу на C без каких-либо проблем:
gcc test.c -L/home/test -lfact
Однако при тестировании С++-программы он сбросил ошибку ссылки:
g++ test.cpp -L/home/test -lfact
test.cpp:(.text+0x2f): undefined reference to `factorial(int)'
collect2: ld returned 1 exit status
Я даже попытался добавить команду extern в test.cpp:
extern int factorial(int n) //added just before the main () function
По-прежнему такая же ошибка.
- Может ли кто-нибудь сказать мне, что я здесь не так?
- Есть ли что-то, что я пропустил при создании статической библиотеки?
- Должен ли я добавить что-нибудь в свой
test.cpp
, чтобы он работал?
Ответы
Ответ 1
Проблема в том, что вы не сказали своей программе на С++, что факториал написан на C. Вам нужно изменить заголовочный файл test.h. Как этот
#ifndef __MYLIB_H_
#define __MYLIB_H_
#ifdef __cplusplus
extern "C" {
#endif
int factorial(int n);
#ifdef __cplusplus
}
#endif
#endif
Теперь ваш заголовочный файл должен работать как для программ C, так и для С++. Подробнее см. здесь.
Идентификаторы BTW, содержащие двойной знак подчеркивания, зарезервированы для компилятора (так называются имена, начинающиеся с подчеркивания и заглавная буква), поэтому #ifndef __MYLIB_H_
является незаконным, строго говоря. Я бы изменился на #ifndef MYLIB_H #define MYLIB_H
Ответ 2
Хотя принятый ответ абсолютно правильный, я думал, что просто добавлю наблюдение. Некоторые редакторы имеют проблемы с открытой/закрывающей скобкой и будут отступать от всей области extern "C"
в заголовке. Если mylib.h
является ключевым заголовком для библиотеки, вы можете подумать:
#if defined (__cplusplus)
#define _MYLIB_INIT_DECL extern "C" {
#define _MYLIB_FINI_DECL }
#else
#define _MYLIB_INIT_DECL
#define _MYLIB_FINI_DECL
#endif
Все остальные заголовки в библиотеке mylib
, например mylib_aux.h
, могут иметь следующий вид:
#ifndef _MYLIB_AUX_H
#define _MYLIB_AUX_H
#include <mylib.h>
_MYLIB_INIT_DECL
... header content ...
_MYLIB_FINI_DECL
#endif /* _MYLIB_AUX_H */
Очевидно, что имена, которые я использую, являются произвольными, но для нескольких заголовков библиотек этот подход мне был полезен.