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.
This commit is contained in:
parent
a0551d7d6e
commit
98e7625c64
|
@ -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:
|
||||
for compiler in compilers.values():
|
||||
if compiler.get_id() != 'msvc':
|
||||
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:
|
||||
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…
Reference in New Issue