Search code examples
cincludeprogram-entry-point

Can included C files be also ran directly?


I'm wondering whether a C file can be both included in another script (through a header file), and also run independently (by having its own main function). That is, the C file can be included to provide its functions to another C script, but can also itself be directly ran to provide some alternate functionality.

For example, a python script can do this;

def functionsToBeImported():
    # code to be run by an importing script
    pass

if __name__ == '__main__':
    # code to be run by this script independently
    pass

This code can be imported (import ABOVESCRIPT) by another python file to give access to functionsToBeImported, or independently run (python ABOVESCRIPT.py) to execute the code within the if block.

I've attempted to do this in C via myScript.c:

#include "myScript.h"

void functionsToBeImported() {
}

int main (int narg, char* varg[]) {
}

myScript.h:

#ifndef MY_SCRIPT_H_
#define MY_SCRIPT_H_

void functionsToBeImported();

#endif // MY_SCRIPT_H_

but trying to include this in anotherScript.c:

#include "myScript.h"

int main (int narg, char* varg[]) {

    functionsToBeImported();
}

and trying to compile via

gcc -std=c99 -c myScript.c
gcc -std=c99 -c anotherScript.c
gcc -std=c99 -o anotherScript anotherScript.o myScript.o -lm

gives be a compilation error

duplicate symbol _main in:
    myScript.o
    anotherScript.o

How can I achieve this 'double-use' script?


Solution

  • You cannot link both anotherScript.o and myScript.o, but you could do something like this:

    #define main ignored_main
    // Include myScript.c, not myScript.h
    #include "myScript.c"
    #undef main
    
    int main (int narg, char* varg[]) {
    
        functionsToBeImported();
    }
    

    I have actually seen things like this in code very widely used in production, although I cannot recommend this style (but it is sometimes a tempting shortcut).

    Another option is to include the main function only if a preprocessor macro is defined, like this (in myScript.c):

    #include "myScript.h"
    
    void functionsToBeImported() {
    }
    
    #ifdef USE_MAIN
    int main (int narg, char* varg[]) {
    }
    #endif // USE_MAIN
    

    This is similar in spirit to the Python approach. But again, you will have to compile this file twice into separate object files.