头文件(例如,某些 #include 指令引用的 *.h 文件)与 C 或 C++ compiler 相关。 linker 不知道source files(这是编译器的输入),而只知道assembler 产生的object files(在executable and linkable format 中,即ELF)
库文件(由-lfoo 提供)仅在链接 时相关。编译器不知道库。
dynamic linker 需要知道应该链接哪些库。在运行时,它会进行符号解析(针对一组固定且已知的共享库)。动态链接器不会尝试链接系统上存在的所有可能的共享库(因为它有太多共享对象,或者因为它可能有给定库的多个冲突版本),它只会链接提供的一组固定库在executable 内。使用 objdump(1) & readelf(1) & nm(1) 探索 ELF 对象文件和可执行文件,使用 ldd(1) 了解共享库依赖关系。
请注意g++ 程序用于编译和链接。 (实际上它是一个驱动程序:它启动一些 cc1plus -C++ 编译器 - 将 C++ 代码编译为汇编文件,一些 as - 汇编器 - 将汇编文件汇编成目标文件,还有一些ld -链接器-链接object files和libraries)。
以g++ -v 运行g++ 以了解它在做什么,即它正在运行什么程序。
如果您不链接所需的库,则在链接时,某些引用仍未解析(因为某些目标文件包含外部引用和relocation)。
(使用链接时间优化会稍微复杂一些,我们可以忽略)
另请阅读 Program Library HowTo、Levine's book linkers and loaders 和 Drepper's paper: how to write shared libraries
如果你在运行时使用dynamic loading(通过在某些插件上使用dlopen(3)),你需要知道相关函数的类型和签名(由dlsym(3)返回)。加载插件的程序总是有其特定的插件约定。有关示例,请查看用于 geany plugins 和 GCC plugins 的约定(另请参阅 these slides 关于 GCC 插件)。
实际上,如果您正在开发接受某些插件的应用程序,您将定义一组名称、它们的预期类型、签名和角色。例如
typedef void plugin_start_function_t (const char*);
typedef int plugin_more_function_t (int, double);
然后声明例如一些变量(或数据结构中的字段)以命名约定指向它们
plugin_start_function_t* plustart; // app_plugin_start in plugins
#define NAME_plustart "app_plugin_start"
plugin_more_function_t* plumore; // app_plugin_more in plugins
#define NAME_plumore "app_plugin_more"
然后加载插件并设置这些指针,例如
void* plugdlh = dlopen(plugin_path, RTLD_NOW);
if (!plugdlh) {
fprintf(stderr, "failed to load %s: %s\n", plugin_path, dlerror());
exit(EXIT_FAILURE; }
然后检索符号:
plustart = dlsym(plugdlh, NAME_plustart);
if (!plustart) {
fprintf(stderr, "failed to find %s in %s: %s\n",
NAME_plustart, plugin_path, dlerror();
exit(EXIT_FAILURE);
}
plumore = dlsym(plugdlh, NAME_plumore);
if (!plumore) {
fprintf(stderr, "failed to find %s in %s: %s\n",
NAME_plumore, plugin_path, dlerror();
exit(EXIT_FAILURE);
}
然后适当地使用plustart 和plumore 函数指针。
在你的插件中,你需要编码
extern "C" void app_plugin_start(const char*);
extern "C" int app_plugin_more (int, double);
并给他们两个下一个定义。该插件应编译为position independent code,例如与
g++ -Wall -fPIC -O -g pluginsrc1.c -o pluginsrc1.pic.o
g++ -Wall -fPIC -O -g pluginsrc2.c -o pluginsrc2.pic.o
并链接到
g++ -shared pluginsrc1.pic.o pluginsrc2.pic.o -o yourplugin.so
您可能希望将额外的共享库链接到您的插件。
您通常应该使用-rdynamic 链接标志链接您的主程序(加载插件的那个)(因为您希望您的主程序的某些符号对您的插件可见)。
另请阅读C++ dlopen mini howto