* Sync up to trunk head (r65120).
[reactos.git] / cmake / CMakeDetermineCompilerId.cmake
1
2 #=============================================================================
3 # Copyright 2007-2009 Kitware, Inc.
4 #
5 # Distributed under the OSI-approved BSD License (the "License");
6 # see accompanying file Copyright.txt for details.
7 #
8 # This software is distributed WITHOUT ANY WARRANTY; without even the
9 # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 # See the License for more information.
11 #=============================================================================
12 # (To distribute this file outside of CMake, substitute the full
13 # License text for the above reference.)
14
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.
17 # If successful, sets CMAKE_<lang>_COMPILER_ID and CMAKE_<lang>_PLATFORM_ID
18
19 FUNCTION(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
20 # Make sure the compiler arguments are clean.
21 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 # Make sure user-specified compiler flags are used.
25 IF(CMAKE_${lang}_FLAGS)
26 SET(CMAKE_${lang}_COMPILER_ID_FLAGS ${CMAKE_${lang}_FLAGS})
27 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 # Try building with no extra flags and then try each set
36 # of helper flags. Stop when the compiler is identified.
37 FOREACH(flags "" ${CMAKE_${lang}_COMPILER_ID_TEST_FLAGS})
38 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 ENDFOREACH(file)
43 ENDIF(NOT CMAKE_${lang}_COMPILER_ID)
44 ENDFOREACH(flags)
45
46 # If the compiler is still unknown, try to query its vendor.
47 IF(NOT CMAKE_${lang}_COMPILER_ID)
48 CMAKE_DETERMINE_COMPILER_ID_VENDOR(${lang})
49 ENDIF()
50
51 # if the format is unknown after all files have been checked, put "Unknown" in the cache
52 IF(NOT CMAKE_EXECUTABLE_FORMAT)
53 SET(CMAKE_EXECUTABLE_FORMAT "Unknown" CACHE INTERNAL "Executable file format")
54 ENDIF(NOT CMAKE_EXECUTABLE_FORMAT)
55
56 # Display the final identification result.
57 IF(CMAKE_${lang}_COMPILER_ID)
58 MESSAGE(STATUS "The ${lang} compiler identification is "
59 "${CMAKE_${lang}_COMPILER_ID}")
60 ELSE(CMAKE_${lang}_COMPILER_ID)
61 MESSAGE(STATUS "The ${lang} compiler identification is unknown")
62 ENDIF(CMAKE_${lang}_COMPILER_ID)
63
64 SET(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
65 SET(CMAKE_${lang}_PLATFORM_ID "${CMAKE_${lang}_PLATFORM_ID}" PARENT_SCOPE)
66 SET(MSVC_${lang}_ARCHITECTURE_ID "${MSVC_${lang}_ARCHITECTURE_ID}"
67 PARENT_SCOPE)
68 ENDFUNCTION(CMAKE_DETERMINE_COMPILER_ID)
69
70 #-----------------------------------------------------------------------------
71 # Function to write the compiler id source file.
72 FUNCTION(CMAKE_DETERMINE_COMPILER_ID_WRITE lang src)
73 FILE(READ ${CMAKE_ROOT}/Modules/${src}.in ID_CONTENT_IN)
74 STRING(CONFIGURE "${ID_CONTENT_IN}" ID_CONTENT_OUT @ONLY)
75 FILE(WRITE ${CMAKE_${lang}_COMPILER_ID_DIR}/${src} "${ID_CONTENT_OUT}")
76 ENDFUNCTION(CMAKE_DETERMINE_COMPILER_ID_WRITE)
77
78 #-----------------------------------------------------------------------------
79 # Function to build the compiler id source file and look for output
80 # files.
81 FUNCTION(CMAKE_DETERMINE_COMPILER_ID_BUILD lang testflags src)
82 # Create a clean working directory.
83 FILE(REMOVE_RECURSE ${CMAKE_${lang}_COMPILER_ID_DIR})
84 FILE(MAKE_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR})
85 CMAKE_DETERMINE_COMPILER_ID_WRITE("${lang}" "${src}")
86
87 # Construct a description of this test case.
88 SET(COMPILER_DESCRIPTION
89 "Compiler: ${CMAKE_${lang}_COMPILER} ${CMAKE_${lang}_COMPILER_ID_ARG1}
90 Build flags: ${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}
91 Id flags: ${testflags}
92 ")
93
94 # Compile the compiler identification source.
95 IF(COMMAND EXECUTE_PROCESS)
96 EXECUTE_PROCESS(
97 COMMAND ${CMAKE_${lang}_COMPILER}
98 ${CMAKE_${lang}_COMPILER_ID_ARG1}
99 ${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}
100 ${testflags}
101 "${src}"
102 WORKING_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}
103 OUTPUT_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
104 ERROR_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
105 RESULT_VARIABLE CMAKE_${lang}_COMPILER_ID_RESULT
106 )
107 ELSE(COMMAND EXECUTE_PROCESS)
108 EXEC_PROGRAM(
109 ${CMAKE_${lang}_COMPILER} ${CMAKE_${lang}_COMPILER_ID_DIR}
110 ARGS ${CMAKE_${lang}_COMPILER_ID_ARG1}
111 ${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}
112 ${testflags}
113 \"${src}\"
114 OUTPUT_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
115 RETURN_VALUE CMAKE_${lang}_COMPILER_ID_RESULT
116 )
117 ENDIF(COMMAND EXECUTE_PROCESS)
118
119 # Check the result of compilation.
120 IF(CMAKE_${lang}_COMPILER_ID_RESULT)
121 # Compilation failed.
122 SET(MSG
123 "Compiling the ${lang} compiler identification source file \"${src}\" failed.
124 ${COMPILER_DESCRIPTION}
125 The output was:
126 ${CMAKE_${lang}_COMPILER_ID_RESULT}
127 ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
128
129 ")
130 FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "${MSG}")
131 #IF(NOT CMAKE_${lang}_COMPILER_ID_ALLOW_FAIL)
132 # MESSAGE(FATAL_ERROR "${MSG}")
133 #ENDIF(NOT CMAKE_${lang}_COMPILER_ID_ALLOW_FAIL)
134
135 # No output files should be inspected.
136 SET(COMPILER_${lang}_PRODUCED_FILES)
137 ELSE(CMAKE_${lang}_COMPILER_ID_RESULT)
138 # Compilation succeeded.
139 FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
140 "Compiling the ${lang} compiler identification source file \"${src}\" succeeded.
141 ${COMPILER_DESCRIPTION}
142 The output was:
143 ${CMAKE_${lang}_COMPILER_ID_RESULT}
144 ${CMAKE_${lang}_COMPILER_ID_OUTPUT}
145
146 ")
147
148 # Find the executable produced by the compiler, try all files in the
149 # binary dir.
150 FILE(GLOB COMPILER_${lang}_PRODUCED_FILES
151 RELATIVE ${CMAKE_${lang}_COMPILER_ID_DIR}
152 ${CMAKE_${lang}_COMPILER_ID_DIR}/*)
153 LIST(REMOVE_ITEM COMPILER_${lang}_PRODUCED_FILES "${src}")
154 FOREACH(file ${COMPILER_${lang}_PRODUCED_FILES})
155 FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
156 "Compilation of the ${lang} compiler identification source \""
157 "${src}\" produced \"${file}\"\n\n")
158 ENDFOREACH(file)
159
160 IF(NOT COMPILER_${lang}_PRODUCED_FILES)
161 # No executable was found.
162 FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
163 "Compilation of the ${lang} compiler identification source \""
164 "${src}\" did not produce an executable in \""
165 "${CMAKE_${lang}_COMPILER_ID_DIR}\".\n\n")
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 # Function to extract the compiler id from an executable.
175 FUNCTION(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
176 # Look for a compiler id if not yet known.
177 IF(NOT CMAKE_${lang}_COMPILER_ID)
178 # Read the compiler identification string from the executable file.
179 SET(COMPILER_ID)
180 SET(PLATFORM_ID)
181 FILE(STRINGS ${file}
182 CMAKE_${lang}_COMPILER_ID_STRINGS LIMIT_COUNT 3 REGEX "INFO:")
183 SET(HAVE_COMPILER_TWICE 0)
184 FOREACH(info ${CMAKE_${lang}_COMPILER_ID_STRINGS})
185 IF("${info}" MATCHES ".*INFO:compiler\\[([^]\"]*)\\].*")
186 IF(COMPILER_ID)
187 SET(COMPILER_ID_TWICE 1)
188 ENDIF(COMPILER_ID)
189 STRING(REGEX REPLACE ".*INFO:compiler\\[([^]]*)\\].*" "\\1"
190 COMPILER_ID "${info}")
191 ENDIF("${info}" MATCHES ".*INFO:compiler\\[([^]\"]*)\\].*")
192 IF("${info}" MATCHES ".*INFO:platform\\[([^]\"]*)\\].*")
193 STRING(REGEX REPLACE ".*INFO:platform\\[([^]]*)\\].*" "\\1"
194 PLATFORM_ID "${info}")
195 ENDIF("${info}" MATCHES ".*INFO:platform\\[([^]\"]*)\\].*")
196 IF("${info}" MATCHES ".*INFO:arch\\[([^]\"]*)\\].*")
197 STRING(REGEX REPLACE ".*INFO:arch\\[([^]]*)\\].*" "\\1"
198 ARCHITECTURE_ID "${info}")
199 ENDIF("${info}" MATCHES ".*INFO:arch\\[([^]\"]*)\\].*")
200 ENDFOREACH(info)
201
202 # Check if a valid compiler and platform were found.
203 IF(COMPILER_ID AND NOT COMPILER_ID_TWICE)
204 SET(CMAKE_${lang}_COMPILER_ID "${COMPILER_ID}")
205 SET(CMAKE_${lang}_PLATFORM_ID "${PLATFORM_ID}")
206 SET(MSVC_${lang}_ARCHITECTURE_ID "${ARCHITECTURE_ID}")
207 ENDIF(COMPILER_ID AND NOT COMPILER_ID_TWICE)
208
209 # Check the compiler identification string.
210 IF(CMAKE_${lang}_COMPILER_ID)
211 # The compiler identification was found.
212 FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
213 "The ${lang} compiler identification is ${CMAKE_${lang}_COMPILER_ID}, found in \""
214 "${file}\"\n\n")
215 ELSE(CMAKE_${lang}_COMPILER_ID)
216 # The compiler identification could not be found.
217 FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
218 "The ${lang} compiler identification could not be found in \""
219 "${file}\"\n\n")
220 ENDIF(CMAKE_${lang}_COMPILER_ID)
221 ENDIF(NOT CMAKE_${lang}_COMPILER_ID)
222
223 # try to figure out the executable format: ELF, COFF, Mach-O
224 IF(NOT CMAKE_EXECUTABLE_FORMAT)
225 FILE(READ ${file} CMAKE_EXECUTABLE_MAGIC LIMIT 4 HEX)
226
227 # ELF files start with 0x7f"ELF"
228 IF("${CMAKE_EXECUTABLE_MAGIC}" STREQUAL "7f454c46")
229 SET(CMAKE_EXECUTABLE_FORMAT "ELF" CACHE INTERNAL "Executable file format")
230 ENDIF("${CMAKE_EXECUTABLE_MAGIC}" STREQUAL "7f454c46")
231
232 # # COFF (.exe) files start with "MZ"
233 # IF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "4d5a....")
234 # SET(CMAKE_EXECUTABLE_FORMAT "COFF" CACHE STRING "Executable file format")
235 # ENDIF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "4d5a....")
236 #
237 # # Mach-O files start with CAFEBABE or FEEDFACE, according to http://radio.weblogs.com/0100490/2003/01/28.html
238 # IF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "cafebabe")
239 # SET(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE STRING "Executable file format")
240 # ENDIF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "cafebabe")
241 # IF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "feedface")
242 # SET(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE STRING "Executable file format")
243 # ENDIF("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "feedface")
244
245 ENDIF(NOT CMAKE_EXECUTABLE_FORMAT)
246 IF(NOT DEFINED CMAKE_EXECUTABLE_FORMAT)
247 SET(CMAKE_EXECUTABLE_FORMAT)
248 ENDIF()
249 # Return the information extracted.
250 SET(CMAKE_${lang}_COMPILER_ID "${CMAKE_${lang}_COMPILER_ID}" PARENT_SCOPE)
251 SET(CMAKE_${lang}_PLATFORM_ID "${CMAKE_${lang}_PLATFORM_ID}" PARENT_SCOPE)
252 SET(MSVC_${lang}_ARCHITECTURE_ID "${MSVC_${lang}_ARCHITECTURE_ID}"
253 PARENT_SCOPE)
254 SET(CMAKE_EXECUTABLE_FORMAT "${CMAKE_EXECUTABLE_FORMAT}" PARENT_SCOPE)
255 ENDFUNCTION(CMAKE_DETERMINE_COMPILER_ID_CHECK lang)
256
257 #-----------------------------------------------------------------------------
258 # Function to query the compiler vendor.
259 # This uses a table with entries of the form
260 # list(APPEND CMAKE_${lang}_COMPILER_ID_VENDORS ${vendor})
261 # set(CMAKE_${lang}_COMPILER_ID_VENDOR_FLAGS_${vendor} -some-vendor-flag)
262 # set(CMAKE_${lang}_COMPILER_ID_VENDOR_REGEX_${vendor} "Some Vendor Output")
263 # We try running the compiler with the flag for each vendor and
264 # matching its regular expression in the output.
265 FUNCTION(CMAKE_DETERMINE_COMPILER_ID_VENDOR lang)
266
267 IF(NOT CMAKE_${lang}_COMPILER_ID_DIR)
268 # We get here when this function is called not from within CMAKE_DETERMINE_COMPILER_ID()
269 # This is done e.g. for detecting the compiler ID for assemblers.
270 # Compute the directory in which to run the test and Create a clean working directory.
271 SET(CMAKE_${lang}_COMPILER_ID_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CompilerId${lang})
272 FILE(REMOVE_RECURSE ${CMAKE_${lang}_COMPILER_ID_DIR})
273 FILE(MAKE_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR})
274 ENDIF(NOT CMAKE_${lang}_COMPILER_ID_DIR)
275
276
277 FOREACH(vendor ${CMAKE_${lang}_COMPILER_ID_VENDORS})
278 SET(flags ${CMAKE_${lang}_COMPILER_ID_VENDOR_FLAGS_${vendor}})
279 SET(regex ${CMAKE_${lang}_COMPILER_ID_VENDOR_REGEX_${vendor}})
280 EXECUTE_PROCESS(
281 COMMAND ${CMAKE_${lang}_COMPILER}
282 ${CMAKE_${lang}_COMPILER_ID_ARG1}
283 ${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}
284 ${flags}
285 WORKING_DIRECTORY ${CMAKE_${lang}_COMPILER_ID_DIR}
286 OUTPUT_VARIABLE output ERROR_VARIABLE output
287 RESULT_VARIABLE result
288 TIMEOUT 10
289 )
290
291 IF("${lang}" STREQUAL "ASM")
292 MESSAGE(STATUS "Checked for ${vendor}")
293 MESSAGE(STATUS " Output: -${output}-")
294 MESSAGE(STATUS " Result: -${result}-")
295 ENDIF("${lang}" STREQUAL "ASM")
296
297 IF("${output}" MATCHES "${regex}")
298 FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
299 "Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
300 "matched \"${regex}\":\n${output}")
301 SET(CMAKE_${lang}_COMPILER_ID "${vendor}" PARENT_SCOPE)
302 BREAK()
303 ELSE()
304 IF("${result}" MATCHES "timeout")
305 FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
306 "Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
307 "terminated after 10 s due to timeout.")
308 ELSE()
309 FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
310 "Checking whether the ${lang} compiler is ${vendor} using \"${flags}\" "
311 "did not match \"${regex}\":\n${output}")
312 ENDIF()
313 ENDIF()
314 ENDFOREACH()
315 ENDFUNCTION(CMAKE_DETERMINE_COMPILER_ID_VENDOR)