条件编译/链接与gcc

时间:2013-03-13 12:30:36

标签: gcc makefile ld

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

某些模型属性并不总是与特定问题相关,但是当前用户仍需要为该属性提供空虚函数,以便编译代码。

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

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

如果可能的话,我更倾向于在model.c文件中不需要预处理程序指令的解决方案。

2 个答案:

答案 0 :(得分:4)

是的,你可以。假设你在文件中有简单的代码,比如unexym.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;
}

现在创建“user”函​​数,比如说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,那么它将更喜欢强大的定义弱,并将运行消息。

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

答案 1 :(得分: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 documentation。无论您使用何种操作系统,都很有可能提供类似的工具。