aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/build.py
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2016-12-13 12:22:11 +0200
committerGitHub <noreply@github.com>2016-12-13 12:22:11 +0200
commitde83e94b5a9ce0f540814cee40ef3746b6ebb824 (patch)
treebe5504f488f980b6e394b4a2801864485c4dd792 /mesonbuild/build.py
parent07679f0330ccc4ee3839e702d79ecdd349437593 (diff)
parent2c83bd16fc03afd2d8605734dce1ffc1946bf3d2 (diff)
downloadmeson-de83e94b5a9ce0f540814cee40ef3746b6ebb824.zip
meson-de83e94b5a9ce0f540814cee40ef3746b6ebb824.tar.gz
meson-de83e94b5a9ce0f540814cee40ef3746b6ebb824.tar.bz2
Merge pull request #1171 from centricular/fix-extracted-generated-prebuilt-object-targets-linking
Several fixes to how we handle objects in build targets
Diffstat (limited to 'mesonbuild/build.py')
-rw-r--r--mesonbuild/build.py144
1 files changed, 106 insertions, 38 deletions
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 79759ee..106386c 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -19,6 +19,7 @@ from . import mlog
import copy, os, re
from .mesonlib import File, flatten, MesonException, stringlistify, classify_unity_sources
from .environment import for_windows, for_darwin
+from .compilers import is_object, clike_langs, lang_suffixes
known_basic_kwargs = {'install' : True,
'c_pch' : True,
@@ -62,17 +63,6 @@ known_lib_kwargs.update({'version' : True, # Only for shared libs
'pic' : True, # Only for static libs
})
-def compilers_are_msvc(compilers):
- """
- Check if all the listed compilers are MSVC. Used by Executable,
- StaticLibrary, and SharedLibrary for deciding when to use MSVC-specific
- file naming.
- """
- for compiler in compilers.values():
- if compiler.get_id() != 'msvc':
- return False
- return True
-
class InvalidArguments(MesonException):
pass
@@ -88,8 +78,8 @@ class Build:
self.environment = environment
self.projects = {}
self.targets = {}
- self.compilers = []
- self.cross_compilers = []
+ self.compilers = {}
+ self.cross_compilers = {}
self.global_args = {}
self.projects_args = {}
self.global_link_args = {}
@@ -109,26 +99,19 @@ class Build:
self.dep_manifest = {}
self.cross_stdlibs = {}
- def has_language(self, language):
- for i in self.compilers:
- if i.get_language() == language:
- return True
- return False
-
def add_compiler(self, compiler):
if self.static_linker is None and compiler.needs_static_linker():
self.static_linker = self.environment.detect_static_linker(compiler)
- if self.has_language(compiler.get_language()):
- return
- self.compilers.append(compiler)
+ lang = compiler.get_language()
+ if lang not in self.compilers:
+ self.compilers[lang] = compiler
def add_cross_compiler(self, compiler):
if len(self.cross_compilers) == 0:
self.static_cross_linker = self.environment.detect_static_linker(compiler)
- for i in self.cross_compilers:
- if i.get_language() == compiler.get_language():
- return
- self.cross_compilers.append(compiler)
+ lang = compiler.get_language()
+ if lang not in self.cross_compilers:
+ self.cross_compilers[lang] = compiler
def get_project(self):
return self.projects['']
@@ -204,6 +187,10 @@ class ExtractedObjects():
if is_unity:
self.check_unity_compatible()
+ def __repr__(self):
+ r = '<{0} {1!r}: {2}>'
+ return r.format(self.__class__.__name__, self.target.name, self.srclist)
+
def check_unity_compatible(self):
# Figure out if the extracted object list is compatible with a Unity
# build. When we're doing a Unified build, we go through the sources,
@@ -290,7 +277,14 @@ class BuildTarget():
self.extra_args = {}
self.generated = []
self.extra_files = []
+ # Sources can be:
+ # 1. Pre-existing source files in the source tree
+ # 2. Pre-existing sources generated by configure_file in the build tree
+ # 3. Sources files generated by another target or a Generator
self.process_sourcelist(sources)
+ # Objects can be:
+ # 1. Pre-existing objects provided by the user with the `objects:` kwarg
+ # 2. Compiled objects created by and extracted from another target
self.process_objectlist(objects)
self.process_kwargs(kwargs, environment)
self.check_unknown_kwargs(kwargs)
@@ -333,7 +327,7 @@ class BuildTarget():
for s in objects:
if hasattr(s, 'held_object'):
s = s.held_object
- if isinstance(s, (str, ExtractedObjects)):
+ if isinstance(s, (str, File, ExtractedObjects)):
self.objects.append(s)
elif isinstance(s, (GeneratedList, CustomTarget)):
msg = 'Generated files are not allowed in the \'objects\' kwarg ' + \
@@ -380,19 +374,56 @@ class BuildTarget():
return removed
def process_compilers(self):
- if len(self.sources) + len(self.generated) == 0:
+ '''
+ Populate self.compilers, which is the list of compilers that this
+ target will use for compiling all its sources.
+ We also add compilers that were used by extracted objects to simplify
+ dynamic linker determination.
+ '''
+ if len(self.sources) + len(self.generated) + len(self.objects) == 0:
return
- sources = list(self.sources)
- for gensrc in self.generated:
- sources += gensrc.get_outputs()
# Populate list of compilers
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_sources(compiler, sources):
- self.compilers[lang] = compiler
+ # Pre-existing sources
+ sources = list(self.sources)
+ # All generated sources
+ for gensrc in self.generated:
+ for s in gensrc.get_outputs():
+ # Generated objects can't be compiled, so don't use them for
+ # compiler detection. If our target only has generated objects,
+ # we will fall back to using the first c-like compiler we find,
+ # which is what we need.
+ if not is_object(s):
+ sources.append(s)
+ # Sources that were used to create our extracted objects
+ for o in self.objects:
+ if not isinstance(o, ExtractedObjects):
+ continue
+ for s in o.srclist:
+ # Don't add Vala sources since that will pull in the Vala
+ # compiler even though we will never use it since we are
+ # dealing with compiled C code.
+ if not s.endswith(lang_suffixes['vala']):
+ sources.append(s)
+ if sources:
+ # Add compilers based on the above sources
+ for lang, compiler in compilers.items():
+ # We try to be conservative because sometimes people add files
+ # in the list of sources that we can't determine the type based
+ # just on the suffix.
+ if self.can_compile_sources(compiler, sources):
+ self.compilers[lang] = compiler
+ else:
+ # No source files, target consists of only object files of unknown
+ # origin. Just add the first clike compiler that we have and hope
+ # that it can link these objects
+ for lang in clike_langs:
+ if lang in compilers:
+ self.compilers[lang] = compilers[lang]
+ break
# If all our sources are Vala, our target also needs the C compiler but
# it won't get added above.
if 'vala' in self.compilers and 'c' not in self.compilers:
@@ -766,6 +797,43 @@ class BuildTarget():
def get_aliaslist(self):
return []
+ def get_clike_dynamic_linker(self):
+ '''
+ We use the order of languages in `clike_langs` to determine which
+ linker to use in case the target has sources compiled with multiple
+ compilers. All languages other than those in this list have their own
+ linker.
+ Note that Vala outputs C code, so Vala sources can use any linker
+ that can link compiled C. We don't actually need to add an exception
+ for Vala here because of that.
+ '''
+ for l in clike_langs:
+ if l in self.compilers:
+ return self.compilers[l]
+
+ def get_using_msvc(self):
+ '''
+ Check if the dynamic linker is MSVC. Used by Executable, StaticLibrary,
+ and SharedLibrary for deciding when to use MSVC-specific file naming
+ and debug filenames.
+
+ If at least some code is built with MSVC and the final library is
+ linked with MSVC, we can be sure that some debug info will be
+ generated. We only check the dynamic linker here because the static
+ linker is guaranteed to be of the same type.
+
+ Interesting cases:
+ 1. The Vala compiler outputs C code to be compiled by whatever
+ C compiler we're using, so all objects will still be created by the
+ MSVC compiler.
+ 2. If the target contains only objects, process_compilers guesses and
+ picks the first compiler that smells right.
+ '''
+ linker = self.get_clike_dynamic_linker()
+ if linker and linker.get_id() == 'msvc':
+ return True
+ return False
+
class Generator():
def __init__(self, args, kwargs):
@@ -890,7 +958,7 @@ class Executable(BuildTarget):
self.filename += '.' + self.suffix
# See determine_debug_filenames() in build.SharedLibrary
buildtype = environment.coredata.get_builtin_option('buildtype')
- if compilers_are_msvc(self.compilers) and buildtype.startswith('debug'):
+ if self.get_using_msvc() and buildtype.startswith('debug'):
self.debug_filename = self.prefix + self.name + '.pdb'
def type_suffix(self):
@@ -921,7 +989,7 @@ class StaticLibrary(BuildTarget):
self.filename = self.prefix + self.name + '.' + self.suffix
# See determine_debug_filenames() in build.SharedLibrary
buildtype = environment.coredata.get_builtin_option('buildtype')
- if compilers_are_msvc(self.compilers) and buildtype.startswith('debug'):
+ if self.get_using_msvc() and buildtype.startswith('debug'):
self.debug_filename = self.prefix + self.name + '.pdb'
def type_suffix(self):
@@ -997,7 +1065,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 compilers_are_msvc(self.compilers):
+ if self.get_using_msvc():
# Shared library is of the form foo.dll
prefix = ''
# Import library is called foo.lib
@@ -1044,7 +1112,7 @@ class SharedLibrary(BuildTarget):
determine_filenames() above.
"""
buildtype = env.coredata.get_builtin_option('buildtype')
- if compilers_are_msvc(self.compilers) and buildtype.startswith('debug'):
+ if self.get_using_msvc() 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.