Search code examples
cmacrosc-preprocessorconditional-compilation

Compile different code on whether a function is available or not


Windows provides only GetTickCount up to Windows Vista and starting from that OS also GetTickCount64. How can I make a C program compile with calls to different functions?

How can I make a C compiler check whether a function is declared in the included header files and compile different portions of code depending on whether that particular function is available or not?

#if ??????????????????????????????
unsigned long long get_tick_count(void) { return GetTickCount64(); }
#else
unsigned long long get_tick_count(void) { return GetTickCount(); }
#endif

Looking for a working sample file not just hints.

Edit: I tried the following using gcc 3.4.5 from MinGW on a (64-bit) Windows 7 RC but it didn't help. If this is a MinGW problem, how can I work around this issue?

#include <windows.h>
#if (WINVER >= 0x0600)
unsigned long long get_tick_count(void) { return 600/*GetTickCount64()*/; }
#else
unsigned long long get_tick_count(void) { return 0/*GetTickCount()*/; }
#endif

Solution

  • Previous answers have pointed out checking for the particular #define that would be present for your particular case. This answer is for a more general case of compiling different code whether a function is available or not.

    Rather than trying to do everything in the C file itself, this is the sort of thing where configure scripts really shine. If you were running on linux, I would point you to the GNU Autotools without hesitation. I know there's ports available for Windows, at least if you're using Cygwin or MSYS, but I have no idea how effective they are.

    A simple (and very very ugly) script that could work if you have sh handy (I don't have a Windows setup handy to test this on) would look something like this:

    #!/bin/sh
    
    # First, create a .c file that tests for the existance of GetTickCount64()
    
    cat >conftest.c <<_CONFEOF
    #include <windows.h>
    int main() {
        GetTickCount64();
        return 0;
    }
    _CONFEOF
    
    # Then, try to actually compile the above .c file
    
    gcc conftest.c -o conftest.out
    
    # Check gcc's return value to determine if it worked.
    #   If it returns 0, compilation worked so set CONF_HASGETTICKCOUNT64
    #   If it doesn't return 0, there was an error, so probably no GetTickCount64()
    
    if [ $? -eq 0 ]
    then
        confdefs='-D CONF_HASGETTICKCOUNT64=1'
    fi
    
    # Now get rid of the temporary files we made.
    
    rm conftest.c
    rm conftest.out
    
    # And compile your real program, passing CONF_HASGETTICKCOUNT64 if it exists.
    
    gcc $confdefs yourfile.c
    

    This should be easy enough to translate into your scripting language of choice. If your program requires extra include paths, compiler flags, or whatever, make sure to add the necessary flags to both the test compile and the real compile.

    'yourfile.c' would look something like this:

    #include <windows.h>
    
    unsigned long long get_tick_count(void) {
    #ifdef CONF_HASGETTICKCOUNT64
      return GetTickCount64();
    #else
      return GetTickCount();
    #endif
    }