在c中使用gcc进行动态文件编译

发布于 2025-01-20 14:28:06 字数 1690 浏览 3 评论 0原文

我正在尝试从程序中找到一种方法,检查一个或多个“ .c”文件的存在并加载一个或多个功能。

基本上,我将拥有一个“主”程序,该程序将检查是否存在“ script.c”文件,并将启动(如果存在)该文件的主要()函数。

这是我的“主要”程序的内容:

int main(int argc, char *argv[]){
    ...
    if(argc == 1){
        FILE *file;
        if((file = fopen("script.c", "r"))){
            printf("file script.c loaded.");
            // to compile the script.c file and modify on it the "main()" function to "_main()" (in order to be able to recompile it with the main library) before restarting the program
            int ret = system("gcc -c script.c && objcopy --redefine-sym main=_main script.o && gcc main script.o -o main && ./main -l script.o");
            printf("ret(0)=%d\n", ret);
        }
        else{
            int ret = system("./main -l");
            printf("ret(1)=%d\n", ret);
        }
    }
    else{
        if(argc == 3 && strcmp(argv[2], "script.o") == 0){
            _main(argc, argv);
        }
        else{
            printf("no file found.\n");
        }
    }
    ...
}

他是我的“脚本”文件的内容:

int main(int argc, char *argv[]){
    ...
    printf("main() function in script.c loaded.\n");
    ...
}

如果存在脚本。ClunMain应该给出:

file script.c loaded.
ret(0)=0
main() function in script.c loaded.

如果脚本.c文件不存在,则运行主要应该给出:

file script.c loaded.
ret(1)=0
no file found.

显然,这是出于多种原因而起作用的。

  1. 使用“主”程序重新编译脚本。
  2. 不可能 第一次发布,如果没有找到脚本,也有可能在第二次发射)

您是否有想法可以实现自己的目标? 因此,从单个可执行程序(此处为“ main”)可以检查外部文件的存在(shere“ script.c”)并从中启动一个或多个函数... PS:在其他项目中已经看过它,我知道这是可能的,但是我找不到解决方案。 PS2:只有可执行文件(main)和可能存在脚本。将被打开和执行)

I'm trying to find a method to, from a program, check the presence of one or more ".c" files and load one or more functions of it.

Basically, I would have a "main" program which will check if the "script.c" file exists, and will launch (if it exists) the main() function of this one.

Here is the content of my "main" program before compilation:

int main(int argc, char *argv[]){
    ...
    if(argc == 1){
        FILE *file;
        if((file = fopen("script.c", "r"))){
            printf("file script.c loaded.");
            // to compile the script.c file and modify on it the "main()" function to "_main()" (in order to be able to recompile it with the main library) before restarting the program
            int ret = system("gcc -c script.c && objcopy --redefine-sym main=_main script.o && gcc main script.o -o main && ./main -l script.o");
            printf("ret(0)=%d\n", ret);
        }
        else{
            int ret = system("./main -l");
            printf("ret(1)=%d\n", ret);
        }
    }
    else{
        if(argc == 3 && strcmp(argv[2], "script.o") == 0){
            _main(argc, argv);
        }
        else{
            printf("no file found.\n");
        }
    }
    ...
}

He is the content of my "script.c" file:

int main(int argc, char *argv[]){
    ...
    printf("main() function in script.c loaded.\n");
    ...
}

If the script.c file exists, running main should give:

file script.c loaded.
ret(0)=0
main() function in script.c loaded.

If the script.c file does not exist, running main should give:

file script.c loaded.
ret(1)=0
no file found.

Obviously, this does not work for several reasons.

  1. It is impossible to use the "main" program to recompile the script.o file (especially since this is supposed to be in use)
  2. It is impossible to compile my "main" program with a _main() function that does not exist (on the 1st launch, and potentially on the second too if script.c dont found)

Do you have an idea for me to achieve my goal ?
So from a single executable program (here "main") to be able to check the presence of an external file (here "script.c") and launch one or more functions from it...
PS: Having already seen it in other projects, I know it's possible, but I can't find the solution.
PS2: Only the executable file (main) and potentially the script.c file must be present (therefore no main.c...which therefore perhaps suggests that a "main" file should be merged with the "main.o" associated which would be unpacked and executed)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柳若烟 2025-01-27 14:28:06

因此,从单个可执行程序(此处为“main”)能够检查外部文件(此处为“script.c”)是否存在并从中启动一个或多个函数...

我将做出一个假设您提到的 main 函数并不是最重要的,并展示了如何从程序内部将函数集合编译到您加载的共享库中,然后执行函数(除了 main) 中。

一个简单的驱动程序可能如下所示:

// driver.c
#include <dlfcn.h> // to be able to dynamically load shared libraries

#include <stdio.h>
#include <stdlib.h>

// the signature of the `start` function you decide to have in all the files:
typedef void(*start_func_t)(void);

int main(int argc, char *argv[]){
    char sys[1024];

    for(int i = 1; i < argc; ++i) { // loop through all the arguments
        // try to compile the argument into an object file
        // (use a safer version than sprintf in real code)
        sprintf(sys, "gcc -fPIC -c -o %s.o %s", argv[i], argv[i]);
        if(system(sys)) {
            printf("%d failed\n", sys);
            exit(1);
        }

        // try to create a shared library from the object file
        sprintf(sys, "gcc -shared -o libcurrent.so %s.o", argv[i]);
        if(system(sys)) {
            printf("%d failed\n", sys);
            exit(1);
        }

        // load the shared library you just created
        (void)dlerror(); 
        void *handle = dlopen("./libcurrent.so", RTLD_NOW | RTLD_LOCAL);
        if(!handle) {
            puts(dlerror());
            exit(1);
        }

        // lookup the "start" symbol in the shared library:
        start_func_t start = dlsym(handle, "start");
        if(!start) {
            puts(dlerror());
            exit(1);
        }

        // call the loaded function:
        start();

        dlclose(handle); // close the library
    }
}

您需要链接上面的程序带有 dl 库,所以类似这样的东西应该可以工作:

gcc -o driver driver.c -ldl

现在,如果您创建一些示例文件:

// t1.c
#include <stdio.h>
void start(void) { puts("Hello world"); }
// t2.c
#include <stdio.h>
void start(void) { puts("another file"); }

然后运行:

./driver t1.c t2.c

如果一切顺利,它应该产生以下输出:

Hello world
another file

我还做了一个测试如果我将 main 放入库中,看看效果如何。也就是说,将 start_func_t 签名更改为:

typedef int(*start_func_t)(int argc, char *argv[]);

并加载并调用 main

        start_func_t start = dlsym(handle, "main");
        if(!start) {
            puts(dlerror());
            exit(1);
        }

        // call the loaded function with some example arguments:
        char *cargv[] = {
            "foo", "hello", "world", NULL
        };
        start(3, cargv);

并稍微更改测试程序:

// t1.c
#include <stdio.h>
int main(int argc, char *argv[]) {
    for(int i = 0; i < argc; ++i) {
        printf("t1: %s\n", argv[i]);
    }
}
// t2.c
#include <stdio.h>
int main(int argc, char *argv[]) {
    for(int i = 0; i < argc; ++i) {
        printf("t2: %s\n", argv[i]);
    }
}

这也工作得很好。然而,main有点特殊,我不确定这是否违反了任何规则。

So from a single executable program (here "main") to be able to check the presence of an external file (here "script.c") and launch one or more functions from it...

I'm going to make an assumption that the main function you mentioned is not the most important and show how you can, from within your program, compile collections of functions into shared libraries that you load and then execute functions (other than main) in.

A simple driver could look like this:

// driver.c
#include <dlfcn.h> // to be able to dynamically load shared libraries

#include <stdio.h>
#include <stdlib.h>

// the signature of the `start` function you decide to have in all the files:
typedef void(*start_func_t)(void);

int main(int argc, char *argv[]){
    char sys[1024];

    for(int i = 1; i < argc; ++i) { // loop through all the arguments
        // try to compile the argument into an object file
        // (use a safer version than sprintf in real code)
        sprintf(sys, "gcc -fPIC -c -o %s.o %s", argv[i], argv[i]);
        if(system(sys)) {
            printf("%d failed\n", sys);
            exit(1);
        }

        // try to create a shared library from the object file
        sprintf(sys, "gcc -shared -o libcurrent.so %s.o", argv[i]);
        if(system(sys)) {
            printf("%d failed\n", sys);
            exit(1);
        }

        // load the shared library you just created
        (void)dlerror(); 
        void *handle = dlopen("./libcurrent.so", RTLD_NOW | RTLD_LOCAL);
        if(!handle) {
            puts(dlerror());
            exit(1);
        }

        // lookup the "start" symbol in the shared library:
        start_func_t start = dlsym(handle, "start");
        if(!start) {
            puts(dlerror());
            exit(1);
        }

        // call the loaded function:
        start();

        dlclose(handle); // close the library
    }
}

You need to link the above program with the dl library, so something like this should work:

gcc -o driver driver.c -ldl

Now, if you create some example files:

// t1.c
#include <stdio.h>
void start(void) { puts("Hello world"); }
// t2.c
#include <stdio.h>
void start(void) { puts("another file"); }

and then run:

./driver t1.c t2.c

It should produce this output if everything works out:

Hello world
another file

I also made a test to see how this works out if I put main in the library. That is, change the start_func_t signature to:

typedef int(*start_func_t)(int argc, char *argv[]);

and load and call main instead:

        start_func_t start = dlsym(handle, "main");
        if(!start) {
            puts(dlerror());
            exit(1);
        }

        // call the loaded function with some example arguments:
        char *cargv[] = {
            "foo", "hello", "world", NULL
        };
        start(3, cargv);

and change the test programs slightly:

// t1.c
#include <stdio.h>
int main(int argc, char *argv[]) {
    for(int i = 0; i < argc; ++i) {
        printf("t1: %s\n", argv[i]);
    }
}
// t2.c
#include <stdio.h>
int main(int argc, char *argv[]) {
    for(int i = 0; i < argc; ++i) {
        printf("t2: %s\n", argv[i]);
    }
}

and this worked fine too. However, main is a bit special and I'm not sure if this violates any rules.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文