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# This is used internally by CMake and should not be included by user code. 5 6# helper function that parses implicit include dirs from a single line 7# for compilers that report them that way. on success we return the 8# list of dirs in id_var and set state_var to the 'done' state. 9function(cmake_parse_implicit_include_line line lang id_var log_var state_var) 10 # clear variables we append to (avoids possible pollution from parent scopes) 11 unset(rv) 12 set(log "") 13 14 # Cray compiler (from cray wrapper, via PrgEnv-cray) 15 if(CMAKE_${lang}_COMPILER_ID STREQUAL "Cray" AND 16 line MATCHES "^/" AND line MATCHES "/ccfe |/ftnfe " AND 17 line MATCHES " -isystem| -I") 18 string(REGEX MATCHALL " (-I ?|-isystem )(\"[^\"]+\"|[^ \"]+)" incs "${line}") 19 foreach(inc IN LISTS incs) 20 string(REGEX REPLACE " (-I ?|-isystem )(\"[^\"]+\"|[^ \"]+)" "\\2" idir "${inc}") 21 list(APPEND rv "${idir}") 22 endforeach() 23 if(rv) 24 string(APPEND log " got implicit includes via cray ccfe parser!\n") 25 else() 26 string(APPEND log " warning: cray ccfe parse failed!\n") 27 endif() 28 endif() 29 30 # PGI compiler 31 if(CMAKE_${lang}_COMPILER_ID STREQUAL "PGI") 32 # pgc++ verbose output differs 33 if((lang STREQUAL "C" OR lang STREQUAL "Fortran") AND 34 line MATCHES "^/" AND 35 line MATCHES "/pgc |/pgf901 |/pgftnc " AND 36 line MATCHES " -cmdline ") 37 # cmdline has unparsed cmdline, remove it 38 string(REGEX REPLACE "-cmdline .*" "" line "${line}") 39 if("${line}" MATCHES " -nostdinc ") 40 set(rv "") # defined, but empty 41 else() 42 string(REGEX MATCHALL " -stdinc ([^ ]*)" incs "${line}") 43 foreach(inc IN LISTS incs) 44 string(REGEX REPLACE " -stdinc ([^ ]*)" "\\1" idir "${inc}") 45 string(REPLACE ":" ";" idir "${idir}") 46 list(APPEND rv ${idir}) 47 endforeach() 48 endif() 49 if(DEFINED rv) 50 string(APPEND log " got implicit includes via PGI C/F parser!\n") 51 else() 52 string(APPEND log " warning: PGI C/F parse failed!\n") 53 endif() 54 elseif(lang STREQUAL "CXX" AND line MATCHES "^/" AND 55 line MATCHES "/pggpp1 " AND line MATCHES " -I") 56 # oddly, -Mnostdinc does not get rid of system -I's, at least in 57 # PGI 18.10.1 ... 58 string(REGEX MATCHALL " (-I ?)([^ ]*)" incs "${line}") 59 foreach(inc IN LISTS incs) 60 string(REGEX REPLACE " (-I ?)([^ ]*)" "\\2" idir "${inc}") 61 if(NOT idir STREQUAL "-") # filter out "-I-" 62 list(APPEND rv "${idir}") 63 endif() 64 endforeach() 65 if(DEFINED rv) 66 string(APPEND log " got implicit includes via PGI CXX parser!\n") 67 else() 68 string(APPEND log " warning: PGI CXX parse failed!\n") 69 endif() 70 endif() 71 endif() 72 73 # SunPro compiler 74 if(CMAKE_${lang}_COMPILER_ID STREQUAL "SunPro" AND 75 (line MATCHES "-D__SUNPRO_C" OR line MATCHES "-D__SUNPRO_F")) 76 string(REGEX MATCHALL " (-I ?)([^ ]*)" incs "${line}") 77 foreach(inc IN LISTS incs) 78 string(REGEX REPLACE " (-I ?)([^ ]*)" "\\2" idir "${inc}") 79 if(NOT "${idir}" STREQUAL "-xbuiltin") 80 list(APPEND rv "${idir}") 81 endif() 82 endforeach() 83 if(rv) 84 if (lang STREQUAL "C" OR lang STREQUAL "CXX") 85 # /usr/include appears to be hardwired in 86 list(APPEND rv "/usr/include") 87 endif() 88 string(APPEND log " got implicit includes via sunpro parser!\n") 89 else() 90 string(APPEND log " warning: sunpro parse failed!\n") 91 endif() 92 endif() 93 94 # XL compiler 95 if((CMAKE_${lang}_COMPILER_ID STREQUAL "XL" 96 OR CMAKE_${lang}_COMPILER_ID STREQUAL "XLClang") 97 AND line MATCHES "^/" 98 AND ( (lang STREQUAL "Fortran" AND 99 line MATCHES "/xl[fF]entry " AND 100 line MATCHES "OSVAR\\([^ ]+\\)") 101 OR 102 ( (lang STREQUAL "C" OR lang STREQUAL "CXX") AND 103 line MATCHES "/xl[cC]2?entry " AND 104 line MATCHES " -qosvar=") 105 ) ) 106 # -qnostdinc cancels other stdinc flags, even if present 107 string(FIND "${line}" " -qnostdinc" nostd) 108 if(NOT nostd EQUAL -1) 109 set(rv "") # defined but empty 110 string(APPEND log " got implicit includes via XL parser (nostdinc)\n") 111 else() 112 if(lang STREQUAL "CXX") 113 string(REGEX MATCHALL " -qcpp_stdinc=([^ ]*)" std "${line}") 114 string(REGEX MATCHALL " -qgcc_cpp_stdinc=([^ ]*)" gcc_std "${line}") 115 else() 116 string(REGEX MATCHALL " -qc_stdinc=([^ ]*)" std "${line}") 117 string(REGEX MATCHALL " -qgcc_c_stdinc=([^ ]*)" gcc_std "${line}") 118 endif() 119 set(xlstd ${std} ${gcc_std}) 120 foreach(inc IN LISTS xlstd) 121 string(REGEX REPLACE " -q(cpp|gcc_cpp|c|gcc_c)_stdinc=([^ ]*)" "\\2" 122 ipath "${inc}") 123 string(REPLACE ":" ";" ipath "${ipath}") 124 list(APPEND rv ${ipath}) 125 endforeach() 126 endif() 127 # user can add -I flags via CMAKE_{C,CXX}_FLAGS, look for that too 128 string(REGEX MATCHALL " (-I ?)([^ ]*)" incs "${line}") 129 unset(urv) 130 foreach(inc IN LISTS incs) 131 string(REGEX REPLACE " (-I ?)([^ ]*)" "\\2" idir "${inc}") 132 list(APPEND urv "${idir}") 133 endforeach() 134 if(urv) 135 if ("${rv}" STREQUAL "") 136 set(rv ${urv}) 137 else() 138 list(APPEND rv ${urv}) 139 endif() 140 endif() 141 142 if(DEFINED rv) 143 string(APPEND log " got implicit includes via XL parser!\n") 144 else() 145 string(APPEND log " warning: XL parse failed!\n") 146 endif() 147 endif() 148 149 # Fujitsu compiler 150 if(CMAKE_${lang}_COMPILER_ID STREQUAL "Fujitsu" AND 151 line MATCHES "/ccpcom") 152 string(REGEX MATCHALL " (-I *|--sys_include=|--preinclude +)(\"[^\"]+\"|[^ \"]+)" incs "${line}") 153 foreach(inc IN LISTS incs) 154 string(REGEX REPLACE " (-I *|--sys_include=|--preinclude +)(\"[^\"]+\"|[^ \"]+)" "\\2" idir "${inc}") 155 list(APPEND rv "${idir}") 156 endforeach() 157 if(rv) 158 string(APPEND log " got implicit includes via fujitsu ccpcom parser!\n") 159 else() 160 string(APPEND log " warning: fujitsu ccpcom parse failed!\n") 161 endif() 162 endif() 163 164 if(log) 165 set(${log_var} "${log}" PARENT_SCOPE) 166 else() 167 unset(${log_var} PARENT_SCOPE) 168 endif() 169 if(DEFINED rv) 170 set(${id_var} "${rv}" PARENT_SCOPE) 171 set(${state_var} "done" PARENT_SCOPE) 172 endif() 173endfunction() 174 175# top-level function to parse implicit include directory information 176# from verbose compiler output. sets state_var in parent to 'done' on success. 177function(cmake_parse_implicit_include_info text lang dir_var log_var state_var) 178 set(state start) # values: start, loading, done 179 180 # clear variables we append to (avoids possible pollution from parent scopes) 181 set(implicit_dirs_tmp) 182 set(log "") 183 184 # go through each line of output... 185 string(REGEX REPLACE "\r*\n" ";" output_lines "${text}") 186 foreach(line IN LISTS output_lines) 187 if(state STREQUAL start) 188 string(FIND "${line}" "#include \"...\" search starts here:" rv) 189 if(rv GREATER -1) 190 set(state loading) 191 set(preload 1) # looking for include <...> now 192 string(APPEND log " found start of include info\n") 193 else() 194 cmake_parse_implicit_include_line("${line}" "${lang}" implicit_dirs_tmp 195 linelog state) 196 if(linelog) 197 string(APPEND log ${linelog}) 198 endif() 199 if(state STREQUAL done) 200 break() 201 endif() 202 endif() 203 elseif(state STREQUAL loading) 204 string(FIND "${line}" "End of search list." rv) 205 if(rv GREATER -1) 206 set(state done) 207 string(APPEND log " end of search list found\n") 208 break() 209 endif() 210 if(preload) 211 string(FIND "${line}" "#include <...> search starts here:" rv) 212 if(rv GREATER -1) 213 set(preload 0) 214 string(APPEND log " found start of implicit include info\n") 215 endif() 216 continue() 217 endif() 218 if("${line}" MATCHES "^ ") 219 string(SUBSTRING "${line}" 1 -1 line) # remove leading space 220 endif() 221 if ("${line}" MATCHES " \\(framework directory\\)$") 222 continue() # frameworks are handled elsewhere, ignore them here 223 endif() 224 string(REPLACE "\\" "/" path "${line}") 225 list(APPEND implicit_dirs_tmp "${path}") 226 string(APPEND log " add: [${path}]\n") 227 endif() 228 endforeach() 229 230 set(implicit_dirs "") 231 foreach(d IN LISTS implicit_dirs_tmp) 232 if(IS_ABSOLUTE "${d}") 233 get_filename_component(dir "${d}" ABSOLUTE) 234 list(APPEND implicit_dirs "${dir}") 235 string(APPEND log " collapse include dir [${d}] ==> [${dir}]\n") 236 elseif("${d}" MATCHES [[^\.\.[\/]\.\.[\/](.*)$]]) 237 # This relative path is deep enough to get out of the CMakeFiles/CMakeTmp 238 # directory where the ABI check is done. Assume that the compiler has 239 # computed this path adaptively based on the current working directory 240 # such that the effective result is absolute. 241 get_filename_component(dir "${CMAKE_BINARY_DIR}/${CMAKE_MATCH_1}" ABSOLUTE) 242 list(APPEND implicit_dirs "${dir}") 243 string(APPEND log " collapse relative include dir [${d}] ==> [${dir}]\n") 244 else() 245 string(APPEND log " skipping relative include dir [${d}]\n") 246 endif() 247 endforeach() 248 list(REMOVE_DUPLICATES implicit_dirs) 249 250 # Log results. 251 if(state STREQUAL done) 252 string(APPEND log " implicit include dirs: [${implicit_dirs}]\n") 253 else() 254 string(APPEND log " warn: unable to parse implicit include dirs!\n") 255 endif() 256 257 # Return results. 258 set(${dir_var} "${implicit_dirs}" PARENT_SCOPE) 259 set(${log_var} "${log}" PARENT_SCOPE) 260 set(${state_var} "${state}" PARENT_SCOPE) 261 262endfunction() 263