# - Finds C99 standard support # This internally calls the check_c_source_compiles macro to determine the # appropriate flags for a C99 standard compilation. #============================================================================= # Copyright 2013 Ian Liu Rodrigues # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . #============================================================================= include(CheckCSourceCompiles) set(C99_C_TEST_SOURCE "#include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug (\"Flag\"); debug (\"X = %d\\\\n\", x); showlist (The first, second, and third items.); report (x>y, \"x is %d but y is %d\", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK your preprocessor is broken; #endif #if BIG_OK #else your preprocessor is broken; #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\\\\0'; ++i) continue; return 0; } // Check varargs and va_copy. static _Bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = NULL; int number = 0; float fnumber = 0.0; while (*format) { switch (*format++) { case 's': // string str = va_arg (args_copy, const char *); break; case 'd': // int number = va_arg (args_copy, int); break; case 'f': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return (number != 0) && (str != NULL) && (fnumber != 0.0); } int main () { // Check bool. _Bool success = false; // Check restrict. if (test_restrict (\"String literal\") == 0) success = true; char *restrict newvar = \"Another string\"; // Check varargs. if (!test_varargs (\"s, d' f .\", \"string\", 65, 34.234)) success = false; test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L\"Test wide string\", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ; return 0; }") set(C99_C_FLAG_CANDIDATES " " "-std=gnu99" "-c99" "-AC99" "-xc99=all" "-qlanglvl=extc99" ) if(DEFINED C99_C_FLAGS) set(C99_C_FLAG_CANDIDATES) endif(DEFINED C99_C_FLAGS) set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") foreach(FLAG ${C99_C_FLAG_CANDIDATES}) set(CMAKE_REQUIRED_FLAGS "${FLAG}") unset(C99_FLAG_DETECTED CACHE) message(STATUS "Try C99 C flag = [${FLAG}]") check_c_source_compiles("${C99_C_TEST_SOURCE}" C99_FLAG_DETECTED) if(C99_FLAG_DETECTED) set(C99_C_FLAGS_INTERNAL "${FLAG}") break() endif(C99_FLAG_DETECTED) endforeach(FLAG ${C99_C_FLAG_CANDIDATES}) set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}") set(C99_C_FLAGS "${C99_C_FLAGS_INTERNAL}" CACHE STRING "C compiler flags for C99 standard") mark_as_advanced(C99_C_FLAGS)