1
2function(check_compile RESULT FILE FLAG TYPE)
3
4	string(REGEX REPLACE "[^a-zA-Z0-9_][^a-zA-Z0-9_]*" "-" cachevar "${TYPE}-${FLAG}")
5	set(cahevar "CHECK_COMPILE_${cahevar}")
6
7	if(DEFINED ${cachevar})
8		if(${cachevar})
9			set(${RESULT} "${FLAG}" PARENT_SCOPE)
10		else()
11			set(${RESULT} "" PARENT_SCOPE)
12		endif()
13		return()
14	endif()
15
16	# CMake already has a check_cxx_compiler_flag macro in CheckCXXCompilerFlag, but
17	# it prints the result variable in the output (which is ugly!) and also uses it
18	# as a key to cache checks - so it would need to be unique for each flag.
19	# Unfortunately it also naively pastes the variable name inside a regexp so
20	# if we tried to use the flag itself in the variable name it will fail for -std=c++11.
21	# But we can at least use the expressions for warnings from that macro (and more):
22	set(fail_regexps
23		"warning:"                                     # general
24		"unrecognized .*option"                        # GNU
25		"unknown .*option"                             # Clang
26		"ignoring unknown option"                      # MSVC
27		"warning D9002"                                # MSVC, any lang
28		"option.*not supported"                        # Intel
29		"invalid argument .*option"                    # Intel
30		"ignoring option .*argument required"          # Intel
31		"command line warning"                         # Intel
32		"[Uu]nknown option"                            # HP
33		"[Ww]arning: [Oo]ption"                        # SunPro
34		"command option .* is not recognized"          # XL
35		"not supported in this configuration; ignored" # AIX
36		"File with unknown suffix passed to linker"    # PGI
37		"WARNING: unknown flag:"                       # Open64
38	)
39
40	# Set the flags to check
41	set(old_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
42	set(old_CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
43	set(old_CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
44	set(old_CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}")
45	if("${TYPE}" STREQUAL "linker flag")
46		set(CMAKE_EXE_LINKER_FLAGS "${old_CMAKE_EXE_LINKER_FLAGS} ${FLAG}")
47		set(CMAKE_SHARED_LINKER_FLAGS "${old_CMAKE_SHARED_LINKER_FLAGS} ${FLAG}")
48		set(CMAKE_MODULE_LINKER_FLAGS "${old_CMAKE_MODULE_LINKER_FLAGS} ${FLAG}")
49	elseif("${TYPE}" STREQUAL "compiler flag")
50		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}")
51	endif()
52
53	# Check if we can compile and link a simple file with the new flags
54	try_compile(
55		check_compiler_flag ${CMAKE_BINARY_DIR} ${FILE}
56		CMAKE_FLAGS "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
57		            "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}"
58		            "-DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS}"
59		            "-DCMAKE_MODULE_LINKER_FLAGS=${CMAKE_MODULE_LINKER_FLAGS}"
60		            "-DLINK_LIBRARIES=${ARGV4}"
61		OUTPUT_VARIABLE ERRORLOG
62	)
63
64	# Restore the old flags
65	set(CMAKE_CXX_FLAGS "${old_CMAKE_CXX_FLAGS}")
66	set(CMAKE_EXE_LINKER_FLAGS "${old_CMAKE_EXE_LINKER_FLAGS}")
67	set(CMAKE_SHARED_LINKER_FLAGS "${old_CMAKE_SHARED_LINKER_FLAGS}")
68	set(CMAKE_MODULE_LINKER_FLAGS "${old_CMAKE_MODULE_LINKER_FLAGS}")
69
70	set(errormsg "unsupported")
71	if(${ARGC} GREATER 4)
72		set(errormsg "${ARGV5}")
73	endif()
74
75	if(NOT check_compiler_flag)
76		message(STATUS "Checking ${TYPE}: ${FLAG} - ${errormsg}")
77		set(${RESULT} "" PARENT_SCOPE)
78		set("${cachevar}" 0 CACHE INTERNAL "...")
79	else()
80
81		set(has_warning 0)
82		foreach(expr IN LISTS fail_regexps)
83			if("${ERRORLOG}" MATCHES "${expr}")
84				set(has_warning 1)
85			endif()
86		endforeach()
87
88		if(has_warning)
89			message(STATUS "Checking ${TYPE}: ${FLAG} - ${errormsg} (warning)")
90			set(${RESULT} "" PARENT_SCOPE)
91			set("${cachevar}" 0 CACHE INTERNAL "...")
92		else()
93			message(STATUS "Checking ${TYPE}: ${FLAG}")
94			set(${RESULT} "${FLAG}" PARENT_SCOPE)
95			set("${cachevar}" 1 CACHE INTERNAL "...")
96		endif()
97
98	endif()
99
100endfunction(check_compile)
101
102function(check_flag RESULT FLAG TYPE)
103	set(compile_test_file "${CMAKE_CURRENT_BINARY_DIR}/compile_flag_test.cpp")
104	file(WRITE ${compile_test_file} "__attribute__((const)) int main(){ return 0; }\n")
105	check_compile(result "${compile_test_file}" "${FLAG}" "${TYPE} flag")
106	set(${RESULT} "${result}" PARENT_SCOPE)
107endfunction(check_flag)
108
109function(check_compiler_flag RESULT FLAG)
110	check_flag(result "${FLAG}" compiler)
111	set(${RESULT} "${result}" PARENT_SCOPE)
112endfunction(check_compiler_flag)
113
114function(check_linker_flag RESULT FLAG)
115	check_flag(result "${FLAG}" linker)
116	set(${RESULT} "${result}" PARENT_SCOPE)
117endfunction(check_linker_flag)
118
119function(add_cxxflag FLAG)
120
121	check_compiler_flag(RESULT "${FLAG}")
122
123	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RESULT}" PARENT_SCOPE)
124
125	if("${RESULT}" STREQUAL "")
126		set(FLAG_FOUND 0 PARENT_SCOPE)
127	else()
128		set(FLAG_FOUND 1 PARENT_SCOPE)
129	endif()
130
131endfunction(add_cxxflag)
132
133function(add_ldflag FLAG)
134
135	check_linker_flag(RESULT "${FLAG}")
136
137	set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${RESULT}" PARENT_SCOPE)
138	set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${RESULT}" PARENT_SCOPE)
139	set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${RESULT}" PARENT_SCOPE)
140
141	if("${RESULT}" STREQUAL "")
142		set(FLAG_FOUND 0 PARENT_SCOPE)
143	else()
144		set(FLAG_FOUND 1 PARENT_SCOPE)
145	endif()
146
147endfunction(add_ldflag)
148
149function(try_link_library LIBRARY_NAME LIBRARY_FILE ERROR_VAR)
150	# See if we can link a simple program with the library using the configured c++ compiler
151	set(link_test_file "${CMAKE_CURRENT_BINARY_DIR}/link_test.cpp")
152	file(WRITE ${link_test_file} "int main(){}\n")
153	if(CMAKE_THREAD_LIBS_INIT)
154		list(APPEND LIBRARY_FILE "${CMAKE_THREAD_LIBS_INIT}")
155	endif()
156	try_compile(
157		CHECK_${LIBRARY_NAME}_LINK "${CMAKE_BINARY_DIR}" "${link_test_file}"
158		CMAKE_FLAGS "-DLINK_LIBRARIES=${LIBRARY_FILE}"
159		            "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
160		            "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}"
161		            "-DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS}"
162		            "-DCMAKE_MODULE_LINKER_FLAGS=${CMAKE_MODULE_LINKER_FLAGS}"
163		OUTPUT_VARIABLE ERRORLOG
164	)
165	set(${ERROR_VAR} "${ERRORLOG}" PARENT_SCOPE)
166endfunction(try_link_library)
167
168##############################################################################
169# Check that a a library actually works for the current configuration
170function(check_link_library LIBRARY_NAME LIBRARY_VARIABLE)
171
172	set(lib_current "${${LIBRARY_VARIABLE}}")
173	set(found_var "ARX_CLL_${LIBRARY_NAME}_FOUND")
174	set(working_var "ARX_CLL_${LIBRARY_NAME}_WORKING")
175
176	if(CHECK_${LIBRARY_NAME}_LINK)
177		set(lib_found "${${found_var}}")
178		set(lib_working "${${working_var}}")
179		if((lib_current STREQUAL lib_found) OR (lib_current STREQUAL lib_working))
180			set("${LIBRARY_VARIABLE}" "${lib_working}" PARENT_SCOPE)
181			return()
182		endif()
183	endif()
184
185	set("${found_var}" "${lib_current}" CACHE INTERNAL "...")
186
187	if(NOT lib_current STREQUAL "")
188		message(STATUS "Checking ${LIBRARY_NAME}: ${lib_current}")
189	endif()
190
191	# Check if we can link to the full path found by find_package
192	try_link_library(${LIBRARY_NAME} "${lib_current}" ERRORLOG1)
193
194	if(CHECK_${LIBRARY_NAME}_LINK)
195		set("${working_var}" "${lib_current}" CACHE INTERNAL "...")
196		return()
197	endif()
198
199	# Check if the linker is smarter than cmake and try to link with only the library name
200	string(REGEX REPLACE "(^|;)[^;]*/lib([^;/]*)\\.so" "\\1-l\\2"
201	       LIBRARY_FILE "${lib_current}")
202
203	if(NOT LIBRARY_FILE STREQUAL lib_current)
204
205		try_link_library(${LIBRARY_NAME} "${LIBRARY_FILE}" ERRORLOG2)
206
207		if(CHECK_${LIBRARY_NAME}_LINK)
208			message(STATUS " -> using ${LIBRARY_FILE} instead")
209			set("${LIBRARY_VARIABLE}" "${LIBRARY_FILE}" PARENT_SCOPE)
210			set("${working_var}" "${LIBRARY_FILE}" CACHE INTERNAL "...")
211			return()
212		endif()
213
214	endif()
215
216	# Force cmake to search again, as the cached library doesn't work
217	unset(FIND_PACKAGE_MESSAGE_DETAILS_${ARGV2} CACHE)
218	unset(FIND_PACKAGE_MESSAGE_DETAILS_${LIBRARY_NAME} CACHE)
219
220	message(FATAL_ERROR "\n${ERRORLOG1}\n\n${ERRORLOG2}\n\n"
221	        "!! No suitable version of ${LIBRARY_NAME} found.\n"
222	        "   Maybe you don't have the right (32 vs.64 bit) architecture installed?\n\n"
223	        "   Tried ${lib_current} and ${LIBRARY_FILE}\n"
224	        "   Using compiler ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS}\n\n\n")
225
226endfunction(check_link_library)
227
228function(force_recheck_library LIBRARY_NAME)
229	unset(FIND_PACKAGE_MESSAGE_DETAILS_${ARGV1} CACHE)
230	unset(FIND_PACKAGE_MESSAGE_DETAILS_${LIBRARY_NAME} CACHE)
231	unset(CHECK_${LIBRARY_NAME}_LINK CACHE)
232endfunction()
233