llvm.org GIT mirror llvm / 837d04d
[lit] Force site configs to be run before source-tree configs This patch simplifies LLVM's lit infrastructure by enforcing an ordering that a site config is always run before a source-tree config. A significant amount of the complexity from lit config files arises from the fact that inside of a source-tree config file, we don't yet know if the site config has been run. However it is *always* required to run a site config first, because it passes various variables down through CMake that the main config depends on. As a result, every config file has to do a bunch of magic to try to reverse-engineer the location of the site config file if they detect (heuristically) that the site config file has not yet been run. This patch solves the problem by emitting a mapping from source tree config file to binary tree site config file in llvm-lit.py. Then, during discovery when we find a config file, we check to see if we have a target mapping for it, and if so we use that instead. This mechanism is generic enough that it does not affect external users of lit. They will just not have a config mapping defined, and everything will work as normal. On the other hand, for us it allows us to make many simplifications: * We are guaranteed that a site config will be executed first * Inside of a main config, we no longer have to assume that attributes might not be present and use getattr everywhere. * We no longer have to pass parameters such as --param llvm_site_config=<path> on the command line. * It is future-proof, meaning you don't have to edit llvm-lit.in to add support for new projects. * All of the duplicated logic of trying various fallback mechanisms of finding a site config from the main config are now gone. One potentially noteworthy thing that was required to implement this change is that whereas the ninja check targets previously used the first method to spawn lit, they now use the second. In particular, you can no longer run lit.py against the source tree while specifying the various `foo_site_config=<path>` parameters. Instead, you need to run llvm-lit.py. Differential Revision: https://reviews.llvm.org/D37756 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@313270 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 1 year, 11 months ago
8 changed file(s) with 82 addition(s) and 186 deletion(s). Raw diff Collapse all Expand all
844844 add_subdirectory(utils/PerfectShuffle)
845845 add_subdirectory(utils/count)
846846 add_subdirectory(utils/not)
847 add_subdirectory(utils/llvm-lit)
848847 add_subdirectory(utils/yaml-bench)
849848 else()
850849 if ( LLVM_INCLUDE_TESTS )
931930
932931 add_subdirectory(cmake/modules)
933932
933 # Do this last so that all lit targets have already been created.
934 if (LLVM_INCLUDE_UTILS)
935 add_subdirectory(utils/llvm-lit)
936 endif()
937
934938 if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
935939 install(DIRECTORY include/llvm include/llvm-c
936940 DESTINATION include
11731173 endif()
11741174
11751175 configure_file(${input} ${output} @ONLY)
1176 get_filename_component(INPUT_DIR ${input} DIRECTORY)
1177 if (EXISTS "${INPUT_DIR}/lit.cfg")
1178 set(PYTHON_STATEMENT "map_config('${INPUT_DIR}/lit.cfg', '${output}')")
1179 get_property(LLVM_LIT_CONFIG_MAP GLOBAL PROPERTY LLVM_LIT_CONFIG_MAP)
1180 set(LLVM_LIT_CONFIG_MAP "${LLVM_LIT_CONFIG_MAP}\n${PYTHON_STATEMENT}")
1181 set_property(GLOBAL PROPERTY LLVM_LIT_CONFIG_MAP ${LLVM_LIT_CONFIG_MAP})
1182 endif()
11761183 endfunction()
11771184
11781185 # A raw function to create a lit target. This is used to implement the testuite
11841191 if (NOT CMAKE_CFG_INTDIR STREQUAL ".")
11851192 list(APPEND LIT_ARGS --param build_mode=${CMAKE_CFG_INTDIR})
11861193 endif ()
1187 if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
1188 set (LIT_COMMAND "${PYTHON_EXECUTABLE};${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py"
1189 CACHE STRING "Command used to spawn llvm-lit")
1190 else()
1191 find_program(LIT_COMMAND NAMES llvm-lit lit.py lit)
1194
1195 if (WIN32 AND NOT CYGWIN)
1196 # llvm-lit needs suffix.py for multiprocess to find a main module.
1197 set(suffix .py)
11921198 endif ()
1199 set(llvm_lit_path ${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-lit${suffix})
1200
1201 set (LIT_COMMAND "${PYTHON_EXECUTABLE};${llvm_lit_path}"
1202 CACHE STRING "Command used to spawn llvm-lit" FORCE)
1203
11931204 list(APPEND LIT_COMMAND ${LIT_ARGS})
11941205 foreach(param ${ARG_PARAMS})
11951206 list(APPEND LIT_COMMAND --param ${param})
1717
1818 # test_source_root: The root path where tests are located.
1919 # test_exec_root: The root path where tests should be run.
20 llvm_obj_root = getattr(config, 'llvm_obj_root', None)
21 if llvm_obj_root is not None:
22 config.test_exec_root = os.path.join(llvm_obj_root, 'unittests')
23 config.test_source_root = config.test_exec_root
20 config.test_exec_root = os.path.join(config.llvm_obj_root, 'unittests')
21 config.test_source_root = config.test_exec_root
2422
2523 # testFormat: The test format to use to interpret tests.
26 llvm_build_mode = getattr(config, 'llvm_build_mode', "Debug")
27 config.test_format = lit.formats.GoogleTest(llvm_build_mode, 'Tests')
24 config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, 'Tests')
2825
2926 # Propagate the temp directory. Windows requires this because it uses \Windows\
3027 # if none of these are present.
4643 # Win32 may use %SYSTEMDRIVE% during file system shell operations, so propogate.
4744 if sys.platform == 'win32' and 'SYSTEMDRIVE' in os.environ:
4845 config.environment['SYSTEMDRIVE'] = os.environ['SYSTEMDRIVE']
49
50 ###
51
52 # Check that the object root is known.
53 if config.test_exec_root is None:
54 # Otherwise, we haven't loaded the site specific configuration (the user is
55 # probably trying to run on a test file directly, and either the site
56 # configuration hasn't been created by the build system, or we are in an
57 # out-of-tree build situation).
58
59 # Check for 'llvm_unit_site_config' user parameter, and use that if available.
60 site_cfg = lit_config.params.get('llvm_unit_site_config', None)
61 if site_cfg and os.path.exists(site_cfg):
62 lit_config.load_config(config, site_cfg)
63 raise SystemExit
64
65 # Try to detect the situation where we are using an out-of-tree build by
66 # looking for 'llvm-config'.
67 #
68 # FIXME: I debated (i.e., wrote and threw away) adding logic to
69 # automagically generate the lit.site.cfg if we are in some kind of fresh
70 # build situation. This means knowing how to invoke the build system
71 # though, and I decided it was too much magic.
72
73 llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
74 if not llvm_config:
75 lit_config.fatal('No site specific configuration available!')
76
77 # Get the source and object roots.
78 llvm_src_root = subprocess.check_output(['llvm-config', '--src-root']).strip()
79 llvm_obj_root = subprocess.check_output(['llvm-config', '--obj-root']).strip()
80
81 # Validate that we got a tree which points to here.
82 this_src_root = os.path.join(os.path.dirname(__file__),'..','..')
83 if os.path.realpath(llvm_src_root) != os.path.realpath(this_src_root):
84 lit_config.fatal('No site specific configuration available!')
85
86 # Check that the site specific configuration exists.
87 site_cfg = os.path.join(llvm_obj_root, 'test', 'Unit', 'lit.site.cfg')
88 if not os.path.exists(site_cfg):
89 lit_config.fatal('No site specific configuration available!')
90
91 # Okay, that worked. Notify the user of the automagic, and reconfigure.
92 lit_config.note('using out-of-tree build at %r' % llvm_obj_root)
93 lit_config.load_config(config, site_cfg)
94 raise SystemExit
5252 config.test_source_root = os.path.dirname(__file__)
5353
5454 # test_exec_root: The root path where tests should be run.
55 llvm_obj_root = getattr(config, 'llvm_obj_root', None)
56 if llvm_obj_root is not None:
57 config.test_exec_root = os.path.join(llvm_obj_root, 'test')
55 config.test_exec_root = os.path.join(config.llvm_obj_root, 'test')
5856
5957 # Tweak the PATH to include the tools dir.
60 if llvm_obj_root is not None:
61 llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
62 if not llvm_tools_dir:
63 lit_config.fatal('No LLVM tools dir set!')
64 path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
65 config.environment['PATH'] = path
58 path = os.path.pathsep.join((config.llvm_tools_dir, config.environment['PATH']))
59 config.environment['PATH'] = path
6660
6761 # Propagate 'HOME' through the environment.
6862 if 'HOME' in os.environ:
8478 config.environment['TEMP'] = os.environ['TEMP']
8579
8680 # Propagate LLVM_SRC_ROOT into the environment.
87 config.environment['LLVM_SRC_ROOT'] = getattr(config, 'llvm_src_root', '')
81 config.environment['LLVM_SRC_ROOT'] = config.llvm_src_root
8882
8983 # Propagate PYTHON_EXECUTABLE into the environment
9084 config.environment['PYTHON_EXECUTABLE'] = getattr(config, 'python_executable',
9690 config.environment[symbolizer] = os.environ[symbolizer]
9791
9892 # Set up OCAMLPATH to include newly built OCaml libraries.
99 llvm_lib_dir = getattr(config, 'llvm_lib_dir', None)
100 if llvm_lib_dir is None:
101 if llvm_obj_root is not None:
102 llvm_lib_dir = os.path.join(llvm_obj_root, 'lib')
103
104 if llvm_lib_dir is not None:
105 top_ocaml_lib = os.path.join(llvm_lib_dir, 'ocaml')
106 llvm_ocaml_lib = os.path.join(top_ocaml_lib, 'llvm')
107 if llvm_ocaml_lib is not None:
108 ocamlpath = os.path.pathsep.join((llvm_ocaml_lib, top_ocaml_lib))
109 if 'OCAMLPATH' in os.environ:
110 ocamlpath = os.path.pathsep.join((ocamlpath, os.environ['OCAMLPATH']))
111 config.environment['OCAMLPATH'] = ocamlpath
112
113 if 'CAML_LD_LIBRARY_PATH' in os.environ:
114 caml_ld_library_path = os.path.pathsep.join((llvm_ocaml_lib,
115 os.environ['CAML_LD_LIBRARY_PATH']))
116 config.environment['CAML_LD_LIBRARY_PATH'] = caml_ld_library_path
117 else:
118 config.environment['CAML_LD_LIBRARY_PATH'] = llvm_ocaml_lib
93 top_ocaml_lib = os.path.join(config.llvm_lib_dir, 'ocaml')
94 llvm_ocaml_lib = os.path.join(top_ocaml_lib, 'llvm')
95 ocamlpath = os.path.pathsep.join((llvm_ocaml_lib, top_ocaml_lib))
96 if 'OCAMLPATH' in os.environ:
97 ocamlpath = os.path.pathsep.join((ocamlpath, os.environ['OCAMLPATH']))
98 config.environment['OCAMLPATH'] = ocamlpath
99
100 if 'CAML_LD_LIBRARY_PATH' in os.environ:
101 caml_ld_library_path = os.path.pathsep.join((llvm_ocaml_lib,
102 os.environ['CAML_LD_LIBRARY_PATH']))
103 config.environment['CAML_LD_LIBRARY_PATH'] = caml_ld_library_path
104 else:
105 config.environment['CAML_LD_LIBRARY_PATH'] = llvm_ocaml_lib
119106
120107 # Set up OCAMLRUNPARAM to enable backtraces in OCaml tests.
121108 config.environment['OCAMLRUNPARAM'] = 'b'
122
123 ###
124
125 import os
126
127 # Check that the object root is known.
128 if config.test_exec_root is None:
129 # Otherwise, we haven't loaded the site specific configuration (the user is
130 # probably trying to run on a test file directly, and either the site
131 # configuration hasn't been created by the build system, or we are in an
132 # out-of-tree build situation).
133
134 # Check for 'llvm_site_config' user parameter, and use that if available.
135 site_cfg = lit_config.params.get('llvm_site_config', None)
136 if site_cfg and os.path.exists(site_cfg):
137 lit_config.load_config(config, site_cfg)
138 raise SystemExit
139
140 # Try to detect the situation where we are using an out-of-tree build by
141 # looking for 'llvm-config'.
142 #
143 # FIXME: I debated (i.e., wrote and threw away) adding logic to
144 # automagically generate the lit.site.cfg if we are in some kind of fresh
145 # build situation. This means knowing how to invoke the build system
146 # though, and I decided it was too much magic.
147
148 llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
149 if not llvm_config:
150 lit_config.fatal('No site specific configuration available!')
151
152 # Get the source and object roots.
153 llvm_src_root = subprocess.check_output(['llvm-config', '--src-root']).strip()
154 llvm_obj_root = subprocess.check_output(['llvm-config', '--obj-root']).strip()
155
156 # Validate that we got a tree which points to here.
157 this_src_root = os.path.dirname(config.test_source_root)
158 if os.path.realpath(llvm_src_root) != os.path.realpath(this_src_root):
159 lit_config.fatal('No site specific configuration available!')
160
161 # Check that the site specific configuration exists.
162 site_cfg = os.path.join(llvm_obj_root, 'test', 'lit.site.cfg')
163 if not os.path.exists(site_cfg):
164 lit_config.fatal('No site specific configuration available!')
165
166 # Okay, that worked. Notify the user of the automagic, and reconfigure.
167 lit_config.note('using out-of-tree build at %r' % llvm_obj_root)
168 lit_config.load_config(config, site_cfg)
169 raise SystemExit
170
171 ###
172109
173110 # Provide the path to asan runtime lib 'libclang_rt.asan_osx_dynamic.dylib' if
174111 # available. This is darwin specific since it's currently only needed on darwin.
230167 # Support tests for both native and bytecode builds.
231168 config.substitutions.append( ('%ocamlc',
232169 "%s ocamlc -cclib -L%s %s" %
233 (config.ocamlfind_executable, llvm_lib_dir, config.ocaml_flags)) )
170 (config.ocamlfind_executable, config.llvm_lib_dir, config.ocaml_flags)) )
234171 if config.have_ocamlopt:
235172 config.substitutions.append( ('%ocamlopt',
236173 "%s ocamlopt -cclib -L%s -cclib -Wl,-rpath,%s %s" %
237 (config.ocamlfind_executable, llvm_lib_dir, llvm_lib_dir, config.ocaml_flags)) )
174 (config.ocamlfind_executable, config.llvm_lib_dir, config.llvm_lib_dir, config.ocaml_flags)) )
238175 else:
239176 config.substitutions.append( ('%ocamlopt', "true" ) )
240177
266203 # llvm-lit "-Dllc=llc -enable-misched -verify-machineinstrs"
267204 tool_path = lit_config.params.get(tool_name)
268205 if tool_path is None:
269 tool_path = lit.util.which(tool_name, llvm_tools_dir)
206 tool_path = lit.util.which(tool_name, config.llvm_tools_dir)
270207 if tool_path is None:
271208 return tool_name, tool_path, tool_pipe
272209 if (tool_name == "llc" and
332269 tool_name, tool_path, tool_pipe = find_tool_substitution(pattern)
333270 if not tool_path:
334271 # Warn, but still provide a substitution.
335 lit_config.note('Did not find ' + tool_name + ' in ' + llvm_tools_dir)
336 tool_path = llvm_tools_dir + '/' + tool_name
272 lit_config.note('Did not find ' + tool_name + ' in ' + config.llvm_tools_dir)
273 tool_path = config.llvm_tools_dir + '/' + tool_name
337274 config.substitutions.append((pattern, tool_pipe + tool_path))
338275
339276 # For tools that are optional depending on the config, we won't warn
349286 tool_name, tool_path, tool_pipe = find_tool_substitution(pattern)
350287 if not tool_path:
351288 # Provide a substitution anyway, for the sake of consistent errors.
352 tool_path = llvm_tools_dir + '/' + tool_name
289 tool_path = config.llvm_tools_dir + '/' + tool_name
353290 config.substitutions.append((pattern, tool_pipe + tool_path))
354291
355292
481418 # Ask llvm-config about assertion mode.
482419 try:
483420 llvm_config_cmd = subprocess.Popen(
484 [os.path.join(llvm_tools_dir, 'llvm-config'), '--assertion-mode'],
421 [os.path.join(config.llvm_tools_dir, 'llvm-config'), '--assertion-mode'],
485422 stdout = subprocess.PIPE,
486423 env=config.environment)
487424 except OSError:
488 print("Could not find llvm-config in " + llvm_tools_dir)
425 print("Could not find llvm-config in " + config.llvm_tools_dir)
489426 exit(42)
490427
491428 if re.search(r'ON', llvm_config_cmd.stdout.read().decode('ascii')):
537474 # Ask llvm-config about global-isel.
538475 try:
539476 llvm_config_cmd = subprocess.Popen(
540 [os.path.join(llvm_tools_dir, 'llvm-config'), '--has-global-isel'],
477 [os.path.join(config.llvm_tools_dir, 'llvm-config'), '--has-global-isel'],
541478 stdout = subprocess.PIPE,
542479 env=config.environment)
543480 except OSError:
544 print("Could not find llvm-config in " + llvm_tools_dir)
481 print("Could not find llvm-config in " + config.llvm_tools_dir)
545482 exit(42)
546483
547484 if re.search(r'ON', llvm_config_cmd.stdout.read().decode('ascii')):
3838
3939 ts, relative = search(parent)
4040 return (ts, relative + (base,))
41
42 # This is a private builtin parameter which can be used to perform
43 # translation of configuration paths. Specifically, this parameter
44 # can be set to a dictionary that the discovery process will consult
45 # when it finds a configuration it is about to load. If the given
46 # path is in the map, the value of that key is a path to the
47 # configuration to load instead.
48 config_map = litConfig.params.get('config_map')
49 if config_map:
50 cfgpath = os.path.normpath(cfgpath)
51 cfgpath = os.path.normcase(cfgpath)
52 target = config_map.get(cfgpath)
53 if target:
54 cfgpath = target
4155
4256 # We found a test suite, create a new config for it and load it.
4357 if litConfig.debug:
211225 f.close()
212226 else:
213227 actual_inputs.append(input)
214
228
215229 # Load the tests from the inputs.
216230 tests = []
217231 test_suite_cache = {}
6464 config.available_features.add('windows')
6565
6666 # Add llvm tools directory if this config is being loaded indirectly
67 llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
68 if llvm_tools_dir != None:
69 path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
67 if config.llvm_tools_dir is not None:
68 path = os.path.pathsep.join((config.llvm_tools_dir, config.environment['PATH']))
7069 config.environment['PATH'] = path
22 set(suffix .py)
33 endif ()
44 set(llvm_lit_path ${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-lit${suffix})
5
6 get_property(LLVM_LIT_CONFIG_MAP GLOBAL PROPERTY LLVM_LIT_CONFIG_MAP)
57
68 if(NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".")
79 foreach(BUILD_MODE ${CMAKE_CONFIGURATION_TYPES})
11
22 import os
33 import sys
4
5 config_map = {}
6
7 def map_config(source_dir, site_config):
8 global config_map
9 source_dir = os.path.normpath(source_dir)
10 source_dir = os.path.normcase(source_dir)
11 site_config = os.path.normpath(site_config)
12 config_map[source_dir] = site_config
413
514 # Variables configured at build time.
615 llvm_source_root = "@LLVM_SOURCE_DIR@"
1120
1221 # Set up some builtin parameters, so that by default the LLVM test suite
1322 # configuration file knows how to find the object tree.
14 builtin_parameters = {
15 'build_mode' : "@BUILD_MODE@",
16 'llvm_site_config' : os.path.join(llvm_obj_root, 'test', 'lit.site.cfg'),
17 'llvm_unit_site_config' : os.path.join(llvm_obj_root, 'test', 'Unit',
18 'lit.site.cfg')
19 }
23 builtin_parameters = { 'build_mode' : "@BUILD_MODE@" }
2024
21 clang_obj_root = os.path.join(llvm_obj_root, 'tools', 'clang')
25 @LLVM_LIT_CONFIG_MAP@
2226
23 if os.path.exists(clang_obj_root):
24 builtin_parameters['clang_site_config'] = \
25 os.path.join(clang_obj_root, 'test', 'lit.site.cfg')
26 clang_tools_extra_obj_root = os.path.join(clang_obj_root, 'tools', 'extra')
27 if os.path.exists(clang_tools_extra_obj_root):
28 builtin_parameters['clang_tools_extra_site_config'] = \
29 os.path.join(clang_tools_extra_obj_root, 'test', 'lit.site.cfg')
30
31 lld_obj_root = os.path.join(llvm_obj_root, 'tools', 'lld')
32 if os.path.exists(lld_obj_root):
33 builtin_parameters['lld_site_config'] = \
34 os.path.join(lld_obj_root, 'test', 'lit.site.cfg')
35
36 compilerrt_obj_root = os.path.join(llvm_obj_root, 'projects', 'compiler-rt')
37 if os.path.exists(compilerrt_obj_root):
38 builtin_parameters['compilerrt_site_basedir'] = \
39 os.path.join(compilerrt_obj_root, 'test')
40
41 libcxx_obj_root = os.path.join(llvm_obj_root, 'projects', 'libcxx')
42 if os.path.exists(libcxx_obj_root):
43 builtin_parameters['libcxx_site_config'] = \
44 os.path.join(libcxx_obj_root, 'test', 'lit.site.cfg')
45
46 libcxxabi_obj_root = os.path.join(llvm_obj_root, 'projects', 'libcxxabi')
47 if os.path.exists(libcxxabi_obj_root):
48 builtin_parameters['libcxxabi_site_config'] = \
49 os.path.join(libcxxabi_obj_root, 'test', 'lit.site.cfg')
27 builtin_parameters['config_map'] = config_map
5028
5129 if __name__=='__main__':
5230 from lit.main import main