| # Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| # file LICENSE.rst or https://cmake.org/licensing for details. | |
| # Function to compile a source file to identify the compiler ABI. | |
| # This is used internally by CMake and should not be included by user | |
| # code. | |
| include(${CMAKE_ROOT}/Modules/Internal/CMakeDetermineLinkerId.cmake) | |
| include(${CMAKE_ROOT}/Modules/CMakeParseImplicitIncludeInfo.cmake) | |
| include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake) | |
| include(${CMAKE_ROOT}/Modules/CMakeParseLibraryArchitecture.cmake) | |
| include(CMakeTestCompilerCommon) | |
| function(CMAKE_DETERMINE_COMPILER_ABI lang src) | |
| set(abi_variables | |
| CMAKE_${lang}_COMPILER_WORKS | |
| CMAKE_${lang}_COMPILER_ARCHITECTURE_ID | |
| CMAKE_${lang}_SIZEOF_DATA_PTR | |
| CMAKE_${lang}_BYTE_ORDER | |
| CMAKE_${lang}_COMPILER_ABI | |
| CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES | |
| CMAKE_${lang}_COMPILER_LINKER | |
| CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES | |
| CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES | |
| CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES | |
| CMAKE_${lang}_LIBRARY_ARCHITECTURE) | |
| if (CMAKE_${lang}_COMPILER_LINKER) | |
| list(APPEND abi_variables | |
| CMAKE_${lang}_COMPILER_LINKER_ARCHITECTURE_FLAGS | |
| CMAKE_${lang}_COMPILER_LINKER_ID | |
| CMAKE_${lang}_COMPILER_LINKER_VERSION | |
| CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT) | |
| endif () | |
| if (lang STREQUAL "Fortran") | |
| list(APPEND abi_variables | |
| CMAKE_${lang}_COMPILER_SUPPORTS_F90) | |
| endif () | |
| if (lang MATCHES "^(CUDA|HIP)$") | |
| list(APPEND abi_variables | |
| CMAKE_${lang}_ARCHITECTURES | |
| CMAKE_${lang}_HOST_COMPILER_ID | |
| CMAKE_${lang}_HOST_COMPILER_VERSION | |
| CMAKE_${lang}_RUNTIME_LIBRARY) | |
| endif () | |
| set(all_abi_variables_defined 1) | |
| foreach (abi_variable IN LISTS abi_variables) | |
| if (NOT DEFINED "${abi_variable}") | |
| set(all_abi_variables_defined 0) | |
| break () | |
| endif () | |
| endforeach () | |
| if (all_abi_variables_defined AND CMAKE_${lang}_COMPILER_WORKS) | |
| set(CMAKE_${lang}_ABI_COMPILED 1) | |
| endif () | |
| if(NOT DEFINED CMAKE_${lang}_ABI_COMPILED) | |
| message(CHECK_START "Detecting ${lang} compiler ABI info") | |
| # Compile the ABI identification source. | |
| set(BIN "${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerABI_${lang}.bin") | |
| set(CMAKE_FLAGS ) | |
| set(COMPILE_DEFINITIONS ) | |
| set(LINK_OPTIONS ) | |
| if(DEFINED CMAKE_${lang}_VERBOSE_FLAG) | |
| set(LINK_OPTIONS "${CMAKE_${lang}_VERBOSE_FLAG}") | |
| set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_FLAG}") | |
| endif() | |
| if(DEFINED CMAKE_${lang}_VERBOSE_COMPILE_FLAG) | |
| set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_COMPILE_FLAG}") | |
| endif() | |
| if(DEFINED CMAKE_${lang}_VERBOSE_LINK_FLAG) | |
| list(APPEND LINK_OPTIONS "${CMAKE_${lang}_VERBOSE_LINK_FLAG}") | |
| endif() | |
| if(lang MATCHES "^(CUDA|HIP)$") | |
| if(CMAKE_CUDA_ARCHITECTURES STREQUAL "native") | |
| # We are about to detect the native architectures, so we do | |
| # not yet know them. Use all architectures during detection. | |
| set(CMAKE_${lang}_ARCHITECTURES "all") | |
| endif() | |
| set(CMAKE_${lang}_RUNTIME_LIBRARY "Static") | |
| endif() | |
| if(lang STREQUAL "CXX") | |
| set(CMAKE_${lang}_SCAN_FOR_MODULES OFF) | |
| endif() | |
| if(NOT "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC") | |
| # Avoid adding our own platform standard libraries for compilers | |
| # from which we might detect implicit link libraries. | |
| list(APPEND CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD_LIBRARIES=") | |
| endif() | |
| list(JOIN LINK_OPTIONS " " LINK_OPTIONS) | |
| list(APPEND CMAKE_FLAGS "-DEXE_LINKER_FLAGS=${LINK_OPTIONS}") | |
| __TestCompiler_setTryCompileTargetType() | |
| # Avoid failing ABI detection caused by non-functionally relevant | |
| # compiler arguments | |
| if(CMAKE_TRY_COMPILE_CONFIGURATION) | |
| string(TOUPPER "${CMAKE_TRY_COMPILE_CONFIGURATION}" _tc_config) | |
| else() | |
| set(_tc_config "DEBUG") | |
| endif() | |
| foreach(v CMAKE_${lang}_FLAGS CMAKE_${lang}_FLAGS_${_tc_config}) | |
| # Avoid failing ABI detection on warnings. | |
| string(REGEX REPLACE "(^| )-Werror([= ][^-][^ ]*)?( |$)" " " ${v} "${${v}}") | |
| # Avoid passing of "-pipe" when determining the compiler internals. With | |
| # "-pipe" GCC will use pipes to pass data between the involved | |
| # executables. This may lead to issues when their stderr output (which | |
| # contains the relevant compiler internals) becomes interweaved. | |
| string(REGEX REPLACE "(^| )-pipe( |$)" " " ${v} "${${v}}") | |
| # Suppress any formatting of warnings and/or errors | |
| string(REGEX REPLACE "(-f|/)diagnostics(-|:)color(=[a-z]+)?" "" ${v} "${${v}}") | |
| endforeach() | |
| # Save the current LC_ALL, LC_MESSAGES, and LANG environment variables | |
| # and set them to "C" that way GCC's "search starts here" text is in | |
| # English and we can grok it. | |
| set(_orig_lc_all $ENV{LC_ALL}) | |
| set(_orig_lc_messages $ENV{LC_MESSAGES}) | |
| set(_orig_lang $ENV{LANG}) | |
| set(ENV{LC_ALL} C) | |
| set(ENV{LC_MESSAGES} C) | |
| set(ENV{LANG} C) | |
| try_compile(CMAKE_${lang}_ABI_COMPILED | |
| SOURCES ${src} | |
| CMAKE_FLAGS ${CMAKE_FLAGS} | |
| # Ignore unused flags when we are just determining the ABI. | |
| "--no-warn-unused-cli" | |
| COMPILE_DEFINITIONS ${COMPILE_DEFINITIONS} | |
| NO_CACHE | |
| OUTPUT_VARIABLE OUTPUT | |
| COPY_FILE "${BIN}" | |
| COPY_FILE_ERROR _copy_error | |
| __CMAKE_INTERNAL ABI | |
| ) | |
| # Restore original LC_ALL, LC_MESSAGES, and LANG | |
| set(ENV{LC_ALL} ${_orig_lc_all}) | |
| set(ENV{LC_MESSAGES} ${_orig_lc_messages}) | |
| set(ENV{LANG} ${_orig_lang}) | |
| if(CMAKE_${lang}_ABI_COMPILED AND _copy_error) | |
| set(CMAKE_${lang}_ABI_COMPILED 0) | |
| endif() | |
| set(CMAKE_${lang}_ABI_COMPILED ${CMAKE_${lang}_ABI_COMPILED} PARENT_SCOPE) | |
| # Load the resulting information strings. | |
| if(CMAKE_${lang}_ABI_COMPILED) | |
| message(CHECK_PASS "done") | |
| if(CMAKE_HOST_APPLE AND CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT CMAKE_OSX_ARCHITECTURES MATCHES "\\$") | |
| file(READ_MACHO "${BIN}" ARCHITECTURES archs CAPTURE_ERROR macho_error) # undocumented file() subcommand | |
| if (NOT macho_error) | |
| # sort and prune the list of found architectures | |
| set(arch_list_sorted ${archs}) | |
| list(SORT arch_list_sorted) | |
| list(REMOVE_DUPLICATES arch_list_sorted) | |
| # sort and prune the list of requested architectures | |
| set(requested_arch_list ${CMAKE_OSX_ARCHITECTURES}) | |
| list(SORT requested_arch_list) | |
| list(REMOVE_DUPLICATES requested_arch_list) | |
| message(CONFIGURE_LOG | |
| "Effective list of requested architectures (possibly empty) : \"${requested_arch_list}\"\n" | |
| "Effective list of architectures found in the ABI info binary: \"${arch_list_sorted}\"\n") | |
| # If all generated architectures were known to READ_MACHO (i.e. libmacho): | |
| # Compare requested and found: | |
| # - if no architecture(s) were requested explicitly, just check if READ_MACHO returned | |
| # an architecture for the ABI info binary. | |
| # - otherwise, check if the requested and found lists are equal | |
| if(arch_list_sorted MATCHES "unknown") | |
| # Rare but not impossible: a host with a toolchain capable of generating binaries with | |
| # architectures that the system libmacho is too old to know. Report the found archs as | |
| # usual, warn about the unknowns and skip the comparison with CMAKE_OSX_ARCHITECTURES. | |
| message(WARNING "The ${lang} compiler generates universal binaries with at least 1 architecture not known to the host") | |
| elseif(requested_arch_list AND arch_list_sorted | |
| AND NOT "${requested_arch_list}" STREQUAL "${arch_list_sorted}") | |
| # inform the user of the mismatch but show the raw input and output lists | |
| message(FATAL_ERROR | |
| "The ${lang} compiler targets architectures:\n" | |
| " \"${archs}\"\n" | |
| "but CMAKE_OSX_ARCHITECTURES is\n" | |
| " \"${CMAKE_OSX_ARCHITECTURES}\"\n") | |
| endif() | |
| endif() | |
| endif() | |
| cmake_policy(PUSH) | |
| cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n> | |
| file(STRINGS "${BIN}" ABI_STRINGS LIMIT_COUNT 32 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]") | |
| cmake_policy(POP) | |
| set(ABI_SIZEOF_DPTR "NOTFOUND") | |
| set(ABI_BYTE_ORDER "NOTFOUND") | |
| set(ABI_NAME "NOTFOUND") | |
| set(ARCHITECTURE_ID "") | |
| foreach(info ${ABI_STRINGS}) | |
| if("${info}" MATCHES "INFO:sizeof_dptr\\[0*([^]]*)\\]" AND NOT ABI_SIZEOF_DPTR) | |
| set(ABI_SIZEOF_DPTR "${CMAKE_MATCH_1}") | |
| endif() | |
| if("${info}" MATCHES "INFO:byte_order\\[(BIG_ENDIAN|LITTLE_ENDIAN)\\]") | |
| set(byte_order "${CMAKE_MATCH_1}") | |
| if(ABI_BYTE_ORDER STREQUAL "NOTFOUND") | |
| # Tentatively use the value because this is the first occurrence. | |
| set(ABI_BYTE_ORDER "${byte_order}") | |
| elseif(NOT ABI_BYTE_ORDER STREQUAL "${byte_order}") | |
| # Drop value because multiple occurrences do not match. | |
| set(ABI_BYTE_ORDER "") | |
| endif() | |
| endif() | |
| if("${info}" MATCHES "INFO:abi\\[([^]]*)\\]" AND NOT ABI_NAME) | |
| set(ABI_NAME "${CMAKE_MATCH_1}") | |
| endif() | |
| if("${info}" MATCHES "INFO:arch\\[([^]\"]*)\\]") | |
| list(APPEND ARCHITECTURE_ID "${CMAKE_MATCH_1}") | |
| endif() | |
| endforeach() | |
| if(ABI_SIZEOF_DPTR) | |
| set(CMAKE_${lang}_SIZEOF_DATA_PTR "${ABI_SIZEOF_DPTR}" PARENT_SCOPE) | |
| elseif(CMAKE_${lang}_SIZEOF_DATA_PTR_DEFAULT) | |
| set(CMAKE_${lang}_SIZEOF_DATA_PTR "${CMAKE_${lang}_SIZEOF_DATA_PTR_DEFAULT}" PARENT_SCOPE) | |
| endif() | |
| if(ABI_BYTE_ORDER) | |
| set(CMAKE_${lang}_BYTE_ORDER "${ABI_BYTE_ORDER}" PARENT_SCOPE) | |
| endif() | |
| if(ABI_NAME) | |
| set(CMAKE_${lang}_COMPILER_ABI "${ABI_NAME}" PARENT_SCOPE) | |
| endif() | |
| # The GNU Fortran compiler does not predefine architecture macros. | |
| if(NOT CMAKE_${lang}_COMPILER_ARCHITECTURE_ID AND NOT ARCHITECTURE_ID | |
| AND lang STREQUAL "Fortran" AND CMAKE_${lang}_COMPILER_ID STREQUAL "GNU") | |
| execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" -dumpmachine | |
| OUTPUT_VARIABLE _dumpmachine_triple OUTPUT_STRIP_TRAILING_WHITESPACE | |
| ERROR_VARIABLE _dumpmachine_stderr | |
| RESULT_VARIABLE _dumpmachine_result | |
| ) | |
| if(_dumpmachine_result EQUAL 0) | |
| include(Internal/CMakeParseCompilerArchitectureId) | |
| cmake_parse_compiler_architecture_id("${_dumpmachine_triple}" ARCHITECTURE_ID) | |
| endif() | |
| endif() | |
| # For some compilers we detect the architecture id during compiler identification. | |
| # If this was not one of those, use what was detected during compiler ABI detection, | |
| # which might be a list, e.g., when CMAKE_OSX_ARCHITECTURES has multiple values. | |
| if(NOT CMAKE_${lang}_COMPILER_ARCHITECTURE_ID AND ARCHITECTURE_ID) | |
| list(SORT ARCHITECTURE_ID) | |
| set(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID "${ARCHITECTURE_ID}" PARENT_SCOPE) | |
| endif() | |
| # Parse implicit include directory for this language, if available. | |
| if(CMAKE_${lang}_VERBOSE_FLAG) | |
| set (implicit_incdirs "") | |
| cmake_parse_implicit_include_info("${OUTPUT}" "${lang}" | |
| implicit_incdirs log rv) | |
| message(CONFIGURE_LOG | |
| "Parsed ${lang} implicit include dir info: rv=${rv}\n${log}\n\n") | |
| if("${rv}" STREQUAL "done") | |
| # Entries that we have been told to explicitly pass as standard include | |
| # directories will not be implicitly added by the compiler. | |
| if(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES) | |
| list(REMOVE_ITEM implicit_incdirs ${CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES}) | |
| endif() | |
| # We parsed implicit include directories, so override the default initializer. | |
| set(_CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT "${implicit_incdirs}") | |
| endif() | |
| endif() | |
| set(CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES "${_CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT}" PARENT_SCOPE) | |
| if(_CMAKE_${lang}_IMPLICIT_LINK_INFORMATION_DETERMINED_EARLY) | |
| # Use implicit linker information detected during compiler id step. | |
| set(implicit_dirs "${CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES}") | |
| set(implicit_objs "") | |
| set(implicit_libs "${CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES}") | |
| set(implicit_fwks "${CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES}") | |
| else() | |
| # Parse implicit linker information for this language, if available. | |
| set(implicit_dirs "") | |
| set(implicit_objs "") | |
| set(implicit_libs "") | |
| set(implicit_fwks "") | |
| set(compute_artifacts COMPUTE_LINKER linker_tool) | |
| if(CMAKE_${lang}_VERBOSE_FLAG) | |
| list(APPEND compute_artifacts COMPUTE_IMPLICIT_LIBS implicit_libs | |
| COMPUTE_IMPLICIT_DIRS implicit_dirs | |
| COMPUTE_IMPLICIT_FWKS implicit_fwks | |
| COMPUTE_IMPLICIT_OBJECTS implicit_objs) | |
| endif() | |
| cmake_parse_implicit_link_info2("${OUTPUT}" log "${CMAKE_${lang}_IMPLICIT_OBJECT_REGEX}" | |
| ${compute_artifacts} LANGUAGE ${lang}) | |
| message(CONFIGURE_LOG | |
| "Parsed ${lang} implicit link information:\n${log}\n\n") | |
| # for VS IDE Intel Fortran we have to figure out the | |
| # implicit link path for the fortran run time using | |
| # a try-compile | |
| if("${lang}" MATCHES "Fortran" | |
| AND "${CMAKE_GENERATOR}" MATCHES "Visual Studio") | |
| message(CHECK_START "Determine Intel Fortran Compiler Implicit Link Path") | |
| # Build a sample project which reports symbols. | |
| try_compile(IFORT_LIB_PATH_COMPILED | |
| PROJECT IntelFortranImplicit | |
| SOURCE_DIR ${CMAKE_ROOT}/Modules/IntelVSImplicitPath | |
| BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath | |
| CMAKE_FLAGS | |
| "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}" | |
| OUTPUT_VARIABLE _output) | |
| file(WRITE | |
| "${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.txt" | |
| "${_output}") | |
| include(${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.cmake OPTIONAL) | |
| message(CHECK_PASS "done") | |
| endif() | |
| endif() | |
| # Implicit link libraries cannot be used explicitly for multiple | |
| # OS X architectures, so we skip it. | |
| if(DEFINED CMAKE_OSX_ARCHITECTURES) | |
| if("${CMAKE_OSX_ARCHITECTURES}" MATCHES ";") | |
| set(implicit_libs "") | |
| endif() | |
| endif() | |
| # Filter out implicit link directories excluded by our Platform/<os>* modules. | |
| if(DEFINED CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES_EXCLUDE) | |
| list(REMOVE_ITEM implicit_dirs ${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES_EXCLUDE}) | |
| endif() | |
| # Filter out implicit link information excluded by the environment. | |
| if(DEFINED ENV{CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES_EXCLUDE}) | |
| list(REMOVE_ITEM implicit_libs $ENV{CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES_EXCLUDE}) | |
| endif() | |
| if(DEFINED ENV{CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES_EXCLUDE}) | |
| list(REMOVE_ITEM implicit_dirs $ENV{CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES_EXCLUDE}) | |
| endif() | |
| set(CMAKE_${lang}_COMPILER_LINKER "${linker_tool}" PARENT_SCOPE) | |
| cmake_determine_linker_id(${lang} "${linker_tool}") | |
| if(CMAKE_${lang}_COMPILER_LINKER_ID MATCHES "GNU|LLD|MOLD|WILD") | |
| set(CMAKE_${lang}_COMPILER_LINKER_ARCHITECTURE_FLAGS "${linker_tool_ARCH_FLAGS}" PARENT_SCOPE) | |
| else() | |
| set(CMAKE_${lang}_COMPILER_LINKER_ARCHITECTURE_FLAGS "" PARENT_SCOPE) | |
| endif() | |
| set(CMAKE_${lang}_COMPILER_LINKER_ID "${CMAKE_${lang}_COMPILER_LINKER_ID}" PARENT_SCOPE) | |
| set(CMAKE_${lang}_COMPILER_LINKER_VERSION ${CMAKE_${lang}_COMPILER_LINKER_VERSION} PARENT_SCOPE) | |
| set(CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT ${CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT} PARENT_SCOPE) | |
| set(CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES "${implicit_libs}" PARENT_SCOPE) | |
| set(CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES "${implicit_dirs}" PARENT_SCOPE) | |
| set(CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "${implicit_fwks}" PARENT_SCOPE) | |
| cmake_parse_library_architecture(${lang} "${implicit_dirs}" "${implicit_objs}" architecture_flag) | |
| if(architecture_flag) | |
| set(CMAKE_${lang}_LIBRARY_ARCHITECTURE "${architecture_flag}" PARENT_SCOPE) | |
| endif() | |
| else() | |
| message(CHECK_FAIL "failed") | |
| endif() | |
| endif() | |
| endfunction() |