【问题标题】:Conditional compiling/linking with gcc使用 gcc 进行条件编译/链接
【发布时间】:2013-03-01 09:26:59
【问题描述】:

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

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

只有当用户提供的model.c 不包含该属性的子例程时,是否可以在源代码中嵌入模型属性的虚拟子例程?

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

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

【问题讨论】:

  • 使用c++类和继承怎么样?您可以创建一个将所有功能实现为虚拟的父类。然后每个想要使用函数的人都可以简单地在其派生类中重写它。
  • 这确实是一个选择。然而,用 c++ 重新实现整个代码将是一项重大工作。我希望有一个不涉及重新设计代码的简单解决方案。
  • 如何将dummy_function.c 重命名为main.c 并提供给用户?想要使用某个函数的用户可以用真实函数替换该虚拟函数。

标签: gcc makefile ld


【解决方案1】:

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

【讨论】:

  • 这太完美了!非常感谢。
  • 好一个。不知道那个。 +1
【解决方案2】:

既然您说用户的子例程“在运行时编译成代码”,您可以使用动态链接来加载用户提供的二进制文件并在运行时查找它们的入口点。在 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。无论您使用什么操作系统,都可能提供类似的工具。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-12
    • 2019-01-30
    • 1970-01-01
    • 2019-10-15
    • 2019-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多