diff --git a/utils/llvm-build/llvmbuild/configutil.py b/utils/llvm-build/llvmbuild/configutil.py new file mode 100644 index 00000000000..b5582c34de4 --- /dev/null +++ b/utils/llvm-build/llvmbuild/configutil.py @@ -0,0 +1,66 @@ +""" +Defines utilities useful for performing standard "configuration" style tasks. +""" + +import re +import os + +def configure_file(input_path, output_path, substitutions): + """configure_file(input_path, output_path, substitutions) -> bool + + Given an input and output path, "configure" the file at the given input path + by replacing variables in the file with those given in the substitutions + list. Returns true if the output file was written. + + The substitutions list should be given as a list of tuples (regex string, + replacement), where the regex and replacement will be used as in 're.sub' to + execute the variable replacement. + + The output path's parent directory need not exist (it will be created). + + If the output path does exist and the configured data is not different than + it's current contents, the output file will not be modified. This is + designed to limit the impact of configured files on build dependencies. + """ + + # Read in the input data. + f = open(input_path, "rb") + try: + data = f.read() + finally: + f.close() + + # Perform the substitutions. + for regex_string,replacement in substitutions: + regex = re.compile(regex_string) + data = regex.sub(replacement, data) + + # Ensure the output parent directory exists. + output_parent_path = os.path.dirname(os.path.abspath(output_path)) + if not os.path.exists(output_parent_path): + os.makedirs(output_parent_path) + + # If the output path exists, load it and compare to the configured contents. + if os.path.exists(output_path): + current_data = None + try: + f = open(output_path, "rb") + try: + current_data = f.read() + except: + current_data = None + f.close() + except: + current_data = None + + if current_data is not None and current_data == data: + return False + + # Write the output contents. + f = open(output_path, "wb") + try: + f.write(data) + finally: + f.close() + + return True diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py index 51923ebad7b..fa76aa5d8ed 100644 --- a/utils/llvm-build/llvmbuild/main.py +++ b/utils/llvm-build/llvmbuild/main.py @@ -2,6 +2,7 @@ import os import sys import componentinfo +import configutil from util import * @@ -616,6 +617,9 @@ def main(): help=( "If given, an alternate path to search for LLVMBuild.txt files"), action="store", default=None, metavar="PATH") + group.add_option("", "--build-root", dest="build_root", metavar="PATH", + help="Path to the build directory (if needed) [%default]", + action="store", default=None) parser.add_option_group(group) group = OptionGroup(parser, "Output Options") @@ -637,6 +641,14 @@ def main(): dest="write_make_fragment", metavar="PATH", help="Write the Makefile project information to PATH", action="store", default=None) + group.add_option("", "--configure-target-def-file", + dest="configure_target_def_files", + help="""Configure the given file at SUBPATH (relative to +the inferred or given source root, and with a '.in' suffix) by replacing certain +substitution variables with lists of targets that support certain features (for +example, targets with AsmPrinters) and write the result to the build root (as +given by --build-root) at the same SUBPATH""", + metavar="SUBPATH", action="append", default=None) parser.add_option_group(group) group = OptionGroup(parser, "Configuration Options") @@ -701,5 +713,40 @@ def main(): if opts.write_cmake_fragment: project_info.write_cmake_fragment(opts.write_cmake_fragment) + # Configure target definition files, if requested. + if opts.configure_target_def_files: + # Verify we were given a build root. + if not opts.build_root: + parser.error("must specify --build-root when using " + "--configure-target-def-file") + + # Create the substitution list. + available_targets = [ci for ci in project_info.component_infos + if ci.type_name == 'TargetGroup'] + substitutions = [ + ("@LLVM_ENUM_TARGETS@", + ' '.join('LLVM_TARGET(%s)' % ci.name + for ci in available_targets)), + ("@LLVM_ENUM_ASM_PRINTERS@", + ' '.join('LLVM_ASM_PRINTER(%s)' % ci.name + for ci in available_targets + if ci.has_asmprinter)), + ("@LLVM_ENUM_ASM_PARSERS@", + ' '.join('LLVM_ASM_PARSER(%s)' % ci.name + for ci in available_targets + if ci.has_asmparser)), + ("@LLVM_ENUM_DISASSEMBLERS@", + ' '.join('LLVM_DISASSEMBLER(%s)' % ci.name + for ci in available_targets + if ci.has_disassembler))] + + # Configure the given files. + for subpath in opts.configure_target_def_files: + inpath = os.path.join(source_root, subpath + '.in') + outpath = os.path.join(opts.build_root, subpath) + result = configutil.configure_file(inpath, outpath, substitutions) + if not result: + note("configured file %r hasn't changed" % outpath) + if __name__=='__main__': main() diff --git a/utils/llvm-build/llvmbuild/util.py b/utils/llvm-build/llvmbuild/util.py index cf6fa285735..e581af23d45 100644 --- a/utils/llvm-build/llvmbuild/util.py +++ b/utils/llvm-build/llvmbuild/util.py @@ -1,16 +1,9 @@ -import inspect import os import sys def _write_message(kind, message): - # Get the file/line where this message was generated. - f = inspect.currentframe() - # Step out of _write_message, and then out of wrapper. - f = f.f_back.f_back - file,line,_,_,_ = inspect.getframeinfo(f) - location = '%s:%d' % (os.path.basename(file), line) - - print >>sys.stderr, '%s: %s: %s' % (location, kind, message) + program = os.path.basename(sys.argv[0]) + print >>sys.stderr, '%s: %s: %s' % (program, kind, message) note = lambda message: _write_message('note', message) warning = lambda message: _write_message('warning', message)