|
- # ==============================================================================
- #
- # Copyright 2020 <Huawei Technologies Co., Ltd>
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- # ==============================================================================
-
- # lint_cmake: -whitespace/indent
-
- include(CheckCompilerFlag OPTIONAL RESULT_VARIABLE _check_compiler_flag)
- if(NOT _check_compiler_flag)
- include(Internal/CMakeCheckCompilerFlag)
- endif()
-
- # Check if a language has been enabled without attempting to enable it
- #
- # is_language_enabled(<lang> <resultvar>)
- #
- # If the language <lang> has already been enabled, <resultvar> is set to TRUE. Otherwise it is set to FALSE.
- function(is_language_enabled _lang _var)
- get_property(_supported_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
- if(NOT _lang IN_LIST _supported_languages)
- set(${_var}
- FALSE
- PARENT_SCOPE)
- else()
- set(${_var}
- TRUE
- PARENT_SCOPE)
- endif()
- endfunction()
-
- # ==============================================================================
-
- # ~~~
- # Convenience function to test for the existence of some compiler flags for a a particular language
- #
- # check_compiler_flag(<lang> <var_prefix> <flags1> [<flags2>...])
- #
- # Check whether a compiler option is valid for the <lang> compiler. For each set of compiler options provided in the
- # lists <flagsN>, it will test whether one of the element can be used by the corresponding compiler. If a flag is valid,
- # it will be added to the GLOBAL property named <prefix>_<lang> as well as to a variable with the same name. If the
- # property already exists, any valid flag is appended to the current value.
- #
- # Each call to this function also sets the _added_count variable to the number of flags added automatically (if any).
- # ~~~
- function(check_compiler_flags lang var_prefix)
- # cmake-lint: disable=C0103,E1120
- set(_${lang}_opts)
-
- foreach(_flag_list ${ARGN})
- separate_arguments(_flag_list)
-
- foreach(_flag ${_flag_list})
- # Drop the first character (most likely either '-' or '/')
- string(SUBSTRING ${_flag} 1 -1 _flag_name)
- string(REGEX REPLACE "^-+" "" _flag_name ${_flag_name})
- string(REGEX REPLACE "[-:/,=]" "_" _flag_name ${_flag_name})
-
- cmake_check_compiler_flag(${lang} ${_flag} ${lang}_compiler_has_${_flag_name})
- if(${lang}_compiler_has_${_flag_name})
- list(APPEND _${lang}_opts ${_flag})
- break()
- endif()
- endforeach()
- endforeach()
-
- # Is there a property that already corresponds to this?
- get_property(_opts GLOBAL PROPERTY ${var_prefix}_${lang})
- if(_opts)
- list(APPEND _opts ${_${lang}_opts})
- else()
- define_property(
- GLOBAL
- PROPERTY ${var_prefix}_${lang}
- BRIEF_DOCS "Compiler flags for ${var_prefix}"
- FULL_DOCS "Compiler flags for ${var_prefix}")
- set(_opts ${_${lang}_opts})
- endif()
-
- # Set GLOBAL property so that other parts of the code can have access to it
- set_property(GLOBAL PROPERTY ${var_prefix}_${lang} ${_opts})
-
- list(LENGTH _${lang}_opts _added_count)
- set(_added_count
- ${_added_count}
- PARENT_SCOPE)
- set(_added_flags
- ${_${lang}_opts}
- PARENT_SCOPE)
-
- # Also set a variable for convenience
- set(${var_prefix}_${lang}
- ${_opts}
- PARENT_SCOPE)
- endfunction()
-
- # ~~~
- # Convenience function to test for the existence of some compiler flags for a set of languages.
- #
- # test_compile_option(<prefix>
- # LANGS <lang1> [<lang2>...]
- # FLAGS <flags1> [<flags2>...]
- # [AUTO_ADD_CO]
- # [GENEX <genex>])
- #
- # Check that a compiler option can be applied to each of the specified languages <lang>. For each set of compiler
- # options provided in the lists <flagsN>, it will test whether one of the element can be used by the corresponding
- # compiler. If a flag is valid, it will be added to the GLOBAL property named <prefix>_<lang> as well as to a variable
- # with the same name.
- # If AUTO_ADD_CO is specified, the compiler option will be automatically added globally using
- # add_compile_option(...). By default, the generator expression used in that function call restricts the compile option
- # to the current language (ie. $<$<COMPILE_LANGUAGE:@lang@>:${_flag}>). This can be changed by using the <genex>
- # argument (which defaults to "$<COMPILE_LANGUAGE:@lang@>").
- #
- # NB: This function calls check_compiler_flags() internally.
- #
- # ~~~
- function(test_compile_option prefix)
- cmake_parse_arguments(PARSE_ARGV 1 TEST_CO "AUTO_ADD_CO" "GENEX" "LANGS;FLAGS")
-
- if(NOT TEST_CO_LANGS)
- message(FATAL_ERROR "Missing LANGS argument")
- endif()
- if(NOT TEST_CO_FLAGS)
- message(FATAL_ERROR "Missing FLAGS argument")
- endif()
-
- if(NOT TEST_CO_GENEX)
- set(TEST_CO_GENEX "$<COMPILE_LANGUAGE:@lang@>")
- endif()
-
- # cmake-lint: disable=C0103
- foreach(lang ${TEST_CO_LANGS})
- is_language_enabled(${lang} _enabled)
- if(_enabled)
- check_compiler_flags(${lang} ${prefix} ${TEST_CO_FLAGS})
-
- set(${prefix}_${lang}
- ${${prefix}_${lang}}
- PARENT_SCOPE)
-
- if(TEST_CO_AUTO_ADD_CO AND _added_flags)
- string(CONFIGURE "${TEST_CO_GENEX}" _genex @ONLY)
- list(LENGTH ${prefix}_${lang} _L)
- math(EXPR _start_idx "${_L} - ${_added_count}")
- list(SUBLIST ${prefix}_${lang} ${_start_idx} -1 _added_flags)
- foreach(_flag ${_added_flags})
- add_compile_options("$<${_genex}:${_flag}>")
- endforeach()
- endif()
- else()
- set(${prefix}_${lang} PARENT_SCOPE)
- endif()
- endforeach()
- endfunction()
-
- # ==============================================================================
-
- # ~~~
- # Convenience function to test for the existence of some compiler flags for a a particular language
- #
- # check_link_flag(<lang> <var_prefix> [VERBATIM] <flags1> [<flags2>...])
- #
- # Check whether a linker option is valid for the <lang> linker. For each set of linker options provided in the lists
- # <flagsN>, it will test whether one of the element can be used by the corresponding compiler. If a flag is valid, it
- # will be added to the GLOBAL property named <prefix>_<lang> as well as to a variable with the same name. If the
- # property already exists, any valid flag is appended to the current value.
- #
- # If VERBATIM is passed as argument, the flag is passed onto the linker without prepending the 'LINKER:' prefix.
- #
- # Each call to this function also sets the _added_count variable to the number of flags added automatically (if any).
- # ~~~
- function(check_link_flags lang var_prefix)
- # cmake-lint: disable=R0915,C0103,E1120
-
- cmake_parse_arguments(PARSE_ARGV 2 CHECK_LF "VERBATIM" "" "")
- set(_${lang}_link_opts)
- # This is a CMake 3.18 addition
- include(CheckLinkerFlag OPTIONAL RESULT_VARIABLE _check_linker_flags)
-
- set(_wrapper_flag ${CMAKE_${lang}_LINKER_WRAPPER_FLAG})
- list(GET _wrapper_flag -1 _last)
- set(_separate_options FALSE)
- if(_last STREQUAL " ")
- set(_separate_options TRUE)
- list(REMOVE_AT _wrapper_flag -1)
- endif()
- string(REPLACE ";" " " _wrapper_flag "${_wrapper_flag}")
-
- foreach(_flag_list ${CHECK_LF_UNPARSED_ARGUMENTS})
- separate_arguments(_flag_list)
-
- foreach(_flag ${_flag_list})
- # Drop the first character (most likely either '-' or '/')
- string(SUBSTRING ${_flag} 1 -1 _flag_name)
- string(REGEX REPLACE "^-+" "" _flag_name ${_flag_name})
- string(REGEX REPLACE "[-:/,=]" "_" _flag_name ${_flag_name})
- if(CHECK_LF_VERBATIM)
- set(_prefix)
- else()
- set(_prefix "LINKER:")
- endif()
-
- if(_check_linker_flags)
- check_linker_flag(${lang} "${_prefix}${_flag}" ${lang}_linker_has_${_flag_name})
- else()
- if(NOT CHECK_LF_VERBATIM)
- if(_separate_options)
- string(REPLACE "," ";" _flags ${_flag})
- set(_expanded_flag)
- foreach(subflag ${_flags})
- set(_expanded_flag "${_expanded_flag} ${_wrapper_flag} ${subflag}")
- endforeach()
- else()
- set(_expanded_flag "${_wrapper_flag}${_flag}")
- endif()
- else()
- set(_expanded_flag "${_flag}")
- endif()
-
- set(CMAKE_REQUIRED_LINK_OPTIONS ${_expanded_flag})
- check_compiler_flag(${lang} "" ${lang}_linker_has_${_flag_name})
- endif()
-
- if(${lang}_linker_has_${_flag_name})
- list(APPEND _${lang}_link_opts ${_flag})
- break()
- endif()
- endforeach()
- endforeach()
-
- # Is there a property that already corresponds to this?
- get_property(_opts GLOBAL PROPERTY ${var_prefix}_${lang})
- if(_opts)
- list(APPEND _opts ${_${lang}_link_opts})
- else()
- define_property(
- GLOBAL
- PROPERTY ${var_prefix}_${lang}
- BRIEF_DOCS "Linker flags ${var_prefix}"
- FULL_DOCS "Linker flags ${var_prefix}")
- set(_opts ${_${lang}_link_opts})
- endif()
-
- # Set GLOBAL property so that other parts of the code can have access to it
- set_property(GLOBAL PROPERTY ${var_prefix}_${lang} ${_opts})
-
- list(LENGTH _${lang}_link_opts _added_count)
- set(_added_count
- ${_added_count}
- PARENT_SCOPE)
- set(_added_flags
- ${_${lang}_link_opts}
- PARENT_SCOPE)
-
- # Also set a variable for convenience
- set(${var_prefix}_${lang}
- ${_opts}
- PARENT_SCOPE)
- endfunction()
-
- # ~~~
- # Convenience function to test for the existence of some linker flags for a set of languages.
- #
- # test_link_option(<prefix>
- # LANGS <lang1> [<lang2>...]
- # FLAGS <flags1> [<flags2>...]
- # [AUTO_ADD_LO]
- # [VERBATIM]
- # [GENEX <genex>])
- #
- # Check that a linker option can be applied to each of the specified languages <lang>. For each set of linker
- # options provided in the lists <flagsN>, it will test whether one of the element can be used by the corresponding
- # linker. If a flag is valid, it will be added to the GLOBAL property named <prefix>_<lang> as well as to a variable
- # with the same name.
- # If VERBATIM is passed as argument, the flag is passed onto the linker without prepending the 'LINKER:' prefix.
- # If AUTO_ADD_LO is specified, the linker option will be automatically added globally using
- # add_compile_option(...). By default, the generator expression used in that function call restricts the compile option
- # to the current language (ie. $<$<LINK_LANGUAGE:@lang@>:LINKER:${_flag}>). This can be changed by using the <genex>
- # argument (which defaults to "$<LINK_LANGUAGE:@lang@>").
- #
- # NB: This function calls check_link_flags() internally.
- # ~~~
- function(test_link_option prefix)
- cmake_parse_arguments(PARSE_ARGV 1 TEST_LO "AUTO_ADD_LO;VERBATIM" "GENEX" "LANGS;FLAGS")
-
- if(NOT TEST_LO_LANGS)
- message(FATAL_ERROR "Missing LANGS argument")
- endif()
- if(NOT TEST_LO_FLAGS)
- message(FATAL_ERROR "Missing FLAGS argument")
- endif()
-
- if(NOT TEST_LO_GENEX)
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.18)
- set(TEST_LO_GENEX "$<LINK_LANGUAGE:@lang@>")
- else()
- set(TEST_LO_GENEX "1")
- endif()
- endif()
-
- # cmake-lint: disable=C0103
- foreach(lang ${TEST_LO_LANGS})
- is_language_enabled(${lang} _enabled)
- if(_enabled)
- set(_args ${TEST_LO_FLAGS})
- if(TEST_LO_VERBATIM)
- set(_args "VERBATIM;${_args}")
- endif()
- check_link_flags(${lang} ${prefix} ${_args})
-
- set(${prefix}_${lang}
- ${${prefix}_${lang}}
- PARENT_SCOPE)
-
- if(TEST_LO_AUTO_ADD_LO AND _added_flags)
- string(CONFIGURE "${TEST_LO_GENEX}" _genex @ONLY)
- list(LENGTH ${prefix}_${lang} _L)
- math(EXPR _start_idx "${_L} - ${_added_count}")
- list(SUBLIST ${prefix}_${lang} ${_start_idx} -1 _added_flags)
- foreach(_flag ${_added_flags})
- if(TEST_LO_VERBATIM)
- add_link_options("$<${_genex}:${_flag}>")
- else()
- add_link_options("$<${_genex}:LINKER:${_flag}>")
- endif()
- endforeach()
- endif()
- else()
- set(${prefix}_${lang} PARENT_SCOPE)
- endif()
- endforeach()
- endfunction()
-
- # ==============================================================================
-
- # ~~~
- # Append a value to a property (creating the latter if necessary)
- #
- # append_to_property(<property_name>
- # <GLOBAL |
- # DIRECTORY [<dir>] |
- # TARGET <target> |
- # SOURCE <source> |
- # [DIRECTORY <dir> | TARGET_DIRECTORY <target>] |
- # INSTALL <file> |
- # TEST <test> |
- # CACHE <entry> |
- # VARIABLE >
- # <value>)
- # ~~~
- macro(append_to_property name scope value)
- get_property(_prop ${scope} PROPERTY ${name})
- if(_prop)
- list(APPEND _prop ${value})
- else()
- define_property(
- ${scope}
- PROPERTY ${name}
- BRIEF_DOCS "${scope} property for ${name}"
- FULL_DOCS "${scope} property for ${name}")
- set(_prop ${value})
- endif()
-
- set_property(${scope} PROPERTY ${name} ${_prop})
- endmacro()
-
- # ==============================================================================
-
- # Automatically set the output directory for a particular target with a potential hint
- #
- # set_output_directory_auto(<target> <hint>)
- #
- # Automatically set the output directory for <target>. <hint> must be an existing path in the current CMake project
- # directory. It is only used if the CMake variable IN_PLACE_BUILD is set to a truthful value. Otherwise, the macro will
- # look at ${target}_OUTPUT_DIR CMake variable (if it exists) to set the output directory (it will create the directory
- # if it does not already exist on the filesystem).
- #
- macro(set_output_directory_auto target hint)
- string(TOUPPER ${target} _TARGET)
-
- if(IN_PLACE_BUILD)
- # Automatically calculate the output directory
- set(${_TARGET}_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/${hint})
- endif()
-
- # Normalize variable name
- if(${target}_OUTPUT_DIR)
- set(${_TARGET}_OUTPUT_DIR ${${target}_OUTPUT_DIR})
- endif()
-
- # Create output directory if it does not exist already
- if(${_TARGET}_OUTPUT_DIR AND NOT EXISTS ${${_TARGET}_OUTPUT_DIR})
- file(MAKE_DIRECTORY ${${_TARGET}_OUTPUT_DIR})
- endif()
-
- # Properly set output directory for a target so that during an installation using either 'pip install' or 'python3
- # setup.py install' the libraries get built in the proper directory
- if(${_TARGET}_OUTPUT_DIR)
- set_target_properties(
- ${target}
- PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${${_TARGET}_OUTPUT_DIR}
- LIBRARY_OUTPUT_DIRECTORY_DEBUG ${${_TARGET}_OUTPUT_DIR}
- LIBRARY_OUTPUT_DIRECTORY_RELEASE ${${_TARGET}_OUTPUT_DIR}
- LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${${_TARGET}_OUTPUT_DIR}
- LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL ${${_TARGET}_OUTPUT_DIR})
- elseif(IS_PYTHON_BUILD)
- message(
- WARNING "IS_PYTHON_BUILD=ON but ${_TARGET}_OUTPUT_DIR "
- "was not defined! The shared library for target ${target} "
- "will probably not be copied to the correct directory. "
- "Did you forget to add a CMakeExtension in setup.py?")
- elseif(CMAKE_LIBRARY_OUTPUT_DIRECTORY)
- set_target_properties(
- ${target}
- PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
- LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
- LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
- LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
- LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
- endif()
- endmacro()
-
- # ==============================================================================
-
- # Set RPATH of target only if building for Python (ie. IS_PYTHON_BUILD=ON) or if building in-place (IN_PLACE_BUILD=ON)
- macro(python_install_set_rpath target path)
- if((IS_PYTHON_BUILD OR IN_PLACE_BUILD) AND LINKER_RPATH)
- if(APPLE)
- set_target_properties(${target} PROPERTIES INSTALL_RPATH "@loader_path/${path}")
- elseif(UNIX)
- set_target_properties(${target} PROPERTIES INSTALL_RPATH "$ORIGIN/${path}")
- endif()
- endif()
- endmacro()
-
- # ==============================================================================
-
- include(FindPackageHandleStandardArgs)
- # Find a Python module in the current (potential virtual) environment
- #
- # find_python_module(<module> [REQUIRED|EXACT|QUIET] [VERSION <version>])
- #
- # Usage is similar to the builtin find_package(...)
- function(find_python_module module)
- # cmake-lint: disable=C0103
- cmake_parse_arguments(PARSE_ARGV 1 PYMOD "REQUIRED;EXACT;QUIET" "VERSION" "")
-
- string(REPLACE "-" "_" module_name ${module})
- string(TOUPPER ${module_name} MODULE)
- if(NOT PYMOD_${MODULE})
- if(PYMOD_REQUIRED)
- set(PYMOD_${module}_FIND_REQUIRED TRUE)
- set(PYMOD_${MODULE}_FIND_REQUIRED TRUE)
- endif()
- if(PYMOD_QUIET)
- set(PYMOD_${module}_FIND_QUIETLY TRUE)
- set(PYMOD_${MODULE}_FIND_QUIETLY TRUE)
- endif()
- if(PYMOD_EXACT)
- set(PYMOD_${module}_FIND_VERSION_EXACT TRUE)
- set(PYMOD_${MODULE}_FIND_VERSION_EXACT TRUE)
- endif()
- if(PYMOD_VERSION)
- set(PYMOD_${module}_FIND_VERSION ${PYMOD_VERSION})
- set(PYMOD_${MODULE}_FIND_VERSION ${PYMOD_VERSION})
- endif()
-
- execute_process(
- COMMAND "${Python_EXECUTABLE}" "-c" "import os, ${module_name}; print(os.path.dirname(${module_name}.__file__))"
- RESULT_VARIABLE _${MODULE}_status
- OUTPUT_VARIABLE _${MODULE}_location
- ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
-
- if(NOT _${MODULE}_status)
- set(PYMOD_${MODULE}_PATH
- ${_${MODULE}_location}
- CACHE STRING "Location of Python module ${module}")
-
- if(PYMOD_VERSION)
- execute_process(
- COMMAND "${Python_EXECUTABLE}" "-c" "import ${module_name}; print(${module_name}.__version__)"
- RESULT_VARIABLE _${MODULE}_status
- OUTPUT_VARIABLE _${MODULE}_version
- ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
-
- if(NOT _${MODULE}_status)
- set(PYMOD_${MODULE}_VERSION
- ${_${MODULE}_version}
- CACHE STRING "Version of Python module ${module}")
- set(PYMOD_${module}_VERSION
- ${PYMOD_${MODULE}_VERSION}
- CACHE STRING "Version of Python module ${module}")
- endif()
- endif()
- endif()
- endif()
-
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19 AND CMAKE_VERSION VERSION_LESS 3.20)
- set(CMAKE_FIND_PACKAGE_NAME PYMOD_${module})
- endif()
-
- find_package_handle_standard_args(
- PYMOD_${module_name}
- REQUIRED_VARS PYMOD_${MODULE}_PATH
- VERSION_VAR PYMOD_${MODULE}_VERSION)
-
- set(PYMOD_${MODULE}_FOUND
- ${PYMOD_${MODULE}_FOUND}
- CACHE INTERNAL "")
-
- mark_as_advanced(PYMOD_${MODULE}_FOUND PYMOD_${MODULE}_PATH PYMOD_${MODULE}_VERSION)
- endfunction()
-
- # ==============================================================================
|