Christian Brinch
Christian Brinch

Reputation: 99

Conditional compiling/linking with gcc

I have scientific simulation code written in C that runs from the command line. The user provides an input model as a set of C subroutines in a model.c file that are then compiled into code at runtime.

Certain model properties are not always relevant for a specific problem but currently the user still needs to provide an empty dummy function for that property in order for the code to compile.

Is it possible to have dummy subroutines for the model properties embedded in the source code that are linked only if the user-provided model.c does not contain a subroutine for that property?

As an example, if model.c contains a subroutine called temperature(), the code should link to that one, rather than the subroutine called temperature() found in src/dummy_function.c. If model.c does not have temperature() the compiler should use the dummy function in src/dummy_function.c.

If possible, I would prefer a solution that does not require preprocessor directives in the model.c file.

Upvotes: 1

Views: 812

Answers (2)

Konstantin Vladimirov
Konstantin Vladimirov

Reputation: 6999

Yes you can. Suppose you have simple code in file, say undesym.c:

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

Create weak stub in say file fakeone.c

#include "assert.h"

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

Now create "user" function in, say goodone.c

#include "stdio.h"

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

Now if you will link together gcc undesym.c fakeone.c then a.out will run to assert, but if you will add goodone.c to compilation, like gcc undesym.c fakeone.c goodone.c, then it will prefer strong definition to weak, and will run to message.

You may adopt the same mechanism, defining default functions weak.

Upvotes: 4

Idelic
Idelic

Reputation: 15582

Since you say that the user's subroutines are "compiled into the code at runtime", you could use dynamic linking to load a user-provided binary and look for their entry points at runtime. In linux (or any POSIX system), this would be based on dlopen()/dlsym() and look more or less like this:

#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();

See the dlopen documentation for details. A similar facility is very likely available in whatever OS you're using.

Upvotes: 0

Related Questions