diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake --- a/llvm/cmake/modules/AddLLVM.cmake +++ b/llvm/cmake/modules/AddLLVM.cmake @@ -1391,6 +1391,52 @@ endif () endmacro() +# Takes a list of path names in pathlist and a base directory, and returns +# a list of paths relative to the base directory in out_pathlist. +# Paths that are on a different drive than the basedir (on Windows) or that +# contain symlinks are returned absolute. +# Use with LLVM_LIT_PATH_FUNCTION below. +function(make_paths_relative out_pathlist basedir pathlist) + # Passing ARG_PATH_VALUES as-is to execute_process() makes cmake strip + # empty list entries. So escape the ;s in the list and do the splitting + # outselves. cmake has no relpath function, so use Python for that. + string(REPLACE ";" "\\;" pathlist_escaped "${pathlist}") + execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" "\n +import os, sys\n +base = sys.argv[1] +def haslink(p):\n + if not p or p == os.path.dirname(p): return False\n + return os.path.islink(p) or haslink(os.path.dirname(p))\n +def relpath(p):\n + if not p: return ''\n + if os.path.splitdrive(p)[0] != os.path.splitdrive(base)[0]: return p\n + if haslink(p) or haslink(base): return p\n + return os.path.relpath(p, base).replace(os.sep, '/')\n +sys.stdout.write(';'.join(relpath(p) for p in sys.argv[2].split(';')))" + ${basedir} + ${pathlist_escaped} + OUTPUT_VARIABLE pathlist_relative) + set(${out_pathlist} "${pathlist_relative}" PARENT_SCOPE) +endfunction() + +# Converts a file that's relative to the current python file to an absolute +# path. Since this uses __file__, it has to be emitted into python files that +# use it and can't be in a lit module. Use with make_paths_relative(). +string(CONCAT LLVM_LIT_PATH_FUNCTION + # Lit converts config paths to lower case in discovery.py, before + # loading the config. This causes __file__ to be all lower-case (including + # the drive letter), but several clang tests pass -include %s and a + # clang warning checks that passed case matches on-disk cache. So it's + # important that this restores the on-disk case of the prefix. + "# Allow generated file to be relocatable.\n" + "def path(p):\n" + " if not p: return ''\n" + " p = os.path.join(os.path.dirname(os.path.abspath(__file__)), p)\n" + " p = os.path.normpath(p).replace(os.sep, '/')\n" + " if os.name == 'nt' and os.path.isabs(p): return p[0].upper() + p[1:]\n" + " return p\n" + ) + # This function provides an automatic way to 'configure'-like generate a file # based on a set of common and custom variables, specifically targeting the # variables needed for the 'lit.site.cfg' files. This function bundles the @@ -1453,20 +1499,9 @@ set(HOST_CXX "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}") set(HOST_LDFLAGS "${CMAKE_EXE_LINKER_FLAGS}") - set(LIT_SITE_CFG_IN_HEADER "# Autogenerated from ${site_in}\n# Do not edit!") - - # Lit converts config paths to lower case in discovery.py, before - # loading the config. This causes __file__ to be all lower-case (including - # the drive letter), but several clang tests pass -include %s and a - # clang warning checks that passed case matches on-disk cache. So it's - # important that this restores the on-disk case of the prefix. - string(CONCAT LIT_SITE_CFG_IN_HEADER "${LIT_SITE_CFG_IN_HEADER}\n\n" - "# Allow generated lit.site.cfg.py to be relocatable.\n" - "def path(p):\n" - " if not p: return ''\n" - " p = os.path.normpath(os.path.join(os.path.dirname(__file__), p)).replace(os.sep, '/')\n" - " if os.name == 'nt' and os.path.isabs(p): return p[0].upper() + p[1:]\n" - " return p\n" + string(CONCAT LIT_SITE_CFG_IN_HEADER + "# Autogenerated from ${site_in}\n# Do not edit!\n\n" + "${LLVM_LIT_PATH_FUNCTION}" ) # Override config_target_triple (and the env) @@ -1493,27 +1528,9 @@ endforeach() list(REMOVE_AT ARG_PATH_VALUES 0) - # Compute paths relative to the directory containing output lit.site.cfg.py. - # Passing ARG_PATH_VALUES as-is to execute_process() makes cmake strip - # empty list entries. So escape the ;s in the list and do the splitting - # outselves. cmake has no relpath function, so use Python for that. - string(REPLACE ";" "\\;" ARG_PATH_VALUES_ESCAPED "${ARG_PATH_VALUES}") get_filename_component(OUTPUT_DIR ${site_out} DIRECTORY) - execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" "\n -import os, sys\n -base = sys.argv[1] -def haslink(p):\n - if not p or p == os.path.dirname(p): return False\n - return os.path.islink(p) or haslink(os.path.dirname(p))\n -def relpath(p):\n - if not p: return ''\n - if os.path.splitdrive(p)[0] != os.path.splitdrive(base)[0]: return p\n - if haslink(p) or haslink(base): return p\n - return os.path.relpath(p, base).replace(os.sep, '/')\n -sys.stdout.write(';'.join(relpath(p) for p in sys.argv[2].split(';')))" - ${OUTPUT_DIR} - ${ARG_PATH_VALUES_ESCAPED} - OUTPUT_VARIABLE ARG_PATH_VALUES_RELATIVE) + make_paths_relative( + ARG_PATH_VALUES_RELATIVE "${OUTPUT_DIR}" "${ARG_PATH_VALUES}") list(LENGTH ARG_PATHS len_paths) list(LENGTH ARG_PATH_VALUES len_path_values) @@ -1537,10 +1554,10 @@ configure_file(${site_in} ${site_out} @ONLY) if (EXISTS "${ARG_MAIN_CONFIG}") - set(PYTHON_STATEMENT "map_config('${ARG_MAIN_CONFIG}', '${site_out}')") - get_property(LLVM_LIT_CONFIG_MAP GLOBAL PROPERTY LLVM_LIT_CONFIG_MAP) - set(LLVM_LIT_CONFIG_MAP "${LLVM_LIT_CONFIG_MAP}\n${PYTHON_STATEMENT}") - set_property(GLOBAL PROPERTY LLVM_LIT_CONFIG_MAP ${LLVM_LIT_CONFIG_MAP}) + # Remember main config / generated site config for llvm-lit.in. + get_property(LLVM_LIT_CONFIG_FILES GLOBAL PROPERTY LLVM_LIT_CONFIG_FILES) + list(APPEND LLVM_LIT_CONFIG_FILES "${ARG_MAIN_CONFIG}" "${site_out}") + set_property(GLOBAL PROPERTY LLVM_LIT_CONFIG_FILES ${LLVM_LIT_CONFIG_FILES}) endif() endfunction() diff --git a/llvm/utils/llvm-lit/CMakeLists.txt b/llvm/utils/llvm-lit/CMakeLists.txt --- a/llvm/utils/llvm-lit/CMakeLists.txt +++ b/llvm/utils/llvm-lit/CMakeLists.txt @@ -1,7 +1,26 @@ -get_property(LLVM_LIT_CONFIG_MAP GLOBAL PROPERTY LLVM_LIT_CONFIG_MAP) +get_property(LLVM_LIT_CONFIG_FILES GLOBAL PROPERTY LLVM_LIT_CONFIG_FILES) +list(LENGTH LLVM_LIT_CONFIG_FILES file_len) +math(EXPR file_last "${file_len} - 1") get_llvm_lit_path(LIT_BASE_DIR LIT_FILE_NAME) +# LLVM_LIT_CONFIG_FILES contains interleaved main config (in the source tree) +# and site config (in the build tree) pairs. Make them relative to +# llvm-lit and then convert them to map_config() calls. +if("${CMAKE_CFG_INTDIR}" STREQUAL ".") + make_paths_relative( + LLVM_LIT_CONFIG_FILES "${LIT_BASE_DIR}" "${LLVM_LIT_CONFIG_FILES}") +endif() + +set(LLVM_LIT_CONFIG_MAP "${LLVM_LIT_PATH_FUNCTION}\n") +foreach(i RANGE 0 ${file_last} 2) + list(GET LLVM_LIT_CONFIG_FILES ${i} main_config) + math(EXPR i1 "${i} + 1") + list(GET LLVM_LIT_CONFIG_FILES ${i1} site_out) + set(map "map_config(path('${main_config}'), path('${site_out}'))") + set(LLVM_LIT_CONFIG_MAP "${LLVM_LIT_CONFIG_MAP}\n${map}") +endforeach() + set(LLVM_SOURCE_DIR ${LLVM_MAIN_SRC_DIR}) if(NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".")