我已经在我的应用程序和extension-functions.c(hxxps://www.sqlite.org/contrib)中将sqlite3.c构建到一个共享库中,它工作正常,但对于我正在研究的项目我必须将sqlite3 +扩展函数静态链接到C ++应用程序。 我已经阅读了很多关于这个主题的消息来源,但我无法让它发挥作用。
最小例子(test.cc):
#include "sqlite3.h"
#include<cstdlib>
void sqlite3_extension_functions_init(void);
// typedef struct sqlite3_api_routines sqlite3_api_routines;
// int sqlite3_extension_functions_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
int main(int argc,char *argv[]) {
// sqlite3_auto_extension( (void(*)(void))sqlite3_extension_functions_init );
sqlite3_auto_extension( sqlite3_extension_functions_init );
sqlite3 *database_;
sqlite3_open_v2("test.db", &database_, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
sqlite3_close_v2(database_);
return 0;
}
构建命令:
gcc -o test sqlite3.c extension_functions.c test.cc -lpthread -lm -ldl -DSQLITE_CORE
( - DSQLITE_CORE没影响?)
错误:
/tmp/ccPfaDLE.o: In function `main':
test.cc:(.text+0x10): undefined reference to `sqlite3_extension_functions_init()'
collect2: ld returned 1 exit status
使用注释行代替:
/tmp/ccrs9B0K.o: In function `main':
test.cc:(.text+0x10): undefined reference to `sqlite3_extension_functions_init(sqlite3*, char**, sqlite3_api_routines const*)'
collect2: ld returned 1 exit status
int sqlite3_extension_init()
重命名为int sqlite3_extension_functions_init()
我使用的其他来源:
也许我是盲目的,但函数原型在test.cc中给出,函数定义在extension_functions.c中。有谁知道这个代码示例有什么问题?提前感谢您的帮助。(我很抱歉hxxp://链接,但我不允许发布两个以上的链接)
答案 0 :(得分:1)
不要将C语言的“链接”概念与将一组编译函数物理“链接”到一个完整程序的过程混淆。后者是与源编译逻辑上独立的操作,尽管受前者的影响。
预处理器宏可以影响代码的编译方式,但不会(直接)影响代码的链接方式。你的扩展函数可能需要用-DSQLITE_CORE
编译(虽然我对此没有信心),但你需要 link 选项来构建一个单片可执行文件。您还需要SQLite库的静态版本。
GCC提供了一个用于编译和链接的公共前端(gcc
),因此您需要做的主要事情是(在链接阶段)传递gcc
一个选项,指示它执行静态链接。该选项拼写为-static
。
答案 1 :(得分:1)
在混合C和C ++代码时,请确保在C ++端将C函数的声明标记为C,如:
extern "C" {
int sqlite3_extension_functions_init(sqlite3 *db, char **pzErrMsg,
const sqlite3_api_routines *pApi);
// more declarations
}
编译器为外部声明为C或C ++生成不同的符号。错误消息反映出:
test.cc:(.text+0x10): undefined reference to `sqlite3_extension_functions_init(sqlite3*, char**, sqlite3_api_routines const*)'
在这种情况下,编译器准备了一个符号名称,因为它认为它处理的是C ++函数,而实际上驻留在extension_functions.c
中的函数将是一个C函数,并且链接器应该期望解析一个不同的符号名称。此错误消息指出链接器无法解析基于C ++命名法的符号名称。
背景btw。是C ++支持函数重载,而C不支持。所以在C ++中你可以有两个不同的函数:
extern void foobar(int x, int y);
extern void foobar(char const *x);
为了区分,C ++编译器通常通过使函数参数的原型成为符号名称的一部分来为这些不同的函数分配不同的符号。相比之下,带有任何函数参数的int foobar()
之类的C函数只会生成符号foobar
,而不会在符号名称中生成参数原型,因为简单的C没有函数重载。
顺便提一下,为什么声明C函数但必须可用于C和C ++的头文件的结构通常如下:
#ifdef __cplusplus
extern "C" {
#endif
/* Now follow declarations of C functions, such as extern int printf()
* or whatever
*/
#ifdef __cplusplus
}
#endif