CMakeParseImplicitIncludeInfo.cmake 9.1 KB

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