1

我有从命令行运行的用 C 语言编写的科学模拟代码。用户将输入模型作为model.c文件中的一组 C 子例程提供,然后在运行时编译成代码。

某些模型属性并不总是与特定问题相关,但目前用户仍需要为该属性提供一个空的虚拟函数才能编译代码。

是否可以在源代码中嵌入模型属性的虚拟子程序,这些虚拟子程序仅在用户提供的model.c不包含该属性的子程序时才链接?

例如,如果model.c包含名为 的子例程temperature(),则代码应链接到该子例程,而不是在temperature()中找到的子例程src/dummy_function.c。如果model.c没有temperature()编译器应该使用src/dummy_function.c.

model.c如果可能的话,我更喜欢在文件中不需要预处理器指令的解决方案。

4

2 回答 2

4

是的你可以。假设您在文件中有简单的代码,比如 undesym.c:

int
main(void)
{
  user_routine();
  return 0;
}

在说文件 fakeone.c 中创建弱存根

#include "assert.h"

int  __attribute__((weak))
user_routine(void)
{
  assert(0 == "stub user_routine is not for call");
  return 0;
}

现在在 goodone.c 中创建“用户”函数

#include "stdio.h"

int
user_routine(void)
{
  printf("user_routine Ok\n");
  return 0;
}

现在,如果您将链接在一起,gcc undesym.c fakeone.c那么 a.out 将运行到断言,但如果您将添加goodone.c到编译中,例如gcc undesym.c fakeone.c goodone.c,那么它将更喜欢强定义而不是弱定义,并将运行到消息。

您可以采用相同的机制,定义默认函数weak。

于 2013-03-13T15:11:54.337 回答
0

由于您说用户的子例程“在运行时编译到代码中”,因此您可以使用动态链接来加载用户提供的二进制文件并在运行时查找它们的入口点。在 linux(或任何 POSIX 系统)中,这将基于dlopen()/dlsym()并且看起来或多或少像这样:

#include <dlfcn.h>

/* ... */

/* Link the UserModule.so into the executable */
void *user_module = dlopen("UserModule.so", RTLD_NOW);

if (!user_module) {
    /* Module could not be loaded, handle error */
}

/* Locate the "temperature" function */
void *temperature_ptr = dlsym(user_module, "temperature"):

if (!temperature_ptr) {
    /* Module does not define the "temperature" function */
}

void (*user_temperature)() = (void(*)())temperature_ptr;

/* Call the user function */
user_temperature();

有关详细信息,请参阅dlopen 文档。在您使用的任何操作系统中,很可能都可以使用类似的工具。

于 2013-03-13T15:04:48.930 回答