为什么包含带有外部变量和funcs的h文件会导致未定义的引用

为什么包含带有外部变量和funcs的h文件会导致未定义的引用,c,linux,gcc,extern,dlopen,C,Linux,Gcc,Extern,Dlopen,如果我希望在运行时使用dlopen解析这些外部,该怎么办 我试图理解为什么在C可执行程序中包含一个h文件(带有共享库外部变量和func)会导致未定义/未解析。链接时 如果我只想在运行时解析这些符号,为什么我必须向gcc链接添加-lsomelib标志呢 链接时间链接器需要这些定义的原因是什么。为什么在使用dlopen时不能等待运行时的解决方案 有人能帮我理解这一点吗?这里有一些可能有助于理解的东西: 有3种类型的链接: 静态链接。答:编译器在链接时将库的内容包含到您的代码中,以便您可以将代码移动到

如果我希望在运行时使用dlopen解析这些外部,该怎么办

我试图理解为什么在C可执行程序中包含一个h文件(带有共享库外部变量和func)会导致未定义/未解析。链接时

如果我只想在运行时解析这些符号,为什么我必须向gcc链接添加-lsomelib标志呢

链接时间链接器需要这些定义的原因是什么。为什么在使用dlopen时不能等待运行时的解决方案


有人能帮我理解这一点吗?

这里有一些可能有助于理解的东西: 有3种类型的链接:

静态链接。答:编译器在链接时将库的内容包含到您的代码中,以便您可以将代码移动到具有相同体系结构的其他计算机上并运行它。 动态链接。因此:编译器在编译期间在链接时解析符号;但在可执行文件中不包含库的代码。程序启动时,将加载库。如果找不到库,程序将停止。您需要运行该程序的计算机上的库 动态加载:您负责在运行时加载库函数,使用专门用于插件的dlopen等 另见:和
这里有一些可能有助于理解: 有3种类型的链接:

静态链接。答:编译器在链接时将库的内容包含到您的代码中,以便您可以将代码移动到具有相同体系结构的其他计算机上并运行它。 动态链接。因此:编译器在编译期间在链接时解析符号;但在可执行文件中不包含库的代码。程序启动时,将加载库。如果找不到库,程序将停止。您需要运行该程序的计算机上的库 动态加载:您负责在运行时加载库函数,使用专门用于插件的dlopen等 另见:和

由某些包含指令引用的头文件,例如A*.h文件,与C或C++相关。不知道哪些是编译器的输入,但只知道in生成的,即ELF

lfoo提供的库文件仅在链接时相关。编译器不了解库

用户需要知道应该链接哪些库。在运行时,它对一组固定且已知的共享库执行符号解析。动态链接器不会尝试链接系统上存在的所有可能的共享库,因为它有太多的共享对象,或者因为它可能有给定库的多个冲突版本,它将只链接系统中提供的一组固定库。使用&&探索ELF对象文件和可执行文件,并了解共享库的依赖关系

请注意,g++程序用于编译和链接。实际上,它是一个驱动程序:它启动一些C1+ + C++编译器,将C++代码编译成汇编文件,有的汇编成汇编文件到对象文件中,有的LD链接器链接到./P> 以g++-v的形式运行g++以了解它在做什么,即它在运行什么程序

如果未链接所需的库,则在链接时,某些引用仍无法解析,因为某些对象文件包含外部引用和

链接时间优化稍微复杂一些,我们可以忽略它

同时阅读,并

如果您在运行时通过在某个插件上使用,那么您需要知道由返回的相关函数的类型和签名。加载插件的程序总是有其特定的插件约定。有关示例,请查看用于GCC插件的约定&另请参见关于GCC插件的约定

实际上,如果您正在开发接受一些插件的应用程序,您将定义一组名称、它们的预期类型、签名和角色。e、 g

 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);
并给它们下一个定义。插件应编译为,例如,使用

 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 link标志将主程序链接到加载插件的程序,因为您希望主程序的一些符号对插件可见

Read

< P>一个头文件,例如由某些包含指令引用的A*.h文件与C或C++相关。不知道哪些是编译器的输入,但只知道 在,即小精灵

lfoo提供的库文件仅在链接时相关。编译器不了解库

用户需要知道应该链接哪些库。在运行时,它对一组固定且已知的共享库执行符号解析。动态链接器不会尝试链接系统上存在的所有可能的共享库,因为它有太多的共享对象,或者因为它可能有给定库的多个冲突版本,它将只链接系统中提供的一组固定库。使用&&探索ELF对象文件和可执行文件,并了解共享库的依赖关系

请注意,g++程序用于编译和链接。实际上,它是一个驱动程序:它启动一些C1+ + C++编译器,将C++代码编译成汇编文件,有的汇编成汇编文件到对象文件中,有的LD链接器链接到./P> 以g++-v的形式运行g++以了解它在做什么,即它在运行什么程序

如果未链接所需的库,则在链接时,某些引用仍无法解析,因为某些对象文件包含外部引用和

链接时间优化稍微复杂一些,我们可以忽略它

同时阅读,并

如果您在运行时通过在某个插件上使用,那么您需要知道由返回的相关函数的类型和签名。加载插件的程序总是有其特定的插件约定。有关示例,请查看用于GCC插件的约定&另请参见关于GCC插件的约定

实际上,如果您正在开发接受一些插件的应用程序,您将定义一组名称、它们的预期类型、签名和角色。e、 g

 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);
并给它们下一个定义。插件应编译为,例如,使用

 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 link标志将主程序链接到加载插件的程序,因为您希望主程序的一些符号对插件可见


也请阅读

是的,但我要问的是:为什么动态链接/加载在编译/链接过程中需要任何解析,而不仅仅是在运行机器上的运行时。链接器需要符号的任何定义/解析,如果在运行时使用运行机器上的共享LIB执行此操作,那么链接器会做什么?动态链接需要确保您正在调用的函数存在于某个位置,因为系统将为您执行所有操作。这是他们需要解决的问题。对于动态加载,我从未使用过它,我真的帮不上忙。但是从我的理解来看,我认为你不需要在链接的时候解决这个问题,也可以从我为linux系统中的动态加载提供的一个链接,你只需要链接到系统库,这个库用于在运行时打开库并加载函数。这没问题。但是为什么我必须解析我包含的h文件中的外部。如果我不添加-lhfileSymbolsResolutionLib,gcc操作将导致错误!!!是的,但我想问的是:为什么动态链接/加载在编译/链接过程中需要任何解析,而不仅仅是在运行机器上的运行时。链接器需要符号的任何定义/解析,如果在运行时使用运行机器上的共享LIB执行此操作,那么链接器会做什么?动态链接需要确保您正在调用的函数存在于某个位置,因为系统将为您执行所有操作。这是他们需要解决的问题。对于动态加载,我从未使用过它,我真的帮不上忙。但是从我的理解来看,我认为你不需要在链接的时候解决这个问题,也可以从我为linux系统中的动态加载提供的一个链接,你只需要链接到系统库,这个库用于在运行时打开库并加载函数。这没问题。但是为什么我必须解析我包含的h文件中的外部。如果我不添加-lhfileSymbolsResolutionLib,gcc操作将导致错误!!!阅读我的问题不是关于共享lib,而是关于从h文件解析外部。如果有时我只想使用动态链接,而且无论如何符号只能在运行时解析,为什么我总是必须使用-lthelib向gcc提供符号定义?我开始阅读这篇47页的关于共享lib的论文。它很有趣,可能回答了我关于这个过程的许多问题。但与此同时阅读我的问题不是关于共享lib,而是关于从h文件解析外部。为什么我总是要提供符号定义
如果有时我只想使用动态链接,而且无论如何符号只能在运行时解析,那么就使用-lthelib将其转换为gcc?我开始阅读这篇47页的关于共享lib的论文。它很有趣,可能回答了我关于这个过程的许多问题。但与此同时谢谢,但是.h文件引入了外部全局变量和函数,这些变量和函数稍后会在链接中创建未解决/未定义的错误。我可能会在这里遗漏一些内容。你说如果你没有链接所需的库,在链接的时候,一些引用仍然没有解决,我问:那么如果它们没有解决呢?这不是动态链接的全部内容吗?直到运行时才解决?不,运行时链接是针对一组已知的库的,您需要将它们提供给g++dlopen才能打开我提供的任何库。已知或未知。因此,gcc/g++仍然不清楚为什么以后需要了解dlopen使用的LIB。如果我不包括一个带有funcs和全局变量的h文件,我就不需要添加任何-l选项,因为在dlopen之前不需要解决任何问题。不,dlopen正在打开一个固定的已知库,如其第一个参数所示。遵循我给你的链接。谢谢。但是一个.h文件引入了外部全局变量和函数,这些变量和函数稍后在链接中创建了未解决/未定义的错误。我可能在这里遗漏了一些东西。你说如果你没有链接所需的库,在链接的时候,一些引用仍然没有解决,我问:那么如果它们没有解决呢?这不是动态链接的全部内容吗?直到运行时才解决?不,运行时链接是针对一组已知的库的,您需要将它们提供给g++dlopen才能打开我提供的任何库。已知或未知。因此,gcc/g++仍然不清楚为什么以后需要了解dlopen使用的LIB。如果我不包括一个带有funcs和全局变量的h文件,我就不需要添加任何-l选项,因为在dlopen之前不需要解决任何问题。不,dlopen正在打开一个固定的已知库,如其第一个参数所示。跟随我给你的链接。