如何使用模块在C中编译应用程序?

时间:2012-12-26 14:16:57

标签: c++ c

我想做应用程序,可以用外部模块编译,例如在php中。在php中,您可以在运行时加载模块,或者将模块与模块一起编译,因此模块可以在运行时加载而无需加载。但我不明白如何做到这一点。如果我在module.c中有模块,并且有一个名为say_hello的函数,如果你理解我的意思,我如何将它注册到主应用程序?

/* module.c */
#include <stdio.h>

// here register say_hello function, but how, if i can't in global scope
// call another function?

void say_hello() 
{
  printf("hello!");
}

如果我将所有文件(主应用程序+模块)编译在一起,则不会从主应用程序引用say_hello函数,因为仅当用户在其代码中调用它时才会调用它。那么我怎么能对我的应用说,嘿,有say_hello功能,如果有人想叫它,你知道它存在。

EDIT1:我需要在运行时使用像table这样的东西,在那里我可以看到用户是否存在函数(具有C equivavent)。头文件对我没有帮助。

EDIT2:我的应用程序是我的脚本langugage的解释。

EDIT3:如果有人在php中调用函数,php解释必须知道该函数存在。我知道动态链接,如果加载了.so或.dll,那么调用一些启动例程,你可以在该dll中简单地注册函数,所以php解释可以看到,如果某些模块注册了例如名为“say_hello”的函数。但是如果我想用例如gd支持编译php,那么如何将gd函数注册到某些php函数列表,哈希表等等?

4 个答案:

答案 0 :(得分:2)

我想你正在寻找的是动态库(我们将运行时可加载模块称为C和OS世界中的动态/共享库)。举例来说,Pidgin支持插件以扩展其功能。它为它的插件制作者提供了一个特定的接口,比如注册,加载,卸载和使用的功能,插件必须遵循这些接口。

当程序加载时,它会在它的plugins目录中查找这样的动态库,如果存在,它将加载并使用它,否则它将跳过暴露功能。需要接口的原因在于,由于不同的模块可以具有不同的功能,这些功能在运行时是一个未知的应用程序。必须有一个共同的,商定的方式“谈论”它的插件/模块。

每个C程序都可以链接到静态或动态库; static会将代码从库复制到所述程序,在那里不会让程序运行依赖,而链接到动态库则需要在程序启动时存在动态库。第三种方法,不是链接到DLL,而只是要求操作系统执行库的加载操作。如果成功,则使用动态模块,否则忽略。只有在加载调用成功时,动态库应该执行的功能才会向用户公开。

需要注意的是,这是一个操作系统提供的功能,它与所使用的语言无关(C或C ++或Python在这里无关紧要);就C而言,编译器仍链接到已知代码,即编译时可用的代码。这就是不同操作系统的原因,需要编写不同的代码来加载动态模块。更重要的是,syuch库的文件类型/格式因系统而异。在Linux中,它被称为共享对象(.so),在Mac中称为动态库(.dylib),在Windows中称为动态链接库(.dll)。

答案 1 :(得分:1)

C不是解释语言。所以你需要链接,你可能需要静态链接或动态链接。

计划构建包括两个主要阶段:编译和链接。在编译期间,所有c文件都被转换为机器代码,使被调用的函数无法解析(objo文件)。然后链接器将所有这些文件合并为一个可执行文件,解决未解决的问题。

这是静态链接。链接模块成为可执行文件的组成部分。

动态链接是特定于平台的。在Windows下,这些是DLL。您应该发出一个系统调用来加载DLL,之后您就可以从中调用函数。

答案 2 :(得分:1)

您需要的是动态库。我们先来看看the Linux manpage of dlopen(3)中提供的示例:

/* Load the math library, and print the cosine of 2.0: */
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int argc, char **argv) {
    void *handle;
    double (*cosine)(double);
    char *error;

    handle = dlopen("libm.so", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE);
    }

    dlerror();    /* Clear any existing error */

    /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
       would seem more natural, but the C99 standard leaves
       casting from "void *" to a function pointer undefined.
       The assignment used below is a workaround. */

    *(void **) (&cosine) = dlsym(handle, "cos");

    if ((error = dlerror()) != NULL)  {
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }

    printf("%f\n", (*cosine)(2.0));
    dlclose(handle);
    exit(EXIT_SUCCESS);
}

还有C++ dlopen mini HOWTO

有关动态加载的更多常规信息,请先从the wikipedia page开始。

答案 3 :(得分:-5)

如果我明白你的意思,我认为这是不可能的。因为它是编译语言。