################################################################################ # # CPPAN macros and functions # ################################################################################ ######################################## # FUNCTION set_win32 ######################################## function(set_win32 var) if (WIN32) set(${var} "${ARGN}" PARENT_SCOPE) endif() endfunction(set_win32) ######################################## # FUNCTION set_unix ######################################## function(set_unix var) if (UNIX) set(${var} "${ARGN}" PARENT_SCOPE) endif() endfunction(set_unix) ######################################## # FUNCTION set_apple ######################################## function(set_apple var) if (APPLE) set(${var} "${ARGN}" PARENT_SCOPE) endif() endfunction(set_apple) ######################################## # FUNCTION add_src ######################################## function(add_src var) list(APPEND src ${SDIR}/${var}) set(src ${src} PARENT_SCOPE) endfunction(add_src) ######################################## # FUNCTION add_src_win32 ######################################## function(add_src_win32 var) if (WIN32) list(APPEND src ${SDIR}/${var}) set(src ${src} PARENT_SCOPE) endif() endfunction(add_src_win32) ######################################## # FUNCTION add_src_unix ######################################## function(add_src_unix var) if (UNIX) list(APPEND src ${SDIR}/${var}) set(src ${src} PARENT_SCOPE) endif() endfunction(add_src_unix) ######################################## # FUNCTION add_src_unix_not_apple ######################################## function(add_src_unix_not_apple var) if (UNIX AND NOT APPLE) list(APPEND src ${SDIR}/${var}) set(src ${src} PARENT_SCOPE) endif() endfunction(add_src_unix_not_apple) ######################################## # FUNCTION add_src_apple ######################################## function(add_src_apple var) if (APPLE) list(APPEND src ${SDIR}/${var}) set(src ${src} PARENT_SCOPE) endif() endfunction(add_src_apple) ######################################## # FUNCTION add_src_dir ######################################## function(add_src_dir var) file(GLOB_RECURSE add ${SDIR}/${var}) if (add) set(src ${src} ${add} PARENT_SCOPE) endif() endfunction(add_src_dir) ######################################## # FUNCTION remove_src ######################################## function(remove_src var) if (src) list(REMOVE_ITEM src ${SDIR}/${var}) set(src ${src} PARENT_SCOPE) endif() endfunction(remove_src) ######################################## # FUNCTION remove_src_win32 ######################################## function(remove_src_win32 var) if (WIN32 AND src) list(REMOVE_ITEM src ${SDIR}/${var}) set(src ${src} PARENT_SCOPE) endif() endfunction(remove_src_win32) ######################################## # FUNCTION remove_src_unix ######################################## function(remove_src_unix var) if (UNIX AND src) list(REMOVE_ITEM src ${SDIR}/${var}) set(src ${src} PARENT_SCOPE) endif() endfunction(remove_src_unix) ######################################## # FUNCTION remove_src_dir ######################################## function(remove_src_dir var) file(GLOB_RECURSE rm ${SDIR}/${var}) if (rm AND src) list(REMOVE_ITEM src ${rm}) set(src ${src} PARENT_SCOPE) endif() endfunction(remove_src_dir) ######################################## # FUNCTION remove_src_dir_regex ######################################## function(remove_src_dir_regex var) if (src) list(FILTER src EXCLUDE REGEX "${var}") set(src ${src} PARENT_SCOPE) endif() endfunction(remove_src_dir_regex) ######################################## # FUNCTION project_group ######################################## function(project_group target name) set_target_properties(${target} PROPERTIES FOLDER ${name}) endfunction(project_group) ######################################## # FUNCTION file_write_safe ######################################## function(file_write_safe f c) set(lock ${f}.lock) file( LOCK ${lock} GUARD FUNCTION # CMake bug workaround https://gitlab.kitware.com/cmake/cmake/issues/16295 RESULT_VARIABLE lock_result ) file(WRITE ${f} "${c}") file(LOCK ${lock} RELEASE) endfunction(file_write_safe) ######################################## # FUNCTION find_flag ######################################## function(find_flag in_flags f out) if (NOT "${${out}}" STREQUAL "") return() endif() if ("${in_flags}" STREQUAL "") set(${out} 0 PARENT_SCOPE) return() endif() set(flags ${in_flags}) string(TOLOWER ${f} f) string(TOLOWER ${flags} flags) string(FIND "${flags}" "${f}" flags) if (NOT ${flags} EQUAL -1) set(${out} 1 PARENT_SCOPE) else() set(${out} 0 PARENT_SCOPE) endif() endfunction(find_flag) ######################################## # FUNCTION prepare_config_part ######################################## function(prepare_config_part o i) if (NOT i) return() endif() string(REPLACE " " "_" i "${i}") string(REPLACE "${CPPAN_CONFIG_PART_DELIMETER}" "_" i "${i}") string(TOLOWER ${i} i) set(${o} "${i}" PARENT_SCOPE) endfunction(prepare_config_part) ######################################## # FUNCTION get_config_hash ######################################## function(get_config_hash c o) string(${CPPAN_CONFIG_HASH_METHOD} h "${c}") string(SUBSTRING "${h}" 0 ${CPPAN_CONFIG_HASH_SHORT_LENGTH} h) set(${o} "${h}" PARENT_SCOPE) endfunction(get_config_hash) ######################################## # FUNCTION get_configuration_unhashed ######################################## function(get_configuration_unhashed out) set(mt_flag) if (MSVC) find_flag("${CMAKE_C_FLAGS_RELEASE}" /MT C_MTR ) find_flag("${CMAKE_C_FLAGS_RELWITHDEBINFO}" /MT C_MTRWDI ) find_flag("${CMAKE_C_FLAGS_MINSIZEREL}" /MT C_MTMSR ) find_flag("${CMAKE_C_FLAGS_DEBUG}" /MTd C_MTD ) find_flag("${CMAKE_CXX_FLAGS_RELEASE}" /MT CXX_MTR ) find_flag("${CMAKE_CXX_FLAGS_RELWITHDEBINFO}" /MT CXX_MTRWDI ) find_flag("${CMAKE_CXX_FLAGS_MINSIZEREL}" /MT CXX_MTMSR ) find_flag("${CMAKE_CXX_FLAGS_DEBUG}" /MTd CXX_MTD ) if ( C_MTR OR C_MTRWDI OR C_MTMSR OR C_MTD OR CXX_MTR OR CXX_MTRWDI OR CXX_MTMSR OR CXX_MTD) set(mt_flag ${CPPAN_CONFIG_PART_DELIMETER}mt) set(CPPAN_MT_BUILD 1 CACHE STRING "MT (static crt) flag" FORCE) else() set(CPPAN_MT_BUILD 0 CACHE STRING "MT (static crt) flag" FORCE) endif() endif() prepare_config_part(system "${CMAKE_SYSTEM_NAME}") prepare_config_part(processor "${CMAKE_SYSTEM_PROCESSOR}") prepare_config_part(compiler "${CMAKE_CXX_COMPILER_ID}") set(config ${system}${CPPAN_CONFIG_PART_DELIMETER}${processor}${CPPAN_CONFIG_PART_DELIMETER}${compiler}) string(REGEX MATCH "[0-9]+\\.[0-9]+" version "${CMAKE_CXX_COMPILER_VERSION}") if (CMAKE_SIZEOF_VOID_P) math(EXPR bits "${CMAKE_SIZEOF_VOID_P} * 8") elseif(SIZEOF_VOID_P) math(EXPR bits "${SIZEOF_VOID_P} * 8") else() set(bits unk) endif() set(sysver) if (CMAKE_SYSTEM_VERSION AND (WIN32 OR APPLE)) # apple too? prepare_config_part(sysver "${CMAKE_SYSTEM_VERSION}") set(sysver ${CPPAN_CONFIG_PART_DELIMETER}${sysver}) endif() set(dll) if (CPPAN_BUILD_SHARED_LIBS) set(dll ${CPPAN_CONFIG_PART_DELIMETER}dll) endif() set(toolset) if (CMAKE_GENERATOR_TOOLSET) prepare_config_part(toolset "${CMAKE_GENERATOR_TOOLSET}") set(toolset ${CPPAN_CONFIG_PART_DELIMETER}${toolset}) endif() if (VISUAL_STUDIO_ACCELERATE_CLANG AND CPPAN_GET_CHILDREN_VARIABLES) set(toolset) endif() # msvc arch # it can be same as ${bits} # but still it is set explicitly for some rare cases set(msvc_arch) if (MSVC) set(msvc_c_arch) if (MSVC_C_ARCHITECTURE_ID) prepare_config_part(msvc_c_arch "${MSVC_C_ARCHITECTURE_ID}") set(msvc_c_arch ${CPPAN_CONFIG_PART_DELIMETER}${msvc_c_arch}) endif() set(msvc_cxx_arch) if (MSVC_CXX_ARCHITECTURE_ID) prepare_config_part(msvc_cxx_arch "${MSVC_CXX_ARCHITECTURE_ID}") set(msvc_cxx_arch ${CPPAN_CONFIG_PART_DELIMETER}${msvc_cxx_arch}) endif() if ("${msvc_c_arch}" STREQUAL "${msvc_cxx_arch}") set(msvc_arch ${msvc_c_arch}) else() set(msvc_arch ${msvc_c_arch}${msvc_cxx_arch}) endif() endif() # *nix arch set(nix_arch) if (CMAKE_C_LIBRARY_ARCHITECTURE OR CMAKE_CXX_LIBRARY_ARCHITECTURE) set(nix_c_arch) if (CMAKE_C_LIBRARY_ARCHITECTURE) prepare_config_part(nix_c_arch "${CMAKE_C_LIBRARY_ARCHITECTURE}") set(nix_c_arch ${CPPAN_CONFIG_PART_DELIMETER}${nix_c_arch}) endif() set(nix_cxx_arch) if (CMAKE_CXX_LIBRARY_ARCHITECTURE) prepare_config_part(nix_cxx_arch "${CMAKE_CXX_LIBRARY_ARCHITECTURE}") set(nix_cxx_arch ${CPPAN_CONFIG_PART_DELIMETER}${nix_cxx_arch}) endif() if ("${nix_c_arch}" STREQUAL "${nix_cxx_arch}") set(nix_arch ${nix_c_arch}) else() set(nix_arch ${nix_c_arch}${nix_cxx_arch}) endif() endif() # add suffix (configuration) to distinguish build types # for non VS/XCODE builds set(configuration) if (NOT (XCODE OR VISUAL_STUDIO)) if (CMAKE_BUILD_TYPE)# AND NOT CPPAN_CONFIG_NO_BUILD_TYPE) set(configuration ${CPPAN_CONFIG_PART_DELIMETER}${CMAKE_BUILD_TYPE}) endif() endif() if (VISUAL_STUDIO_ACCELERATE_CLANG AND CPPAN_GET_CHILDREN_VARIABLES)# AND NOT CPPAN_CONFIG_NO_BUILD_TYPE) set(configuration ${CPPAN_CONFIG_PART_DELIMETER}${CMAKE_BUILD_TYPE}) endif() set(config ${config}${CPPAN_CONFIG_PART_DELIMETER}${version}) set(config ${config}${CPPAN_CONFIG_PART_DELIMETER}${bits}${nix_arch}${msvc_arch}${mt_flag}${dll}${sysver}${toolset}) set(config ${config}${configuration}) set(${out} ${config} PARENT_SCOPE) endfunction(get_configuration_unhashed) ######################################## # FUNCTION get_configuration_with_generator_unhashed ######################################## function(get_configuration_with_generator_unhashed out) get_configuration_unhashed(config) prepare_config_part(generator "${CMAKE_GENERATOR}") if (NOT "${generator}" STREQUAL "") if (VISUAL_STUDIO_ACCELERATE_CLANG AND CPPAN_GET_CHILDREN_VARIABLES) # fake ninja generator to get correct config for deps building set(config ${config}${CPPAN_CONFIG_PART_DELIMETER}ninja) else() set(config ${config}${CPPAN_CONFIG_PART_DELIMETER}${generator}) endif() endif() set(${out} ${config} PARENT_SCOPE) endfunction(get_configuration_with_generator_unhashed) ######################################## # FUNCTION get_configuration_exe_unhashed ######################################## function(get_configuration_exe_unhashed out) if (NOT NINJA AND NOT UNIX) get_configuration_unhashed(config) set(${out} ${config} PARENT_SCOPE) return() endif() prepare_config_part(system "${CMAKE_SYSTEM_NAME}") prepare_config_part(processor "${CMAKE_HOST_SYSTEM_PROCESSOR}") set(config ${system}${CPPAN_CONFIG_PART_DELIMETER}${processor}) # add generator to executables since we're using the same generator as for libraries prepare_config_part(generator "${CMAKE_GENERATOR}") if (NOT "${generator}" STREQUAL "") if (VISUAL_STUDIO_ACCELERATE_CLANG AND CPPAN_GET_CHILDREN_VARIABLES) # fake ninja generator to get correct config for deps building set(config ${config}${CPPAN_CONFIG_PART_DELIMETER}ninja) else() set(config ${config}${CPPAN_CONFIG_PART_DELIMETER}${generator}) endif() endif() set(${out} ${config} PARENT_SCOPE) endfunction(get_configuration_exe_unhashed) ######################################## # FUNCTION get_configuration_variables_unhashed ######################################## function(get_configuration_variables_unhashed) get_configuration_unhashed(config_lib) get_configuration_with_generator_unhashed(config_lib_gen) get_configuration_exe_unhashed(config_exe) if (NOT EXECUTABLE) set(config ${config_lib}) set(config_dir ${config_lib_gen}) else() set(config ${config_exe}) set(config_dir ${config_exe}) endif() set(config_unhashed ${config} PARENT_SCOPE) set(config_lib_unhashed ${config_lib} PARENT_SCOPE) set(config_lib_gen_unhashed ${config_lib_gen} PARENT_SCOPE) set(config_exe_unhashed ${config_exe} PARENT_SCOPE) set(config_dir_unhashed ${config_dir} PARENT_SCOPE) endfunction(get_configuration_variables_unhashed) ######################################## # FUNCTION get_configuration ######################################## function(get_configuration out) get_configuration_unhashed(config) get_config_hash(${config} config) set(${out} ${config} PARENT_SCOPE) endfunction(get_configuration) ######################################## # FUNCTION get_configuration_with_generator ######################################## function(get_configuration_with_generator out) get_configuration_with_generator_unhashed(config) get_config_hash(${config} config) set(${out} ${config} PARENT_SCOPE) endfunction(get_configuration_with_generator) ######################################## # FUNCTION get_configuration_exe ######################################## function(get_configuration_exe out) get_configuration_exe_unhashed(config) get_config_hash(${config} config) set(${out} ${config} PARENT_SCOPE) endfunction(get_configuration_exe) ######################################## # FUNCTION get_configuration_variables ######################################## function(get_configuration_variables) get_configuration(config_lib) get_configuration_with_generator(config_lib_gen) get_configuration_exe(config_exe) if (NOT EXECUTABLE) set(config ${config_lib}) set(config_dir ${config_lib_gen}) else() set(config ${config_exe}) set(config_dir ${config_exe}) endif() set(config ${config} PARENT_SCOPE) set(config_lib ${config_lib} PARENT_SCOPE) set(config_lib_gen ${config_lib_gen} PARENT_SCOPE) set(config_exe ${config_exe} PARENT_SCOPE) set(config_dir ${config_dir} PARENT_SCOPE) endfunction(get_configuration_variables) ######################################## # FUNCTION get_number_of_cores ######################################## function(get_number_of_cores NC) include(ProcessorCount) ProcessorCount(N) if(N EQUAL 0) set(N 2) endif() set(${NC} ${N} PARENT_SCOPE) endfunction(get_number_of_cores) ######################################## # FUNCTION add_variable ######################################## function(add_variable array variable) list(FIND ${array}_KEYS "${variable}" found) if(NOT found EQUAL -1) # check if new value is active, then replace list(GET ${array}_VALUES ${found} v) if (NOT v AND ${variable}) #message(STATUS "Replacing element in array") #message(STATUS "Old value: ${v}") #message(STATUS "New value: ${${variable}}") #message(STATUS "Old array: ${${array}_VALUES}") list(REMOVE_AT ${array}_VALUES ${found}) list(INSERT ${array}_VALUES ${found} "${${variable}}") #message(STATUS "New array: ${${array}_VALUES}") set(${array}_VALUES ${${array}_VALUES} CACHE STRING "Cached array." FORCE) endif() return() endif() list(APPEND ${array}_TYPES "STRING") list(APPEND ${array}_KEYS "${variable}") if ("${${variable}}" STREQUAL "") list(APPEND ${array}_VALUES "0") else() list(APPEND ${array}_VALUES "${${variable}}") endif() set(${array}_TYPES ${${array}_TYPES} CACHE STRING "Cached array." FORCE) set(${array}_KEYS ${${array}_KEYS} CACHE STRING "Cached array." FORCE) set(${array}_VALUES ${${array}_VALUES} CACHE STRING "Cached array." FORCE) endfunction(add_variable) ######################################## # FUNCTION clear_variables ######################################## function(clear_variables array) unset(${array}_TYPES CACHE) unset(${array}_KEYS CACHE) unset(${array}_VALUES CACHE) endfunction(clear_variables) ######################################## # FUNCTION read_variables_file ######################################## function(read_variables_file array f) if (NOT EXISTS ${f}) return() endif() set(lock ${f}.lock) file( LOCK ${lock} GUARD FUNCTION # CMake bug workaround https://gitlab.kitware.com/cmake/cmake/issues/16295 RESULT_VARIABLE lock_result ) if (NOT ${lock_result} EQUAL 0) message(FATAL_ERROR "Lock error: ${lock_result}") endif() file(STRINGS ${f} vars) file(LOCK ${lock} RELEASE) list(LENGTH vars N) if (N EQUAL 0) return() endif() math(EXPR N "${N}-1") foreach(i RANGE ${N}) list(GET vars ${i} var) list(GET var 0 t) list(GET var 1 k) list(GET var 2 v) set(${k} "${v}" CACHE ${t} "Cached variable" FORCE) add_variable(${array} ${k}) endforeach() set(${array}_TYPES ${${array}_TYPES} CACHE STRING "Cached array." FORCE) set(${array}_KEYS ${${array}_KEYS} CACHE STRING "Cached array." FORCE) set(${array}_VALUES ${${array}_VALUES} CACHE STRING "Cached array." FORCE) endfunction(read_variables_file) ######################################## # FUNCTION write_variables_file ######################################## function(write_variables_file array f) set(lock ${f}.lock) file( LOCK ${lock} GUARD FUNCTION # CMake bug workaround https://gitlab.kitware.com/cmake/cmake/issues/16295 RESULT_VARIABLE lock_result ) if (NOT ${lock_result} EQUAL 0) message(FATAL_ERROR "Lock error: ${lock_result}") endif() list(LENGTH ${array}_TYPES N) math(EXPR N "${N}-1") file(WRITE ${f} "") foreach(i RANGE ${N}) list(GET ${array}_TYPES ${i} type) list(GET ${array}_KEYS ${i} key) list(GET ${array}_VALUES ${i} value) set(vars "${type}" "${key}" "${value}") file(APPEND ${f} "${vars}\n") endforeach() file(LOCK ${lock} RELEASE) endfunction(write_variables_file) ######################################## # FUNCTION add_check_variable ######################################## function(add_check_variable v) add_variable(CPPAN_VARIABLES ${v}) set(CPPAN_NEW_VARIABLE_ADDED 1 PARENT_SCOPE) endfunction(add_check_variable) ######################################## # FUNCTION read_check_variables_file ######################################## function(read_check_variables_file f) read_variables_file(CPPAN_VARIABLES ${f}) endfunction(read_check_variables_file) ######################################## # FUNCTION write_check_variables_file ######################################## function(write_check_variables_file f) write_variables_file(CPPAN_VARIABLES ${f}) endfunction(write_check_variables_file) ######################################## # FUNCTION set_c_sources_as_cpp ######################################## function(set_c_sources_as_cpp) if (MSVC) file(GLOB_RECURSE csrc "*.c") set_source_files_properties(${csrc} PROPERTIES LANGUAGE CXX) endif() endfunction(set_c_sources_as_cpp) ######################################## # FUNCTION add_win32_version_info ######################################## function(add_win32_version_info dir) if (WIN32 OR CYGWIN) if (NOT EXECUTABLE AND NOT LIBRARY_TYPE STREQUAL SHARED) return() endif() if (NOT CYGWIN) # cygwin won't have this var, so it will be eliminated from rc file set(PACKAGE_BUILD_CONFIG PACKAGE_BUILD_CONFIG) endif() if (PACKAGE_IS_BRANCH) set(rcfile_in ${STORAGE_DIR_ETC_STATIC}/branch.rc.in) else(PACKAGE_IS_VERSION) set(rcfile_in ${STORAGE_DIR_ETC_STATIC}/version.rc.in) endif() set(rcfile ${CMAKE_CURRENT_BINARY_DIR}/version.rc) configure_file(${rcfile_in} ${rcfile} @ONLY) set(src ${src} ${rcfile} PARENT_SCOPE) endif() endfunction(add_win32_version_info) ######################################## # FUNCTION check_result_variable ######################################## function(check_result_variable ret) if (${ret} EQUAL 0) return() endif() message(FATAL_ERROR "Last execute_process() with message '${ARGN}' failed with error: ${ret}") endfunction(check_result_variable) ######################################## # FUNCTION file_write_once ######################################## function(file_write_once f c) # multiple instances safe set(once ${f}.cppan.once) string(SHA1 h "${c}") if (NOT EXISTS ${once}) file_write_safe(${f} "${c}") file_write_safe(${once} "${h}") return() endif() file(READ ${once} h2) if (NOT "${h}" STREQUAL "${h2}") file_write_safe(${f} "${c}") file_write_safe(${once} "${h}") return() endif() endfunction(file_write_once) ######################################## # FUNCTION replace_in_file_once ######################################## # TODO: create files in BDIR function(replace_in_file_once f from to) string(SHA1 h "${f}${from}${to}") string(SUBSTRING "${h}" 0 5 h) # cannot set this file to bdir because multiple configs use # different bdirs and will do multiple replacements set(h ${f}.${h}) set(ch ${f}.cppan.hash) if (EXISTS ${h} AND EXISTS ${ch}) file(READ ${ch} h2) file(READ ${f} fc) string(SHA1 h3 "${fc}") if ("${h2}" STREQUAL "${h3}") return() endif() endif() set(lock ${f}.lock) file( LOCK ${lock} GUARD FUNCTION # CMake bug workaround https://gitlab.kitware.com/cmake/cmake/issues/16295 RESULT_VARIABLE lock_result ) if (NOT ${lock_result} EQUAL 0) message(FATAL_ERROR "Lock error: ${lock_result}") endif() # double check if (EXISTS ${h} AND EXISTS ${ch}) file(READ ${ch} h2) file(READ ${f} fc) string(SHA1 h3 "${fc}") if ("${h2}" STREQUAL "${h3}") return() endif() endif() file(READ ${f} fc) string(REPLACE "${from}" "${to}" fc "${fc}") string(SHA1 h2 "${fc}") file(WRITE "${f}" "${fc}") # create flag file file(WRITE ${h} "") file(WRITE ${ch} "${h2}") endfunction(replace_in_file_once) ######################################## # FUNCTION delete_in_file_once ######################################## function(delete_in_file_once f from) replace_in_file_once(${f} "${from}" "") endfunction(delete_in_file_once) ######################################## # FUNCTION push_front_to_file_once ######################################## function(push_front_to_file_once f what) string(SHA1 h "${f}${what}") string(SUBSTRING "${h}" 0 5 h) # cannot set this file to bdir because multiple configs use # different bdirs and will do multiple replacements set(h ${f}.${h}) set(ch ${f}.cppan.hash) if (EXISTS ${h} AND EXISTS ${ch}) file(READ ${ch} h2) file(READ ${f} fc) string(SHA1 h3 "${fc}") if ("${h2}" STREQUAL "${h3}") return() endif() endif() set(lock ${f}.lock) file( LOCK ${lock} GUARD FUNCTION # CMake bug workaround https://gitlab.kitware.com/cmake/cmake/issues/16295 RESULT_VARIABLE lock_result ) if (NOT ${lock_result} EQUAL 0) message(FATAL_ERROR "Lock error: ${lock_result}") endif() # double check if (EXISTS ${h} AND EXISTS ${ch}) file(READ ${ch} h2) file(READ ${f} fc) string(SHA1 h3 "${fc}") if ("${h2}" STREQUAL "${h3}") return() endif() endif() file(READ ${f} fc) string(SHA1 h2 "${what}\n\n${fc}") file(WRITE "${f}" "${what}\n\n${fc}") # create flag file file(WRITE ${h} "") file(WRITE ${ch} "${h2}") endfunction(push_front_to_file_once) ######################################## # FUNCTION push_back_to_file_once ######################################## function(push_back_to_file_once f what) string(SHA1 h "${f}${what}") string(SUBSTRING "${h}" 0 5 h) # cannot set this file to bdir because multiple configs use # different bdirs and will do multiple replacements set(h ${f}.${h}) set(ch ${f}.cppan.hash) if (EXISTS ${h} AND EXISTS ${ch}) file(READ ${ch} h2) file(READ ${f} fc) string(SHA1 h3 "${fc}") if ("${h2}" STREQUAL "${h3}") return() endif() endif() set(lock ${f}.lock) file( LOCK ${lock} GUARD FUNCTION # CMake bug workaround https://gitlab.kitware.com/cmake/cmake/issues/16295 RESULT_VARIABLE lock_result ) if (NOT ${lock_result} EQUAL 0) message(FATAL_ERROR "Lock error: ${lock_result}") endif() # double check if (EXISTS ${h} AND EXISTS ${ch}) file(READ ${ch} h2) file(READ ${f} fc) string(SHA1 h3 "${fc}") if ("${h2}" STREQUAL "${h3}") return() endif() endif() file(READ ${f} fc) string(SHA1 h2 "${fc}\n\n${what}") file(WRITE "${f}" "${fc}\n\n${what}") # create flag file file(WRITE ${h} "") file(WRITE ${ch} "${h2}") endfunction(push_back_to_file_once) ######################################## # FUNCTION copy_file_once ######################################## # this functions prevents changing variables in current scope function(copy_file_once from to) if (NOT EXISTS ${to}) execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${from} ${to}) endif() endfunction(copy_file_once) ######################################## # FUNCTION cppan_include ######################################## # this functions prevents changing variables in current scope function(cppan_include f) include(${f}) endfunction(cppan_include) ######################################## # FUNCTION check_type_alignment ######################################## function(check_type_alignment TYPE LANG NAME) if (DEFINED ${NAME}) return() endif() message(STATUS "Check alignment of ${TYPE} in ${LANG}") set(INCLUDE_HEADERS "#include #include #include ") foreach(f ${CMAKE_REQUIRED_INCLUDES}) set(INCLUDE_HEADERS "${INCLUDE_HEADERS}\n#include <${f}>\n") endforeach() if (HAVE_STDINT_H) set(INCLUDE_HEADERS "${INCLUDE_HEADERS}\n#include \n") endif() file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/c_get_${NAME}_alignment.${LANG}" "${INCLUDE_HEADERS} int main() { char diff; struct foo {char a; ${TYPE} b;}; struct foo *p = (struct foo *) malloc(sizeof(struct foo)); diff = ((char *)&p->b) - ((char *)&p->a); return diff; }" ) try_run(${NAME} COMPILE_RESULT "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/c_get_${NAME}_alignment.${LANG}" COMPILE_OUTPUT_VARIABLE "${NAME}_COMPILE_VAR") message(STATUS "Check alignment of ${TYPE} in ${LANG}: ${${NAME}}") set(${NAME} ${${NAME}} CACHE STRING "Alignment of type: ${TYPE}" FORCE) endfunction(check_type_alignment) ######################################## # FUNCTION find_moc_targets ######################################## function(find_moc_targets out) set(o) foreach(fn ${ARGN}) file(READ ${fn} f) string(FIND "${f}" "Q_OBJECT" i) if (NOT ${i} EQUAL -1) set(o ${o} ${fn}) else() string(FIND "${f}" "Q_GADGET" i) if (NOT ${i} EQUAL -1) set(o ${o} ${fn}) endif() endif() endforeach() set(${out} ${o} PARENT_SCOPE) endfunction() ######################################## # FUNCTION set_src_header_only ######################################## function(set_src_header_only s) set(src2 ${src}) list(FILTER src2 INCLUDE REGEX "${s}") list(LENGTH src2 N) if (N EQUAL 0) return() endif() set_source_files_properties(${src2} PROPERTIES HEADER_FILE_ONLY True) #set(src ${src} ${src2} PARENT_SCOPE) endfunction() ######################################## # FUNCTION set_src_compiled ######################################## function(set_src_compiled s) set(src2 ${src}) list(FILTER src2 INCLUDE REGEX "${s}") list(LENGTH src2 N) if (N EQUAL 0) return() endif() if (${ARGC} GREATER 1) set_source_files_properties(${src2} PROPERTIES LANGUAGE ${ARGV1}) else() set_source_files_properties(${src2} PROPERTIES LANGUAGE CXX) endif() set_source_files_properties(${src2} PROPERTIES HEADER_FILE_ONLY False) #set(src ${src} ${src2} PARENT_SCOPE) endfunction() ######################################## # FUNCTION moc_cpp_file ######################################## function(moc_cpp_file f) get_filename_component(n ${f} NAME_WE) qt5_create_moc_command(${SDIR}/${f} ${BDIR}/${n}.moc "" "" ${this} "") set(src ${src} ${BDIR}/${n}.moc PARENT_SCOPE) # not all mocs must be compiled #set_source_files_properties(${BDIR}/${n}.moc PROPERTIES LANGUAGE CXX) endfunction() ######################################## # FUNCTION create_directory ######################################## function(create_directory d) execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${d}) endfunction() ######################################## # FUNCTION set_cache_var ######################################## function(set_cache_var variable value) set(${variable} ${value} CACHE STRING "" FORCE) endfunction() ######################################## # FUNCTION clear_once_variables ######################################## function(clear_once_variables) #message(STATUS "clear_once_variables - ${CPPAN_ONCE_VARIABLES}") if (NOT CPPAN_ONCE_VARIABLES) return() endif() foreach(v ${CPPAN_ONCE_VARIABLES}) #message(STATUS "unsetting ${v}") unset(${v} CACHE) endforeach() endfunction() ######################################## # FUNCTION set_once_var ######################################## function(set_once_var variable) set_cache_var(${variable} 1) set(CPPAN_ONCE_VARIABLES ${CPPAN_ONCE_VARIABLES} ${variable} CACHE STRING "" FORCE) endfunction() ######################################## # FUNCTION cppan_flex_bison_internal ######################################## function(cppan_flex_bison_internal lexer) set(multiValueArgs LEXER_ARGS PARSERS PARSER_ARGS) cmake_parse_arguments(FB "" "" "${multiValueArgs}" ${ARGN}) set(bdir ${BDIR_PRIVATE}/fb) if (NOT WIN32) find_package(FLEX REQUIRED) find_package(BISON REQUIRED 3.0) set(bison ${BISON_EXECUTABLE}) set(flex ${FLEX_EXECUTABLE}) endif() # parsers set(parser_headers) foreach(parser ${FB_PARSERS}) get_filename_component(name ${parser} NAME) #get_filename_component(name_we ${parser} NAME_WE) set(d ${bdir}/${name}) execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${d}) add_custom_command(OUTPUT ${d}/${name}.cpp ${d}/${name}.hpp COMMAND ${bison} ${FB_PARSER_ARGS} #-Dapi.prefix={yy_${name_we}} -o ${d}/${name}.cpp --defines=${d}/${name}.hpp ${SDIR}/${parser} DEPENDS ${bison} ${SDIR}/${parser} WORKING_DIRECTORY ${d} ) target_include_directories(${this} PRIVATE ${d}) target_sources(${this} PRIVATE ${d}/${name}.cpp ${d}/${name}.hpp ${SDIR}/${parser} ) set(parser_headers ${parser_headers} ${d}/${name}.hpp) endforeach() # lexer get_filename_component(d ${lexer} DIRECTORY) execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${bdir}/${d}) add_custom_command(OUTPUT ${bdir}/${lexer}.cpp #${bdir}/${lexer}.h #COMMAND ${flex} -o ${bdir}/${lexer}.cpp --header-file=${lexer}.h ${SDIR}/${lexer} COMMAND ${flex} ${FB_LEXER_ARGS} -o ${bdir}/${lexer}.cpp ${SDIR}/${lexer} DEPENDS ${flex} ${SDIR}/${lexer} ${parser_headers} WORKING_DIRECTORY ${bdir} ) target_include_directories(${this} PRIVATE ${bdir}/${d}) target_sources(${this} PRIVATE ${bdir}/${lexer}.cpp #${bdir}/${lexer}.h ${SDIR}/${lexer} ) endfunction() ######################################## # MACRO cppan_generate_flex_bison_config ######################################## macro(cppan_generate_flex_bison_config) get_filename_component(dir ${name} DIRECTORY) get_filename_component(name2 ${name} NAME) set(name ${name2}) string(TOUPPER ${name} name_upper) string(SUBSTRING ${name} 0 1 first_letter) string(SUBSTRING ${name} 1 -1 rest) string(TOUPPER ${first_letter} first_letter) set(parser_name ${first_letter}${rest}Parser) set(parser_include ${BDIR_PRIVATE}/${name}_parser.h) set(parser_include_in ${parser_include}.in) file(WRITE ${parser_include_in} "#pragma once #undef THIS_PARSER_NAME #undef THIS_PARSER_NAME_UP #undef THIS_LEXER_NAME #undef THIS_LEXER_NAME_UP #define THIS_PARSER_NAME ${name} #define THIS_PARSER_NAME_UP ${name_upper} #define THIS_LEXER_NAME ${lexer_name} #define THIS_LEXER_NAME_UP ${lexer_name_up} #undef MY_PARSER #define MY_PARSER ${parser_name} #define ${type} #include #undef ${type} #include <${name}.yy.hpp> ") add_custom_command(OUTPUT ${parser_include} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${parser_include_in} ${parser_include} ) target_sources(${this} PRIVATE ${parser_include}) # set potential access to private fields target_compile_definitions(${this} PRIVATE HAVE_BISON_${name_upper}_PARSER) endmacro() ######################################## # FUNCTION cppan_flex_bison_pair ######################################## function(cppan_flex_bison_pair type name) set(lexer_name THIS_PARSER_NAME) set(lexer_name_up THIS_PARSER_NAME_UP) cppan_generate_flex_bison_config() # after include cppan_flex_bison_internal(${dir}/${name}.ll PARSERS ${dir}/${name}.yy LEXER_ARGS --prefix=ll_${name} PARSER_ARGS -Dapi.prefix={yy_${name}}) endfunction() ######################################## # FUNCTION cppan_flex_bison_multiple_parsers ######################################## function(cppan_flex_bison_multiple_parsers type lexer_name) message(FATAL_ERROR "not implemented") set(multiValueArgs PARSERS) cmake_parse_arguments(FB "" "" "${multiValueArgs}" ${ARGN}) get_filename_component(lexer_dir ${lexer_name} DIRECTORY) get_filename_component(lexer_name ${lexer_name} NAME) string(TOUPPER ${lexer_name} lexer_name_up) set(PARSERS) foreach(p ${FB_PARSERS}) set(name ${p}) cppan_generate_flex_bison_config() set(PARSERS ${PARSERS} ${dir}/${name}.yy) endforeach() # after include cppan_flex_bison_internal(${dir}/${name}.ll PARSERS ${PARSERS} LEXER_ARGS --prefix=ll_${name}) endfunction() ################################################################################