aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/build.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/build.py')
-rw-r--r--mesonbuild/build.py161
1 files changed, 79 insertions, 82 deletions
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 65b2c20..7856fbd 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from typing import List
import copy, os, re
from collections import OrderedDict
import itertools, pathlib
@@ -25,12 +24,12 @@ from . import environment
from . import dependencies
from . import mlog
from .mesonlib import (
- File, MesonException, listify, extract_as_list, OrderedSet,
- typeslistify, stringlistify, classify_unity_sources,
- get_filenames_templates_dict, substitute_values,
- for_windows, for_darwin, for_cygwin, for_android, has_path_sep
+ File, MesonException, MachineChoice, PerMachine, OrderedSet, listify,
+ extract_as_list, typeslistify, stringlistify, classify_unity_sources,
+ get_filenames_templates_dict, substitute_values, has_path_sep,
)
from .compilers import Compiler, is_object, clink_langs, sort_clink, lang_suffixes, get_macos_dylib_install_name
+from .linkers import StaticLinker
from .interpreterbase import FeatureNew
pch_kwargs = set(['c_pch', 'cpp_pch'])
@@ -114,21 +113,16 @@ class Build:
self.environment = environment
self.projects = {}
self.targets = OrderedDict()
- self.global_args = {}
- self.projects_args = {}
- self.global_link_args = {}
- self.projects_link_args = {}
- self.cross_global_args = {}
- self.cross_projects_args = {}
- self.cross_global_link_args = {}
- self.cross_projects_link_args = {}
+ self.global_args = PerMachine({}, {}) # type: PerMachine[typing.Dict[str, typing.List[str]]]
+ self.projects_args = PerMachine({}, {}) # type: PerMachine[typing.Dict[str, typing.List[str]]]
+ self.global_link_args = PerMachine({}, {}) # type: PerMachine[typing.Dict[str, typing.List[str]]]
+ self.projects_link_args = PerMachine({}, {}) # type: PerMachine[typing.Dict[str, typing.List[str]]]
self.tests = []
self.benchmarks = []
self.headers = []
self.man = []
self.data = []
- self.static_linker = None
- self.static_cross_linker = None
+ self.static_linker = PerMachine(None, None) # type: PerMachine[StaticLinker]
self.subprojects = {}
self.subproject_dir = ''
self.install_scripts = []
@@ -137,7 +131,7 @@ class Build:
self.install_dirs = []
self.dep_manifest_name = None
self.dep_manifest = {}
- self.cross_stdlibs = {}
+ self.stdlibs = PerMachine({}, {})
self.test_setups = {} # type: typing.Dict[str, TestSetup]
self.test_setup_default_name = None
self.find_overrides = {}
@@ -157,12 +151,8 @@ class Build:
self.__dict__[k] = v
def ensure_static_linker(self, compiler):
- if self.static_linker is None and compiler.needs_static_linker():
- self.static_linker = self.environment.detect_static_linker(compiler)
-
- def ensure_static_cross_linker(self, compiler):
- if self.static_cross_linker is None and compiler.needs_static_linker():
- self.static_cross_linker = self.environment.detect_static_linker(compiler)
+ if self.static_linker[compiler.for_machine] is None and compiler.needs_static_linker():
+ self.static_linker[compiler.for_machine] = self.environment.detect_static_linker(compiler)
def get_project(self):
return self.projects['']
@@ -191,23 +181,23 @@ class Build:
def get_install_subdirs(self):
return self.install_dirs
- def get_global_args(self, compiler, for_cross):
- d = self.cross_global_args if for_cross else self.global_args
+ def get_global_args(self, compiler, for_machine):
+ d = self.global_args[for_machine]
return d.get(compiler.get_language(), [])
- def get_project_args(self, compiler, project, for_cross):
- d = self.cross_projects_args if for_cross else self.projects_args
+ def get_project_args(self, compiler, project, for_machine):
+ d = self.projects_args[for_machine]
args = d.get(project)
if not args:
return []
return args.get(compiler.get_language(), [])
- def get_global_link_args(self, compiler, for_cross):
- d = self.cross_global_link_args if for_cross else self.global_link_args
+ def get_global_link_args(self, compiler, for_machine):
+ d = self.global_link_args[for_machine]
return d.get(compiler.get_language(), [])
- def get_project_link_args(self, compiler, project, for_cross):
- d = self.cross_projects_link_args if for_cross else self.projects_link_args
+ def get_project_link_args(self, compiler, project, for_machine):
+ d = self.projects_link_args[for_machine]
link_args = d.get(project)
if not link_args:
@@ -336,7 +326,7 @@ class EnvironmentVariables:
return env
class Target:
- def __init__(self, name, subdir, subproject, build_by_default):
+ def __init__(self, name, subdir, subproject, build_by_default, for_machine: MachineChoice):
if has_path_sep(name):
# Fix failing test 53 when this becomes an error.
mlog.warning('''Target "%s" has a path separator in its name.
@@ -346,6 +336,7 @@ a hard error in the future.''' % name)
self.subdir = subdir
self.subproject = subproject
self.build_by_default = build_by_default
+ self.for_machine = for_machine
self.install = False
self.build_always_stale = False
self.option_overrides = {}
@@ -438,9 +429,8 @@ a hard error in the future.''' % name)
class BuildTarget(Target):
known_kwargs = known_build_target_kwargs
- def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
- super().__init__(name, subdir, subproject, True)
- self.is_cross = is_cross
+ def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs):
+ super().__init__(name, subdir, subproject, True, for_machine)
unity_opt = environment.coredata.get_builtin_option('unity')
self.is_unity = unity_opt == 'on' or (unity_opt == 'subprojects' and subproject != '')
self.environment = environment
@@ -483,7 +473,7 @@ class BuildTarget(Target):
raise InvalidArguments('Build target %s has no sources.' % name)
self.process_compilers_late()
self.validate_sources()
- self.validate_cross_install(environment)
+ self.validate_install(environment)
self.check_module_linking()
def __lt__(self, other):
@@ -493,9 +483,12 @@ class BuildTarget(Target):
repr_str = "<{0} {1}: {2}>"
return repr_str.format(self.__class__.__name__, self.get_id(), self.filename)
- def validate_cross_install(self, environment):
- if environment.is_cross_build() and not self.is_cross and self.need_install:
- raise InvalidArguments('Tried to install a natively built target in a cross build.')
+ def validate_install(self, environment):
+ if self.for_machine is MachineChoice.BUILD and self.need_install:
+ if environment.is_cross_build():
+ raise InvalidArguments('Tried to install a target for the build machine in a cross build.')
+ else:
+ mlog.warning('Installing target build for the build machine. This will fail in a cross build.')
def check_unknown_kwargs(self, kwargs):
# Override this method in derived classes that have more
@@ -562,10 +555,7 @@ class BuildTarget(Target):
which compiler to use if one hasn't been selected already.
"""
# Populate list of compilers
- if self.is_cross:
- compilers = self.environment.coredata.cross_compilers
- else:
- compilers = self.environment.coredata.compilers
+ compilers = self.environment.coredata.compilers[self.for_machine]
# did user override clink_langs for this target?
link_langs = [self.link_language] if self.link_language else clink_langs
@@ -602,10 +592,7 @@ class BuildTarget(Target):
if not self.sources and not self.generated and not self.objects:
return
# Populate list of compilers
- if self.is_cross:
- compilers = self.environment.coredata.cross_compilers
- else:
- compilers = self.environment.coredata.compilers
+ compilers = self.environment.coredata.compilers[self.for_machine]
# Pre-existing sources
sources = list(self.sources)
# All generated sources
@@ -928,13 +915,14 @@ This will become a hard error in a future Meson release.''')
# You can't disable PIC on OS X. The compiler ignores -fno-PIC.
# PIC is always on for Windows (all code is position-independent
# since library loading is done differently)
- if for_darwin(self.is_cross, self.environment) or for_windows(self.is_cross, self.environment):
+ m = self.environment.machines[self.for_machine]
+ if m.is_darwin() or m.is_windows():
self.pic = True
else:
self.pic = self._extract_pic_pie(kwargs, 'pic')
if isinstance(self, Executable):
# Executables must be PIE on Android
- if for_android(self.is_cross, self.environment):
+ if self.environment.machines[self.for_machine].is_android():
self.pie = True
else:
self.pie = self._extract_pic_pie(kwargs, 'pie')
@@ -1073,8 +1061,12 @@ You probably should put it in link_with instead.''')
msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name)
msg += "Use the 'pic' option to static_library to build with PIC."
raise InvalidArguments(msg)
- if not isinstance(t, (CustomTarget, CustomTargetIndex)) and self.is_cross != t.is_cross:
- raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name))
+ if self.for_machine is not t.for_machine:
+ msg = 'Tried to mix libraries for machines {1} and {2} in target {!r}'.format(self.name, self.for_machine, t.for_machine)
+ if self.environment.is_cross_build():
+ raise InvalidArguments(msg + ' This is not possible in a cross build.')
+ else:
+ mlog.warning(msg + ' This will fail in cross build.')
self.link_targets.append(t)
def link_whole(self, target):
@@ -1090,8 +1082,12 @@ You probably should put it in link_with instead.''')
msg = "Can't link non-PIC static library {!r} into shared library {!r}. ".format(t.name, self.name)
msg += "Use the 'pic' option to static_library to build with PIC."
raise InvalidArguments(msg)
- if not isinstance(t, (CustomTarget, CustomTargetIndex)) and self.is_cross != t.is_cross:
- raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name))
+ if self.for_machine is not t.for_machine:
+ msg = 'Tried to mix libraries for machines {1} and {2} in target {!r}'.format(self.name, self.for_machine, t.for_machine)
+ if self.environment.is_cross_build():
+ raise InvalidArguments(msg + ' This is not possible in a cross build.')
+ else:
+ mlog.warning(msg + ' This will fail in cross build.')
self.link_whole_targets.append(t)
def add_pch(self, language, pchlist):
@@ -1148,7 +1144,7 @@ You probably should put it in link_with instead.''')
def get_aliases(self):
return {}
- def get_langs_used_by_deps(self) -> List[str]:
+ def get_langs_used_by_deps(self) -> typing.List[str]:
'''
Sometimes you want to link to a C++ library that exports C API, which
means the linker must link in the C++ stdlib, and we must use a C++
@@ -1192,10 +1188,7 @@ You probably should put it in link_with instead.''')
'''
# Populate list of all compilers, not just those being used to compile
# sources in this target
- if self.is_cross:
- all_compilers = self.environment.coredata.cross_compilers
- else:
- all_compilers = self.environment.coredata.compilers
+ all_compilers = self.environment.coredata.compilers[self.for_machine]
# Languages used by dependencies
dep_langs = self.get_langs_used_by_deps()
# Pick a compiler based on the language priority-order
@@ -1253,7 +1246,7 @@ You probably should put it in link_with instead.''')
'''
for link_target in self.link_targets:
if isinstance(link_target, SharedModule):
- if for_darwin(self.is_cross, self.environment):
+ if self.environment.machines[self.for_machine].is_darwin():
raise MesonException('''target links against shared modules.
This is not permitted on OSX''')
else:
@@ -1425,19 +1418,19 @@ class GeneratedList:
class Executable(BuildTarget):
known_kwargs = known_exe_kwargs
- def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
+ def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs):
self.typename = 'executable'
if 'pie' not in kwargs and 'b_pie' in environment.coredata.base_options:
kwargs['pie'] = environment.coredata.base_options['b_pie'].value
- super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
+ super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs)
# Unless overridden, executables have no suffix or prefix. Except on
# Windows and with C#/Mono executables where the suffix is 'exe'
if not hasattr(self, 'prefix'):
self.prefix = ''
if not hasattr(self, 'suffix'):
+ machine = environment.machines[for_machine]
# Executable for Windows or C#/Mono
- if (for_windows(is_cross, environment) or
- for_cygwin(is_cross, environment) or 'cs' in self.compilers):
+ if machine.is_windows() or machine.is_cygwin() or 'cs' in self.compilers:
self.suffix = 'exe'
elif ('c' in self.compilers and self.compilers['c'].get_id().startswith('arm') or
'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('arm')):
@@ -1446,7 +1439,7 @@ class Executable(BuildTarget):
'cpp' in self.compilers and self.compilers['cpp'].get_id().startswith('ccrx')):
self.suffix = 'abs'
else:
- self.suffix = ''
+ self.suffix = environment.machines[for_machine].get_exe_suffix()
self.filename = self.name
if self.suffix:
self.filename += '.' + self.suffix
@@ -1475,7 +1468,8 @@ class Executable(BuildTarget):
implib_basename = self.name + '.exe'
if not isinstance(kwargs.get('implib', False), bool):
implib_basename = kwargs['implib']
- if for_windows(is_cross, environment) or for_cygwin(is_cross, environment):
+ m = environment.machines[for_machine]
+ if m.is_windows() or m.is_cygwin():
self.vs_import_filename = '{0}.lib'.format(implib_basename)
self.gcc_import_filename = 'lib{0}.a'.format(implib_basename)
if self.get_using_msvc():
@@ -1515,11 +1509,11 @@ class Executable(BuildTarget):
class StaticLibrary(BuildTarget):
known_kwargs = known_stlib_kwargs
- def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
+ def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs):
self.typename = 'static library'
if 'pic' not in kwargs and 'b_staticpic' in environment.coredata.base_options:
kwargs['pic'] = environment.coredata.base_options['b_staticpic'].value
- super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
+ super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs)
if 'cs' in self.compilers:
raise InvalidArguments('Static libraries not supported for C#.')
if 'rust' in self.compilers:
@@ -1575,7 +1569,7 @@ class StaticLibrary(BuildTarget):
class SharedLibrary(BuildTarget):
known_kwargs = known_shlib_kwargs
- def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
+ def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs):
self.typename = 'shared library'
self.soversion = None
self.ltversion = None
@@ -1588,7 +1582,7 @@ class SharedLibrary(BuildTarget):
self.vs_import_filename = None
# The import library that GCC would generate (and prefer)
self.gcc_import_filename = None
- super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
+ super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs)
if 'rust' in self.compilers:
# If no crate type is specified, or it's the generic lib type, use dylib
if not hasattr(self, 'rust_crate_type') or self.rust_crate_type == 'lib':
@@ -1602,7 +1596,7 @@ class SharedLibrary(BuildTarget):
if not hasattr(self, 'suffix'):
self.suffix = None
self.basic_filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
- self.determine_filenames(is_cross, environment)
+ self.determine_filenames(environment)
def get_link_deps_mapping(self, prefix, environment):
result = {}
@@ -1619,7 +1613,7 @@ class SharedLibrary(BuildTarget):
def get_default_install_dir(self, environment):
return environment.get_shared_lib_dir()
- def determine_filenames(self, is_cross, env):
+ def determine_filenames(self, env):
"""
See https://github.com/mesonbuild/meson/pull/417 for details.
@@ -1652,7 +1646,7 @@ class SharedLibrary(BuildTarget):
# C, C++, Swift, Vala
# Only Windows uses a separate import library for linking
# For all other targets/platforms import_filename stays None
- elif for_windows(is_cross, env):
+ elif env.machines[self.for_machine].is_windows():
suffix = 'dll'
self.vs_import_filename = '{0}{1}.lib'.format(self.prefix if self.prefix is not None else '', self.name)
self.gcc_import_filename = '{0}{1}.dll.a'.format(self.prefix if self.prefix is not None else 'lib', self.name)
@@ -1677,7 +1671,7 @@ class SharedLibrary(BuildTarget):
self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}'
else:
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
- elif for_cygwin(is_cross, env):
+ elif env.machines[self.for_machine].is_cygwin():
suffix = 'dll'
self.gcc_import_filename = '{0}{1}.dll.a'.format(self.prefix if self.prefix is not None else 'lib', self.name)
# Shared library is of the form cygfoo.dll
@@ -1689,7 +1683,7 @@ class SharedLibrary(BuildTarget):
self.filename_tpl = '{0.prefix}{0.name}-{0.soversion}.{0.suffix}'
else:
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
- elif for_darwin(is_cross, env):
+ elif env.machines[self.for_machine].is_darwin():
prefix = 'lib'
suffix = 'dylib'
# On macOS, the filename can only contain the major version
@@ -1699,7 +1693,7 @@ class SharedLibrary(BuildTarget):
else:
# libfoo.dylib
self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}'
- elif for_android(is_cross, env):
+ elif env.machines[self.for_machine].is_android():
prefix = 'lib'
suffix = 'so'
# Android doesn't support shared_library versioning
@@ -1764,7 +1758,7 @@ class SharedLibrary(BuildTarget):
def process_kwargs(self, kwargs, environment):
super().process_kwargs(kwargs, environment)
- if not for_android(self.is_cross, self.environment):
+ if not self.environment.machines[self.for_machine].is_android():
supports_versioning = True
else:
supports_versioning = False
@@ -1884,12 +1878,12 @@ class SharedLibrary(BuildTarget):
class SharedModule(SharedLibrary):
known_kwargs = known_shmod_kwargs
- def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
+ def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs):
if 'version' in kwargs:
raise MesonException('Shared modules must not specify the version kwarg.')
if 'soversion' in kwargs:
raise MesonException('Shared modules must not specify the soversion kwarg.')
- super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
+ super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs)
self.typename = 'shared module'
def get_default_install_dir(self, environment):
@@ -1917,7 +1911,8 @@ class CustomTarget(Target):
def __init__(self, name, subdir, subproject, kwargs, absolute_paths=False):
self.typename = 'custom'
- super().__init__(name, subdir, subproject, False)
+ # TODO expose keyword arg to make MachineChoice.HOST configurable
+ super().__init__(name, subdir, subproject, False, MachineChoice.HOST)
self.dependencies = []
self.extra_depends = []
self.depend_files = [] # Files that this target depends on but are not on the command line.
@@ -2171,7 +2166,8 @@ class CustomTarget(Target):
class RunTarget(Target):
def __init__(self, name, command, args, dependencies, subdir, subproject):
self.typename = 'run'
- super().__init__(name, subdir, subproject, False)
+ # These don't produce output artifacts
+ super().__init__(name, subdir, subproject, False, MachineChoice.BUILD)
self.command = command
self.args = args
self.dependencies = dependencies
@@ -2212,9 +2208,9 @@ class RunTarget(Target):
class Jar(BuildTarget):
known_kwargs = known_jar_kwargs
- def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
+ def __init__(self, name, subdir, subproject, for_machine: MachineChoice, sources, objects, environment, kwargs):
self.typename = 'jar'
- super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
+ super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs)
for s in self.sources:
if not s.endswith('.java'):
raise InvalidArguments('Jar source %s is not a java file.' % s)
@@ -2234,7 +2230,7 @@ class Jar(BuildTarget):
def get_java_args(self):
return self.java_args
- def validate_cross_install(self, environment):
+ def validate_install(self, environment):
# All jar targets are installable.
pass
@@ -2260,6 +2256,7 @@ class CustomTargetIndex:
self.typename = 'custom'
self.target = target
self.output = output
+ self.for_machine = target.for_machine
def __repr__(self):
return '<CustomTargetIndex: {!r}[{}]>'.format(