From 2e93295c2e2ed52abd036687d8a6a947b94f213a Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 27 Mar 2015 23:41:28 +0200 Subject: [PATCH] Generate configure files immediately when they are declared. Closes #88. --- backends.py | 86 +------------------ build.py | 1 - interpreter.py | 6 +- mesonlib.py | 73 +++++++++++++++- ninjabackend.py | 1 - .../common/16 configure file/meson.build | 8 +- vs2010backend.py | 1 - xcodebackend.py | 1 - 8 files changed, 85 insertions(+), 92 deletions(-) diff --git a/backends.py b/backends.py index 47df757e0..83f291ab2 100644 --- a/backends.py +++ b/backends.py @@ -12,80 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import mparser -import os, re, pickle +import os, pickle import build import dependencies +import mesonlib from coredata import MesonException -def do_replacement(regex, line, confdata): - match = re.search(regex, line) - while match: - varname = match.group(1) - if varname in confdata.keys(): - var = confdata.get(varname) - if isinstance(var, str): - pass - elif isinstance(var, mparser.StringNode): - var = var.value - elif isinstance(var, int): - var = str(var) - else: - raise RuntimeError('Tried to replace a variable with something other than a string or int.') - else: - var = '' - line = line.replace('@' + varname + '@', var) - match = re.search(regex, line) - return line - -def do_mesondefine(line, confdata): - arr = line.split() - if len(arr) != 2: - raise build.InvalidArguments('#mesondefine does not contain exactly two tokens: %s', line.strip()) - varname = arr[1] - try: - v = confdata.get(varname) - except KeyError: - return '/* undef %s */\n' % varname - if isinstance(v, mparser.BooleanNode): - v = v.value - if isinstance(v, bool): - if v: - return '#define %s\n' % varname - else: - return '#undef %s\n' % varname - elif isinstance(v, int): - return '#define %s %d\n' % (varname, v) - elif isinstance(v, str): - return '#define %s %s\n' % (varname, v) - else: - raise build.InvalidArguments('#mesondefine argument "%s" is of unknown type.' % varname) - -def replace_if_different(dst, dst_tmp): - # If contents are identical, don't touch the file to prevent - # unnecessary rebuilds. - try: - if open(dst, 'r').read() == open(dst_tmp, 'r').read(): - os.unlink(dst_tmp) - return - except FileNotFoundError: - pass - os.replace(dst_tmp, dst) - -def do_conf_file(src, dst, confdata): - data = open(src).readlines() - regex = re.compile('@(.*?)@') - result = [] - for line in data: - if line.startswith('#mesondefine'): - line = do_mesondefine(line, confdata) - else: - line = do_replacement(regex, line, confdata) - result.append(line) - dst_tmp = dst + '~' - open(dst_tmp, 'w').writelines(result) - replace_if_different(dst, dst_tmp) - class TestSerialisation: def __init__(self, name, fname, is_cross, exe_wrapper, is_parallel, cmd_args, env, should_fail, valgrind_args): @@ -160,7 +92,7 @@ class Backend(): ofile = langlist[language] ofile.write('#include<%s>\n' % src) [x.close() for x in langlist.values()] - [replace_if_different(x, x + '.tmp') for x in abs_files] + [mesonlib.replace_if_different(x, x + '.tmp') for x in abs_files] return result def relpath(self, todir, fromdir): @@ -295,18 +227,6 @@ class Backend(): args += self.build_target_link_arguments(compiler, d.get_dependencies()) return args - def generate_configure_files(self): - for cf in self.build.get_configure_files(): - infile = os.path.join(self.environment.get_source_dir(), - cf.get_subdir(), - cf.get_source_name()) - outdir = os.path.join(self.environment.get_build_dir(), - cf.get_subdir()) - os.makedirs(outdir, exist_ok=True) - outfile = os.path.join(outdir, cf.get_target_name()) - confdata = cf.get_configuration_data() - do_conf_file(infile, outfile, confdata) - def write_test_file(self, datafile): arr = [] for t in self.build.get_tests(): diff --git a/build.py b/build.py index fff3d11c4..89103d51c 100644 --- a/build.py +++ b/build.py @@ -68,7 +68,6 @@ class Build: self.data = [] self.static_linker = None self.static_cross_linker = None - self.configure_files = [] self.pot = [] self.subprojects = {} self.pkgconfig_gens = [] diff --git a/interpreter.py b/interpreter.py index 319aeaded..ee8eca7bc 100644 --- a/interpreter.py +++ b/interpreter.py @@ -1412,8 +1412,10 @@ class Interpreter(): conffile = os.path.join(self.subdir, inputfile) self.build_def_files.append(conffile) - c = ConfigureFileHolder(self.subdir, inputfile, output, conf.held_object) - self.build.configure_files.append(c.held_object) + os.makedirs(os.path.join(self.environment.build_dir, self.subdir), exist_ok=True) + ifile_abs = os.path.join(self.environment.source_dir, self.subdir, inputfile) + ofile_abs = os.path.join(self.environment.build_dir, self.subdir, output) + mesonlib.do_conf_file(ifile_abs, ofile_abs, conf.held_object) conf.mark_used() elif 'command' in kwargs: res = self.func_run_command(node, kwargs['command'], {}) diff --git a/mesonlib.py b/mesonlib.py index 10e5265ac..6ab60515e 100644 --- a/mesonlib.py +++ b/mesonlib.py @@ -14,9 +14,12 @@ """A library of random helper functionality.""" -import platform, subprocess, operator, os, shutil +import platform, subprocess, operator, os, shutil, re + from glob import glob +from coredata import MesonException + def is_osx(): return platform.system().lower() == 'darwin' @@ -120,3 +123,71 @@ def get_library_dirs(): unixdirs.append('/lib64') unixdirs += glob('/lib/' + plat + '*') return unixdirs + + +def do_replacement(regex, line, confdata): + match = re.search(regex, line) + while match: + varname = match.group(1) + if varname in confdata.keys(): + var = confdata.get(varname) + if isinstance(var, str): + pass + elif isinstance(var, int): + var = str(var) + else: + raise RuntimeError('Tried to replace a variable with something other than a string or int.') + else: + var = '' + line = line.replace('@' + varname + '@', var) + match = re.search(regex, line) + return line + +def do_mesondefine(line, confdata): + arr = line.split() + if len(arr) != 2: + raise MesonException('#mesondefine does not contain exactly two tokens: %s', line.strip()) + varname = arr[1] + try: + v = confdata.get(varname) + except KeyError: + return '/* undef %s */\n' % varname + if isinstance(v, bool): + if v: + return '#define %s\n' % varname + else: + return '#undef %s\n' % varname + elif isinstance(v, int): + return '#define %s %d\n' % (varname, v) + elif isinstance(v, str): + return '#define %s %s\n' % (varname, v) + else: + raise MesonException('#mesondefine argument "%s" is of unknown type.' % varname) + + +def do_conf_file(src, dst, confdata): + data = open(src).readlines() + regex = re.compile('@(.*?)@') + result = [] + for line in data: + if line.startswith('#mesondefine'): + line = do_mesondefine(line, confdata) + else: + line = do_replacement(regex, line, confdata) + result.append(line) + dst_tmp = dst + '~' + open(dst_tmp, 'w').writelines(result) + replace_if_different(dst, dst_tmp) + + +def replace_if_different(dst, dst_tmp): + # If contents are identical, don't touch the file to prevent + # unnecessary rebuilds. + try: + if open(dst, 'r').read() == open(dst_tmp, 'r').read(): + os.unlink(dst_tmp) + return + except FileNotFoundError: + pass + os.replace(dst_tmp, dst) + diff --git a/ninjabackend.py b/ninjabackend.py index 3facb0809..d467c075f 100644 --- a/ninjabackend.py +++ b/ninjabackend.py @@ -120,7 +120,6 @@ class NinjaBackend(backends.Backend): outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename) tempfilename = outfilename + '~' outfile = open(tempfilename, 'w') - self.generate_configure_files() self.generate_pkgconfig_files() outfile.write('# This is the build file for project "%s"\n' % self.build.get_project()) outfile.write('# It is autogenerated by the Meson build system.\n') diff --git a/test cases/common/16 configure file/meson.build b/test cases/common/16 configure file/meson.build index 911a50ffa..8dec8fe53 100644 --- a/test cases/common/16 configure file/meson.build +++ b/test cases/common/16 configure file/meson.build @@ -7,11 +7,15 @@ conf.set('other', 'string 2') conf.set('second', ' bonus') conf.set('BE_TRUE', true) -configure_file(input : 'config.h.in', +cfile = configure_file(input : 'config.h.in', output : 'config.h', configuration : conf) -e = executable('inctest', 'prog.c') +e = executable('inctest', 'prog.c', +# Note that you should NOT do this. Don't add generated headers here +# This tests that we do the right thing even if people add in conf files +# to their sources. +cfile) test('inctest', e) # Now generate a header file with an external script. diff --git a/vs2010backend.py b/vs2010backend.py index 9da55be18..062e09a5b 100644 --- a/vs2010backend.py +++ b/vs2010backend.py @@ -62,7 +62,6 @@ class Vs2010Backend(backends.Backend): return all_output_files def generate(self): - self.generate_configure_files() self.generate_pkgconfig_files() sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln') projlist = self.generate_projects() diff --git a/xcodebackend.py b/xcodebackend.py index cd0578880..d2158bc58 100644 --- a/xcodebackend.py +++ b/xcodebackend.py @@ -74,7 +74,6 @@ class XCodeBackend(backends.Backend): self.generate_target_dependency_map() self.generate_pbxdep_map() self.generate_containerproxy_map() - self.generate_configure_files() self.generate_pkgconfig_files() self.proj_dir = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.xcodeproj') os.makedirs(self.proj_dir, exist_ok=True)