| # Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| # file Copyright.txt or https://cmake.org/licensing for details. |
| |
| # This is used internally by CMake and should not be included by user code. |
| |
| # helper function that parses implicit include dirs from a single line |
| # for compilers that report them that way. on success we return the |
| # list of dirs in id_var and set state_var to the 'done' state. |
| function(cmake_parse_implicit_include_line line lang id_var log_var state_var) |
| # clear variables we append to (avoids possible pollution from parent scopes) |
| unset(rv) |
| set(log "") |
| |
| # Cray compiler (from cray wrapper, via PrgEnv-cray) |
| if(CMAKE_${lang}_COMPILER_ID STREQUAL "Cray" AND |
| line MATCHES "^/" AND line MATCHES "/ccfe |/ftnfe " AND |
| line MATCHES " -isystem| -I") |
| string(REGEX MATCHALL " (-I ?|-isystem )(\"[^\"]+\"|[^ \"]+)" incs "${line}") |
| foreach(inc IN LISTS incs) |
| string(REGEX REPLACE " (-I ?|-isystem )(\"[^\"]+\"|[^ \"]+)" "\\2" idir "${inc}") |
| list(APPEND rv "${idir}") |
| endforeach() |
| if(rv) |
| string(APPEND log " got implicit includes via cray ccfe parser!\n") |
| else() |
| string(APPEND log " warning: cray ccfe parse failed!\n") |
| endif() |
| endif() |
| |
| # PGI compiler |
| if(CMAKE_${lang}_COMPILER_ID STREQUAL "PGI") |
| # pgc++ verbose output differs |
| if((lang STREQUAL "C" OR lang STREQUAL "Fortran") AND |
| line MATCHES "^/" AND |
| line MATCHES "/pgc |/pgf901 |/pgftnc " AND |
| line MATCHES " -cmdline ") |
| # cmdline has unparsed cmdline, remove it |
| string(REGEX REPLACE "-cmdline .*" "" line "${line}") |
| if("${line}" MATCHES " -nostdinc ") |
| set(rv "") # defined, but empty |
| else() |
| string(REGEX MATCHALL " -stdinc ([^ ]*)" incs "${line}") |
| foreach(inc IN LISTS incs) |
| string(REGEX REPLACE " -stdinc ([^ ]*)" "\\1" idir "${inc}") |
| string(REPLACE ":" ";" idir "${idir}") |
| list(APPEND rv ${idir}) |
| endforeach() |
| endif() |
| if(DEFINED rv) |
| string(APPEND log " got implicit includes via PGI C/F parser!\n") |
| else() |
| string(APPEND log " warning: PGI C/F parse failed!\n") |
| endif() |
| elseif(lang STREQUAL "CXX" AND line MATCHES "^/" AND |
| line MATCHES "/pggpp1 " AND line MATCHES " -I") |
| # oddly, -Mnostdinc does not get rid of system -I's, at least in |
| # PGI 18.10.1 ... |
| string(REGEX MATCHALL " (-I ?)([^ ]*)" incs "${line}") |
| foreach(inc IN LISTS incs) |
| string(REGEX REPLACE " (-I ?)([^ ]*)" "\\2" idir "${inc}") |
| if(NOT idir STREQUAL "-") # filter out "-I-" |
| list(APPEND rv "${idir}") |
| endif() |
| endforeach() |
| if(DEFINED rv) |
| string(APPEND log " got implicit includes via PGI CXX parser!\n") |
| else() |
| string(APPEND log " warning: PGI CXX parse failed!\n") |
| endif() |
| endif() |
| endif() |
| |
| # SunPro compiler |
| if(CMAKE_${lang}_COMPILER_ID STREQUAL "SunPro" AND |
| (line MATCHES "-D__SUNPRO_C" OR line MATCHES "-D__SUNPRO_F")) |
| string(REGEX MATCHALL " (-I ?)([^ ]*)" incs "${line}") |
| foreach(inc IN LISTS incs) |
| string(REGEX REPLACE " (-I ?)([^ ]*)" "\\2" idir "${inc}") |
| if(NOT "${idir}" STREQUAL "-xbuiltin") |
| list(APPEND rv "${idir}") |
| endif() |
| endforeach() |
| if(rv) |
| if (lang STREQUAL "C" OR lang STREQUAL "CXX") |
| # /usr/include appears to be hardwired in |
| list(APPEND rv "/usr/include") |
| endif() |
| string(APPEND log " got implicit includes via sunpro parser!\n") |
| else() |
| string(APPEND log " warning: sunpro parse failed!\n") |
| endif() |
| endif() |
| |
| # XL compiler |
| if((CMAKE_${lang}_COMPILER_ID STREQUAL "XL" |
| OR CMAKE_${lang}_COMPILER_ID STREQUAL "XLClang") |
| AND line MATCHES "^/" |
| AND ( (lang STREQUAL "Fortran" AND |
| line MATCHES "/xl[fF]entry " AND |
| line MATCHES "OSVAR\\([^ ]+\\)") |
| OR |
| ( (lang STREQUAL "C" OR lang STREQUAL "CXX") AND |
| line MATCHES "/xl[cC]2?entry " AND |
| line MATCHES " -qosvar=") |
| ) ) |
| # -qnostdinc cancels other stdinc flags, even if present |
| string(FIND "${line}" " -qnostdinc" nostd) |
| if(NOT nostd EQUAL -1) |
| set(rv "") # defined but empty |
| string(APPEND log " got implicit includes via XL parser (nostdinc)\n") |
| else() |
| if(lang STREQUAL "CXX") |
| string(REGEX MATCHALL " -qcpp_stdinc=([^ ]*)" std "${line}") |
| string(REGEX MATCHALL " -qgcc_cpp_stdinc=([^ ]*)" gcc_std "${line}") |
| else() |
| string(REGEX MATCHALL " -qc_stdinc=([^ ]*)" std "${line}") |
| string(REGEX MATCHALL " -qgcc_c_stdinc=([^ ]*)" gcc_std "${line}") |
| endif() |
| set(xlstd ${std} ${gcc_std}) |
| foreach(inc IN LISTS xlstd) |
| string(REGEX REPLACE " -q(cpp|gcc_cpp|c|gcc_c)_stdinc=([^ ]*)" "\\2" |
| ipath "${inc}") |
| string(REPLACE ":" ";" ipath "${ipath}") |
| list(APPEND rv ${ipath}) |
| endforeach() |
| endif() |
| # user can add -I flags via CMAKE_{C,CXX}_FLAGS, look for that too |
| string(REGEX MATCHALL " (-I ?)([^ ]*)" incs "${line}") |
| unset(urv) |
| foreach(inc IN LISTS incs) |
| string(REGEX REPLACE " (-I ?)([^ ]*)" "\\2" idir "${inc}") |
| list(APPEND urv "${idir}") |
| endforeach() |
| if(urv) |
| if ("${rv}" STREQUAL "") |
| set(rv ${urv}) |
| else() |
| list(APPEND rv ${urv}) |
| endif() |
| endif() |
| |
| if(DEFINED rv) |
| string(APPEND log " got implicit includes via XL parser!\n") |
| else() |
| string(APPEND log " warning: XL parse failed!\n") |
| endif() |
| endif() |
| |
| # Fujitsu compiler |
| if(CMAKE_${lang}_COMPILER_ID STREQUAL "Fujitsu" AND |
| line MATCHES "/ccpcom") |
| string(REGEX MATCHALL " (-I *|--sys_include=|--preinclude +)(\"[^\"]+\"|[^ \"]+)" incs "${line}") |
| foreach(inc IN LISTS incs) |
| string(REGEX REPLACE " (-I *|--sys_include=|--preinclude +)(\"[^\"]+\"|[^ \"]+)" "\\2" idir "${inc}") |
| list(APPEND rv "${idir}") |
| endforeach() |
| if(rv) |
| string(APPEND log " got implicit includes via fujitsu ccpcom parser!\n") |
| else() |
| string(APPEND log " warning: fujitsu ccpcom parse failed!\n") |
| endif() |
| endif() |
| |
| if(log) |
| set(${log_var} "${log}" PARENT_SCOPE) |
| else() |
| unset(${log_var} PARENT_SCOPE) |
| endif() |
| if(DEFINED rv) |
| set(${id_var} "${rv}" PARENT_SCOPE) |
| set(${state_var} "done" PARENT_SCOPE) |
| endif() |
| endfunction() |
| |
| # top-level function to parse implicit include directory information |
| # from verbose compiler output. sets state_var in parent to 'done' on success. |
| function(cmake_parse_implicit_include_info text lang dir_var log_var state_var) |
| set(state start) # values: start, loading, done |
| |
| # clear variables we append to (avoids possible pollution from parent scopes) |
| set(implicit_dirs_tmp) |
| set(log "") |
| |
| # go through each line of output... |
| string(REGEX REPLACE "\r*\n" ";" output_lines "${text}") |
| foreach(line IN LISTS output_lines) |
| if(state STREQUAL start) |
| string(FIND "${line}" "#include \"...\" search starts here:" rv) |
| if(rv GREATER -1) |
| set(state loading) |
| set(preload 1) # looking for include <...> now |
| string(APPEND log " found start of include info\n") |
| else() |
| cmake_parse_implicit_include_line("${line}" "${lang}" implicit_dirs_tmp |
| linelog state) |
| if(linelog) |
| string(APPEND log ${linelog}) |
| endif() |
| if(state STREQUAL done) |
| break() |
| endif() |
| endif() |
| elseif(state STREQUAL loading) |
| string(FIND "${line}" "End of search list." rv) |
| if(rv GREATER -1) |
| set(state done) |
| string(APPEND log " end of search list found\n") |
| break() |
| endif() |
| if(preload) |
| string(FIND "${line}" "#include <...> search starts here:" rv) |
| if(rv GREATER -1) |
| set(preload 0) |
| string(APPEND log " found start of implicit include info\n") |
| endif() |
| continue() |
| endif() |
| if("${line}" MATCHES "^ ") |
| string(SUBSTRING "${line}" 1 -1 line) # remove leading space |
| endif() |
| if ("${line}" MATCHES " \\(framework directory\\)$") |
| continue() # frameworks are handled elsewhere, ignore them here |
| endif() |
| string(REPLACE "\\" "/" path "${line}") |
| list(APPEND implicit_dirs_tmp "${path}") |
| string(APPEND log " add: [${path}]\n") |
| endif() |
| endforeach() |
| |
| set(implicit_dirs "") |
| foreach(d IN LISTS implicit_dirs_tmp) |
| if(IS_ABSOLUTE "${d}") |
| get_filename_component(dir "${d}" ABSOLUTE) |
| list(APPEND implicit_dirs "${dir}") |
| string(APPEND log " collapse include dir [${d}] ==> [${dir}]\n") |
| elseif("${d}" MATCHES [[^\.\.[\/]\.\.[\/]\.\.[\/](.*)$]]) |
| # This relative path is deep enough to get out of the |
| # CMakeFiles/CMakeScratch/<unique> |
| # directory where the ABI check is done. Assume that the compiler has |
| # computed this path adaptively based on the current working directory |
| # such that the effective result is absolute. |
| get_filename_component(dir "${CMAKE_BINARY_DIR}/${CMAKE_MATCH_1}" ABSOLUTE) |
| list(APPEND implicit_dirs "${dir}") |
| string(APPEND log " collapse relative include dir [${d}] ==> [${dir}]\n") |
| else() |
| string(APPEND log " skipping relative include dir [${d}]\n") |
| endif() |
| endforeach() |
| list(REMOVE_DUPLICATES implicit_dirs) |
| |
| # Log results. |
| if(state STREQUAL done) |
| string(APPEND log " implicit include dirs: [${implicit_dirs}]\n") |
| else() |
| string(APPEND log " warn: unable to parse implicit include dirs!\n") |
| endif() |
| |
| # Return results. |
| set(${dir_var} "${implicit_dirs}" PARENT_SCOPE) |
| set(${log_var} "${log}" PARENT_SCOPE) |
| set(${state_var} "${state}" PARENT_SCOPE) |
| |
| endfunction() |