ninjabackend: List PDBs in output list for targets

This is more correct, and forces the target(s) to be rebuilt if the
PDB files are missing. Increases the minimum required Ninja to 1.7,
which is available in Ubuntu 16.04 under backports.

We can't do the same for import libraries, because it is impossible
for us to know at configure time whether or not an import library will
be generated for a given DLL.
pull/6637/head
Nirbheek Chauhan 5 years ago
parent feb82e0f0f
commit be486a2ec8
  1. 10
      docs/markdown/snippets/ninja_version_bump.md
  2. 21
      mesonbuild/backend/ninjabackend.py
  3. 3
      mesonbuild/compilers/compilers.py
  4. 4
      mesonbuild/environment.py
  5. 15
      mesonbuild/linkers.py
  6. 18
      run_tests.py

@ -0,0 +1,10 @@
## Ninja version requirement bumped to 1.7
Meson now uses the [Implicit outputs](https://ninja-build.org/manual.html#ref_outputs)
feature of Ninja for some types of targets that have multiple outputs which may
not be listed on the command-line. This feature requires Ninja 1.7+.
Note that the latest version of [Ninja available in Ubuntu 16.04](https://packages.ubuntu.com/search?keywords=ninja-build&searchon=names&suite=xenial-backports&section=all)
(the oldest Ubuntu LTS at the time of writing) is 1.7.1. If your distro does
not ship with a new-enough Ninja, you can download the latest release from
Ninja's GitHub page: https://github.com/ninja-build/ninja/releases

@ -120,7 +120,8 @@ class NinjaRule:
outfile.write('\n') outfile.write('\n')
class NinjaBuildElement: class NinjaBuildElement:
def __init__(self, all_outputs, outfilenames, rule, infilenames): def __init__(self, all_outputs, outfilenames, rule, infilenames, implicit_outs=None):
self.implicit_outfilenames = implicit_outs or []
if isinstance(outfilenames, str): if isinstance(outfilenames, str):
self.outfilenames = [outfilenames] self.outfilenames = [outfilenames]
else: else:
@ -155,9 +156,12 @@ class NinjaBuildElement:
def write(self, outfile): def write(self, outfile):
self.check_outputs() self.check_outputs()
line = 'build %s: %s %s' % (' '.join([ninja_quote(i, True) for i in self.outfilenames]), ins = ' '.join([ninja_quote(i, True) for i in self.infilenames])
self.rule, outs = ' '.join([ninja_quote(i, True) for i in self.outfilenames])
' '.join([ninja_quote(i, True) for i in self.infilenames])) implicit_outs = ' '.join([ninja_quote(i, True) for i in self.implicit_outfilenames])
if implicit_outs:
implicit_outs = ' | ' + implicit_outs
line = 'build {}{}: {} {}'.format(outs, implicit_outs, self.rule, ins)
if len(self.deps) > 0: if len(self.deps) > 0:
line += ' | ' + ' '.join([ninja_quote(x, True) for x in self.deps]) line += ' | ' + ' '.join([ninja_quote(x, True) for x in self.deps])
if len(self.orderdeps) > 0: if len(self.orderdeps) > 0:
@ -1947,6 +1951,9 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
else: else:
return compiler.get_compile_debugfile_args(objfile, pch=False) return compiler.get_compile_debugfile_args(objfile, pch=False)
def get_link_debugfile_name(self, linker, target, outname):
return linker.get_link_debugfile_name(outname)
def get_link_debugfile_args(self, linker, target, outname): def get_link_debugfile_args(self, linker, target, outname):
return linker.get_link_debugfile_args(outname) return linker.get_link_debugfile_args(outname)
@ -2449,6 +2456,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
def generate_link(self, target, outname, obj_list, linker, extra_args=None, stdlib_args=None): def generate_link(self, target, outname, obj_list, linker, extra_args=None, stdlib_args=None):
extra_args = extra_args if extra_args is not None else [] extra_args = extra_args if extra_args is not None else []
stdlib_args = stdlib_args if stdlib_args is not None else [] stdlib_args = stdlib_args if stdlib_args is not None else []
implicit_outs = []
if isinstance(target, build.StaticLibrary): if isinstance(target, build.StaticLibrary):
linker_base = 'STATIC' linker_base = 'STATIC'
else: else:
@ -2484,6 +2492,9 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
# Add /DEBUG and the pdb filename when using MSVC # Add /DEBUG and the pdb filename when using MSVC
if self.get_option_for_target('debug', target): if self.get_option_for_target('debug', target):
commands += self.get_link_debugfile_args(linker, target, outname) commands += self.get_link_debugfile_args(linker, target, outname)
debugfile = self.get_link_debugfile_name(linker, target, outname)
if debugfile is not None:
implicit_outs += [debugfile]
# Add link args specific to this BuildTarget type, such as soname args, # Add link args specific to this BuildTarget type, such as soname args,
# PIC, import library generation, etc. # PIC, import library generation, etc.
commands += self.get_target_type_link_args(target, linker) commands += self.get_target_type_link_args(target, linker)
@ -2572,7 +2583,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
dep_targets.extend([self.get_dependency_filename(t) for t in dependencies]) dep_targets.extend([self.get_dependency_filename(t) for t in dependencies])
dep_targets.extend([self.get_dependency_filename(t) dep_targets.extend([self.get_dependency_filename(t)
for t in target.link_depends]) for t in target.link_depends])
elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list) elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list, implicit_outs=implicit_outs)
elem.add_dep(dep_targets + custom_target_libraries) elem.add_dep(dep_targets + custom_target_libraries)
elem.add_item('LINK_ARGS', commands) elem.add_item('LINK_ARGS', commands)
return elem return elem

@ -976,6 +976,9 @@ class Compiler:
def get_compile_debugfile_args(self, rel_obj, **kwargs): def get_compile_debugfile_args(self, rel_obj, **kwargs):
return [] return []
def get_link_debugfile_name(self, targetfile: str) -> str:
return self.linker.get_debugfile_name(targetfile)
def get_link_debugfile_args(self, targetfile: str) -> T.List[str]: def get_link_debugfile_args(self, targetfile: str) -> T.List[str]:
return self.linker.get_debugfile_args(targetfile) return self.linker.get_debugfile_args(targetfile)

@ -140,11 +140,11 @@ def find_coverage_tools():
return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe
def detect_ninja(version: str = '1.5', log: bool = False) -> str: def detect_ninja(version: str = '1.7', log: bool = False) -> str:
r = detect_ninja_command_and_version(version, log) r = detect_ninja_command_and_version(version, log)
return r[0] if r else None return r[0] if r else None
def detect_ninja_command_and_version(version: str = '1.5', log: bool = False) -> (str, str): def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> (str, str):
env_ninja = os.environ.get('NINJA', None) env_ninja = os.environ.get('NINJA', None)
for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']: for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']:
try: try:

@ -75,6 +75,9 @@ class StaticLinker:
def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]: def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]:
return args[:] return args[:]
def get_link_debugfile_name(self, targetfile: str) -> str:
return None
def get_link_debugfile_args(self, targetfile: str) -> T.List[str]: def get_link_debugfile_args(self, targetfile: str) -> T.List[str]:
# Static libraries do not have PDB files # Static libraries do not have PDB files
return [] return []
@ -305,6 +308,10 @@ class DynamicLinker(metaclass=abc.ABCMeta):
m = 'Language {} does not support has_multi_link_arguments.' m = 'Language {} does not support has_multi_link_arguments.'
raise mesonlib.EnvironmentException(m.format(self.id)) raise mesonlib.EnvironmentException(m.format(self.id))
def get_debugfile_name(self, targetfile: str) -> str:
'''Name of debug file written out (see below)'''
return None
def get_debugfile_args(self, targetfile: str) -> T.List[str]: def get_debugfile_args(self, targetfile: str) -> T.List[str]:
"""Some compilers (MSVC) write debug into a separate file. """Some compilers (MSVC) write debug into a separate file.
@ -812,10 +819,12 @@ class VisualStudioLikeLinkerMixin:
def get_std_shared_lib_args(self) -> T.List[str]: def get_std_shared_lib_args(self) -> T.List[str]:
return self._apply_prefix('/DLL') return self._apply_prefix('/DLL')
def get_debugfile_name(self, targetfile: str) -> str:
basename = targetfile.rsplit('.', maxsplit=1)[0]
return basename + '.pdb'
def get_debugfile_args(self, targetfile: str) -> T.List[str]: def get_debugfile_args(self, targetfile: str) -> T.List[str]:
pdbarr = targetfile.split('.')[:-1] return self._apply_prefix(['/DEBUG', '/PDB:' + self.get_debugfile_name(targetfile)])
pdbarr += ['pdb']
return self._apply_prefix(['/DEBUG', '/PDB:' + '.'.join(pdbarr)])
def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
# Only since VS2015 # Only since VS2015

@ -45,17 +45,15 @@ if 'CI' in os.environ:
NINJA_CMD = 'ninja' NINJA_CMD = 'ninja'
else: else:
# Look for 1.9 to see if https://github.com/ninja-build/ninja/issues/1219 # Look for 1.9 to see if https://github.com/ninja-build/ninja/issues/1219
# is fixed, else require 1.6 for -w dupbuild=err # is fixed
for v in ('1.9', '1.6'): NINJA_CMD = detect_ninja('1.9')
NINJA_CMD = detect_ninja(v) if NINJA_CMD is not None:
if NINJA_CMD is not None: NINJA_1_9_OR_NEWER = True
if mesonlib.version_compare(v, '>=1.9'): else:
NINJA_1_9_OR_NEWER = True mlog.warning('Found ninja <1.9, tests will run slower', once=True)
else: NINJA_CMD = detect_ninja()
mlog.warning('Found ninja <1.9, tests will run slower', once=True)
break
if NINJA_CMD is None: if NINJA_CMD is None:
raise RuntimeError('Could not find Ninja v1.6 or newer') raise RuntimeError('Could not find Ninja v1.7 or newer')
def guess_backend(backend, msbuild_exe: str): def guess_backend(backend, msbuild_exe: str):
# Auto-detect backend if unspecified # Auto-detect backend if unspecified

Loading…
Cancel
Save