Add a list of compilers used to each BuildTarget

When the BuildTarget (executable, shared-library, static-library, etc)
is created, process the source list and assign compilers to this target.
This allows us to do compiler-specific file-naming without resorting to
ugly hacks.

This is one step towards consolidating all the 'what language does this
target use' checks and the 'this target should only have $lang files as
sources' checks we have all over the codebase. All those checks should
be done only when the target is created.
pull/814/head
Nirbheek Chauhan 8 years ago
parent a0551d7d6e
commit 98e7625c64
  1. 78
      mesonbuild/build.py

@ -51,36 +51,16 @@ known_shlib_kwargs.update({'version' : True,
'name_suffix' : True,
'vs_module_defs' : True})
def sources_are_suffix(sources, suffix):
for source in sources:
if source.endswith('.' + suffix):
return True
return False
def compiler_is_msvc(sources, is_cross, env):
def compilers_are_msvc(compilers):
"""
Since each target does not currently have the compiler information attached
to it, we must do this detection manually here.
This detection is purposely incomplete and will cause bugs if other code is
extended and this piece of code is forgotten.
Check if all the listed compilers are MSVC. Used by Executable,
StaticLibrary, and SharedLibrary for deciding when to use MSVC-specific
file naming.
"""
compiler = None
if sources_are_suffix(sources, 'c'):
try:
compiler = env.detect_c_compiler(is_cross)
except MesonException:
return False
elif sources_are_suffix(sources, 'cxx') or \
sources_are_suffix(sources, 'cpp') or \
sources_are_suffix(sources, 'cc'):
try:
compiler = env.detect_cpp_compiler(is_cross)
except MesonException:
for compiler in compilers.values():
if compiler.get_id() != 'msvc':
return False
if compiler and compiler.get_id() == 'msvc':
return True
return False
return True
class InvalidArguments(MesonException):
@ -234,7 +214,9 @@ class BuildTarget():
self.subdir = subdir
self.subproject = subproject # Can not be calculated from subdir as subproject dirname can be changed per project.
self.is_cross = is_cross
self.environment = environment
self.sources = []
self.compilers = {}
self.objects = []
self.external_deps = []
self.include_dirs = []
@ -256,6 +238,7 @@ class BuildTarget():
len(self.generated) == 0 and \
len(self.objects) == 0:
raise InvalidArguments('Build target %s has no sources.' % name)
self.process_compilers()
self.validate_sources()
def __repr__(self):
@ -320,6 +303,27 @@ class BuildTarget():
msg = 'Bad source of type {!r} in target {!r}.'.format(type(s).__name__, self.name)
raise InvalidArguments(msg)
@staticmethod
def can_compile_remove_sources(compiler, sources):
removed = False
for s in sources[:]:
if compiler.can_compile(s):
sources.remove(s)
removed = True
return removed
def process_compilers(self):
if len(self.sources) == 0:
return
sources = list(self.sources)
if self.is_cross:
compilers = self.environment.coredata.cross_compilers
else:
compilers = self.environment.coredata.compilers
for lang, compiler in compilers.items():
if self.can_compile_remove_sources(compiler, sources):
self.compilers[lang] = compiler
def validate_sources(self):
if len(self.sources) > 0:
firstname = self.sources[0]
@ -768,7 +772,7 @@ class Executable(BuildTarget):
self.prefix = ''
if not hasattr(self, 'suffix'):
# Executable for Windows or C#/Mono
if for_windows(is_cross, environment) or sources_are_suffix(self.sources, 'cs'):
if for_windows(is_cross, environment) or 'cs' in self.compilers:
self.suffix = 'exe'
else:
self.suffix = ''
@ -777,8 +781,7 @@ class Executable(BuildTarget):
self.filename += '.' + self.suffix
# See determine_debug_filenames() in build.SharedLibrary
buildtype = environment.coredata.get_builtin_option('buildtype')
if compiler_is_msvc(self.sources, is_cross, environment) and \
buildtype.startswith('debug'):
if compilers_are_msvc(self.compilers) and buildtype.startswith('debug'):
self.debug_filename = self.prefix + self.name + '.pdb'
def type_suffix(self):
@ -787,7 +790,7 @@ class Executable(BuildTarget):
class StaticLibrary(BuildTarget):
def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
if sources_are_suffix(self.sources, 'cs'):
if 'cs' in self.compilers:
raise InvalidArguments('Static libraries not supported for C#.')
# By default a static library is named libfoo.a even on Windows because
# MSVC does not have a consistent convention for what static libraries
@ -800,15 +803,14 @@ class StaticLibrary(BuildTarget):
self.prefix = 'lib'
if not hasattr(self, 'suffix'):
# Rust static library crates have .rlib suffix
if sources_are_suffix(self.sources, 'rs'):
if 'rust' in self.compilers:
self.suffix = 'rlib'
else:
self.suffix = 'a'
self.filename = self.prefix + self.name + '.' + self.suffix
# See determine_debug_filenames() in build.SharedLibrary
buildtype = environment.coredata.get_builtin_option('buildtype')
if compiler_is_msvc(self.sources, is_cross, environment) and \
buildtype.startswith('debug'):
if compilers_are_msvc(self.compilers) and buildtype.startswith('debug'):
self.debug_filename = self.prefix + self.name + '.pdb'
def type_suffix(self):
@ -864,12 +866,12 @@ class SharedLibrary(BuildTarget):
if self.prefix != None and self.suffix != None:
pass
# C# and Mono
elif sources_are_suffix(self.sources, 'cs'):
elif 'cs' in self.compilers:
prefix = ''
suffix = 'dll'
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
# Rust
elif sources_are_suffix(self.sources, 'rs'):
elif 'rust' in self.compilers:
# Currently, we always build --crate-type=rlib
prefix = 'lib'
suffix = 'rlib'
@ -881,7 +883,7 @@ class SharedLibrary(BuildTarget):
suffix = 'dll'
self.vs_import_filename = '{0}.lib'.format(self.name)
self.gcc_import_filename = 'lib{0}.dll.a'.format(self.name)
if compiler_is_msvc(self.sources, is_cross, env):
if compilers_are_msvc(self.compilers):
# Shared library is of the form foo.dll
prefix = ''
# Import library is called foo.lib
@ -928,7 +930,7 @@ class SharedLibrary(BuildTarget):
determine_filenames() above.
"""
buildtype = env.coredata.get_builtin_option('buildtype')
if compiler_is_msvc(self.sources, is_cross, env) and buildtype.startswith('debug'):
if compilers_are_msvc(self.compilers) and buildtype.startswith('debug'):
# Currently we only implement separate debug symbol files for MSVC
# since the toolchain does it for us. Other toolchains embed the
# debugging symbols in the file itself by default.

Loading…
Cancel
Save