1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4
5# Function to compile a source file to identify the compiler ABI.
6# This is used internally by CMake and should not be included by user
7# code.
8
9include(${CMAKE_ROOT}/Modules/CMakeParseImplicitIncludeInfo.cmake)
10include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
11include(${CMAKE_ROOT}/Modules/CMakeParseLibraryArchitecture.cmake)
12include(CMakeTestCompilerCommon)
13
14function(CMAKE_DETERMINE_COMPILER_ABI lang src)
15  if(NOT DEFINED CMAKE_${lang}_ABI_COMPILED)
16    message(CHECK_START "Detecting ${lang} compiler ABI info")
17
18    # Compile the ABI identification source.
19    set(BIN "${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerABI_${lang}.bin")
20    set(CMAKE_FLAGS )
21    set(COMPILE_DEFINITIONS )
22    if(DEFINED CMAKE_${lang}_VERBOSE_FLAG)
23      set(CMAKE_FLAGS "-DEXE_LINKER_FLAGS=${CMAKE_${lang}_VERBOSE_FLAG}")
24      set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_FLAG}")
25    endif()
26    if(DEFINED CMAKE_${lang}_VERBOSE_COMPILE_FLAG)
27      set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_COMPILE_FLAG}")
28    endif()
29    if(NOT "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC")
30      # Avoid adding our own platform standard libraries for compilers
31      # from which we might detect implicit link libraries.
32      list(APPEND CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD_LIBRARIES=")
33    endif()
34    __TestCompiler_setTryCompileTargetType()
35
36    # Avoid failing ABI detection on warnings.
37    string(REGEX REPLACE "(^| )-Werror([= ][^ ]*)?( |$)" " " CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS}")
38
39    # Save the current LC_ALL, LC_MESSAGES, and LANG environment variables
40    # and set them to "C" that way GCC's "search starts here" text is in
41    # English and we can grok it.
42    set(_orig_lc_all      $ENV{LC_ALL})
43    set(_orig_lc_messages $ENV{LC_MESSAGES})
44    set(_orig_lang        $ENV{LANG})
45    set(ENV{LC_ALL}      C)
46    set(ENV{LC_MESSAGES} C)
47    set(ENV{LANG}        C)
48
49    try_compile(CMAKE_${lang}_ABI_COMPILED
50      ${CMAKE_BINARY_DIR} ${src}
51      CMAKE_FLAGS ${CMAKE_FLAGS}
52                  # Ignore unused flags when we are just determining the ABI.
53                  "--no-warn-unused-cli"
54      COMPILE_DEFINITIONS ${COMPILE_DEFINITIONS}
55      OUTPUT_VARIABLE OUTPUT
56      COPY_FILE "${BIN}"
57      COPY_FILE_ERROR _copy_error
58      __CMAKE_INTERNAL ABI
59      )
60
61    # Restore original LC_ALL, LC_MESSAGES, and LANG
62    set(ENV{LC_ALL}      ${_orig_lc_all})
63    set(ENV{LC_MESSAGES} ${_orig_lc_messages})
64    set(ENV{LANG}        ${_orig_lang})
65
66    # Move result from cache to normal variable.
67    set(CMAKE_${lang}_ABI_COMPILED ${CMAKE_${lang}_ABI_COMPILED})
68    unset(CMAKE_${lang}_ABI_COMPILED CACHE)
69    if(CMAKE_${lang}_ABI_COMPILED AND _copy_error)
70      set(CMAKE_${lang}_ABI_COMPILED 0)
71    endif()
72    set(CMAKE_${lang}_ABI_COMPILED ${CMAKE_${lang}_ABI_COMPILED} PARENT_SCOPE)
73
74    # Load the resulting information strings.
75    if(CMAKE_${lang}_ABI_COMPILED)
76      message(CHECK_PASS "done")
77      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
78        "Detecting ${lang} compiler ABI info compiled with the following output:\n${OUTPUT}\n\n")
79      file(STRINGS "${BIN}" ABI_STRINGS LIMIT_COUNT 32 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
80      set(ABI_SIZEOF_DPTR "NOTFOUND")
81      set(ABI_BYTE_ORDER "NOTFOUND")
82      set(ABI_NAME "NOTFOUND")
83      foreach(info ${ABI_STRINGS})
84        if("${info}" MATCHES "INFO:sizeof_dptr\\[0*([^]]*)\\]" AND NOT ABI_SIZEOF_DPTR)
85          set(ABI_SIZEOF_DPTR "${CMAKE_MATCH_1}")
86        endif()
87        if("${info}" MATCHES "INFO:byte_order\\[(BIG_ENDIAN|LITTLE_ENDIAN)\\]")
88          set(byte_order "${CMAKE_MATCH_1}")
89          if(ABI_BYTE_ORDER STREQUAL "NOTFOUND")
90            # Tentatively use the value because this is the first occurrence.
91            set(ABI_BYTE_ORDER "${byte_order}")
92          elseif(NOT ABI_BYTE_ORDER STREQUAL "${byte_order}")
93            # Drop value because multiple occurrences do not match.
94            set(ABI_BYTE_ORDER "")
95          endif()
96        endif()
97        if("${info}" MATCHES "INFO:abi\\[([^]]*)\\]" AND NOT ABI_NAME)
98          set(ABI_NAME "${CMAKE_MATCH_1}")
99        endif()
100      endforeach()
101
102      if(ABI_SIZEOF_DPTR)
103        set(CMAKE_${lang}_SIZEOF_DATA_PTR "${ABI_SIZEOF_DPTR}" PARENT_SCOPE)
104      elseif(CMAKE_${lang}_SIZEOF_DATA_PTR_DEFAULT)
105        set(CMAKE_${lang}_SIZEOF_DATA_PTR "${CMAKE_${lang}_SIZEOF_DATA_PTR_DEFAULT}" PARENT_SCOPE)
106      endif()
107
108      if(ABI_BYTE_ORDER)
109        set(CMAKE_${lang}_BYTE_ORDER "${ABI_BYTE_ORDER}" PARENT_SCOPE)
110      endif()
111
112      if(ABI_NAME)
113        set(CMAKE_${lang}_COMPILER_ABI "${ABI_NAME}" PARENT_SCOPE)
114      endif()
115
116      # Parse implicit include directory for this language, if available.
117      if(CMAKE_${lang}_VERBOSE_FLAG)
118        set (implicit_incdirs "")
119        cmake_parse_implicit_include_info("${OUTPUT}" "${lang}"
120          implicit_incdirs log rv)
121        file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
122          "Parsed ${lang} implicit include dir info from above output: rv=${rv}\n${log}\n\n")
123        if("${rv}" STREQUAL "done")
124          # Entries that we have been told to explicitly pass as standard include
125          # directories will not be implicitly added by the compiler.
126          if(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES)
127            list(REMOVE_ITEM implicit_incdirs ${CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES})
128          endif()
129
130          # We parsed implicit include directories, so override the default initializer.
131          set(_CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT "${implicit_incdirs}")
132        endif()
133      endif()
134      set(CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES "${_CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT}" PARENT_SCOPE)
135
136      # Parse implicit linker information for this language, if available.
137      set(implicit_dirs "")
138      set(implicit_objs "")
139      set(implicit_libs "")
140      set(implicit_fwks "")
141      if(CMAKE_${lang}_VERBOSE_FLAG)
142        CMAKE_PARSE_IMPLICIT_LINK_INFO("${OUTPUT}" implicit_libs implicit_dirs implicit_fwks log
143          "${CMAKE_${lang}_IMPLICIT_OBJECT_REGEX}"
144          COMPUTE_IMPLICIT_OBJECTS implicit_objs)
145        file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
146          "Parsed ${lang} implicit link information from above output:\n${log}\n\n")
147      endif()
148      # for VS IDE Intel Fortran we have to figure out the
149      # implicit link path for the fortran run time using
150      # a try-compile
151      if("${lang}" MATCHES "Fortran"
152          AND "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
153        message(CHECK_START "Determine Intel Fortran Compiler Implicit Link Path")
154        # Build a sample project which reports symbols.
155        try_compile(IFORT_LIB_PATH_COMPILED
156          ${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath
157          ${CMAKE_ROOT}/Modules/IntelVSImplicitPath
158          IntelFortranImplicit
159          CMAKE_FLAGS
160          "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
161          OUTPUT_VARIABLE _output)
162        file(WRITE
163          "${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.txt"
164          "${_output}")
165        include(${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.cmake OPTIONAL)
166        message(CHECK_PASS "done")
167      endif()
168
169      # Implicit link libraries cannot be used explicitly for multiple
170      # OS X architectures, so we skip it.
171      if(DEFINED CMAKE_OSX_ARCHITECTURES)
172        if("${CMAKE_OSX_ARCHITECTURES}" MATCHES ";")
173          set(implicit_libs "")
174        endif()
175      endif()
176
177      set(CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES "${implicit_libs}" PARENT_SCOPE)
178      set(CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES "${implicit_dirs}" PARENT_SCOPE)
179      set(CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "${implicit_fwks}" PARENT_SCOPE)
180
181      cmake_parse_library_architecture(${lang} "${implicit_dirs}" "${implicit_objs}" architecture_flag)
182      if(architecture_flag)
183        set(CMAKE_${lang}_LIBRARY_ARCHITECTURE "${architecture_flag}" PARENT_SCOPE)
184      endif()
185
186    else()
187      message(CHECK_FAIL "failed")
188      file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
189        "Detecting ${lang} compiler ABI info failed to compile with the following output:\n${OUTPUT}\n${_copy_error}\n\n")
190    endif()
191  endif()
192endfunction()
193