aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/backend/ninjabackend.py361
1 files changed, 181 insertions, 180 deletions
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index f1527da..8c856b2 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -63,6 +63,48 @@ Please report this error with a test case to the Meson bug tracker.''' % text
raise MesonException(errmsg)
return text
+class NinjaComment:
+ def __init__(self, comment):
+ self.comment = comment
+
+ def write(self, outfile):
+ for l in self.comment.split('\n'):
+ outfile.write('# ')
+ outfile.write(l)
+ outfile.write('\n')
+ outfile.write('\n')
+
+class NinjaRule:
+ def __init__(self, rule, command, args, description,
+ rspable = False, deps = None, depfile = None, extra = None):
+ self.name = rule
+ self.command = command # includes args which never go into a rspfile
+ self.args = args # args which will go into a rspfile, if used
+ self.description = description
+ self.deps = deps # depstyle 'gcc' or 'msvc'
+ self.depfile = depfile
+ self.extra = extra
+ self.rspable = rspable # if a rspfile can be used
+
+ def write(self, outfile):
+ outfile.write('rule %s\n' % self.name)
+ if self.rspable:
+ outfile.write(' command = %s @$out.rsp\n' % self.command)
+ outfile.write(' rspfile = $out.rsp\n')
+ outfile.write(' rspfile_content = %s\n' % self.args)
+ else:
+ outfile.write(' command = %s %s\n' % (self.command, self.args))
+ if self.deps:
+ outfile.write(' deps = %s\n' % self.deps)
+ if self.depfile:
+ outfile.write(' depfile = %s\n' % self.depfile)
+ outfile.write(' description = %s\n' % self.description)
+ if self.extra:
+ for l in self.extra.split('\n'):
+ outfile.write(' ')
+ outfile.write(l)
+ outfile.write('\n')
+ outfile.write('\n')
class NinjaBuildElement:
def __init__(self, all_outputs, outfilenames, rule, infilenames):
@@ -230,6 +272,7 @@ int dummy;
with self.detect_vs_dep_prefix(tempfilename) as outfile:
self.generate_rules(outfile)
+ self.write_rules(outfile)
self.generate_phony(outfile)
outfile.write('# Build rules for targets\n\n')
for t in self.build.get_targets().values():
@@ -781,36 +824,43 @@ int dummy;
self.create_target_alias('meson-benchmark', outfile)
def generate_rules(self, outfile):
- outfile.write('# Rules for compiling.\n\n')
+ self.rules = []
+
+ self.add_rule_comment(NinjaComment('Rules for compiling.'))
self.generate_compile_rules(outfile)
- outfile.write('# Rules for linking.\n\n')
+ self.add_rule_comment(NinjaComment('Rules for linking.'))
if self.environment.is_cross_build():
self.generate_static_link_rules(True, outfile)
self.generate_static_link_rules(False, outfile)
self.generate_dynamic_link_rules(outfile)
- outfile.write('# Other rules\n\n')
- outfile.write('rule CUSTOM_COMMAND\n')
- outfile.write(' command = $COMMAND\n')
- outfile.write(' description = $DESC\n')
- outfile.write(' restat = 1\n\n')
+ self.add_rule_comment(NinjaComment('Other rules'))
# Ninja errors out if you have deps = gcc but no depfile, so we must
# have two rules for custom commands.
- outfile.write('rule CUSTOM_COMMAND_DEP\n')
- outfile.write(' command = $COMMAND\n')
- outfile.write(' description = $DESC\n')
- outfile.write(' deps = gcc\n')
- outfile.write(' depfile = $DEPFILE\n')
- outfile.write(' restat = 1\n\n')
- outfile.write('rule REGENERATE_BUILD\n')
+ self.add_rule(NinjaRule('CUSTOM_COMMAND', '$COMMAND', '', '$DESC',
+ extra='restat = 1'))
+ self.add_rule(NinjaRule('CUSTOM_COMMAND_DEP', '$COMMAND', '', '$DESC',
+ deps='gcc', depfile='$DEPFILE',
+ extra='restat = 1'))
+
c = [ninja_quote(quote_func(x)) for x in self.environment.get_build_command()] + \
['--internal',
'regenerate',
ninja_quote(quote_func(self.environment.get_source_dir())),
ninja_quote(quote_func(self.environment.get_build_dir()))]
- outfile.write(" command = " + ' '.join(c) + ' --backend ninja\n')
- outfile.write(' description = Regenerating build files.\n')
- outfile.write(' generator = 1\n\n')
- outfile.write('\n')
+ self.add_rule(NinjaRule('REGENERATE_BUILD',
+ ' '.join(c) + ' --backend ninja', '',
+ 'Regenerating build files.',
+ extra='generator = 1'))
+
+ def add_rule_comment(self, comment):
+ self.rules.append(comment)
+
+ def add_rule(self, rule):
+ self.rules.append(rule)
+
+ def write_rules(self, outfile):
+ for r in self.rules:
+ r.write(outfile)
def generate_phony(self, outfile):
outfile.write('# Phony build target, always out of date\n')
@@ -976,13 +1026,10 @@ int dummy;
return plain_class_path
def generate_java_link(self, outfile):
- rule = 'rule java_LINKER\n'
- command = ' command = jar $ARGS\n'
- description = ' description = Creating JAR $out.\n'
- outfile.write(rule)
- outfile.write(command)
- outfile.write(description)
- outfile.write('\n')
+ rule = 'java_LINKER'
+ command = 'jar $ARGS'
+ description = 'Creating JAR $out.'
+ self.add_rule(NinjaRule(rule, command, '', description))
def determine_dep_vapis(self, target):
"""
@@ -1427,14 +1474,10 @@ int dummy;
crstr = ''
if static_linker is None:
return
- rule = 'rule STATIC%s_LINKER\n' % crstr
- if static_linker.can_linker_accept_rsp():
- command_template = ''' command = {executable} $LINK_ARGS {output_args} @$out.rsp
- rspfile = $out.rsp
- rspfile_content = $in
-'''
- else:
- command_template = ' command = {executable} $LINK_ARGS {output_args} $in\n'
+ rule = 'STATIC%s_LINKER' % crstr
+ command_template = '{executable} $LINK_ARGS {output_args}'
+ args = '$in'
+
cmdlist = []
# FIXME: Must normalize file names with pathlib.Path before writing
# them out to fix this properly on Windows. See:
@@ -1446,15 +1489,19 @@ int dummy;
# it exists. https://github.com/mesonbuild/meson/issues/1355
cmdlist = [execute_wrapper, rmfile_prefix.format('$out')]
cmdlist += static_linker.get_exelist()
- command = command_template.format(
- executable=' '.join(cmdlist),
- output_args=' '.join(static_linker.get_output_args('$out')))
- description = ' description = Linking static target $out.\n\n'
- outfile.write(rule)
- outfile.write(command)
+ subst = {
+ 'executable': ' '.join(cmdlist),
+ 'output_args': ' '.join(static_linker.get_output_args('$out'))
+ }
+ command = command_template.format(**subst)
+ description = 'Linking static target $out.'
if num_pools > 0:
- outfile.write(' pool = link_pool\n')
- outfile.write(description)
+ pool = 'pool = link_pool'
+ else:
+ pool = None
+ self.add_rule(NinjaRule(rule, command, args, description,
+ rspable=static_linker.can_linker_accept_rsp(),
+ extra=pool))
def generate_dynamic_link_rules(self, outfile):
num_pools = self.environment.coredata.backend_options['backend_max_links'].value
@@ -1473,101 +1520,73 @@ int dummy;
crstr = ''
if is_cross:
crstr = '_CROSS'
- rule = 'rule %s%s_LINKER\n' % (langname, crstr)
- if compiler.can_linker_accept_rsp():
- command_template = ''' command = {executable} @$out.rsp
- rspfile = $out.rsp
- rspfile_content = $ARGS {output_args} $in $LINK_ARGS
-'''
- else:
- command_template = ' command = {executable} $ARGS {output_args} $in $LINK_ARGS\n'
- command = command_template.format(
- executable=' '.join(compiler.get_linker_exelist()),
- output_args=' '.join(compiler.get_linker_output_args('$out'))
- )
- description = ' description = Linking target $out.\n'
- outfile.write(rule)
- outfile.write(command)
+ rule = '%s%s_LINKER' % (langname, crstr)
+ command_template = '{executable}'
+ args_template = '$ARGS {output_args} $in $LINK_ARGS'
+ subst = {
+ 'executable': ' '.join(compiler.get_linker_exelist()),
+ 'output_args': ' '.join(compiler.get_linker_output_args('$out')),
+ }
+ command = command_template.format(**subst)
+ args = args_template.format(**subst)
+ description = 'Linking target $out.'
if num_pools > 0:
- outfile.write(' pool = link_pool\n')
- outfile.write(description)
- outfile.write('\n')
- outfile.write('\n')
+ pool = 'pool = link_pool'
+ else:
+ pool = None
+ self.add_rule(NinjaRule(rule, command, args, description,
+ rspable=compiler.can_linker_accept_rsp(),
+ extra=pool))
+
args = [ninja_quote(quote_func(x)) for x in self.environment.get_build_command()] + \
['--internal',
'symbolextractor',
'$in',
'$out']
- symrule = 'rule SHSYM\n'
- symcmd = ' command = ' + ' '.join(args) + ' $CROSS\n'
- synstat = ' restat = 1\n'
- syndesc = ' description = Generating symbol file $out.\n'
- outfile.write(symrule)
- outfile.write(symcmd)
- outfile.write(synstat)
- outfile.write(syndesc)
- outfile.write('\n')
+ symrule = 'SHSYM'
+ symcmd = ' '.join(args) + ' $CROSS'
+ syndesc = 'Generating symbol file $out.'
+ synstat = 'restat = 1'
+ self.add_rule(NinjaRule(symrule, symcmd, '', syndesc, extra=synstat))
def generate_java_compile_rule(self, compiler, outfile):
- rule = 'rule %s_COMPILER\n' % compiler.get_language()
+ rule = '%s_COMPILER' % compiler.get_language()
invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
- command = ' command = %s $ARGS $in\n' % invoc
- description = ' description = Compiling Java object $in.\n'
- outfile.write(rule)
- outfile.write(command)
- outfile.write(description)
- outfile.write('\n')
+ command = '%s $ARGS $in' % invoc
+ description = 'Compiling Java object $in.'
+ self.add_rule(NinjaRule(rule, command, '', description))
def generate_cs_compile_rule(self, compiler, outfile):
- rule = 'rule %s_COMPILER\n' % compiler.get_language()
+ rule = '%s_COMPILER' % compiler.get_language()
invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
-
- if mesonlib.is_windows():
- command = ''' command = {executable} @$out.rsp
- rspfile = $out.rsp
- rspfile_content = $ARGS $in
-'''.format(executable=invoc)
- else:
- command = ' command = %s $ARGS $in\n' % invoc
-
- description = ' description = Compiling C Sharp target $out.\n'
- outfile.write(rule)
- outfile.write(command)
- outfile.write(description)
- outfile.write('\n')
+ command = '%s' % invoc
+ args = '$ARGS $in'
+ description = 'Compiling C Sharp target $out.'
+ self.add_rule(NinjaRule(rule, command, args, description,
+ rspable=mesonlib.is_windows()))
def generate_vala_compile_rules(self, compiler, outfile):
- rule = 'rule %s_COMPILER\n' % compiler.get_language()
+ rule = '%s_COMPILER' % compiler.get_language()
invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
- command = ' command = %s $ARGS $in\n' % invoc
- description = ' description = Compiling Vala source $in.\n'
- restat = ' restat = 1\n' # ValaC does this always to take advantage of it.
- outfile.write(rule)
- outfile.write(command)
- outfile.write(description)
- outfile.write(restat)
- outfile.write('\n')
+ command = '%s $ARGS $in' % invoc
+ description = 'Compiling Vala source $in.'
+ self.add_rule(NinjaRule(rule, command, '', description, extra='restat = 1'))
def generate_rust_compile_rules(self, compiler, outfile, is_cross):
crstr = ''
if is_cross:
crstr = '_CROSS'
- rule = 'rule %s%s_COMPILER\n' % (compiler.get_language(), crstr)
+ rule = '%s%s_COMPILER' % (compiler.get_language(), crstr)
invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
- command = ' command = %s $ARGS $in\n' % invoc
- description = ' description = Compiling Rust source $in.\n'
- depfile = ' depfile = $targetdep\n'
-
- depstyle = ' deps = gcc\n'
- outfile.write(rule)
- outfile.write(command)
- outfile.write(description)
- outfile.write(depfile)
- outfile.write(depstyle)
- outfile.write('\n')
+ command = '%s $ARGS $in' % invoc
+ description = 'Compiling Rust source $in.'
+ depfile = '$targetdep'
+ depstyle = 'gcc'
+ self.add_rule(NinjaRule(rule, command, '', description, deps=depstyle,
+ depfile=depfile))
def generate_swift_compile_rules(self, compiler, outfile):
- rule = 'rule %s_COMPILER\n' % compiler.get_language()
+ rule = '%s_COMPILER' % compiler.get_language()
full_exe = [ninja_quote(x) for x in self.environment.get_build_command()] + [
'--internal',
'dirchanger',
@@ -1575,49 +1594,37 @@ int dummy;
]
invoc = (' '.join(full_exe) + ' ' +
' '.join(ninja_quote(i) for i in compiler.get_exelist()))
- command = ' command = %s $ARGS $in\n' % invoc
- description = ' description = Compiling Swift source $in.\n'
- outfile.write(rule)
- outfile.write(command)
- outfile.write(description)
- outfile.write('\n')
+ command = '%s $ARGS $in' % invoc
+ description = 'Compiling Swift source $in.'
+ self.add_rule(NinjaRule(rule, command, '', description))
def generate_fortran_dep_hack(self, outfile, crstr):
+ rule = 'FORTRAN_DEP_HACK%s' % (crstr)
if mesonlib.is_windows():
cmd = 'cmd /C ""'
else:
cmd = 'true'
- template = '''# Workaround for these issues:
-# https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8
-# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485
-rule FORTRAN_DEP_HACK%s
- command = %s
- description = Dep hack
- restat = 1
-
-'''
- outfile.write(template % (crstr, cmd))
+ self.add_rule_comment(NinjaComment('''Workaround for these issues:
+https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8
+https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
+ self.add_rule(NinjaRule(rule, cmd, '', 'Dep hack', extra='restat = 1'))
def generate_llvm_ir_compile_rule(self, compiler, is_cross, outfile):
if getattr(self, 'created_llvm_ir_rule', False):
return
- rule = 'rule llvm_ir{}_COMPILER\n'.format('_CROSS' if is_cross else '')
- if compiler.can_linker_accept_rsp():
- command_template = ' command = {executable} @$out.rsp\n' \
- ' rspfile = $out.rsp\n' \
- ' rspfile_content = $ARGS {output_args} {compile_only_args} $in\n'
- else:
- command_template = ' command = {executable} $ARGS {output_args} {compile_only_args} $in\n'
- command = command_template.format(
- executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
- output_args=' '.join(compiler.get_output_args('$out')),
- compile_only_args=' '.join(compiler.get_compile_only_args())
- )
- description = ' description = Compiling LLVM IR object $in.\n'
- outfile.write(rule)
- outfile.write(command)
- outfile.write(description)
- outfile.write('\n')
+ rule = 'llvm_ir{}_COMPILER'.format('_CROSS' if is_cross else '')
+ command_template = '{executable}'
+ args_template = '$ARGS {output_args} {compile_only_args} $in'
+ subst = {
+ 'executable': ' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
+ 'output_args': ' '.join(compiler.get_output_args('$out')),
+ 'compile_only_args': ' '.join(compiler.get_compile_only_args()),
+ }
+ command = command_template.format(**subst)
+ args = args_template.format(**subst)
+ description = 'Compiling LLVM IR object $in.'
+ self.add_rule(NinjaRule(rule, command, args, description,
+ rspable=compiler.can_linker_accept_rsp()))
self.created_llvm_ir_rule = True
def generate_compile_rule_for(self, langname, compiler, is_cross, outfile):
@@ -1646,7 +1653,7 @@ rule FORTRAN_DEP_HACK%s
crstr = ''
if langname == 'fortran':
self.generate_fortran_dep_hack(outfile, crstr)
- rule = 'rule %s%s_COMPILER\n' % (langname, crstr)
+ rule = '%s%s_COMPILER' % (langname, crstr)
depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE')
quoted_depargs = []
for d in depargs:
@@ -1654,30 +1661,26 @@ rule FORTRAN_DEP_HACK%s
d = quote_func(d)
quoted_depargs.append(d)
- if compiler.can_linker_accept_rsp():
- command_template = ''' command = {executable} @$out.rsp
- rspfile = $out.rsp
- rspfile_content = $ARGS {dep_args} {output_args} {compile_only_args} $in
-'''
- else:
- command_template = ' command = {executable} $ARGS {dep_args} {output_args} {compile_only_args} $in\n'
- command = command_template.format(
- executable=' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
- dep_args=' '.join(quoted_depargs),
- output_args=' '.join(compiler.get_output_args('$out')),
- compile_only_args=' '.join(compiler.get_compile_only_args())
- )
- description = ' description = Compiling %s object $out.\n' % compiler.get_display_language()
+ command_template = '{executable}'
+ args_template = '$ARGS {dep_args} {output_args} {compile_only_args} $in'
+ subst = {
+ 'executable': ' '.join([ninja_quote(i) for i in compiler.get_exelist()]),
+ 'dep_args': ' '.join(quoted_depargs),
+ 'output_args': ' '.join(compiler.get_output_args('$out')),
+ 'compile_only_args': ' '.join(compiler.get_compile_only_args()),
+ }
+ command = command_template.format(**subst)
+ args = args_template.format(**subst)
+ description = 'Compiling %s object $out.' % compiler.get_display_language()
if isinstance(compiler, VisualStudioCCompiler):
- deps = ' deps = msvc\n'
+ deps = 'msvc'
+ depfile = None
else:
- deps = ' deps = gcc\n'
- deps += ' depfile = $DEPFILE\n'
- outfile.write(rule)
- outfile.write(command)
- outfile.write(deps)
- outfile.write(description)
- outfile.write('\n')
+ deps = 'gcc'
+ depfile = '$DEPFILE'
+ self.add_rule(NinjaRule(rule, command, args, description,
+ rspable=compiler.can_linker_accept_rsp(),
+ deps=deps, depfile=depfile))
def generate_pch_rule_for(self, langname, compiler, is_cross, outfile):
if langname != 'c' and langname != 'cpp':
@@ -1686,7 +1689,7 @@ rule FORTRAN_DEP_HACK%s
crstr = '_CROSS'
else:
crstr = ''
- rule = 'rule %s%s_PCH\n' % (langname, crstr)
+ rule = '%s%s_PCH' % (langname, crstr)
depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE')
quoted_depargs = []
@@ -1698,23 +1701,21 @@ rule FORTRAN_DEP_HACK%s
output = ''
else:
output = ' '.join(compiler.get_output_args('$out'))
- command = " command = {executable} $ARGS {dep_args} {output_args} {compile_only_args} $in\n".format(
+ command = "{executable} $ARGS {dep_args} {output_args} {compile_only_args} $in".format(
executable=' '.join(compiler.get_exelist()),
dep_args=' '.join(quoted_depargs),
output_args=output,
compile_only_args=' '.join(compiler.get_compile_only_args())
)
- description = ' description = Precompiling header %s.\n' % '$in'
+ description = 'Precompiling header $in.'
if isinstance(compiler, VisualStudioCCompiler):
- deps = ' deps = msvc\n'
+ deps = 'msvc'
+ depfile = None
else:
- deps = ' deps = gcc\n'
- deps += ' depfile = $DEPFILE\n'
- outfile.write(rule)
- outfile.write(command)
- outfile.write(deps)
- outfile.write(description)
- outfile.write('\n')
+ deps = 'gcc'
+ depfile = '$DEPFILE'
+ self.add_rule(NinjaRule(rule, command, '', description, deps=deps,
+ depfile=depfile))
def generate_compile_rules(self, outfile):
for langname, compiler in self.build.compilers.items():