include(CMakeParseArguments) # cmake_parse_arguments function(gen_toolchain_definitions) set(function_name "gen_toolchain_definitions") set(function_synopsis "${function_name}(OUTPUT output [DEFINITIONS def1 def2 ...])") # parse arguments set(parse_prefix x) set(optional_value_args "") set(one_value_args OUTPUT) set(multi_value_args DEFINITIONS) cmake_parse_arguments(${parse_prefix} "" "${one_value_args}" "${multi_value_args}" ${ARGV}) # No free arguments allowed list(LENGTH x_UNPARSED_ARGUMENTS x_len) if(NOT x_len EQUAL 0) message(FATAL_ERROR "'${function_name}' incorrect usage," " expected no free arguments '${x_UNPARSED_ARGUMENTS}'." " Synopsis: ${function_synopsis}" ) endif() # option OUTPUT is mandatory string(COMPARE EQUAL "${x_OUTPUT}" "" is_empty) if(is_empty) message(FATAL_ERROR "'${function_name}' incorrect usage," " option 'OUTPUT' with one argument is mandatory." " Synopsis: ${function_synopsis}" ) endif() string(FIND "${x_OUTPUT}" " " x_OUTPUT_whitespace_position) if(NOT x_OUTPUT_whitespace_position EQUAL -1) message(FATAL_ERROR "'${function_name}' incorrect usage," " definition '${x_OUTPUT}' with whitespaces not allowed." ) endif() # option DEFINITIONS has default values string(COMPARE EQUAL "${x_DEFINITIONS}" "" is_empty) if(is_empty) # set default values for DEFINITIONS set(x_DEFINITIONS # architectures __amd64__ _WIN64 __i386__ _WIN32 _WIN32_WINNT __arm__ __aarch64__ # compiler: MINGW __MINGW32__ __MINGW64__ # compiler: gcc __GNUC__ #// major __GNUC_MINOR__ #// minor __GNUC_PATCHLEVEL__ #// patch # compiler: MSVC _MSC_BUILD _MSC_EXTENSIONS _MSC_FULL_VER _MSC_VER ) endif() set(toolchain_working_dir "${CMAKE_BINARY_DIR}/_toolchain_definitions") set(toolchain_definitions_file "${toolchain_working_dir}/print_toolchain_definitions.cpp") # create temporary print_toolchain_definitions.cpp file file(WRITE ${toolchain_definitions_file} "// This file is automatically generated by '${function_name}'\n" "// do not edit!\n" "\n" "#define DEF_QUOTE(x) #x\n" "#define DEF_STRING(x) DEF_QUOTE(x)\n" "#define DEF_INFO(x) \\\n" " \"__DEF_MACRO_CHECK_BEGIN__\" \\\n" " \"#define \" #x \" \" DEF_STRING(x) \\\n" " \"__DEF_MACRO_CHECK_END__\"\n" "\n" "#include // Check std library version\n" "\n" "#if defined(__ANDROID__)\n" "# include // Header with __ANDROID_API__\n" "#endif\n" "\n" "#if defined(_MSC_VER)\n" "# include // Header with _WIN32_WINNT\n" "#endif\n" "\n" ) foreach(def ${x_DEFINITIONS}) file(APPEND ${toolchain_definitions_file} "#if defined(${def})\n" "# pragma message(DEF_INFO(${def}))\n" "#endif\n" "\n" ) endforeach() # add main function to successfully compile file(APPEND ${toolchain_definitions_file} "int main() {\n" "}\n" ) # compile toolchain-definitions file try_compile( try_compile_result "${toolchain_working_dir}" "${toolchain_definitions_file}" CMAKE_FLAGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" OUTPUT_VARIABLE outresult ) if(NOT try_compile_result) message(FATAL_ERROR "Compilation of '${toolchain_definitions_file}' failed. Result: ${try_compile_result}\n" "Output:\n--- OUTPUT BEGIN ---\n${outresult}\n--- OUTPUT END ---" ) endif() # split result string into list of strings set(string_in "${outresult}") set(list_of_strings "") while(TRUE) string(COMPARE EQUAL "${string_in}" "" is_empty) if(is_empty) break() endif() string(FIND "${string_in}" "\n" eol_pos) if(eol_pos EQUAL -1) list(APPEND list_of_strings "${string_in}") break() endif() string(SUBSTRING "${string_in}" 0 ${eol_pos} substring) list(APPEND list_of_strings "${substring}") math(EXPR eol_pos "${eol_pos} + 1") # Skip EOL character string(SUBSTRING "${string_in}" ${eol_pos} -1 string_in) endwhile() # convert list of strings to defines readable by check_toolchain_definition set(definitions "") foreach(x ${list_of_strings}) string( REGEX MATCH "__DEF_MACRO_CHECK_BEGIN__.*__DEF_MACRO_CHECK_END__" result_x "${x}" ) if(result_x) string( REGEX REPLACE ".*__DEF_MACRO_CHECK_BEGIN__\(.*\)__DEF_MACRO_CHECK_END__.*" "\\1" result_x "${x}" ) set(definitions "${definitions}${result_x}\n") endif() endforeach() set(${x_OUTPUT} ${definitions} PARENT_SCOPE) endfunction()