|
|
|
@ -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. |
|
|
|
|