CMakeDetermineCompilerId.cmake 12.6 KB
Newer Older
1

2
3
4
5
6
7
8
9
10
11
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
12
# (To distribute this file outside of CMake, substitute the full
13
14
#  License text for the above reference.)

15
# Function to compile a source file to identify the compiler.  This is
16
# used internally by CMake and should not be included by user code.
Alexander Neundorf's avatar
 
Alexander Neundorf committed
17
18
# If successful, sets CMAKE_<lang>_COMPILER_ID and CMAKE_<lang>_PLATFORM_ID

19
FUNCTION(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
20
21
  # Make sure the compiler arguments are clean.
  STRING(STRIP "${CMAKE_${lang}_COMPILER_ARG1}" CMAKE_${lang}_COMPILER_ID_ARG1)
22
  STRING(REGEX REPLACE " +" ";" CMAKE_${lang}_COMPILER_ID_ARG1 "${CMAKE_${lang}_COMPILER_ID_ARG1}")
23

24
25
26
27
  # Make sure user-specified compiler flags are used.
  IF(CMAKE_${lang}_FLAGS)
    SET(CMAKE_${lang}_COMPILER_ID_FLAGS ${CMAKE_${lang}_FLAGS})
  ELSE(CMAKE_${lang}_FLAGS)
28
    SET(CMAKE_${lang}_COMPILER_ID_FLAGS $ENV{${flagvar}})
29
  ENDIF(CMAKE_${lang}_FLAGS)
30
  STRING(REGEX REPLACE " " ";" CMAKE_${lang}_COMPILER_ID_FLAGS_LIST "${CMAKE_${lang}_COMPILER_ID_FLAGS}")
31

32
  # Compute the directory in which to run the test.
33
  SET(CMAKE_${lang}_COMPILER_ID_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CompilerId${lang})
34
35
36
37
38

  # Try building with no extra flags and then try each set
  # of helper flags.  Stop when the compiler is identified.
  FOREACH(flags "" ${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS})
    IF(NOT CMAKE_${lang}_COMPILER_ID)
39
      CMAKE_DETERMINE_COMPILER_ID_BUILD("${lang}" "${flags}" "${src}")
40
      FOREACH(file ${COMPILER_${lang}_PRODUCED_FILES})
41
        CMAKE_DETERMINE_COMPILER_ID_CHECK("${lang}" "${CMAKE_${lang}_COMPILER_ID_DIR}/${file}" "${src}")
42
43
44
45
      ENDFOREACH(file)
    ENDIF(NOT CMAKE_${lang}_COMPILER_ID)
  ENDFOREACH(flags)

46
47
48
49
50
  # If the compiler is still unknown, try to query its vendor.
  IF(NOT CMAKE_${lang}_COMPILER_ID)
    CMAKE_DETERMINE_COMPILER_ID_VENDOR(${lang})
  ENDIF()

51
52
  # if the format is unknown after all files have been checked, put "Unknown" in the cache
  IF(NOT CMAKE_EXECUTABLE_FORMAT)
53
    SET(CMAKE_EXECUTABLE_FORMAT "Unknown" CACHE INTERNAL "Executable file format")
54
55
56
57
58
59
60
61
62
63
  ENDIF(NOT CMAKE_EXECUTABLE_FORMAT)

  # Display the final identification result.
  IF(CMAKE_${lang}_COMPILER_ID)
    MESSAGE(STATUS "The ${lang} compiler identification is "
      "${CMAKE_${lang}_COMPILER_ID}")
  ELSE(CMAKE_${lang}_COMPILER_ID)
    MESSAGE(STATUS "The ${lang} compiler identification is unknown")
  ENDIF(CMAKE_${lang}_COMPILER_ID)

64
65
  SET(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
  SET(CMAKE_${lang}_PLATFORM_ID "${CMAKE_${lang}_PLATFORM_ID}" PARENT_SCOPE)
66
67
  SET(MSVC_${lang}_ARCHITECTURE_ID "${MSVC_${lang}_ARCHITECTURE_ID}" 
    PARENT_SCOPE)
68
69
ENDFUNCTION(CMAKE_DETERMINE_COMPILER_ID)

70
71
72
73
74
75
76
77
#-----------------------------------------------------------------------------
# Function to write the compiler id source file.
FUNCTION(CMAKE_DETERMINE_COMPILER_ID_WRITE lang src)
  FILE(READ ${CMAKE_ROOT}/Modules/${src}.in ID_CONTENT_IN)
  STRING(CONFIGURE "${ID_CONTENT_IN}" ID_CONTENT_OUT @ONLY)
  FILE(WRITE ${CMAKE_${lang}_COMPILER_ID_DIR}/${src} "${ID_CONTENT_OUT}")
ENDFUNCTION(CMAKE_DETERMINE_COMPILER_ID_WRITE)

78
79
80
#-----------------------------------------------------------------------------
# Function to build the compiler id source file and look for output
# files.
81
FUNCTION(CMAKE_DETERMINE_COMPILER_ID_BUILD lang testflags src)
82
  # Create a clean working directory.
83
84
  FILE(REMOVE_RECURSE ${CMAKE_${lang}_COMPILER_ID_DIR})
  FILE(MAKE_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR})
85
  CMAKE_DETERMINE_COMPILER_ID_WRITE("${lang}" "${src}")
86

87
88
  # Construct a description of this test case.
  SET(COMPILER_DESCRIPTION
89
90
91
92
    "Compiler: ${CMAKE_${lang}_COMPILER} ${CMAKE_${lang}_COMPILER_ID_ARG1}
Build flags: ${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}
Id flags: ${testflags}
")
93

94
95
96
  # Compile the compiler identification source.
  IF(COMMAND EXECUTE_PROCESS)
    EXECUTE_PROCESS(
97
98
99
100
      COMMAND ${CMAKE_${lang}_COMPILER}
              ${CMAKE_${lang}_COMPILER_ID_ARG1}
              ${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}
              ${testflags}
101
              "${src}"
102
103
104
105
106
107
108
109
      WORKING_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}
      OUTPUT_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
      ERROR_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
      RESULT_VARIABLE CMAKE_${lang}_COMPILER_ID_RESULT
      )
  ELSE(COMMAND EXECUTE_PROCESS)
    EXEC_PROGRAM(
      ${CMAKE_${lang}_COMPILER} ${CMAKE_${lang}_COMPILER_ID_DIR}
110
111
112
      ARGS ${CMAKE_${lang}_COMPILER_ID_ARG1}
           ${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}
           ${testflags}
113
           \"${src}\"
114
115
116
117
118
119
120
121
      OUTPUT_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
      RETURN_VALUE CMAKE_${lang}_COMPILER_ID_RESULT
      )
  ENDIF(COMMAND EXECUTE_PROCESS)

  # Check the result of compilation.
  IF(CMAKE_${lang}_COMPILER_ID_RESULT)
    # Compilation failed.
122
    SET(MSG
123
124
125
126
127
128
129
      "Compiling the ${lang} compiler identification source file \"${src}\" failed.
${COMPILER_DESCRIPTION}
The output was:
${CMAKE_${lang}_COMPILER_ID_RESULT}
${CMAKE_${lang}_COMPILER_ID_OUTPUT}

")
130
131
132
133
134
135
136
    FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${MSG}")
    #IF(NOT CMAKE_${lang}_COMPILER_ID_ALLOW_FAIL)
    #  MESSAGE(FATAL_ERROR "${MSG}")
    #ENDIF(NOT CMAKE_${lang}_COMPILER_ID_ALLOW_FAIL)

    # No output files should be inspected.
    SET(COMPILER_${lang}_PRODUCED_FILES)
137
138
139
  ELSE(CMAKE_${lang}_COMPILER_ID_RESULT)
    # Compilation succeeded.
    FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
140
141
142
143
144
145
146
      "Compiling the ${lang} compiler identification source file \"${src}\" succeeded.
${COMPILER_DESCRIPTION}
The output was:
${CMAKE_${lang}_COMPILER_ID_RESULT}
${CMAKE_${lang}_COMPILER_ID_OUTPUT}

")
147

148
149
    # Find the executable produced by the compiler, try all files in the
    # binary dir.
150
151
152
153
    FILE(GLOB COMPILER_${lang}_PRODUCED_FILES
      RELATIVE ${CMAKE_${lang}_COMPILER_ID_DIR}
      ${CMAKE_${lang}_COMPILER_ID_DIR}/*)
    LIST(REMOVE_ITEM COMPILER_${lang}_PRODUCED_FILES "${src}")
154
    FOREACH(file ${COMPILER_${lang}_PRODUCED_FILES})
155
156
      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
        "Compilation of the ${lang} compiler identification source \""
157
        "${src}\" produced \"${file}\"\n\n")
158
    ENDFOREACH(file)
159

Alexander Neundorf's avatar
 
Alexander Neundorf committed
160
161
    IF(NOT COMPILER_${lang}_PRODUCED_FILES)
      # No executable was found.
162
163
      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
        "Compilation of the ${lang} compiler identification source \""
164
        "${src}\" did not produce an executable in \""
165
        "${CMAKE_${lang}_COMPILER_ID_DIR}\".\n\n")
Alexander Neundorf's avatar
 
Alexander Neundorf committed
166
    ENDIF(NOT COMPILER_${lang}_PRODUCED_FILES)
167
  ENDIF(CMAKE_${lang}_COMPILER_ID_RESULT)
168

169
  # Return the files produced by the compilation.
170
  SET(COMPILER_${lang}_PRODUCED_FILES "${COMPILER_${lang}_PRODUCED_FILES}" PARENT_SCOPE)
171
ENDFUNCTION(CMAKE_DETERMINE_COMPILER_ID_BUILD lang testflags src)
172
173
174
175
176
177
178
179
180
181

#-----------------------------------------------------------------------------
# Function to extract the compiler id from an executable.
FUNCTION(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
  # Look for a compiler id if not yet known.
  IF(NOT CMAKE_${lang}_COMPILER_ID)
    # Read the compiler identification string from the executable file.
    SET(COMPILER_ID)
    SET(PLATFORM_ID)
    FILE(STRINGS ${file}
182
      CMAKE_${lang}_COMPILER_ID_STRINGS LIMIT_COUNT 3 REGEX "INFO:")
183
184
    SET(HAVE_COMPILER_TWICE 0)
    FOREACH(info ${CMAKE_${lang}_COMPILER_ID_STRINGS})
185
      IF("${info}" MATCHES ".*INFO:compiler\\[([^]\"]*)\\].*")
186
187
188
189
190
        IF(COMPILER_ID)
          SET(COMPILER_ID_TWICE 1)
        ENDIF(COMPILER_ID)
        STRING(REGEX REPLACE ".*INFO:compiler\\[([^]]*)\\].*" "\\1"
          COMPILER_ID "${info}")
191
192
      ENDIF("${info}" MATCHES ".*INFO:compiler\\[([^]\"]*)\\].*")
      IF("${info}" MATCHES ".*INFO:platform\\[([^]\"]*)\\].*")
193
194
        STRING(REGEX REPLACE ".*INFO:platform\\[([^]]*)\\].*" "\\1"
          PLATFORM_ID "${info}")
195
      ENDIF("${info}" MATCHES ".*INFO:platform\\[([^]\"]*)\\].*")
196
197
198
199
      IF("${info}" MATCHES ".*INFO:arch\\[([^]\"]*)\\].*")
        STRING(REGEX REPLACE ".*INFO:arch\\[([^]]*)\\].*" "\\1"
          ARCHITECTURE_ID "${info}")
      ENDIF("${info}" MATCHES ".*INFO:arch\\[([^]\"]*)\\].*")
200
201
202
203
204
205
    ENDFOREACH(info)

    # Check if a valid compiler and platform were found.
    IF(COMPILER_ID AND NOT COMPILER_ID_TWICE)
      SET(CMAKE_${lang}_COMPILER_ID "${COMPILER_ID}")
      SET(CMAKE_${lang}_PLATFORM_ID "${PLATFORM_ID}")
206
      SET(MSVC_${lang}_ARCHITECTURE_ID "${ARCHITECTURE_ID}")
207
208
209
    ENDIF(COMPILER_ID AND NOT COMPILER_ID_TWICE)

    # Check the compiler identification string.
210
    IF(CMAKE_${lang}_COMPILER_ID)
211
212
213
214
      # The compiler identification was found.
      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
        "The ${lang} compiler identification is ${CMAKE_${lang}_COMPILER_ID}, found in \""
        "${file}\"\n\n")
215
    ELSE(CMAKE_${lang}_COMPILER_ID)
216
217
218
219
      # The compiler identification could not be found.
      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
        "The ${lang} compiler identification could not be found in \""
        "${file}\"\n\n")
220
    ENDIF(CMAKE_${lang}_COMPILER_ID)
221
222
223
224
225
226
227
228
  ENDIF(NOT CMAKE_${lang}_COMPILER_ID)

  # try to figure out the executable format: ELF, COFF, Mach-O
  IF(NOT CMAKE_EXECUTABLE_FORMAT)
    FILE(READ ${file} CMAKE_EXECUTABLE_MAGIC LIMIT 4 HEX)

    # ELF files start with 0x7f"ELF"
    IF("${CMAKE_EXECUTABLE_MAGIC}" STREQUAL "7f454c46")
229
      SET(CMAKE_EXECUTABLE_FORMAT "ELF" CACHE INTERNAL "Executable file format")
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
    ENDIF("${CMAKE_EXECUTABLE_MAGIC}" STREQUAL "7f454c46")

#    # COFF (.exe) files start with "MZ"
#    IF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "4d5a....")
#      SET(CMAKE_EXECUTABLE_FORMAT "COFF" CACHE STRING "Executable file format")
#    ENDIF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "4d5a....")
#
#    # Mach-O files start with CAFEBABE or FEEDFACE, according to http://radio.weblogs.com/0100490/2003/01/28.html
#    IF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "cafebabe")
#      SET(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE STRING "Executable file format")
#    ENDIF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "cafebabe")
#    IF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "feedface")
#      SET(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE STRING "Executable file format")
#    ENDIF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "feedface")

  ENDIF(NOT CMAKE_EXECUTABLE_FORMAT)

  # Return the information extracted.
248
249
  SET(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
  SET(CMAKE_${lang}_PLATFORM_ID "${CMAKE_${lang}_PLATFORM_ID}" PARENT_SCOPE)
250
251
  SET(MSVC_${lang}_ARCHITECTURE_ID "${MSVC_${lang}_ARCHITECTURE_ID}" 
    PARENT_SCOPE)
252
  SET(CMAKE_EXECUTABLE_FORMAT "${CMAKE_EXECUTABLE_FORMAT}" PARENT_SCOPE)
253
ENDFUNCTION(CMAKE_DETERMINE_COMPILER_ID_CHECK lang)
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

#-----------------------------------------------------------------------------
# Function to query the compiler vendor.
# This uses a table with entries of the form
#   list(APPEND CMAKE_${lang}_COMPILER_ID_VENDORS ${vendor})
#   set(CMAKE_${lang}_COMPILER_ID_VENDOR_FLAGS_${vendor} -some-vendor-flag)
#   set(CMAKE_${lang}_COMPILER_ID_VENDOR_REGEX_${vendor} "Some Vendor Output")
# We try running the compiler with the flag for each vendor and
# matching its regular expression in the output.
FUNCTION(CMAKE_DETERMINE_COMPILER_ID_VENDOR lang)
  FOREACH(vendor ${CMAKE_${lang}_COMPILER_ID_VENDORS})
    SET(flags ${CMAKE_${lang}_COMPILER_ID_VENDOR_FLAGS_${vendor}})
    SET(regex ${CMAKE_${lang}_COMPILER_ID_VENDOR_REGEX_${vendor}})
    EXECUTE_PROCESS(
      COMMAND ${CMAKE_${lang}_COMPILER}
      ${CMAKE_${lang}_COMPILER_ID_ARG1}
      ${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}
      ${flags}
      WORKING_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}
      OUTPUT_VARIABLE output ERROR_VARIABLE output
      RESULT_VARIABLE result
      )
    IF("${output}" MATCHES "${regex}")
      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
        "Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
        "matched \"${regex}\":\n${output}")
      SET(CMAKE_${lang}_COMPILER_ID "${vendor}" PARENT_SCOPE)
      BREAK()
    ELSE()
      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
        "Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
        "did not match \"${regex}\":\n${output}")
    ENDIF()
  ENDFOREACH()
ENDFUNCTION(CMAKE_DETERMINE_COMPILER_ID_VENDOR)