From 32e827dcdc451e1c5dde952cf08e4b654eac7057 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 8 Aug 2018 12:27:04 -0400 Subject: [PATCH 1/7] Use `env.machines.*` to avoid some `is_cross` This is a small example of the `is_cross` removal the that abstraction enables. --- mesonbuild/backend/backends.py | 4 +- mesonbuild/backend/ninjabackend.py | 4 +- mesonbuild/build.py | 20 +++++----- mesonbuild/compilers/clike.py | 21 ++++++----- mesonbuild/dependencies/boost.py | 16 ++++---- mesonbuild/environment.py | 19 +++++----- mesonbuild/mesonlib.py | 60 +++++++++++------------------- run_project_tests.py | 24 ++++++------ 8 files changed, 75 insertions(+), 93 deletions(-) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index a044ab5e3..6e7597476 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -743,8 +743,8 @@ class Backend: exe_wrapper = self.environment.get_exe_wrapper() else: exe_wrapper = None - if mesonlib.for_windows(is_cross, self.environment) or \ - mesonlib.for_cygwin(is_cross, self.environment): + if mesonlib.for_windows(self.environment) or \ + mesonlib.for_cygwin(self.environment): extra_bdeps = [] if isinstance(exe, build.CustomTarget): extra_bdeps = exe.get_transitive_build_target_deps() diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 54fb1173a..c919d8f1b 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -665,8 +665,8 @@ int dummy; # CustomTarget command needs extra paths first. is_cross = self.environment.is_cross_build() and \ self.environment.need_exe_wrapper() - if mesonlib.for_windows(is_cross, self.environment) or \ - mesonlib.for_cygwin(is_cross, self.environment): + if mesonlib.for_windows(self.environment) or \ + mesonlib.for_cygwin(self.environment): extra_bdeps = target.get_transitive_build_target_deps() extra_paths = self.determine_windows_extra_paths(target.command[0], extra_bdeps, is_cross) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 65b2c20fc..3394459d7 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -928,7 +928,7 @@ 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): + if for_darwin(self.environment) or for_windows(self.environment): self.pic = True else: self.pic = self._extract_pic_pie(kwargs, 'pic') @@ -1253,7 +1253,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 for_darwin(self.environment): raise MesonException('''target links against shared modules. This is not permitted on OSX''') else: @@ -1436,8 +1436,8 @@ class Executable(BuildTarget): self.prefix = '' if not hasattr(self, 'suffix'): # Executable for Windows or C#/Mono - if (for_windows(is_cross, environment) or - for_cygwin(is_cross, environment) or 'cs' in self.compilers): + if (for_windows(environment) or + for_cygwin(environment) 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')): @@ -1475,7 +1475,7 @@ 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): + if for_windows(environment) or for_cygwin(environment): self.vs_import_filename = '{0}.lib'.format(implib_basename) self.gcc_import_filename = 'lib{0}.a'.format(implib_basename) if self.get_using_msvc(): @@ -1652,7 +1652,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 for_windows(env): 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 +1677,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 for_cygwin(env): 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 +1689,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 for_darwin(env): prefix = 'lib' suffix = 'dylib' # On macOS, the filename can only contain the major version @@ -1699,7 +1699,7 @@ class SharedLibrary(BuildTarget): else: # libfoo.dylib self.filename_tpl = '{0.prefix}{0.name}.{0.suffix}' - elif for_android(is_cross, env): + elif for_android(env): prefix = 'lib' suffix = 'so' # Android doesn't support shared_library versioning @@ -1764,7 +1764,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 for_android(self.environment): supports_versioning = True else: supports_versioning = False diff --git a/mesonbuild/compilers/clike.py b/mesonbuild/compilers/clike.py index 3665f1ffc..968685b5c 100644 --- a/mesonbuild/compilers/clike.py +++ b/mesonbuild/compilers/clike.py @@ -274,9 +274,10 @@ class CLikeCompiler: return [] def gen_export_dynamic_link_args(self, env): - if mesonlib.for_windows(env.is_cross_build(), env) or mesonlib.for_cygwin(env.is_cross_build(), env): + m = env.machines[self.for_machine] + if m.is_windows() or m.is_cygwin(): return ['-Wl,--export-all-symbols'] - elif mesonlib.for_darwin(env.is_cross_build(), env): + elif mesonlib.for_darwin(env): return [] else: return ['-Wl,-export-dynamic'] @@ -884,7 +885,7 @@ class CLikeCompiler: for p in prefixes: for s in suffixes: patterns.append(p + '{}.' + s) - if shared and mesonlib.for_openbsd(self.is_cross, env): + if shared and mesonlib.for_openbsd(env): # Shared libraries on OpenBSD can be named libfoo.so.X.Y: # https://www.openbsd.org/faq/ports/specialtopics.html#SharedLibs # @@ -911,9 +912,9 @@ class CLikeCompiler: else: prefixes = ['lib', ''] # Library suffixes and prefixes - if mesonlib.for_darwin(env.is_cross_build(), env): + if mesonlib.for_darwin(env): shlibext = ['dylib', 'so'] - elif mesonlib.for_windows(env.is_cross_build(), env): + elif mesonlib.for_windows(env): # FIXME: .lib files can be import or static so we should read the # file, figure out which one it is, and reject the wrong kind. if isinstance(self, compilers.VisualStudioLikeCompiler): @@ -922,7 +923,7 @@ class CLikeCompiler: shlibext = ['dll.a', 'lib', 'dll'] # Yep, static libraries can also be foo.lib stlibext += ['lib'] - elif mesonlib.for_cygwin(env.is_cross_build(), env): + elif mesonlib.for_cygwin(env): shlibext = ['dll', 'dll.a'] prefixes = ['cyg'] + prefixes else: @@ -1126,12 +1127,12 @@ class CLikeCompiler: return self.find_framework_impl(name, env, extra_dirs, allow_system) def thread_flags(self, env): - if mesonlib.for_haiku(self.is_cross, env) or mesonlib.for_darwin(self.is_cross, env): + if mesonlib.for_haiku(env) or mesonlib.for_darwin(env): return [] return ['-pthread'] def thread_link_flags(self, env): - if mesonlib.for_haiku(self.is_cross, env) or mesonlib.for_darwin(self.is_cross, env): + if mesonlib.for_haiku(env) or mesonlib.for_darwin(env): return [] return ['-pthread'] @@ -1189,8 +1190,8 @@ class CLikeCompiler: def has_func_attribute(self, name, env): # Just assume that if we're not on windows that dllimport and dllexport # don't work - if not (mesonlib.for_windows(env.is_cross_build(), env) or - mesonlib.for_cygwin(env.is_cross_build(), env)): + if not (mesonlib.for_windows(env) or + mesonlib.for_cygwin(env)): if name in ['dllimport', 'dllexport']: return False, False diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 0de137232..a955b6a75 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -123,13 +123,13 @@ class BoostDependency(ExternalDependency): self.libdir = os.environ['BOOST_LIBRARYDIR'] if self.boost_root is None: - if mesonlib.for_windows(self.want_cross, self.env): + if mesonlib.for_windows(self.env): self.boost_roots = self.detect_win_roots() else: self.boost_roots = self.detect_nix_roots() if self.incdir is None: - if mesonlib.for_windows(self.want_cross, self.env): + if mesonlib.for_windows(self.env): self.incdir = self.detect_win_incdir() else: self.incdir = self.detect_nix_incdir() @@ -268,7 +268,7 @@ class BoostDependency(ExternalDependency): pass # 2. Fall back to the old method else: - if mesonlib.for_windows(self.want_cross, self.env): + if mesonlib.for_windows(self.env): self.detect_lib_modules_win() else: self.detect_lib_modules_nix() @@ -290,7 +290,7 @@ class BoostDependency(ExternalDependency): def compiler_tag(self): tag = None compiler = self.env.detect_cpp_compiler(self.want_cross) - if mesonlib.for_windows(self.want_cross, self.env): + if mesonlib.for_windows(self.env): if compiler.get_id() in ['msvc', 'clang-cl']: comp_ts_version = compiler.get_toolset_version() compiler_ts = comp_ts_version.split('.') @@ -304,10 +304,10 @@ class BoostDependency(ExternalDependency): if not self.is_multithreading: return '' - if mesonlib.for_darwin(self.want_cross, self.env): + if mesonlib.for_darwin(self.env): # - Mac: requires -mt for multithreading, so should not fall back to non-mt libraries. return '-mt' - elif mesonlib.for_windows(self.want_cross, self.env): + elif mesonlib.for_windows(self.env): # - Windows: requires -mt for multithreading, so should not fall back to non-mt libraries. return '-mt' else: @@ -340,7 +340,7 @@ class BoostDependency(ExternalDependency): # FIXME - how to handle different distributions, e.g. for Mac? Currently we handle homebrew and macports, but not fink. def abi_tags(self): - if mesonlib.for_windows(self.want_cross, self.env): + if mesonlib.for_windows(self.env): return [self.versioned_abi_tag(), self.threading_tag()] else: return [self.threading_tag()] @@ -437,7 +437,7 @@ class BoostDependency(ExternalDependency): def detect_lib_modules_nix(self): if self.static: libsuffix = 'a' - elif mesonlib.for_darwin(self.want_cross, self.env): + elif mesonlib.for_darwin(self.env): libsuffix = 'dylib' else: libsuffix = 'so' diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index ff4a6b1cc..f8603f608 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -513,12 +513,11 @@ class Environment: # Various prefixes and suffixes for import libraries, shared libraries, # static libraries, and executables. # Versioning is added to these names in the backends as-needed. - cross = self.is_cross_build() - if mesonlib.for_windows(cross, self): + if mesonlib.for_windows(self): self.exe_suffix = 'exe' self.object_suffix = 'obj' self.win_libdir_layout = True - elif mesonlib.for_cygwin(cross, self): + elif mesonlib.for_cygwin(self): self.exe_suffix = 'exe' self.object_suffix = 'o' self.win_libdir_layout = True @@ -774,9 +773,9 @@ class Environment: cls = ClangClCCompiler if lang == 'c' else ClangClCPPCompiler return cls(compiler, version, is_cross, exe_wrap, target) if 'clang' in out: - if 'Apple' in out or mesonlib.for_darwin(want_cross, self): + if 'Apple' in out or mesonlib.for_darwin(self): compiler_type = CompilerType.CLANG_OSX - elif 'windows' in out or mesonlib.for_windows(want_cross, self): + elif 'windows' in out or mesonlib.for_windows(self): compiler_type = CompilerType.CLANG_MINGW else: compiler_type = CompilerType.CLANG_STANDARD @@ -808,16 +807,16 @@ class Environment: return cls(compiler, version, is_cross, exe_wrap, target) if 'PGI Compilers' in out: - if mesonlib.for_darwin(want_cross, self): + if self.machines[for_machine].is_darwin(): compiler_type = CompilerType.PGI_OSX - elif mesonlib.for_windows(want_cross, self): + elif self.machines[for_machine].is_windows(): compiler_type = CompilerType.PGI_WIN else: compiler_type = CompilerType.PGI_STANDARD cls = PGICCompiler if lang == 'c' else PGICPPCompiler return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap) if '(ICC)' in out: - if mesonlib.for_darwin(want_cross, self): + if self.machine[for_macine].is_darwin(): compiler_type = CompilerType.ICC_OSX elif mesonlib.for_windows(want_cross, self): # TODO: fix ICC on Windows @@ -932,9 +931,9 @@ class Environment: return PathScaleFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) if 'PGI Compilers' in out: - if mesonlib.for_darwin(want_cross, self): + if self.machine[for_macine].is_darwin(): compiler_type = CompilerType.PGI_OSX - elif mesonlib.for_windows(want_cross, self): + elif self.machines[for_machine].is_windows(): compiler_type = CompilerType.PGI_WIN else: compiler_type = CompilerType.PGI_STANDARD diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index e3ddf2832..1b07d85a2 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -463,93 +463,75 @@ def is_dragonflybsd() -> bool: def is_freebsd() -> bool: return platform.system().lower() == 'freebsd' -def _get_machine_is_cross(env, is_cross): - """ - This is not morally correct, but works for now. For cross builds the build - and host machines differ. `is_cross == true` means the host machine, while - `is_cross == false` means the build machine. Both are used in practice, - even though the documentation refers to the host machine implying we should - hard-code it. For non-cross builds `is_cross == false` is passed but the - host and build machines are identical so it doesn't matter. - - Users for `for_*` should instead specify up front which machine they want - and query that like: - - env.machines[MachineChoice.HOST].is_haiku() - - """ - for_machine = MachineChoice.HOST if is_cross else MachineChoice.BUILD - return env.machines[for_machine] - -def for_windows(is_cross, env): +def for_windows(env): """ Host machine is windows? - Deprecated: Please use `env.machines[for_machine].is_windows()`. + Deprecated: Please use `env.machines.host.is_windows()`. Note: 'host' is the machine on which compiled binaries will run """ - return _get_machine_is_cross(env, is_cross).is_windows() + return env.machines.host.is_windows() -def for_cygwin(is_cross, env): +def for_cygwin(env): """ Host machine is cygwin? - Deprecated: Please use `env.machines[for_machine].is_cygwin()`. + Deprecated: Please use `env.machines.host.is_cygwin()`. Note: 'host' is the machine on which compiled binaries will run """ - return _get_machine_is_cross(env, is_cross).is_cygwin() + return env.machines.host.is_cygwin() -def for_linux(is_cross, env): +def for_linux(env): """ Host machine is linux? - Deprecated: Please use `env.machines[for_machine].is_linux()`. + Deprecated: Please use `env.machines.host.is_linux()`. Note: 'host' is the machine on which compiled binaries will run """ - return _get_machine_is_cross(env, is_cross).is_linux() + return env.machines.host.is_linux() -def for_darwin(is_cross, env): +def for_darwin(env): """ Host machine is Darwin (iOS/OS X)? - Deprecated: Please use `env.machines[for_machine].is_darwin()`. + Deprecated: Please use `env.machines.host.is_darwin()`. Note: 'host' is the machine on which compiled binaries will run """ - return _get_machine_is_cross(env, is_cross).is_darwin() + return env.machines.host.is_darwin() -def for_android(is_cross, env): +def for_android(env): """ Host machine is Android? - Deprecated: Please use `env.machines[for_machine].is_android()`. + Deprecated: Please use `env.machines.host.is_android()`. Note: 'host' is the machine on which compiled binaries will run """ - return _get_machine_is_cross(env, is_cross).is_android() + return env.machines.host.is_android() -def for_haiku(is_cross, env): +def for_haiku(env): """ Host machine is Haiku? - Deprecated: Please use `env.machines[for_machine].is_haiku()`. + Deprecated: Please use `env.machines.host.is_haiku()`. Note: 'host' is the machine on which compiled binaries will run """ - return _get_machine_is_cross(env, is_cross).is_haiku() + return env.machines.host.is_haiku() -def for_openbsd(is_cross, env): +def for_openbsd(env): """ Host machine is OpenBSD? - Deprecated: Please use `env.machines[for_machine].is_openbsd()`. + Deprecated: Please use `env.machines.host.is_openbsd()`. Note: 'host' is the machine on which compiled binaries will run """ - return _get_machine_is_cross(env, is_cross).is_openbsd() + return env.machines.host.is_openbsd() def exe_exists(arglist: List[str]) -> bool: try: diff --git a/run_project_tests.py b/run_project_tests.py index f6d83b5c2..0f3e913ef 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -126,14 +126,14 @@ def platform_fix_name(fname, compiler, env): canonical_compiler = compiler if '?lib' in fname: - if mesonlib.for_windows(env.is_cross_build(), env) and canonical_compiler == 'msvc': + if env.machines.host.is_windows() and canonical_compiler == 'msvc': fname = re.sub(r'lib/\?lib(.*)\.', r'bin/\1.', fname) fname = re.sub(r'/\?lib/', r'/bin/', fname) - elif mesonlib.for_windows(env.is_cross_build(), env): + elif env.machines.host.is_windows(): fname = re.sub(r'lib/\?lib(.*)\.', r'bin/lib\1.', fname) fname = re.sub(r'\?lib(.*)\.dll$', r'lib\1.dll', fname) fname = re.sub(r'/\?lib/', r'/bin/', fname) - elif mesonlib.for_cygwin(env.is_cross_build(), env): + elif env.machines.host.is_cygwin(): fname = re.sub(r'lib/\?lib(.*)\.so$', r'bin/cyg\1.dll', fname) fname = re.sub(r'lib/\?lib(.*)\.', r'bin/cyg\1.', fname) fname = re.sub(r'\?lib(.*)\.dll$', r'cyg\1.dll', fname) @@ -143,7 +143,7 @@ def platform_fix_name(fname, compiler, env): if fname.endswith('?exe'): fname = fname[:-4] - if mesonlib.for_windows(env.is_cross_build(), env) or mesonlib.for_cygwin(env.is_cross_build(), env): + if env.machines.host.is_windows() or env.machines.host.is_cygwin(): return fname + '.exe' if fname.startswith('?msvc:'): @@ -158,40 +158,40 @@ def platform_fix_name(fname, compiler, env): if fname.startswith('?cygwin:'): fname = fname[8:] - if not mesonlib.for_cygwin(env.is_cross_build(), env): + if not env.machines.host.is_cygwin(): return None if fname.startswith('?!cygwin:'): fname = fname[9:] - if mesonlib.for_cygwin(env.is_cross_build(), env): + if env.machines.host.is_cygwin(): return None if fname.endswith('?so'): - if mesonlib.for_windows(env.is_cross_build(), env) and canonical_compiler == 'msvc': + if env.machines.host.is_windows() and canonical_compiler == 'msvc': fname = re.sub(r'lib/([^/]*)\?so$', r'bin/\1.dll', fname) fname = re.sub(r'/(?:lib|)([^/]*?)\?so$', r'/\1.dll', fname) return fname - elif mesonlib.for_windows(env.is_cross_build(), env): + elif env.machines.host.is_windows(): fname = re.sub(r'lib/([^/]*)\?so$', r'bin/\1.dll', fname) fname = re.sub(r'/([^/]*?)\?so$', r'/\1.dll', fname) return fname - elif mesonlib.for_cygwin(env.is_cross_build(), env): + elif env.machines.host.is_cygwin(): fname = re.sub(r'lib/([^/]*)\?so$', r'bin/\1.dll', fname) fname = re.sub(r'/lib([^/]*?)\?so$', r'/cyg\1.dll', fname) fname = re.sub(r'/([^/]*?)\?so$', r'/\1.dll', fname) return fname - elif mesonlib.for_darwin(env.is_cross_build(), env): + elif env.machines.host.is_darwin(): return fname[:-3] + '.dylib' else: return fname[:-3] + '.so' if fname.endswith('?implib') or fname.endswith('?implibempty'): - if mesonlib.for_windows(env.is_cross_build(), env) and canonical_compiler == 'msvc': + if env.machines.host.is_windows() and canonical_compiler == 'msvc': # only MSVC doesn't generate empty implibs if fname.endswith('?implibempty') and compiler == 'msvc': return None return re.sub(r'/(?:lib|)([^/]*?)\?implib(?:empty|)$', r'/\1.lib', fname) - elif mesonlib.for_windows(env.is_cross_build(), env) or mesonlib.for_cygwin(env.is_cross_build(), env): + elif env.machines.host.is_windows() or env.machines.host.is_cygwin(): return re.sub(r'\?implib(?:empty|)$', r'.dll.a', fname) else: return None From 07777e15d47dbddaf849d24b3a30c85745c533ca Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 4 Oct 2018 20:52:08 -0400 Subject: [PATCH 2/7] Purge `is_cross` and friends without changing user interfaces In most cases instead pass `for_machine`, the name of the relevant machines (what compilers target, what targets run on, etc). This allows us to use the cross code path in the native case, deduplicating the code. As one can see, environment got bigger as more information is kept structured there, while ninjabackend got a smaller. Overall a few amount of lines were added, but the hope is what's added is a lot simpler than what's removed. --- mesonbuild/ast/introspection.py | 15 +- mesonbuild/backend/backends.py | 88 +++--- mesonbuild/backend/ninjabackend.py | 283 ++++++++---------- mesonbuild/backend/vs2010backend.py | 24 +- mesonbuild/backend/xcodebackend.py | 4 +- mesonbuild/build.py | 157 +++++----- mesonbuild/cmake/client.py | 5 +- mesonbuild/cmake/interpreter.py | 6 +- mesonbuild/compilers/c.py | 50 ++-- mesonbuild/compilers/clike.py | 36 +-- mesonbuild/compilers/compilers.py | 7 +- mesonbuild/compilers/cpp.py | 50 ++-- mesonbuild/compilers/cs.py | 14 +- mesonbuild/compilers/cuda.py | 6 +- mesonbuild/compilers/d.py | 26 +- mesonbuild/compilers/fortran.py | 52 ++-- mesonbuild/compilers/java.py | 6 +- mesonbuild/compilers/objc.py | 20 +- mesonbuild/compilers/objcpp.py | 20 +- mesonbuild/compilers/rust.py | 8 +- mesonbuild/compilers/swift.py | 14 +- mesonbuild/compilers/vala.py | 20 +- mesonbuild/coredata.py | 39 +-- mesonbuild/dependencies/base.py | 102 +++---- mesonbuild/dependencies/boost.py | 28 +- mesonbuild/dependencies/dev.py | 22 +- mesonbuild/dependencies/misc.py | 12 +- mesonbuild/dependencies/ui.py | 13 +- mesonbuild/environment.py | 228 +++++++------- mesonbuild/interpreter.py | 137 ++++----- mesonbuild/modules/cmake.py | 2 +- mesonbuild/modules/gnome.py | 2 +- mesonbuild/modules/pkgconfig.py | 2 +- mesonbuild/modules/python.py | 2 +- mesonbuild/modules/windows.py | 9 +- mesonbuild/munstable_coredata.py | 33 +- run_project_tests.py | 12 +- run_unittests.py | 84 +++--- .../55 pkg_config_path option/meson.build | 7 +- 39 files changed, 749 insertions(+), 896 deletions(-) diff --git a/mesonbuild/ast/introspection.py b/mesonbuild/ast/introspection.py index 5ac61334c..617b14099 100644 --- a/mesonbuild/ast/introspection.py +++ b/mesonbuild/ast/introspection.py @@ -18,6 +18,7 @@ from . import AstInterpreter from .. import compilers, environment, mesonlib, optinterpreter from .. import coredata as cdata +from ..mesonlib import MachineChoice from ..interpreterbase import InvalidArguments from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary from ..mparser import BaseNode, ArithmeticNode, ArrayNode, ElementaryNode, IdNode, FunctionNode, StringNode @@ -127,11 +128,11 @@ class IntrospectionInterpreter(AstInterpreter): def func_add_languages(self, node, args, kwargs): args = self.flatten_args(args) - need_cross_compiler = self.environment.is_cross_build() - for lang in sorted(args, key=compilers.sort_clink): - lang = lang.lower() - if lang not in self.coredata.compilers: - self.environment.detect_compilers(lang, need_cross_compiler) + for for_machine in [MachineChoice.BUILD, MachineChoice.HOST]: + for lang in sorted(args, key=compilers.sort_clink): + lang = lang.lower() + if lang not in self.coredata.compilers[for_machine]: + self.environment.detect_compiler_for(lang, for_machine) def func_dependency(self, node, args, kwargs): args = self.flatten_args(args) @@ -195,10 +196,10 @@ class IntrospectionInterpreter(AstInterpreter): kwargs_reduced = {k: v for k, v in kwargs.items() if k in targetclass.known_kwargs and k in ['install', 'build_by_default', 'build_always']} kwargs_reduced = {k: v.value if isinstance(v, ElementaryNode) else v for k, v in kwargs_reduced.items()} kwargs_reduced = {k: v for k, v in kwargs_reduced.items() if not isinstance(v, BaseNode)} - is_cross = False + for_machine = MachineChoice.HOST objects = [] empty_sources = [] # Passing the unresolved sources list causes errors - target = targetclass(name, self.subdir, self.subproject, is_cross, empty_sources, objects, self.environment, kwargs_reduced) + target = targetclass(name, self.subdir, self.subproject, for_machine, empty_sources, objects, self.environment, kwargs_reduced) new_target = { 'name': target.get_basename(), diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 6e7597476..5e71933f1 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -195,14 +195,9 @@ class Backend: self.environment.coredata.base_options) def get_compiler_options_for_target(self, target): - if self.environment.is_cross_build() and not target.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - return OptionOverrideProxy( target.option_overrides, - self.environment.coredata.compiler_options[for_machine]) + self.environment.coredata.compiler_options[target.for_machine]) def get_option_for_target(self, option_name, target): if option_name in target.option_overrides: @@ -357,17 +352,15 @@ class Backend: with open(exe_data, 'wb') as f: if isinstance(exe, dependencies.ExternalProgram): exe_cmd = exe.get_command() - exe_is_native = True + exe_for_machine = exe.for_machine elif isinstance(exe, (build.BuildTarget, build.CustomTarget)): exe_cmd = [self.get_target_filename_abs(exe)] - exe_is_native = not exe.is_cross + exe_for_machine = exe.for_machine else: exe_cmd = [exe] - exe_is_native = True - is_cross_built = (not exe_is_native) and \ - self.environment.is_cross_build() and \ - self.environment.need_exe_wrapper() - if is_cross_built: + exe_for_machine = MachineChoice.BUILD + is_cross_built = not self.environment.machines.matches_build_machine(exe_for_machine) + if is_cross_built and self.environment.need_exe_wrapper(): exe_wrapper = self.environment.get_exe_wrapper() if not exe_wrapper.found(): msg = 'The exe_wrapper {!r} defined in the cross file is ' \ @@ -397,10 +390,7 @@ class Backend: Otherwise, we query the target for the dynamic linker. ''' if isinstance(target, build.StaticLibrary): - if target.is_cross: - return self.build.static_cross_linker, [] - else: - return self.build.static_linker, [] + return self.build.static_linker[target.for_machine], [] l, stdlib_args = target.get_clink_dynamic_linker_and_stdlibs() return l, stdlib_args @@ -476,7 +466,8 @@ class Backend: else: source = os.path.relpath(os.path.join(build_dir, rel_src), os.path.join(self.environment.get_source_dir(), target.get_subdir())) - return source.replace('/', '_').replace('\\', '_') + '.' + self.environment.get_object_suffix() + machine = self.environment.machines[target.for_machine] + return source.replace('/', '_').replace('\\', '_') + '.' + machine.get_object_suffix() def determine_ext_objs(self, extobj, proj_dir_to_build_root): result = [] @@ -608,18 +599,14 @@ class Backend: commands += compiler.get_optimization_args(self.get_option_for_target('optimization', target)) commands += compiler.get_debug_args(self.get_option_for_target('debug', target)) # Add compile args added using add_project_arguments() - commands += self.build.get_project_args(compiler, target.subproject, target.is_cross) + commands += self.build.get_project_args(compiler, target.subproject, target.for_machine) # Add compile args added using add_global_arguments() # These override per-project arguments - commands += self.build.get_global_args(compiler, target.is_cross) - if self.environment.is_cross_build() and not target.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST + commands += self.build.get_global_args(compiler, target.for_machine) # Compile args added from the env: CFLAGS/CXXFLAGS, etc, or the cross # file. We want these to override all the defaults, but not the # per-target compile args. - commands += self.environment.coredata.get_external_args(for_machine, compiler.get_language()) + commands += self.environment.coredata.get_external_args(target.for_machine, compiler.get_language()) # Always set -fPIC for shared libraries if isinstance(target, build.SharedLibrary): commands += compiler.get_pic_args() @@ -679,11 +666,11 @@ class Backend: def get_mingw_extra_paths(self, target): paths = OrderedSet() # The cross bindir - root = self.environment.properties.host.get_root() + root = self.environment.properties[target.for_machine].get_root() if root: paths.add(os.path.join(root, 'bin')) # The toolchain bindir - sys_root = self.environment.properties.host.get_sys_root() + sys_root = self.environment.properties[target.for_machine].get_sys_root() if sys_root: paths.add(os.path.join(sys_root, 'bin')) # Get program and library dirs from all target compilers @@ -693,7 +680,7 @@ class Backend: paths.update(cc.get_library_dirs(self.environment)) return list(paths) - def determine_windows_extra_paths(self, target, extra_bdeps, is_cross=False): + def determine_windows_extra_paths(self, target: typing.Union[build.BuildTarget, str], extra_bdeps): '''On Windows there is no such thing as an rpath. We must determine all locations of DLLs that this exe links to and return them so they can be used in unit @@ -713,7 +700,8 @@ class Backend: continue dirseg = os.path.join(self.environment.get_build_dir(), self.get_target_dir(ld)) result.add(dirseg) - if is_cross: + if (isinstance(target, build.BuildTarget) and + not self.environment.machines.matches_build_machine(target.for_machine)): result.update(self.get_mingw_extra_paths(target)) return list(result) @@ -731,24 +719,23 @@ class Backend: cmd = exe.get_command() else: cmd = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(t.get_exe()))] - is_cross = self.environment.is_cross_build() and \ - self.environment.need_exe_wrapper() - if isinstance(exe, build.BuildTarget): - is_cross = is_cross and exe.is_cross - if isinstance(exe, dependencies.ExternalProgram): + if isinstance(exe, (build.BuildTarget, dependencies.ExternalProgram)): + test_for_machine = exe.for_machine + else: # E.g. an external verifier or simulator program run on a generated executable. # Can always be run without a wrapper. - is_cross = False - if is_cross: + test_for_machine = MachineChoice.BUILD + is_cross = not self.environment.machines.matches_build_machine(test_for_machine) + if is_cross and self.environment.need_exe_wrapper(): exe_wrapper = self.environment.get_exe_wrapper() else: exe_wrapper = None - if mesonlib.for_windows(self.environment) or \ - mesonlib.for_cygwin(self.environment): + machine = self.environment.machines[exe.for_machine] + if machine.is_windows() or machine.is_cygwin(): extra_bdeps = [] if isinstance(exe, build.CustomTarget): extra_bdeps = exe.get_transitive_build_target_deps() - extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps, is_cross) + extra_paths = self.determine_windows_extra_paths(exe, extra_bdeps) else: extra_paths = [] cmd_args = [] @@ -811,15 +798,22 @@ class Backend: return deps def exe_object_to_cmd_array(self, exe): - if self.environment.is_cross_build() and \ - isinstance(exe, build.BuildTarget) and exe.is_cross: - if self.environment.exe_wrapper is None and self.environment.need_exe_wrapper(): - s = textwrap.dedent(''' - Can not use target {} as a generator because it is cross-built - and no exe wrapper is defined or needs_exe_wrapper is true. - You might want to set it to native instead.'''.format(exe.name)) - raise MesonException(s) if isinstance(exe, build.BuildTarget): + if exe.for_machine is not MachineChoice.BUILD: + if (self.environment.is_cross_build() and + self.environment.exe_wrapper is None and + self.environment.need_exe_wrapper()): + s = textwrap.dedent(''' + Cannot use target {} as a generator because it is built for the + host machine and no exe wrapper is defined or needs_exe_wrapper is + true. You might want to set `native: true` instead to build it for + the build machine.'''.format(exe.name)) + raise MesonException(s) + else: + mlog.warning(''' + Target {} is used as a generator, but is built for the host + machine. This means most cross builds will fail. You might want to + set `native: true` instead to build it for the build machine.'''.format(exe.name)) exe_arr = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))] else: exe_arr = exe.get_command() diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index c919d8f1b..9f9574d6a 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -29,9 +29,11 @@ from .. import build from .. import mlog from .. import dependencies from .. import compilers -from ..compilers import CompilerArgs, CCompiler, VisualStudioLikeCompiler, FortranCompiler +from ..compilers import Compiler, CompilerArgs, CCompiler, VisualStudioLikeCompiler, FortranCompiler from ..linkers import ArLinker -from ..mesonlib import File, MachineChoice, MesonException, OrderedSet, LibType +from ..mesonlib import ( + File, LibType, MachineChoice, MesonException, OrderedSet, PerMachine +) from ..mesonlib import get_compiler_for_source, has_path_sep from .backends import CleanTrees from ..build import InvalidArguments @@ -202,6 +204,7 @@ class NinjaBackend(backends.Backend): self.fortran_deps = {} self.all_outputs = {} self.introspection_data = {} + self.created_llvm_ir_rule = PerMachine(False, False) def create_target_alias(self, to_target): # We need to use aliases for targets that might be used as directory @@ -219,7 +222,8 @@ class NinjaBackend(backends.Backend): def detect_vs_dep_prefix(self, tempfilename): '''VS writes its dependency in a locale dependent format. Detect the search prefix to use.''' - for compiler in self.environment.coredata.compilers.values(): + # TODO don't hard-code host + for compiler in self.environment.coredata.compilers.host.values(): # Have to detect the dependency format # IFort on windows is MSVC like, but doesn't have /showincludes @@ -314,10 +318,12 @@ int dummy; # http://clang.llvm.org/docs/JSONCompilationDatabase.html def generate_compdb(self): - pch_compilers = ['%s_PCH' % i for i in self.environment.coredata.compilers] - native_compilers = ['%s_COMPILER' % i for i in self.environment.coredata.compilers] - cross_compilers = ['%s_CROSS_COMPILER' % i for i in self.environment.coredata.cross_compilers] - ninja_compdb = [self.ninja_command, '-t', 'compdb'] + pch_compilers + native_compilers + cross_compilers + rules = [] + for for_machine in MachineChoice: + for lang in self.environment.coredata.compilers[for_machine]: + rules += [self.get_compiler_rule_name(lang, for_machine)] + rules += [self.get_pch_rule_name(lang, for_machine)] + ninja_compdb = [self.ninja_command, '-t', 'compdb'] + rules builddir = self.environment.get_build_dir() try: jsondb = subprocess.check_output(ninja_compdb, cwd=builddir) @@ -663,13 +669,10 @@ int dummy; # the project, we need to set PATH so the DLLs are found. We use # a serialized executable wrapper for that and check if the # CustomTarget command needs extra paths first. - is_cross = self.environment.is_cross_build() and \ - self.environment.need_exe_wrapper() - if mesonlib.for_windows(self.environment) or \ - mesonlib.for_cygwin(self.environment): + machine = self.environment.machines[target.for_machine] + if machine.is_windows() or machine.is_cygwin(): extra_bdeps = target.get_transitive_build_target_deps() - extra_paths = self.determine_windows_extra_paths(target.command[0], - extra_bdeps, is_cross) + extra_paths = self.determine_windows_extra_paths(target.command[0], extra_bdeps) if extra_paths: serialize = True if serialize: @@ -846,9 +849,7 @@ int dummy; self.add_rule_comment(NinjaComment('Rules for compiling.')) self.generate_compile_rules() self.add_rule_comment(NinjaComment('Rules for linking.')) - if self.environment.is_cross_build(): - self.generate_static_link_rules(True) - self.generate_static_link_rules(False) + self.generate_static_link_rules() self.generate_dynamic_link_rules() self.add_rule_comment(NinjaComment('Other rules')) # Ninja errors out if you have deps = gcc but no depfile, so we must @@ -1014,10 +1015,10 @@ int dummy; for dep in target.get_external_deps(): commands.extend_direct(dep.get_link_args()) - commands += self.build.get_project_args(compiler, target.subproject, target.is_cross) - commands += self.build.get_global_args(compiler, target.is_cross) + commands += self.build.get_project_args(compiler, target.subproject, target.for_machine) + commands += self.build.get_global_args(compiler, target.for_machine) - elem = NinjaBuildElement(self.all_outputs, outputs, 'cs_COMPILER', rel_srcs + generated_rel_srcs) + elem = NinjaBuildElement(self.all_outputs, outputs, self.get_compiler_rule_name('cs', target.for_machine), rel_srcs + generated_rel_srcs) elem.add_dep(deps) elem.add_item('ARGS', commands) self.add_build(elem) @@ -1028,8 +1029,8 @@ int dummy; def determine_single_java_compile_args(self, target, compiler): args = [] args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target)) - args += self.build.get_global_args(compiler, target.is_cross) - args += self.build.get_project_args(compiler, target.subproject, target.is_cross) + args += self.build.get_global_args(compiler, target.for_machine) + args += self.build.get_project_args(compiler, target.subproject, target.for_machine) args += target.get_java_args() args += compiler.get_output_args(self.get_target_private_dir(target)) args += target.get_classpath_args() @@ -1051,7 +1052,7 @@ int dummy; rel_src = src.rel_to_builddir(self.build_to_src) plain_class_path = src.fname[:-4] + 'class' rel_obj = os.path.join(self.get_target_private_dir(target), plain_class_path) - element = NinjaBuildElement(self.all_outputs, rel_obj, compiler.get_language() + '_COMPILER', rel_src) + element = NinjaBuildElement(self.all_outputs, rel_obj, self.compiler_to_rule_name(compiler), rel_src) element.add_dep(deps) element.add_item('ARGS', args) self.add_build(element) @@ -1248,7 +1249,7 @@ int dummy; extra_dep_files += dependency_vapis args += extra_args element = NinjaBuildElement(self.all_outputs, valac_outputs, - valac.get_language() + '_COMPILER', + self.compiler_to_rule_name(valac), all_files + dependency_vapis) element.add_item('ARGS', args) element.add_dep(extra_dep_files) @@ -1285,8 +1286,8 @@ int dummy; args += ['--crate-name', target.name] args += rustc.get_buildtype_args(self.get_option_for_target('buildtype', target)) args += rustc.get_debug_args(self.get_option_for_target('debug', target)) - args += self.build.get_global_args(rustc, target.is_cross) - args += self.build.get_project_args(rustc, target.subproject, target.is_cross) + args += self.build.get_global_args(rustc, target.for_machine) + args += self.build.get_project_args(rustc, target.subproject, target.for_machine) depfile = os.path.join(target.subdir, target.name + '.d') args += ['--emit', 'dep-info={}'.format(depfile), '--emit', 'link'] args += target.get_extra_args('rust') @@ -1334,10 +1335,7 @@ int dummy; # installations for rpath_arg in rpath_args: args += ['-C', 'link-arg=' + rpath_arg + ':' + os.path.join(rustc.get_sysroot(), 'lib')] - crstr = '' - if target.is_cross: - crstr = '_CROSS' - compiler_name = 'rust%s_COMPILER' % crstr + compiler_name = self.get_compiler_rule_name('rust', target.for_machine) element = NinjaBuildElement(self.all_outputs, target_name, compiler_name, main_rust_file) if len(orderdeps) > 0: element.add_orderdep(orderdeps) @@ -1349,6 +1347,26 @@ int dummy; self.generate_shsym(target) self.create_target_source_introspection(target, rustc, args, [main_rust_file], []) + @staticmethod + def get_rule_suffix(for_machine: MachineChoice) -> str: + return PerMachine('_FOR_BUILD', '')[for_machine] + + @classmethod + def get_compiler_rule_name(cls, lang: str, for_machine: MachineChoice) -> str: + return '%s_COMPILER%s' % (lang, cls.get_rule_suffix(for_machine)) + + @classmethod + def get_pch_rule_name(cls, lang: str, for_machine: MachineChoice) -> str: + return '%s_PCH%s' % (lang, cls.get_rule_suffix(for_machine)) + + @classmethod + def compiler_to_rule_name(cls, compiler: Compiler) -> str: + return cls.get_compiler_rule_name(compiler.get_language(), compiler.for_machine) + + @classmethod + def compiler_to_pch_rule_name(cls, compiler: Compiler) -> str: + return cls.get_pch_rule_name(compiler.get_language(), compiler.for_machine) + def swift_module_file_name(self, target): return os.path.join(self.get_target_private_dir(target), self.target_swift_modulename(target) + '.swiftmodule') @@ -1417,8 +1435,8 @@ int dummy; compile_args += swiftc.get_optimization_args(self.get_option_for_target('optimization', target)) compile_args += swiftc.get_debug_args(self.get_option_for_target('debug', target)) compile_args += swiftc.get_module_args(module_name) - compile_args += self.build.get_project_args(swiftc, target.subproject, target.is_cross) - compile_args += self.build.get_global_args(swiftc, target.is_cross) + compile_args += self.build.get_project_args(swiftc, target.subproject, target.for_machine) + compile_args += self.build.get_global_args(swiftc, target.for_machine) for i in reversed(target.get_include_dirs()): basedir = i.get_curdir() for d in i.get_incdirs(): @@ -1430,8 +1448,8 @@ int dummy; sargs = swiftc.get_include_args(srctreedir) compile_args += sargs link_args = swiftc.get_output_args(os.path.join(self.environment.get_build_dir(), self.get_target_filename(target))) - link_args += self.build.get_project_link_args(swiftc, target.subproject, target.is_cross) - link_args += self.build.get_global_link_args(swiftc, target.is_cross) + link_args += self.build.get_project_link_args(swiftc, target.subproject, target.for_machine) + link_args += self.build.get_global_link_args(swiftc, target.for_machine) rundir = self.get_target_private_dir(target) out_module_name = self.swift_module_file_name(target) in_module_files = self.determine_swift_dep_modules(target) @@ -1458,17 +1476,17 @@ int dummy; objects.append(oname) rel_objects.append(os.path.join(self.get_target_private_dir(target), oname)) + rulename = self.get_compiler_rule_name('swift', target.for_machine) + # Swiftc does not seem to be able to emit objects and module files in one go. - elem = NinjaBuildElement(self.all_outputs, rel_objects, - 'swift_COMPILER', - abssrc) + elem = NinjaBuildElement(self.all_outputs, rel_objects, rulename, abssrc) elem.add_dep(in_module_files + rel_generated) elem.add_dep(abs_headers) elem.add_item('ARGS', compile_args + header_imports + abs_generated + module_includes) elem.add_item('RUNDIR', rundir) self.add_build(elem) elem = NinjaBuildElement(self.all_outputs, out_module_name, - 'swift_COMPILER', + self.get_compiler_rule_name('swift', target.for_machine), abssrc) elem.add_dep(in_module_files + rel_generated) elem.add_item('ARGS', compile_args + abs_generated + module_includes + swiftc.get_mod_gen_args()) @@ -1476,10 +1494,10 @@ int dummy; self.add_build(elem) if isinstance(target, build.StaticLibrary): elem = self.generate_link(target, self.get_target_filename(target), - rel_objects, self.build.static_linker) + rel_objects, self.build.static_linker[target.for_machine]) self.add_build(elem) elif isinstance(target, build.Executable): - elem = NinjaBuildElement(self.all_outputs, self.get_target_filename(target), 'swift_COMPILER', []) + elem = NinjaBuildElement(self.all_outputs, self.get_target_filename(target), rulename, []) elem.add_dep(rel_objects) elem.add_dep(link_deps) elem.add_item('ARGS', link_args + swiftc.get_std_exe_link_args() + objects + abs_link_deps) @@ -1490,61 +1508,49 @@ int dummy; # Introspection information self.create_target_source_introspection(target, swiftc, compile_args + header_imports + module_includes, relsrc, rel_generated) - def generate_static_link_rules(self, is_cross): + def generate_static_link_rules(self): num_pools = self.environment.coredata.backend_options['backend_max_links'].value - if 'java' in self.environment.coredata.compilers: - if not is_cross: - self.generate_java_link() - if is_cross: - if self.environment.is_cross_build(): - static_linker = self.build.static_cross_linker + if 'java' in self.environment.coredata.compilers.host: + self.generate_java_link() + for for_machine in MachineChoice: + static_linker = self.build.static_linker[for_machine] + if static_linker is None: + return + rule = 'STATIC_LINKER%s' % self.get_rule_suffix(for_machine) + cmdlist = [] + args = ['$in'] + # FIXME: Must normalize file names with pathlib.Path before writing + # them out to fix this properly on Windows. See: + # https://github.com/mesonbuild/meson/issues/1517 + # https://github.com/mesonbuild/meson/issues/1526 + if isinstance(static_linker, ArLinker) and not mesonlib.is_windows(): + # `ar` has no options to overwrite archives. It always appends, + # which is never what we want. Delete an existing library first if + # it exists. https://github.com/mesonbuild/meson/issues/1355 + cmdlist = execute_wrapper + [c.format('$out') for c in rmfile_prefix] + cmdlist += static_linker.get_exelist() + cmdlist += ['$LINK_ARGS'] + cmdlist += static_linker.get_output_args('$out') + description = 'Linking static target $out.' + if num_pools > 0: + pool = 'pool = link_pool' else: - static_linker = self.build.static_linker - crstr = '_CROSS' - else: - static_linker = self.build.static_linker - crstr = '' - if static_linker is None: - return - rule = 'STATIC%s_LINKER' % crstr - cmdlist = [] - args = ['$in'] - # FIXME: Must normalize file names with pathlib.Path before writing - # them out to fix this properly on Windows. See: - # https://github.com/mesonbuild/meson/issues/1517 - # https://github.com/mesonbuild/meson/issues/1526 - if isinstance(static_linker, ArLinker) and not mesonlib.is_windows(): - # `ar` has no options to overwrite archives. It always appends, - # which is never what we want. Delete an existing library first if - # it exists. https://github.com/mesonbuild/meson/issues/1355 - cmdlist = execute_wrapper + [c.format('$out') for c in rmfile_prefix] - cmdlist += static_linker.get_exelist() - cmdlist += ['$LINK_ARGS'] - cmdlist += static_linker.get_output_args('$out') - description = 'Linking static target $out.' - if num_pools > 0: - pool = 'pool = link_pool' - else: - pool = None - self.add_rule(NinjaRule(rule, cmdlist, args, description, - rspable=static_linker.can_linker_accept_rsp(), - extra=pool)) + pool = None + self.add_rule(NinjaRule(rule, cmdlist, args, description, + rspable=static_linker.can_linker_accept_rsp(), + extra=pool)) def generate_dynamic_link_rules(self): num_pools = self.environment.coredata.backend_options['backend_max_links'].value - ctypes = [(self.environment.coredata.compilers, False), - (self.environment.coredata.cross_compilers, True)] - for (complist, is_cross) in ctypes: + for for_machine in MachineChoice: + complist = self.environment.coredata.compilers[for_machine] for langname, compiler in complist.items(): if langname == 'java' \ or langname == 'vala' \ or langname == 'rust' \ or langname == 'cs': continue - crstr = '' - if is_cross: - crstr = '_CROSS' - rule = '%s%s_LINKER' % (langname, crstr) + rule = '%s_LINKER%s' % (langname, self.get_rule_suffix(for_machine)) command = compiler.get_linker_exelist() args = ['$ARGS'] + compiler.get_linker_output_args('$out') + ['$in', '$LINK_ARGS'] description = 'Linking target $out.' @@ -1568,14 +1574,14 @@ int dummy; self.add_rule(NinjaRule(symrule, symcmd, [], syndesc, extra=synstat)) def generate_java_compile_rule(self, compiler): - rule = '%s_COMPILER' % compiler.get_language() + rule = self.compiler_to_rule_name(compiler) invoc = [ninja_quote(i) for i in compiler.get_exelist()] command = invoc + ['$ARGS', '$in'] description = 'Compiling Java object $in.' self.add_rule(NinjaRule(rule, command, [], description)) def generate_cs_compile_rule(self, compiler): - rule = '%s_COMPILER' % compiler.get_language() + rule = self.compiler_to_rule_name(compiler) invoc = [ninja_quote(i) for i in compiler.get_exelist()] command = invoc args = ['$ARGS', '$in'] @@ -1584,17 +1590,14 @@ int dummy; rspable=mesonlib.is_windows())) def generate_vala_compile_rules(self, compiler): - rule = '%s_COMPILER' % compiler.get_language() + rule = self.compiler_to_rule_name(compiler) invoc = [ninja_quote(i) for i in compiler.get_exelist()] command = invoc + ['$ARGS', '$in'] description = 'Compiling Vala source $in.' self.add_rule(NinjaRule(rule, command, [], description, extra='restat = 1')) - def generate_rust_compile_rules(self, compiler, is_cross): - crstr = '' - if is_cross: - crstr = '_CROSS' - rule = '%s%s_COMPILER' % (compiler.get_language(), crstr) + def generate_rust_compile_rules(self, compiler): + rule = self.compiler_to_rule_name(compiler) invoc = [ninja_quote(i) for i in compiler.get_exelist()] command = invoc + ['$ARGS', '$in'] description = 'Compiling Rust source $in.' @@ -1604,7 +1607,7 @@ int dummy; depfile=depfile)) def generate_swift_compile_rules(self, compiler): - rule = '%s_COMPILER' % compiler.get_language() + rule = self.compiler_to_rule_name(compiler) full_exe = [ninja_quote(x) for x in self.environment.get_build_command()] + [ '--internal', 'dirchanger', @@ -1626,44 +1629,41 @@ https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) self.add_rule(NinjaRule(rule, cmd, [], 'Dep hack', extra='restat = 1')) - def generate_llvm_ir_compile_rule(self, compiler, is_cross): - if getattr(self, 'created_llvm_ir_rule', False): + def generate_llvm_ir_compile_rule(self, compiler): + if self.created_llvm_ir_rule[compiler.for_machine]: return - rule = 'llvm_ir{}_COMPILER'.format('_CROSS' if is_cross else '') + rule = self.get_compiler_rule_name('llvm_ir', compiler.for_machine) command = [ninja_quote(i) for i in compiler.get_exelist()] args = ['$ARGS'] + compiler.get_output_args('$out') + compiler.get_compile_only_args() + ['$in'] description = 'Compiling LLVM IR object $in.' self.add_rule(NinjaRule(rule, command, args, description, rspable=compiler.can_linker_accept_rsp())) - self.created_llvm_ir_rule = True + self.created_llvm_ir_rule[compiler.for_machine] = True - def generate_compile_rule_for(self, langname, compiler, is_cross): + def generate_compile_rule_for(self, langname, compiler): if langname == 'java': - if not is_cross: + if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_java_compile_rule(compiler) return if langname == 'cs': - if not is_cross: + if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_cs_compile_rule(compiler) return if langname == 'vala': - if not is_cross: + if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_vala_compile_rules(compiler) return if langname == 'rust': - self.generate_rust_compile_rules(compiler, is_cross) + self.generate_rust_compile_rules(compiler) return if langname == 'swift': - if not is_cross: + if self.environment.machines.matches_build_machine(compiler.for_machine): self.generate_swift_compile_rules(compiler) return - if is_cross: - crstr = '_CROSS' - else: - crstr = '' + crstr = self.get_rule_suffix(compiler.for_machine) if langname == 'fortran': self.generate_fortran_dep_hack(crstr) - rule = '%s%s_COMPILER' % (langname, crstr) + rule = self.get_compiler_rule_name(langname, compiler.for_machine) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') quoted_depargs = [] for d in depargs: @@ -1684,14 +1684,10 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) rspable=compiler.can_linker_accept_rsp(), deps=deps, depfile=depfile)) - def generate_pch_rule_for(self, langname, compiler, is_cross): + def generate_pch_rule_for(self, langname, compiler): if langname != 'c' and langname != 'cpp': return - if is_cross: - crstr = '_CROSS' - else: - crstr = '' - rule = '%s%s_PCH' % (langname, crstr) + rule = self.compiler_to_pch_rule_name(compiler) depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE') quoted_depargs = [] @@ -1715,18 +1711,13 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) depfile=depfile)) def generate_compile_rules(self): - for langname, compiler in self.environment.coredata.compilers.items(): - if compiler.get_id() == 'clang': - self.generate_llvm_ir_compile_rule(compiler, False) - self.generate_compile_rule_for(langname, compiler, False) - self.generate_pch_rule_for(langname, compiler, False) - if self.environment.is_cross_build(): - cclist = self.environment.coredata.cross_compilers - for langname, compiler in cclist.items(): + for for_machine in MachineChoice: + clist = self.environment.coredata.compilers[for_machine] + for langname, compiler in clist.items(): if compiler.get_id() == 'clang': - self.generate_llvm_ir_compile_rule(compiler, True) - self.generate_compile_rule_for(langname, compiler, True) - self.generate_pch_rule_for(langname, compiler, True) + self.generate_llvm_ir_compile_rule(compiler) + self.generate_compile_rule_for(langname, compiler) + self.generate_pch_rule_for(langname, compiler) def generate_generator_list_rules(self, target): # CustomTargets have already written their rules and @@ -1820,7 +1811,8 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) Find all module and submodule made available in a Fortran code file. """ compiler = None - for lang, c in self.environment.coredata.compilers.items(): + # TODO other compilers + for lang, c in self.environment.coredata.compilers.host.items(): if lang == 'fortran': compiler = c break @@ -1881,7 +1873,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) return mod_files def get_cross_stdlib_args(self, target, compiler): - if not target.is_cross: + if self.environment.machines.matches_build_machine(target.for_machine): return [] if not self.environment.properties.host.has_stdlib(compiler.language): return [] @@ -1964,7 +1956,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) src_filename = src obj_basename = src_filename.replace('/', '_').replace('\\', '_') rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename) - rel_obj += '.' + self.environment.get_object_suffix() + rel_obj += '.' + self.environment.machines[target.for_machine].get_object_suffix() commands += self.get_compile_debugfile_args(compiler, target, rel_obj) if isinstance(src, File) and src.is_built: rel_src = src.fname @@ -1973,7 +1965,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) else: raise InvalidArguments('Invalid source type: {!r}'.format(src)) # Write the Ninja build command - compiler_name = 'llvm_ir{}_COMPILER'.format('_CROSS' if target.is_cross else '') + compiler_name = self.get_compiler_rule_name('llvm_ir', compiler.for_machine) element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src) # Convert from GCC-style link argument naming to the naming used by the # current compiler. @@ -2161,10 +2153,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) arr.append(i) pch_dep = arr - crstr = '' - if target.is_cross: - crstr = '_CROSS' - compiler_name = '%s%s_COMPILER' % (compiler.get_language(), crstr) + compiler_name = self.compiler_to_rule_name(compiler) extra_deps = [] if compiler.get_language() == 'fortran': # Can't read source file to scan for deps if it's generated later @@ -2181,6 +2170,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) compiler.module_name_to_filename(modname)) if srcfile == src: + crstr = self.get_rule_suffix(target.for_machine) depelem = NinjaBuildElement(self.all_outputs, modfile, 'FORTRAN_DEP_HACK' + crstr, rel_obj) self.add_build(depelem) commands += compiler.get_module_outdir_args(self.get_target_private_dir(target)) @@ -2268,10 +2258,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) def generate_pch(self, target, header_deps=None): header_deps = header_deps if header_deps is not None else [] - cstr = '' pch_objects = [] - if target.is_cross: - cstr = '_CROSS' for lang in ['c', 'cpp']: pch = target.get_pch(lang) if not pch: @@ -2293,7 +2280,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) (commands, dep, dst, objs) = self.generate_gcc_pch_command(target, compiler, pch[0]) extradep = None pch_objects += objs - rulename = compiler.get_language() + cstr + '_PCH' + rulename = self.compiler_to_pch_rule_name(compiler) elem = NinjaBuildElement(self.all_outputs, dst, rulename, src) if extradep is not None: elem.add_dep(extradep) @@ -2310,11 +2297,12 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) symname = os.path.join(targetdir, target_name + '.symbols') elem = NinjaBuildElement(self.all_outputs, symname, 'SHSYM', target_file) if self.environment.is_cross_build(): - elem.add_item('CROSS', '--cross-host=' + self.environment.machines.host.system) + elem.add_item('CROSS', '--cross-host=' + self.environment.machines[target.for_machine].system) self.add_build(elem) def get_cross_stdlib_link_args(self, target, linker): - if isinstance(target, build.StaticLibrary) or not target.is_cross: + if isinstance(target, build.StaticLibrary) or \ + self.environment.machines.matches_build_machine(target.for_machine): return [] if not self.environment.properties.host.has_stdlib(linker.language): return [] @@ -2455,10 +2443,8 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) linker_base = linker.get_language() # Fixme. if isinstance(target, build.SharedLibrary): self.generate_shsym(target) - crstr = '' - if target.is_cross: - crstr = '_CROSS' - linker_rule = linker_base + crstr + '_LINKER' + crstr = self.get_rule_suffix(target.for_machine) + linker_rule = linker_base + '_LINKER' + crstr # Create an empty commands list, and start adding link arguments from # various sources in the order in which they must override each other # starting from hard-coded defaults followed by build options and so on. @@ -2492,20 +2478,15 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) if not isinstance(target, build.StaticLibrary): commands += self.get_link_whole_args(linker, target) - if self.environment.is_cross_build() and not target.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - if not isinstance(target, build.StaticLibrary): # Add link args added using add_project_link_arguments() - commands += self.build.get_project_link_args(linker, target.subproject, target.is_cross) + commands += self.build.get_project_link_args(linker, target.subproject, target.for_machine) # Add link args added using add_global_link_arguments() # These override per-project link arguments - commands += self.build.get_global_link_args(linker, target.is_cross) + commands += self.build.get_global_link_args(linker, target.for_machine) # Link args added from the env: LDFLAGS. We want these to override # all the defaults but not the per-target link args. - commands += self.environment.coredata.get_external_link_args(for_machine, linker.get_language()) + commands += self.environment.coredata.get_external_link_args(target.for_machine, linker.get_language()) # Now we will add libraries and library paths from various sources @@ -2544,7 +2525,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) # to be after all internal and external libraries so that unresolved # symbols from those can be found here. This is needed when the # *_winlibs that we want to link to are static mingw64 libraries. - commands += linker.get_option_link_args(self.environment.coredata.compiler_options[for_machine]) + commands += linker.get_option_link_args(self.environment.coredata.compiler_options[target.for_machine]) dep_targets = [] dep_targets.extend(self.guess_external_link_dependencies(linker, target, commands, internal)) diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index ef08fdbb4..86a7f8307 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -27,7 +27,7 @@ from .. import mlog from .. import compilers from ..compilers import CompilerArgs from ..mesonlib import ( - MesonException, MachineChoice, File, python_command, replace_if_different + MesonException, File, python_command, replace_if_different ) from ..environment import Environment, build_filename @@ -720,7 +720,7 @@ class Vs2010Backend(backends.Backend): # No source files, only objects, but we still need a compiler, so # return a found compiler if len(target.objects) > 0: - for lang, c in self.environment.coredata.compilers.items(): + for lang, c in self.environment.coredata.compilers[target.for_machine].items(): if lang in ('c', 'cpp'): return c raise MesonException('Could not find a C or C++ compiler. MSVC can only build C/C++ projects.') @@ -883,27 +883,23 @@ class Vs2010Backend(backends.Backend): file_inc_dirs = dict((lang, []) for lang in target.compilers) # The order in which these compile args are added must match # generate_single_compile() and generate_basic_compiler_args() - if self.environment.is_cross_build() and not target.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST for l, comp in target.compilers.items(): if l in file_args: file_args[l] += compilers.get_base_compile_args(self.get_base_options_for_target(target), comp) - file_args[l] += comp.get_option_compile_args(self.environment.coredata.compiler_options[for_machine]) + file_args[l] += comp.get_option_compile_args(self.environment.coredata.compiler_options[target.for_machine]) # Add compile args added using add_project_arguments() - for l, args in self.build.projects_args.get(target.subproject, {}).items(): + for l, args in self.build.projects_args[target.for_machine].get(target.subproject, {}).items(): if l in file_args: file_args[l] += args # Add compile args added using add_global_arguments() # These override per-project arguments - for l, args in self.build.global_args.items(): + for l, args in self.build.global_args[target.for_machine].items(): if l in file_args: file_args[l] += args # Compile args added from the env or cross file: CFLAGS/CXXFLAGS, etc. We want these # to override all the defaults, but not the per-target compile args. - for key, opt in self.environment.coredata.compiler_options[for_machine].items(): + for key, opt in self.environment.coredata.compiler_options[target.for_machine].items(): l, suffix = key.split('_', 1) if suffix == 'args' and l in file_args: file_args[l] += opt.value @@ -1083,14 +1079,14 @@ class Vs2010Backend(backends.Backend): options = self.environment.coredata.base_options extra_link_args += compiler.get_std_shared_module_link_args(options) # Add link args added using add_project_link_arguments() - extra_link_args += self.build.get_project_link_args(compiler, target.subproject, target.is_cross) + extra_link_args += self.build.get_project_link_args(compiler, target.subproject, target.for_machine) # Add link args added using add_global_link_arguments() # These override per-project link arguments - extra_link_args += self.build.get_global_link_args(compiler, target.is_cross) + extra_link_args += self.build.get_global_link_args(compiler, target.for_machine) # Link args added from the env: LDFLAGS, or the cross file. We want # these to override all the defaults but not the per-target link # args. - extra_link_args += self.environment.coredata.get_external_link_args(for_machine, compiler.get_language()) + extra_link_args += self.environment.coredata.get_external_link_args(target.for_machine, compiler.get_language()) # Only non-static built targets need link args and link dependencies extra_link_args += target.link_args # External deps must be last because target link libraries may depend on them. @@ -1113,7 +1109,7 @@ class Vs2010Backend(backends.Backend): # to be after all internal and external libraries so that unresolved # symbols from those can be found here. This is needed when the # *_winlibs that we want to link to are static mingw64 libraries. - extra_link_args += compiler.get_option_link_args(self.environment.coredata.compiler_options[for_machine]) + extra_link_args += compiler.get_option_link_args(self.environment.coredata.compiler_options[compiler.for_machine]) (additional_libpaths, additional_links, extra_link_args) = self.split_link_args(extra_link_args.to_native()) # Add more libraries to be linked if needed diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py index be22c7846..7c6625081 100644 --- a/mesonbuild/backend/xcodebackend.py +++ b/mesonbuild/backend/xcodebackend.py @@ -742,10 +742,10 @@ class XCodeBackend(backends.Backend): if lang not in langnamemap: continue # Add compile args added using add_project_arguments() - pargs = self.build.projects_args.get(target.subproject, {}).get(lang, []) + pargs = self.build.projects_args[target.for_machine].get(target.subproject, {}).get(lang, []) # Add compile args added using add_global_arguments() # These override per-project arguments - gargs = self.build.global_args.get(lang, []) + gargs = self.build.global_args[target.for_machine].get(lang, []) targs = target.get_extra_args(lang) args = pargs + gargs + targs if args: diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 3394459d7..763e5c9fb 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -25,10 +25,9 @@ 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 .interpreterbase import FeatureNew @@ -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({}, {}) + self.projects_args = PerMachine({}, {}) + self.global_link_args = PerMachine({}, {}) + self.projects_link_args = PerMachine({}, {}) 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) 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.environment) or for_windows(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): @@ -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.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(environment) or - for_cygwin(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(environment) or for_cygwin(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(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(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(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(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.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 ''.format( diff --git a/mesonbuild/cmake/client.py b/mesonbuild/cmake/client.py index f4b549b14..93985e927 100644 --- a/mesonbuild/cmake/client.py +++ b/mesonbuild/cmake/client.py @@ -18,6 +18,7 @@ from .common import CMakeException from ..environment import Environment from ..dependencies.base import CMakeDependency, ExternalProgram +from ..mesonlib import MachineChoice from .. import mlog from contextlib import contextmanager from subprocess import Popen, PIPE, TimeoutExpired @@ -473,8 +474,8 @@ class CMakeClient: def startup(self) -> None: if self.proc is not None: raise CMakeException('The CMake server was already started') - - cmake_exe, cmake_vers, _ = CMakeDependency.find_cmake_binary(self.env) + for_machine = MachineChoice.HOST # TODO make parameter + cmake_exe, cmake_vers, _ = CMakeDependency.find_cmake_binary(self.env, for_machine) if cmake_exe is None or cmake_exe is False: raise CMakeException('Unable to find CMake') assert(isinstance(cmake_exe, ExternalProgram)) diff --git a/mesonbuild/cmake/interpreter.py b/mesonbuild/cmake/interpreter.py index ec1790637..435f8d23b 100644 --- a/mesonbuild/cmake/interpreter.py +++ b/mesonbuild/cmake/interpreter.py @@ -20,6 +20,7 @@ from .client import CMakeClient, RequestCMakeInputs, RequestConfigure, RequestCo from .. import mlog from ..build import Build from ..environment import Environment +from ..mesonlib import MachineChoice from ..mparser import Token, BaseNode, CodeBlockNode, FunctionNode, ArrayNode, ArgumentNode, AssignmentNode, BooleanNode, StringNode, IdNode, MethodNode from ..backend.backends import Backend from ..compilers.compilers import lang_suffixes, header_suffixes, obj_suffixes @@ -300,8 +301,9 @@ class CMakeInterpreter: self.generated_targets = {} def configure(self, extra_cmake_options: List[str]) -> None: + for_machine = MachineChoice.HOST # TODO make parameter # Find CMake - cmake_exe, cmake_vers, _ = CMakeDependency.find_cmake_binary(self.env) + cmake_exe, cmake_vers, _ = CMakeDependency.find_cmake_binary(self.env, for_machine) if cmake_exe is None or cmake_exe is False: raise CMakeException('Unable to find CMake') assert(isinstance(cmake_exe, ExternalProgram)) @@ -312,7 +314,7 @@ class CMakeInterpreter: cmake_args = cmake_exe.get_command() # Map meson compiler to CMake variables - for lang, comp in self.env.coredata.compilers.items(): + for lang, comp in self.env.coredata.compilers[for_machine].items(): if lang not in language_map: continue cmake_lang = language_map[lang] diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 3e536ea33..3b58a076d 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -16,7 +16,7 @@ import os.path import typing from .. import coredata -from ..mesonlib import MesonException, version_compare, mlog +from ..mesonlib import MachineChoice, MesonException, mlog, version_compare from .c_function_attributes import C_FUNC_ATTRIBUTES from .clike import CLikeCompiler @@ -47,11 +47,11 @@ class CCompiler(CLikeCompiler, Compiler): except KeyError: raise MesonException('Unknown function attribute "{}"'.format(name)) - def __init__(self, exelist, version, is_cross: bool, + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrapper: typing.Optional[str] = None, **kwargs): # If a child ObjC or CPP class has already set it, don't set it ourselves self.language = 'c' - Compiler.__init__(self, exelist, version, **kwargs) + Compiler.__init__(self, exelist, version, for_machine, **kwargs) CLikeCompiler.__init__(self, is_cross, exe_wrapper) def get_no_stdinc_args(self): @@ -76,8 +76,8 @@ class CCompiler(CLikeCompiler, Compiler): class ClangCCompiler(ClangCompiler, CCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) ClangCompiler.__init__(self, compiler_type) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], @@ -119,8 +119,8 @@ class ClangCCompiler(ClangCompiler, CCompiler): class ArmclangCCompiler(ArmclangCompiler, CCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) ArmclangCompiler.__init__(self, compiler_type) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], @@ -148,8 +148,8 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler): class GnuCCompiler(GnuCompiler, CCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None, **kwargs): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None, **kwargs): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], @@ -191,14 +191,14 @@ class GnuCCompiler(GnuCompiler, CCompiler): class PGICCompiler(PGICompiler, CCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) PGICompiler.__init__(self, compiler_type) class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None, **kwargs): - GnuCCompiler.__init__(self, exelist, version, compiler_type, is_cross, exe_wrapper, defines, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None, **kwargs): + GnuCCompiler.__init__(self, exelist, version, compiler_type, for_machine, is_cross, exe_wrapper, defines, **kwargs) ElbrusCompiler.__init__(self, compiler_type, defines) # It does support some various ISO standards and c/gnu 90, 9x, 1x in addition to those which GNU CC supports. @@ -223,8 +223,8 @@ class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) IntelGnuLikeCompiler.__init__(self, compiler_type) self.lang_header = 'c-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark'] @@ -267,14 +267,14 @@ class VisualStudioLikeCCompilerMixin: class VisualStudioCCompiler(VisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler): - def __init__(self, exelist, version, is_cross, exe_wrap, target: str): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target: str): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap) VisualStudioLikeCompiler.__init__(self, target) self.id = 'msvc' class ClangClCCompiler(VisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler): - def __init__(self, exelist, version, is_cross, exe_wrap, target): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap) VisualStudioLikeCompiler.__init__(self, target) self.id = 'clang-cl' @@ -285,8 +285,8 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM __have_warned = False - def __init__(self, exelist, version, is_cross, exe_wrap, target): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap) IntelVisualStudioLikeCompiler.__init__(self, target) def get_options(self): @@ -310,8 +310,8 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM class ArmCCompiler(ArmCompiler, CCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) ArmCompiler.__init__(self, compiler_type) def get_options(self): @@ -329,8 +329,8 @@ class ArmCCompiler(ArmCompiler, CCompiler): return args class CcrxCCompiler(CcrxCompiler, CCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): - CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + CCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) CcrxCompiler.__init__(self, compiler_type) # Override CCompiler.get_always_args diff --git a/mesonbuild/compilers/clike.py b/mesonbuild/compilers/clike.py index 968685b5c..89419313d 100644 --- a/mesonbuild/compilers/clike.py +++ b/mesonbuild/compilers/clike.py @@ -30,7 +30,7 @@ import typing from pathlib import Path from .. import mesonlib -from ..mesonlib import MachineChoice, LibType +from ..mesonlib import LibType from .. import mlog from . import compilers @@ -277,7 +277,7 @@ class CLikeCompiler: m = env.machines[self.for_machine] if m.is_windows() or m.is_cygwin(): return ['-Wl,--export-all-symbols'] - elif mesonlib.for_darwin(env): + elif env.machines[self.for_machine].is_darwin(): return [] else: return ['-Wl,-export-dynamic'] @@ -384,13 +384,9 @@ class CLikeCompiler: # Select a CRT if needed since we're linking if mode == 'link': args += self.get_linker_debug_crt_args() - if env.is_cross_build() and not self.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST if mode in {'compile', 'preprocess'}: # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS and CPPFLAGS from the env - sys_args = env.coredata.get_external_args(for_machine, self.language) + sys_args = env.coredata.get_external_args(self.for_machine, self.language) # Apparently it is a thing to inject linker flags both # via CFLAGS _and_ LDFLAGS, even though the former are # also used during linking. These flags can break @@ -399,7 +395,7 @@ class CLikeCompiler: args += cleaned_sys_args elif mode == 'link': # Add LDFLAGS from the env - args += env.coredata.get_external_link_args(for_machine, self.language) + args += env.coredata.get_external_link_args(self.for_machine, self.language) return args def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): @@ -885,7 +881,7 @@ class CLikeCompiler: for p in prefixes: for s in suffixes: patterns.append(p + '{}.' + s) - if shared and mesonlib.for_openbsd(env): + if shared and env.machines[self.for_machine].is_openbsd(): # Shared libraries on OpenBSD can be named libfoo.so.X.Y: # https://www.openbsd.org/faq/ports/specialtopics.html#SharedLibs # @@ -912,9 +908,9 @@ class CLikeCompiler: else: prefixes = ['lib', ''] # Library suffixes and prefixes - if mesonlib.for_darwin(env): + if env.machines[self.for_machine].is_darwin(): shlibext = ['dylib', 'so'] - elif mesonlib.for_windows(env): + elif env.machines[self.for_machine].is_windows(): # FIXME: .lib files can be import or static so we should read the # file, figure out which one it is, and reject the wrong kind. if isinstance(self, compilers.VisualStudioLikeCompiler): @@ -923,7 +919,7 @@ class CLikeCompiler: shlibext = ['dll.a', 'lib', 'dll'] # Yep, static libraries can also be foo.lib stlibext += ['lib'] - elif mesonlib.for_cygwin(env): + elif env.machines[self.for_machine].is_cygwin(): shlibext = ['dll', 'dll.a'] prefixes = ['cyg'] + prefixes else: @@ -1074,11 +1070,7 @@ class CLikeCompiler: commands = self.get_exelist() + ['-v', '-E', '-'] commands += self.get_always_args() # Add CFLAGS/CXXFLAGS/OBJCFLAGS/OBJCXXFLAGS from the env - if env.is_cross_build() and not self.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - commands += env.coredata.get_external_args(for_machine, self.language) + commands += env.coredata.get_external_args(self.for_machine, self.language) mlog.debug('Finding framework path by running: ', ' '.join(commands), '\n') os_env = os.environ.copy() os_env['LC_ALL'] = 'C' @@ -1127,12 +1119,14 @@ class CLikeCompiler: return self.find_framework_impl(name, env, extra_dirs, allow_system) def thread_flags(self, env): - if mesonlib.for_haiku(env) or mesonlib.for_darwin(env): + host_m = env.machines[self.for_machine] + if host_m.is_haiku() or host_m.is_darwin(): return [] return ['-pthread'] def thread_link_flags(self, env): - if mesonlib.for_haiku(env) or mesonlib.for_darwin(env): + host_m = env.machines[self.for_machine] + if host_m.is_haiku() or host_m.is_darwin(): return [] return ['-pthread'] @@ -1190,8 +1184,8 @@ class CLikeCompiler: def has_func_attribute(self, name, env): # Just assume that if we're not on windows that dllimport and dllexport # don't work - if not (mesonlib.for_windows(env) or - mesonlib.for_cygwin(env)): + m = env.machines[self.for_machine] + if not (m.is_windows() or m.is_cygwin()): if name in ['dllimport', 'dllexport']: return False, False diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 3ad80fef7..0a228b4b6 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -21,7 +21,7 @@ from .. import coredata from .. import mlog from .. import mesonlib from ..mesonlib import ( - EnvironmentException, MesonException, OrderedSet, + EnvironmentException, MachineChoice, MesonException, OrderedSet, version_compare, Popen_safe ) from ..envconfig import ( @@ -871,7 +871,7 @@ class Compiler: # manually searched. internal_libs = () - def __init__(self, exelist, version, **kwargs): + def __init__(self, exelist, version, for_machine: MachineChoice, **kwargs): if isinstance(exelist, str): self.exelist = [exelist] elif isinstance(exelist, list): @@ -889,6 +889,7 @@ class Compiler: self.full_version = kwargs['full_version'] else: self.full_version = None + self.for_machine = for_machine self.base_options = [] def __repr__(self): @@ -2183,7 +2184,7 @@ class ClangCompiler(GnuLikeCompiler): class ArmclangCompiler: def __init__(self, compiler_type): - if not self.is_cross: + if self.is_cross: raise EnvironmentException('armclang supports only cross-compilation.') # Check whether 'armlink.exe' is available in path self.linker_exe = 'armlink.exe' diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 253525a5c..e43d839dd 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -19,7 +19,7 @@ import typing from .. import coredata from .. import mlog -from ..mesonlib import MesonException, version_compare +from ..mesonlib import MesonException, MachineChoice, version_compare from .compilers import ( gnu_winlibs, @@ -55,11 +55,11 @@ class CPPCompiler(CLikeCompiler, Compiler): except KeyError: raise MesonException('Unknown function attribute "{}"'.format(name)) - def __init__(self, exelist, version, is_cross: bool, + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap: typing.Optional[str] = None, **kwargs): # If a child ObjCPP class has already set it, don't set it ourselves self.language = 'cpp' - Compiler.__init__(self, exelist, version, **kwargs) + Compiler.__init__(self, exelist, version, for_machine, **kwargs) CLikeCompiler.__init__(self, is_cross, exe_wrap) def get_display_language(self): @@ -147,8 +147,8 @@ class CPPCompiler(CLikeCompiler, Compiler): class ClangCPPCompiler(ClangCompiler, CPPCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) ClangCompiler.__init__(self, compiler_type) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], @@ -185,8 +185,8 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler): class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) ArmclangCompiler.__init__(self, compiler_type) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], @@ -221,8 +221,8 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): class GnuCPPCompiler(GnuCompiler, CPPCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrap, defines, **kwargs): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrap, defines, **kwargs): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs) GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], @@ -272,14 +272,14 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): class PGICPPCompiler(PGICompiler, CPPCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) PGICompiler.__init__(self, compiler_type) class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None, **kwargs): - GnuCPPCompiler.__init__(self, exelist, version, compiler_type, is_cross, exe_wrapper, defines, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None, **kwargs): + GnuCPPCompiler.__init__(self, exelist, version, compiler_type, for_machine, is_cross, exe_wrapper, defines, **kwargs) ElbrusCompiler.__init__(self, compiler_type, defines) # It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98. @@ -308,8 +308,8 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrap, **kwargs): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrap, **kwargs): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs) IntelGnuLikeCompiler.__init__(self, compiler_type) self.lang_header = 'c++-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', @@ -441,8 +441,8 @@ class CPP11AsCPP14Mixin: class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler): - def __init__(self, exelist, version, is_cross, exe_wrap, target): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap, target): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap) VisualStudioLikeCompiler.__init__(self, target) self.base_options = ['b_pch', 'b_vscrt'] # FIXME add lto, pgo and the like self.id = 'msvc' @@ -474,8 +474,8 @@ class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixi return args class ClangClCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler): - def __init__(self, exelist, version, is_cross, exe_wrap, target): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap) VisualStudioLikeCompiler.__init__(self, target) self.id = 'clang-cl' @@ -486,8 +486,8 @@ class ClangClCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, Vi class IntelClCPPCompiler(VisualStudioLikeCPPCompilerMixin, IntelVisualStudioLikeCompiler, CPPCompiler): - def __init__(self, exelist, version, is_cross, exe_wrap, target): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrap, target): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap) IntelVisualStudioLikeCompiler.__init__(self, target) def get_options(self): @@ -497,8 +497,8 @@ class IntelClCPPCompiler(VisualStudioLikeCPPCompilerMixin, IntelVisualStudioLike class ArmCPPCompiler(ArmCompiler, CPPCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrap=None, **kwargs): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrap=None, **kwargs): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs) ArmCompiler.__init__(self, compiler_type) def get_options(self): @@ -525,8 +525,8 @@ class ArmCPPCompiler(ArmCompiler, CPPCompiler): class CcrxCPPCompiler(CcrxCompiler, CPPCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrap=None, **kwargs): - CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrap=None, **kwargs): + CPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrap, **kwargs) CcrxCompiler.__init__(self, compiler_type) # Override CCompiler.get_always_args diff --git a/mesonbuild/compilers/cs.py b/mesonbuild/compilers/cs.py index c6355f28f..8069ab19e 100644 --- a/mesonbuild/compilers/cs.py +++ b/mesonbuild/compilers/cs.py @@ -17,7 +17,7 @@ import os.path, subprocess from ..mesonlib import EnvironmentException from ..mesonlib import is_windows -from .compilers import Compiler, mono_buildtype_args +from .compilers import Compiler, MachineChoice, mono_buildtype_args cs_optimization_args = {'0': [], 'g': [], @@ -28,9 +28,9 @@ cs_optimization_args = {'0': [], } class CsCompiler(Compiler): - def __init__(self, exelist, version, comp_id, runner=None): + def __init__(self, exelist, version, for_machine: MachineChoice, comp_id, runner=None): self.language = 'cs' - super().__init__(exelist, version) + super().__init__(exelist, version, for_machine) self.id = comp_id self.is_cross = False self.runner = runner @@ -143,14 +143,14 @@ class CsCompiler(Compiler): return cs_optimization_args[optimization_level] class MonoCompiler(CsCompiler): - def __init__(self, exelist, version): - super().__init__(exelist, version, 'mono', + def __init__(self, exelist, version, for_machine: MachineChoice): + super().__init__(exelist, version, for_machine, 'mono', 'mono') class VisualStudioCsCompiler(CsCompiler): - def __init__(self, exelist, version): - super().__init__(exelist, version, 'csc') + def __init__(self, exelist, version, for_machine: MachineChoice): + super().__init__(exelist, version, for_machine, 'csc') def get_buildtype_args(self, buildtype): res = mono_buildtype_args[buildtype] diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 51a1300f9..3c38c09da 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -15,15 +15,15 @@ import re, os.path from .. import mlog -from ..mesonlib import EnvironmentException, Popen_safe +from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe from .compilers import (Compiler, cuda_buildtype_args, cuda_optimization_args, cuda_debug_args, CompilerType, get_gcc_soname_args) class CudaCompiler(Compiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None): if not hasattr(self, 'language'): self.language = 'cuda' - super().__init__(exelist, version) + super().__init__(exelist, version, for_machine) self.is_cross = is_cross self.exe_wrapper = exe_wrapper self.id = 'nvcc' diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 46cc0541e..b7bc49a13 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -73,11 +73,10 @@ class DCompiler(Compiler): 'mtd': ['-mscrtlib=libcmtd'], } - def __init__(self, exelist, version, is_cross, arch, **kwargs): + def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs): self.language = 'd' - super().__init__(exelist, version, **kwargs) + super().__init__(exelist, version, for_machine, **kwargs) self.id = 'unknown' - self.is_cross = is_cross self.arch = arch def sanity_check(self, work_dir, environment): @@ -308,17 +307,12 @@ class DCompiler(Compiler): # Add link flags needed to find dependencies args += d.get_link_args() - if env.is_cross_build() and not self.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - if mode == 'compile': # Add DFLAGS from the env - args += env.coredata.get_external_args(for_machine, self.language) + args += env.coredata.get_external_args(self.for_machine, self.language) elif mode == 'link': # Add LDFLAGS from the env - args += env.coredata.get_external_link_args(for_machine, self.language) + args += env.coredata.get_external_link_args(self.for_machine, self.language) # extra_args must override all other arguments, so we add them last args += extra_args return args @@ -494,8 +488,8 @@ class DCompiler(Compiler): return ['-pthread'] class GnuDCompiler(DCompiler): - def __init__(self, exelist, version, is_cross, arch, **kwargs): - DCompiler.__init__(self, exelist, version, is_cross, arch, **kwargs) + def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs): + DCompiler.__init__(self, exelist, version, for_machine, arch, **kwargs) self.id = 'gcc' default_warn_args = ['-Wall', '-Wdeprecated'] self.warn_args = {'0': [], @@ -557,8 +551,8 @@ class GnuDCompiler(DCompiler): return gnu_optimization_args[optimization_level] class LLVMDCompiler(DCompiler): - def __init__(self, exelist, version, is_cross, arch, **kwargs): - DCompiler.__init__(self, exelist, version, is_cross, arch, **kwargs) + def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs): + DCompiler.__init__(self, exelist, version, for_machine, arch, **kwargs) self.id = 'llvm' self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt'] @@ -595,8 +589,8 @@ class LLVMDCompiler(DCompiler): class DmdDCompiler(DCompiler): - def __init__(self, exelist, version, is_cross, arch, **kwargs): - DCompiler.__init__(self, exelist, version, is_cross, arch, **kwargs) + def __init__(self, exelist, version, for_machine: MachineChoice, arch, **kwargs): + DCompiler.__init__(self, exelist, version, for_machine, arch, **kwargs) self.id = 'dmd' self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt'] diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 5de1de42c..fe23b6b81 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -40,9 +40,9 @@ from mesonbuild.mesonlib import ( class FortranCompiler(CLikeCompiler, Compiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwargs): + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwargs): self.language = 'fortran' - Compiler.__init__(self, exelist, version, **kwargs) + Compiler.__init__(self, exelist, version, for_machine, **kwargs) CLikeCompiler.__init__(self, is_cross, exe_wrapper) self.id = 'unknown' @@ -62,12 +62,8 @@ class FortranCompiler(CLikeCompiler, Compiler): source_name.write_text('print *, "Fortran compilation is working."; end') - if environment.is_cross_build() and not self.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - extra_flags = environment.coredata.get_external_args(for_machine, self.language) - extra_flags += environment.coredata.get_external_link_args(for_machine, self.language) + extra_flags = environment.coredata.get_external_args(self.for_machine, self.language) + extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language) extra_flags += self.get_always_args() # %% build the test executable pc = subprocess.Popen(self.exelist + extra_flags + [str(source_name), '-o', str(binary_name)]) @@ -167,8 +163,8 @@ class FortranCompiler(CLikeCompiler, Compiler): class GnuFortranCompiler(GnuCompiler, FortranCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None, **kwargs): - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None, **kwargs): + FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwargs) GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall'] self.warn_args = {'0': [], @@ -189,13 +185,13 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): return ['-lgfortran', '-lm'] class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None, **kwargs): - GnuFortranCompiler.__init__(self, exelist, version, compiler_type, is_cross, exe_wrapper, defines, **kwargs) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None, **kwargs): + GnuFortranCompiler.__init__(self, exelist, version, compiler_type, for_machine, is_cross, exe_wrapper, defines, **kwargs) ElbrusCompiler.__init__(self, compiler_type, defines) class G95FortranCompiler(FortranCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): + FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) self.id = 'g95' default_warn_args = ['-Wall'] self.warn_args = {'0': [], @@ -212,8 +208,8 @@ class G95FortranCompiler(FortranCompiler): class SunFortranCompiler(FortranCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): + FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) self.id = 'sun' def get_dependency_gen_args(self, outtarget, outfile): @@ -236,9 +232,9 @@ class SunFortranCompiler(FortranCompiler): class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): self.file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp') - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) + FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) # FIXME: Add support for OS X and Windows in detect_fortran_compiler so # we are sent the type of compiler IntelGnuLikeCompiler.__init__(self, CompilerType.ICC_STANDARD) @@ -293,8 +289,8 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): class PathScaleFortranCompiler(FortranCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): + FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) self.id = 'pathscale' default_warn_args = ['-fullwarn'] self.warn_args = {'0': [], @@ -307,8 +303,8 @@ class PathScaleFortranCompiler(FortranCompiler): class PGIFortranCompiler(PGICompiler, FortranCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwags): - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): + FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) PGICompiler.__init__(self, compiler_type) def language_stdlib_only_link_flags(self) -> List[str]: @@ -316,8 +312,8 @@ class PGIFortranCompiler(PGICompiler, FortranCompiler): '-lpgf90rtl', '-lpgftnrtl', '-lrt'] class FlangFortranCompiler(ClangCompiler, FortranCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): + FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) ClangCompiler.__init__(self, CompilerType.CLANG_STANDARD) self.id = 'flang' default_warn_args = ['-Minform=inform'] @@ -327,8 +323,8 @@ class FlangFortranCompiler(ClangCompiler, FortranCompiler): '3': default_warn_args} class Open64FortranCompiler(FortranCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): + FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) self.id = 'open64' default_warn_args = ['-fullwarn'] self.warn_args = {'0': [], @@ -341,8 +337,8 @@ class Open64FortranCompiler(FortranCompiler): class NAGFortranCompiler(FortranCompiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): - FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None, **kwags): + FortranCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper, **kwags) self.id = 'nagfor' def get_warn_args(self, level): diff --git a/mesonbuild/compilers/java.py b/mesonbuild/compilers/java.py index 5d7f865cb..ea1fa0f76 100644 --- a/mesonbuild/compilers/java.py +++ b/mesonbuild/compilers/java.py @@ -14,14 +14,14 @@ import os.path, shutil, subprocess -from ..mesonlib import EnvironmentException +from ..mesonlib import EnvironmentException, MachineChoice from .compilers import Compiler, java_buildtype_args class JavaCompiler(Compiler): - def __init__(self, exelist, version): + def __init__(self, exelist, version, for_machine: MachineChoice): self.language = 'java' - super().__init__(exelist, version) + super().__init__(exelist, version, for_machine) self.id = 'unknown' self.is_cross = False self.javarunner = 'java' diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index 55311ed6f..f9ca793be 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -21,9 +21,9 @@ from .clike import CLikeCompiler from .compilers import Compiler, ClangCompiler, GnuCompiler class ObjCCompiler(CLikeCompiler, Compiler): - def __init__(self, exelist, version, is_cross: bool, exe_wrap: typing.Optional[str]): + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap: typing.Optional[str]): self.language = 'objc' - Compiler.__init__(self, exelist, version) + Compiler.__init__(self, exelist, version, for_machine) CLikeCompiler.__init__(self, is_cross, exe_wrap) def get_display_language(self): @@ -33,15 +33,11 @@ class ObjCCompiler(CLikeCompiler, Compiler): # TODO try to use sanity_check_impl instead of duplicated code source_name = os.path.join(work_dir, 'sanitycheckobjc.m') binary_name = os.path.join(work_dir, 'sanitycheckobjc') - if environment.is_cross_build() and not self.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - extra_flags = environment.coredata.get_external_args(for_machine, self.language) + extra_flags = environment.coredata.get_external_args(self.for_machine, self.language) if self.is_cross: extra_flags += self.get_compile_only_args() else: - extra_flags += environment.coredata.get_external_link_args(for_machine, self.language) + extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language) with open(source_name, 'w') as ofile: ofile.write('#import\n' 'int main(int argc, char **argv) { return 0; }\n') @@ -59,8 +55,8 @@ class ObjCCompiler(CLikeCompiler, Compiler): class GnuObjCCompiler(GnuCompiler, ObjCCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None): - ObjCCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None): + ObjCCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper) GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], @@ -70,8 +66,8 @@ class GnuObjCCompiler(GnuCompiler, ObjCCompiler): class ClangObjCCompiler(ClangCompiler, ObjCCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None): - ObjCCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None): + ObjCCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper) ClangCompiler.__init__(self, compiler_type) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'0': [], diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index 6743f89f3..2e81b4c39 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -21,9 +21,9 @@ from .clike import CLikeCompiler from .compilers import Compiler, ClangCompiler, GnuCompiler class ObjCPPCompiler(CLikeCompiler, Compiler): - def __init__(self, exelist, version, is_cross: bool, exe_wrap: typing.Optional[str]): + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross: bool, exe_wrap: typing.Optional[str]): self.language = 'objcpp' - Compiler.__init__(self, exelist, version) + Compiler.__init__(self, exelist, version, for_machine) CLikeCompiler.__init__(self, is_cross, exe_wrap) def get_display_language(self): @@ -33,15 +33,11 @@ class ObjCPPCompiler(CLikeCompiler, Compiler): # TODO try to use sanity_check_impl instead of duplicated code source_name = os.path.join(work_dir, 'sanitycheckobjcpp.mm') binary_name = os.path.join(work_dir, 'sanitycheckobjcpp') - if environment.is_cross_build() and not self.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - extra_flags = environment.coredata.get_external_args(for_machine, self.language) + extra_flags = environment.coredata.get_external_args(self.for_machine, self.language) if self.is_cross: extra_flags += self.get_compile_only_args() else: - extra_flags += environment.coredata.get_external_link_args(for_machine, self.language) + extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language) with open(source_name, 'w') as ofile: ofile.write('#import\n' 'class MyClass;' @@ -60,8 +56,8 @@ class ObjCPPCompiler(CLikeCompiler, Compiler): class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None): - ObjCPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None, defines=None): + ObjCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper) GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], @@ -71,8 +67,8 @@ class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler): class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler): - def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None): - ObjCPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + def __init__(self, exelist, version, compiler_type, for_machine: MachineChoice, is_cross, exe_wrapper=None): + ObjCPPCompiler.__init__(self, exelist, version, for_machine, is_cross, exe_wrapper) ClangCompiler.__init__(self, compiler_type) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'0': [], diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index 410125ae3..17b7e3b03 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -14,7 +14,7 @@ import subprocess, os.path -from ..mesonlib import EnvironmentException, Popen_safe +from ..mesonlib import EnvironmentException, MachineChoice, Popen_safe from .compilers import Compiler, rust_buildtype_args, clike_debug_args @@ -27,12 +27,12 @@ rust_optimization_args = {'0': [], } class RustCompiler(Compiler): - def __init__(self, exelist, version, is_cross, exe_wrapper=None): + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross, exe_wrapper=None): self.language = 'rust' - super().__init__(exelist, version) - self.is_cross = is_cross + super().__init__(exelist, version, for_machine) self.exe_wrapper = exe_wrapper self.id = 'rustc' + self.is_cross = is_cross def needs_static_linker(self): return False diff --git a/mesonbuild/compilers/swift.py b/mesonbuild/compilers/swift.py index 17705acb4..00382649b 100644 --- a/mesonbuild/compilers/swift.py +++ b/mesonbuild/compilers/swift.py @@ -27,12 +27,12 @@ swift_optimization_args = {'0': [], } class SwiftCompiler(Compiler): - def __init__(self, exelist, version): + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross): self.language = 'swift' - super().__init__(exelist, version) + super().__init__(exelist, version, for_machine) self.version = version self.id = 'llvm' - self.is_cross = False + self.is_cross = is_cross def get_linker_exelist(self): return self.exelist[:] @@ -102,15 +102,11 @@ class SwiftCompiler(Compiler): src = 'swifttest.swift' source_name = os.path.join(work_dir, src) output_name = os.path.join(work_dir, 'swifttest') - if environment.is_cross_build() and not self.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - extra_flags = environment.coredata.get_external_args(for_machine, self.language) + extra_flags = environment.coredata.get_external_args(self.for_machine, self.language) if self.is_cross: extra_flags += self.get_compile_only_args() else: - extra_flags += environment.coredata.get_external_link_args(for_machine, self.language) + extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language) with open(source_name, 'w') as ofile: ofile.write('''print("Swift compilation is working.") ''') diff --git a/mesonbuild/compilers/vala.py b/mesonbuild/compilers/vala.py index c0b2a6824..0a612ae09 100644 --- a/mesonbuild/compilers/vala.py +++ b/mesonbuild/compilers/vala.py @@ -20,12 +20,12 @@ from ..mesonlib import EnvironmentException, MachineChoice, version_compare from .compilers import Compiler class ValaCompiler(Compiler): - def __init__(self, exelist, version): + def __init__(self, exelist, version, for_machine: MachineChoice, is_cross): self.language = 'vala' - super().__init__(exelist, version) + super().__init__(exelist, version, for_machine) self.version = version + self.is_cross = is_cross self.id = 'valac' - self.is_cross = False self.base_options = ['b_colorout'] def name_string(self): @@ -87,15 +87,11 @@ class ValaCompiler(Compiler): def sanity_check(self, work_dir, environment): code = 'class MesonSanityCheck : Object { }' - if environment.is_cross_build() and not self.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - extra_flags = environment.coredata.get_external_args(for_machine, self.language) + extra_flags = environment.coredata.get_external_args(self.for_machine, self.language) if self.is_cross: extra_flags += self.get_compile_only_args() else: - extra_flags += environment.coredata.get_external_link_args(for_machine, self.language) + extra_flags += environment.coredata.get_external_link_args(self.for_machine, self.language) with self.cached_compile(code, environment.coredata, extra_args=extra_flags, mode='compile') as p: if p.returncode != 0: msg = 'Vala compiler {!r} can not compile programs' \ @@ -114,11 +110,7 @@ class ValaCompiler(Compiler): # no extra dirs are specified. if not extra_dirs: code = 'class MesonFindLibrary : Object { }' - if env.is_cross_build() and not self.is_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - args = env.coredata.get_external_args(for_machine, self.language) + args = env.coredata.get_external_args(self.for_machine, self.language) vapi_args = ['--pkg', libname] args += vapi_args with self.cached_compile(code, env.coredata, extra_args=args, mode='compile') as p: diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 173bdc762..9984d1c62 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -365,13 +365,11 @@ class CoreData: self.compiler_options = PerMachine({}, {}) self.base_options = {} # : Dict[str, UserOption] self.cross_files = self.__load_config_files(options.cross_file, 'cross') - self.compilers = OrderedDict() - self.cross_compilers = OrderedDict() + self.compilers = PerMachine(OrderedDict(), OrderedDict()) build_cache = DependencyCache(self.builtins_per_machine, MachineChoice.BUILD) host_cache = DependencyCache(self.builtins_per_machine, MachineChoice.BUILD) self.deps = PerMachine(build_cache, host_cache) # type: PerMachine[DependencyCache] - self.compiler_check_cache = OrderedDict() # Only to print a warning if it changes between Meson invocations. self.config_files = self.__load_config_files(options.native_file, 'native') @@ -681,35 +679,20 @@ class CoreData: self.set_options(options, subproject) - def process_new_compilers(self, lang: str, comp, cross_comp, env): + def process_new_compiler(self, lang: str, comp, env): from . import compilers - self.compilers[lang] = comp - if cross_comp is not None: - self.cross_compilers[lang] = cross_comp - - # Native compiler always exist so always add its options. - new_options_for_build = comp.get_and_default_options(env.properties.build) - if cross_comp is not None: - new_options_for_host = cross_comp.get_and_default_options(env.properties.host) - else: - new_options_for_host = comp.get_and_default_options(env.properties.host) - - opts_machines_list = [ - (new_options_for_build, MachineChoice.BUILD), - (new_options_for_host, MachineChoice.HOST), - ] + self.compilers[comp.for_machine][lang] = comp optprefix = lang + '_' - for new_options, for_machine in opts_machines_list: - for k, o in new_options.items(): - if not k.startswith(optprefix): - raise MesonException('Internal error, %s has incorrect prefix.' % k) - # prefixed compiler options affect just this machine - opt_prefix = for_machine.get_prefix() - if opt_prefix + k in env.cmd_line_options: - o.set_value(env.cmd_line_options[opt_prefix + k]) - self.compiler_options[for_machine].setdefault(k, o) + for k, o in comp.get_and_default_options(env.properties[comp.for_machine]).items(): + if not k.startswith(optprefix): + raise MesonException('Internal error, %s has incorrect prefix.' % k) + # prefixed compiler options affect just this machine + opt_prefix = comp.for_machine.get_prefix() + if opt_prefix + k in env.cmd_line_options: + o.set_value(env.cmd_line_options[opt_prefix + k]) + self.compiler_options[comp.for_machine].setdefault(k, o) enabled_opts = [] for optname in comp.base_options: diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 9a142322c..4c0d410bc 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -239,10 +239,13 @@ class InternalDependency(Dependency): final_link_args, final_libraries, final_whole_libraries, final_sources, final_deps) +class HasNativeKwarg: + def __init__(self, kwargs): + self.for_machine = MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST -class ExternalDependency(Dependency): +class ExternalDependency(Dependency, HasNativeKwarg): def __init__(self, type_name, environment, language, kwargs): - super().__init__(type_name, kwargs) + Dependency.__init__(self, type_name, kwargs) self.env = environment self.name = type_name # default self.is_found = False @@ -255,18 +258,12 @@ class ExternalDependency(Dependency): self.static = kwargs.get('static', False) if not isinstance(self.static, bool): raise DependencyException('Static keyword must be boolean') - # Is this dependency for cross-compilation? - if 'native' in kwargs and self.env.is_cross_build(): - self.want_cross = not kwargs['native'] - else: - self.want_cross = self.env.is_cross_build() + # Is this dependency to be run on the build platform? + HasNativeKwarg.__init__(self, kwargs) self.clib_compiler = None # Set the compiler that will be used by this dependency # This is only used for configuration checks - if self.want_cross: - compilers = self.env.coredata.cross_compilers - else: - compilers = self.env.coredata.compilers + compilers = self.env.coredata.compilers[self.for_machine] # Set the compiler for this dependency if a language is specified, # else try to pick something that looks usable. if self.language: @@ -561,18 +558,13 @@ class PkgConfigDependency(ExternalDependency): # stored in the pickled coredata and recovered. self.pkgbin = None - if not self.want_cross and environment.is_cross_build(): - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - # Create an iterator of options def search(): # Lookup in cross or machine file. - potential_pkgpath = environment.binaries[for_machine].lookup_entry('pkgconfig') + potential_pkgpath = environment.binaries[self.for_machine].lookup_entry('pkgconfig') if potential_pkgpath is not None: mlog.debug('Pkg-config binary for {} specified from cross file, native file, ' - 'or env var as {}'.format(for_machine, potential_pkgpath)) + 'or env var as {}'.format(self.for_machine, potential_pkgpath)) yield ExternalProgram.from_entry('pkgconfig', potential_pkgpath) # We never fallback if the user-specified option is no good, so # stop returning options. @@ -580,42 +572,42 @@ class PkgConfigDependency(ExternalDependency): mlog.debug('Pkg-config binary missing from cross or native file, or env var undefined.') # Fallback on hard-coded defaults. # TODO prefix this for the cross case instead of ignoring thing. - if environment.machines.matches_build_machine(for_machine): + if environment.machines.matches_build_machine(self.for_machine): for potential_pkgpath in environment.default_pkgconfig: mlog.debug('Trying a default pkg-config fallback at', potential_pkgpath) yield ExternalProgram(potential_pkgpath, silent=True) # Only search for pkg-config for each machine the first time and store # the result in the class definition - if PkgConfigDependency.class_pkgbin[for_machine] is False: - mlog.debug('Pkg-config binary for %s is cached as not found.' % for_machine) - elif PkgConfigDependency.class_pkgbin[for_machine] is not None: - mlog.debug('Pkg-config binary for %s is cached.' % for_machine) + if PkgConfigDependency.class_pkgbin[self.for_machine] is False: + mlog.debug('Pkg-config binary for %s is cached as not found.' % self.for_machine) + elif PkgConfigDependency.class_pkgbin[self.for_machine] is not None: + mlog.debug('Pkg-config binary for %s is cached.' % self.for_machine) else: - assert PkgConfigDependency.class_pkgbin[for_machine] is None - mlog.debug('Pkg-config binary for %s is not cached.' % for_machine) + assert PkgConfigDependency.class_pkgbin[self.for_machine] is None + mlog.debug('Pkg-config binary for %s is not cached.' % self.for_machine) for potential_pkgbin in search(): mlog.debug('Trying pkg-config binary {} for machine {} at {}' - .format(potential_pkgbin.name, for_machine, potential_pkgbin.command)) + .format(potential_pkgbin.name, self.for_machine, potential_pkgbin.command)) version_if_ok = self.check_pkgconfig(potential_pkgbin) if not version_if_ok: continue if not self.silent: mlog.log('Found pkg-config:', mlog.bold(potential_pkgbin.get_path()), '(%s)' % version_if_ok) - PkgConfigDependency.class_pkgbin[for_machine] = potential_pkgbin + PkgConfigDependency.class_pkgbin[self.for_machine] = potential_pkgbin break else: if not self.silent: mlog.log('Found Pkg-config:', mlog.red('NO')) # Set to False instead of None to signify that we've already # searched for it and not found it - PkgConfigDependency.class_pkgbin[for_machine] = False + PkgConfigDependency.class_pkgbin[self.for_machine] = False - self.pkgbin = PkgConfigDependency.class_pkgbin[for_machine] + self.pkgbin = PkgConfigDependency.class_pkgbin[self.for_machine] if self.pkgbin is False: self.pkgbin = None - msg = 'Pkg-config binary for machine %s not found. Giving up.' % for_machine + msg = 'Pkg-config binary for machine %s not found. Giving up.' % self.for_machine if self.required: raise DependencyException(msg) else: @@ -665,12 +657,7 @@ class PkgConfigDependency(ExternalDependency): else: env = env.copy() - if not self.want_cross and self.env.is_cross_build(): - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - - extra_paths = self.env.coredata.builtins_per_machine[for_machine]['pkg_config_path'].value + extra_paths = self.env.coredata.builtins_per_machine[self.for_machine]['pkg_config_path'].value new_pkg_config_path = ':'.join([p for p in extra_paths]) mlog.debug('PKG_CONFIG_PATH: ' + new_pkg_config_path) env['PKG_CONFIG_PATH'] = new_pkg_config_path @@ -1059,7 +1046,7 @@ class CMakeDependency(ExternalDependency): # List of successfully found modules self.found_modules = [] - self.cmakebin, self.cmakevers, for_machine = self.find_cmake_binary(environment, self.want_cross, self.silent) + self.cmakebin, self.cmakevers, for_machine = self.find_cmake_binary(environment, self.for_machine, self.silent) if self.cmakebin is False: self.cmakebin = None msg = 'No CMake binary for machine %s not found. Giving up.' % for_machine @@ -1068,9 +1055,9 @@ class CMakeDependency(ExternalDependency): mlog.debug(msg) return - if CMakeDependency.class_cmakeinfo[for_machine] is None: - CMakeDependency.class_cmakeinfo[for_machine] = self._get_cmake_info() - self.cmakeinfo = CMakeDependency.class_cmakeinfo[for_machine] + if CMakeDependency.class_cmakeinfo[self.for_machine] is None: + CMakeDependency.class_cmakeinfo[self.for_machine] = self._get_cmake_info() + self.cmakeinfo = CMakeDependency.class_cmakeinfo[self.for_machine] if self.cmakeinfo is None: raise self._gen_exception('Unable to obtain CMake system information') @@ -1082,24 +1069,16 @@ class CMakeDependency(ExternalDependency): if cm_path: cm_args.append('-DCMAKE_MODULE_PATH=' + ';'.join(cm_path)) - pref_path = self.env.coredata.builtins_per_machine[for_machine]['cmake_prefix_path'].value + pref_path = self.env.coredata.builtins_per_machine[self.for_machine]['cmake_prefix_path'].value if pref_path: cm_args.append('-DCMAKE_PREFIX_PATH={}'.format(';'.join(pref_path))) - if not self._preliminary_find_check(name, cm_path, pref_path, environment.machines[for_machine]): + if not self._preliminary_find_check(name, cm_path, pref_path, environment.machines[self.for_machine]): return self._detect_dep(name, modules, cm_args) - @staticmethod - def find_cmake_binary(environment: Environment, want_cross: bool = False, silent: bool = False) -> Tuple[str, str, MachineChoice]: - # When finding dependencies for cross-compiling, we don't care about - # the 'native' CMake binary - # TODO: Test if this works as expected - if environment.is_cross_build() and not want_cross: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST - + @classmethod + def find_cmake_binary(cls, environment: Environment, for_machine: MachineChoice, silent: bool = False) -> Tuple[str, str, MachineChoice]: # Create an iterator of options def search(): # Lookup in cross or machine file. @@ -1130,7 +1109,7 @@ class CMakeDependency(ExternalDependency): for potential_cmakebin in search(): mlog.debug('Trying CMake binary {} for machine {} at {}' .format(potential_cmakebin.name, for_machine, potential_cmakebin.command)) - version_if_ok = CMakeDependency.check_cmake(potential_cmakebin) + version_if_ok = cls.check_cmake(potential_cmakebin) if not version_if_ok: continue if not silent: @@ -2098,6 +2077,8 @@ class DubDependency(ExternalDependency): class ExternalProgram: windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd') + # An 'ExternalProgram' always runs on the build machine + for_machine = MachineChoice.BUILD def __init__(self, name: str, command: typing.Optional[typing.List[str]] = None, silent: bool = False, search_dir: typing.Optional[str] = None): @@ -2479,7 +2460,7 @@ def get_dep_identifier(name, kwargs) -> Tuple: identifier = (name, ) for key, value in kwargs.items(): # 'version' is irrelevant for caching; the caller must check version matches - # 'native' is handled above with `want_cross` + # 'native' is handled above with `for_machine` # 'required' is irrelevant for caching; the caller handles it separately # 'fallback' subprojects cannot be cached -- they must be initialized # 'default_options' is only used in fallback case @@ -2520,12 +2501,9 @@ def find_external_dependency(name, env, kwargs): # display the dependency name with correct casing display_name = display_name_map.get(lname, lname) - # if this isn't a cross-build, it's uninteresting if native: is used or not - if not env.is_cross_build(): - type_text = 'Dependency' - else: - type_text = 'Native' if kwargs.get('native', False) else 'Cross' - type_text += ' dependency' + for_machine = MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST + + type_text = PerMachine('Build-time', 'Run-time')[for_machine] + ' dependency' # build a list of dependency methods to try candidates = _build_external_dependency_list(name, env, kwargs) @@ -2648,12 +2626,12 @@ def _build_external_dependency_list(name, env: Environment, kwargs: Dict[str, An return candidates -def strip_system_libdirs(environment, link_args): +def strip_system_libdirs(environment, for_machine: MachineChoice, link_args): """Remove -L arguments. leaving these in will break builds where a user has a version of a library in the system path, and a different version not in the system path if they want to link against the non-system path version. """ - exclude = {'-L{}'.format(p) for p in environment.get_compiler_system_dirs()} + exclude = {'-L{}'.format(p) for p in environment.get_compiler_system_dirs(for_machine)} return [l for l in link_args if l not in exclude] diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index a955b6a75..5c9e0b5d5 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -123,13 +123,13 @@ class BoostDependency(ExternalDependency): self.libdir = os.environ['BOOST_LIBRARYDIR'] if self.boost_root is None: - if mesonlib.for_windows(self.env): + if self.env.machines[self.for_machine].is_windows(): self.boost_roots = self.detect_win_roots() else: self.boost_roots = self.detect_nix_roots() if self.incdir is None: - if mesonlib.for_windows(self.env): + if self.env.machines[self.for_machine].is_windows(): self.incdir = self.detect_win_incdir() else: self.incdir = self.detect_nix_incdir() @@ -268,7 +268,7 @@ class BoostDependency(ExternalDependency): pass # 2. Fall back to the old method else: - if mesonlib.for_windows(self.env): + if self.env.machines[self.for_machine].is_windows(): self.detect_lib_modules_win() else: self.detect_lib_modules_nix() @@ -289,8 +289,8 @@ class BoostDependency(ExternalDependency): def compiler_tag(self): tag = None - compiler = self.env.detect_cpp_compiler(self.want_cross) - if mesonlib.for_windows(self.env): + compiler = self.env.detect_cpp_compiler(self.for_machine) + if self.env.machines[self.for_machine].is_windows(): if compiler.get_id() in ['msvc', 'clang-cl']: comp_ts_version = compiler.get_toolset_version() compiler_ts = comp_ts_version.split('.') @@ -304,10 +304,10 @@ class BoostDependency(ExternalDependency): if not self.is_multithreading: return '' - if mesonlib.for_darwin(self.env): + if self.env.machines[self.for_machine].is_darwin(): # - Mac: requires -mt for multithreading, so should not fall back to non-mt libraries. return '-mt' - elif mesonlib.for_windows(self.env): + elif self.env.machines[self.for_machine].is_windows(): # - Windows: requires -mt for multithreading, so should not fall back to non-mt libraries. return '-mt' else: @@ -323,12 +323,12 @@ class BoostDependency(ExternalDependency): def arch_tag(self): # currently only applies to windows msvc installed binaries - if self.env.detect_cpp_compiler(self.want_cross).get_id() not in ['msvc', 'clang-cl']: + if self.env.detect_cpp_compiler(self.for_machine).get_id() not in ['msvc', 'clang-cl']: return '' # pre-compiled binaries only added arch tag for versions > 1.64 if float(self.version) < 1.65: return '' - arch = detect_cpu_family(self.env.coredata.compilers) + arch = detect_cpu_family(self.env.coredata.compilers.host) if arch == 'x86': return '-x32' elif arch == 'x86_64': @@ -340,16 +340,16 @@ class BoostDependency(ExternalDependency): # FIXME - how to handle different distributions, e.g. for Mac? Currently we handle homebrew and macports, but not fink. def abi_tags(self): - if mesonlib.for_windows(self.env): + if self.env.machines[self.for_machine].is_windows(): return [self.versioned_abi_tag(), self.threading_tag()] else: return [self.threading_tag()] def sourceforge_dir(self): - if self.env.detect_cpp_compiler(self.want_cross).get_id() != 'msvc': + if self.env.detect_cpp_compiler(self.for_machine).get_id() != 'msvc': return None - comp_ts_version = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version() - arch = detect_cpu_family(self.env.coredata.compilers) + comp_ts_version = self.env.detect_cpp_compiler(self.for_machine).get_toolset_version() + arch = detect_cpu_family(self.env.coredata.compilers.host) if arch == 'x86': return 'lib32-msvc-{}'.format(comp_ts_version) elif arch == 'x86_64': @@ -437,7 +437,7 @@ class BoostDependency(ExternalDependency): def detect_lib_modules_nix(self): if self.static: libsuffix = 'a' - elif mesonlib.for_darwin(self.env): + elif self.env.machines[self.for_machine].is_darwin(): libsuffix = 'dylib' else: libsuffix = 'so' diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 19991c3e9..5fd547b57 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -24,20 +24,21 @@ from .. import mesonlib, mlog from ..mesonlib import version_compare, stringlistify, extract_as_list, MachineChoice from .base import ( DependencyException, DependencyMethods, ExternalDependency, PkgConfigDependency, - strip_system_libdirs, ConfigToolDependency, CMakeDependency + strip_system_libdirs, ConfigToolDependency, CMakeDependency, HasNativeKwarg ) from .misc import ThreadDependency from typing import List, Tuple -def get_shared_library_suffix(environment, native): +def get_shared_library_suffix(environment, for_machine: MachineChoice): """This is only gauranteed to work for languages that compile to machine code, not for languages like C# that use a bytecode and always end in .dll """ - if mesonlib.for_windows(native, environment): + m = environment.machines[for_machine] + if m.is_windows(): return '.dll' - elif mesonlib.for_darwin(native, environment): + elif m.is_darwin(): return '.dylib' return '.so' @@ -203,6 +204,10 @@ class LLVMDependencyConfigTool(ConfigToolDependency): __cpp_blacklist = {'-DNDEBUG'} def __init__(self, environment, kwargs): + # Already called by `super().__init__`, but need `self.for_machine` + # before `super().__init__` is called. + HasNativeKwarg.__init__(self, kwargs) + # Ordered list of llvm-config binaries to try. Start with base, then try # newest back to oldest (3.5 is arbitrary), and finally the devel version. # Please note that llvm-config-6.0 is a development snapshot and it should @@ -227,8 +232,7 @@ class LLVMDependencyConfigTool(ConfigToolDependency): # of bits in the isa that llvm targets, for example, on x86_64 # and aarch64 the name will be llvm-config-64, on x86 and arm # it will be llvm-config-32. - m = MachineChoice.BUILD if environment.is_cross_build() and kwargs.get('native', True) else MachineChoice.HOST - if environment.machines[m].is_64_bit: + if environment.machines[self.for_machine].is_64_bit: self.tools.append('llvm-config-64') else: self.tools.append('llvm-config-32') @@ -256,7 +260,7 @@ class LLVMDependencyConfigTool(ConfigToolDependency): self._set_new_link_args(environment) else: self._set_old_link_args() - self.link_args = strip_system_libdirs(environment, self.link_args) + self.link_args = strip_system_libdirs(environment, self.for_machine, self.link_args) self.link_args = self.__fix_bogus_link_args(self.link_args) self._add_sub_dependency(ThreadDependency, environment, kwargs) @@ -271,7 +275,7 @@ class LLVMDependencyConfigTool(ConfigToolDependency): "-L IBPATH:...", if we're using an msvc like compilers convert that to "/LIBPATH", otherwise to "-L ..." """ - cpp = self.env.coredata.compilers['cpp'] + cpp = self.env.coredata.compilers[self.for_machine]['cpp'] new_args = [] for arg in args: @@ -316,7 +320,7 @@ class LLVMDependencyConfigTool(ConfigToolDependency): try: self.__check_libfiles(True) except DependencyException: - lib_ext = get_shared_library_suffix(environment, self.native) + lib_ext = get_shared_library_suffix(environment, self.for_machine) libdir = self.get_config_value(['--libdir'], 'link_args')[0] # Sort for reproducability matches = sorted(glob.iglob(os.path.join(libdir, 'libLLVM*{}'.format(lib_ext)))) diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 72ba7b3bf..a537716a6 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -213,7 +213,7 @@ class MPIDependency(ExternalDependency): if not self.is_found and mesonlib.is_windows(): # only Intel Fortran compiler is compatible with Microsoft MPI at this time. - if language == 'fortran' and environment.detect_fortran_compiler(False).name_string() != 'intel': + if language == 'fortran' and environment.detect_fortran_compiler(self.for_machine).name_string() != 'intel': return result = self._try_msmpi() if result is not None: @@ -228,7 +228,7 @@ class MPIDependency(ExternalDependency): result = [] multi_args = ('-I', ) if self.language == 'fortran': - fc = self.env.coredata.compilers['fortran'] + fc = self.env.coredata.compilers[self.for_machine]['fortran'] multi_args += fc.get_module_incdir_args() include_next = False @@ -325,7 +325,7 @@ class MPIDependency(ExternalDependency): if 'MSMPI_INC' not in os.environ: return incdir = os.environ['MSMPI_INC'] - arch = detect_cpu_family(self.env.coredata.compilers) + arch = detect_cpu_family(self.env.coredata.compilers.host) if arch == 'x86': if 'MSMPI_LIB32' not in os.environ: return @@ -396,7 +396,7 @@ class Python3Dependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('python3', environment, None, kwargs) - if self.want_cross: + if not environment.machines.matches_build_machine(self.for_machine): return self.name = 'python3' @@ -480,7 +480,7 @@ class Python3Dependency(ExternalDependency): if pyarch is None: self.is_found = False return - arch = detect_cpu_family(env.coredata.compilers) + arch = detect_cpu_family(env.coredata.compilers.host) if arch == 'x86': arch = '32' elif arch == 'x86_64': @@ -560,7 +560,7 @@ class PcapDependency(ExternalDependency): def get_pcap_lib_version(ctdep): # Since we seem to need to run a program to discover the pcap version, # we can't do that when cross-compiling - if ctdep.want_cross: + if not ctdep.env.machines.matches_build_machine(ctdep.for_machine): return None v = ctdep.clib_compiler.get_return_value('pcap_lib_version', 'string', diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index b1fa632a9..f96668b6a 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -23,8 +23,7 @@ from collections import OrderedDict from .. import mlog from .. import mesonlib from ..mesonlib import ( - MesonException, Popen_safe, extract_as_list, for_windows, - version_compare_many + MesonException, Popen_safe, extract_as_list, version_compare_many ) from ..environment import detect_cpu @@ -38,13 +37,13 @@ class GLDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('gl', environment, None, kwargs) - if mesonlib.for_darwin(self.want_cross, self.env): + if self.env.machines[self.for_machine].is_darwin(): self.is_found = True # FIXME: Use AppleFrameworks dependency self.link_args = ['-framework', 'OpenGL'] # FIXME: Detect version using self.clib_compiler return - if mesonlib.for_windows(self.want_cross, self.env): + if self.env.machines[self.for_machine].is_windows(): self.is_found = True # FIXME: Use self.clib_compiler.find_library() self.link_args = ['-lopengl32'] @@ -310,7 +309,7 @@ class QtBaseDependency(ExternalDependency): language=self.language) modules['Core'] = core - if for_windows(self.env.is_cross_build(), self.env) and self.qtmain: + if self.env.machines[self.for_machine].is_windows() and self.qtmain: # Check if we link with debug binaries debug_lib_name = self.qtpkgname + 'Core' + self._get_modules_lib_suffix(True) is_debug = False @@ -414,7 +413,7 @@ class QtBaseDependency(ExternalDependency): break self.link_args.append(libfile) - if for_windows(self.env.is_cross_build(), self.env) and self.qtmain: + if self.env.machines[self.for_machine].is_windows() and self.qtmain: if not self._link_with_qtmain(is_debug, libdir): self.is_found = False @@ -422,7 +421,7 @@ class QtBaseDependency(ExternalDependency): def _get_modules_lib_suffix(self, is_debug): suffix = '' - if for_windows(self.env.is_cross_build(), self.env): + if self.env.machines[self.for_machine].is_windows(): if is_debug: suffix += 'd' if self.qtver == '4': diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index f8603f608..ce78162a0 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -510,22 +510,6 @@ class Environment: self.default_cmake = ['cmake'] self.default_pkgconfig = ['pkg-config'] - # Various prefixes and suffixes for import libraries, shared libraries, - # static libraries, and executables. - # Versioning is added to these names in the backends as-needed. - if mesonlib.for_windows(self): - self.exe_suffix = 'exe' - self.object_suffix = 'obj' - self.win_libdir_layout = True - elif mesonlib.for_cygwin(self): - self.exe_suffix = 'exe' - self.object_suffix = 'o' - self.win_libdir_layout = True - else: - self.exe_suffix = '' - self.object_suffix = 'o' - self.win_libdir_layout = False - def create_new_coredata(self, options): # WARNING: Don't use any values from coredata in __init__. It gets # re-initialized with project options by the interpreter during @@ -631,17 +615,11 @@ class Environment: return CompilerType.GCC_CYGWIN return CompilerType.GCC_STANDARD - def _get_compilers(self, lang, want_cross): + def _get_compilers(self, lang, for_machine): ''' The list of compilers is detected in the exact same way for C, C++, ObjC, ObjC++, Fortran, CS so consolidate it here. ''' - - # This morally assumes `want_cross = !native`. It may not yet be - # consistently set that way in the non cross build case, but it doesn't - # really matter since both options are the same in that case. - for_machine = MachineChoice.HOST if want_cross else MachineChoice.BUILD - value = self.binaries[for_machine].lookup_entry(lang) if value is not None: compilers, ccache = BinaryTable.parse_entry(value) @@ -654,13 +632,11 @@ class Environment: ccache = BinaryTable.detect_ccache() if self.machines.matches_build_machine(for_machine): - is_cross = False exe_wrap = None else: - is_cross = True exe_wrap = self.get_exe_wrapper() - return compilers, ccache, is_cross, exe_wrap + return compilers, ccache, exe_wrap def _handle_exceptions(self, exceptions, binaries, bintype='compiler'): errmsg = 'Unknown {}(s): {}'.format(bintype, binaries) @@ -670,9 +646,10 @@ class Environment: errmsg += '\nRunning "{0}" gave "{1}"'.format(c, e) raise EnvironmentException(errmsg) - def _detect_c_or_cpp_compiler(self, lang, want_cross): + def _detect_c_or_cpp_compiler(self, lang, for_machine): popen_exceptions = {} - compilers, ccache, is_cross, exe_wrap = self._get_compilers(lang, want_cross) + compilers, ccache, exe_wrap = self._get_compilers(lang, for_machine) + is_cross = not self.machines.matches_build_machine(for_machine) for compiler in compilers: if isinstance(compiler, str): @@ -737,7 +714,7 @@ class Environment: else: version = self.get_gnu_version_from_defines(defines) cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler - return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap, defines, full_version=full_version) + return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, full_version=full_version) if 'armclang' in out: # The compiler version is not present in the first line of output, @@ -755,7 +732,7 @@ class Environment: full_version = arm_ver_str compiler_type = CompilerType.ARM_WIN cls = ArmclangCCompiler if lang == 'c' else ArmclangCPPCompiler - return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap, full_version=full_version) + return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version) if 'CL.EXE COMPATIBILITY' in out: # if this is clang-cl masquerading as cl, detect it as cl, not # clang @@ -771,21 +748,22 @@ class Environment: else: target = 'unknown target' cls = ClangClCCompiler if lang == 'c' else ClangClCPPCompiler - return cls(compiler, version, is_cross, exe_wrap, target) + return cls(compiler, version, for_machine, is_cross, exe_wrap, target) if 'clang' in out: - if 'Apple' in out or mesonlib.for_darwin(self): + if 'Apple' in out or self.machines[for_machine].is_darwin(): compiler_type = CompilerType.CLANG_OSX - elif 'windows' in out or mesonlib.for_windows(self): + elif 'windows' in out or self.machines[for_machine].is_windows(): compiler_type = CompilerType.CLANG_MINGW else: compiler_type = CompilerType.CLANG_STANDARD cls = ClangCCompiler if lang == 'c' else ClangCPPCompiler - return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap, full_version=full_version) + return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version) if 'Intel(R) C++ Intel(R)' in err: version = search_version(err) target = 'x86' if 'IA-32' in err else 'x86_64' cls = IntelClCCompiler if lang == 'c' else IntelClCPPCompiler - return cls(compiler, version, is_cross, exe_wrap, target) + return cls(compiler, version, for_machine, is_cross, exe_wrap, target) + return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version) if 'Microsoft' in out or 'Microsoft' in err: # Latest versions of Visual Studio print version # number to stderr but earlier ones print version @@ -804,8 +782,7 @@ class Environment: else: target = 'x86' cls = VisualStudioCCompiler if lang == 'c' else VisualStudioCPPCompiler - return cls(compiler, version, is_cross, exe_wrap, target) - + return cls(compiler, version, for_machine, is_cross, exe_wrap, target) if 'PGI Compilers' in out: if self.machines[for_machine].is_darwin(): compiler_type = CompilerType.PGI_OSX @@ -814,37 +791,37 @@ class Environment: else: compiler_type = CompilerType.PGI_STANDARD cls = PGICCompiler if lang == 'c' else PGICPPCompiler - return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap) + return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, compiler_type, exe_wrap) if '(ICC)' in out: - if self.machine[for_macine].is_darwin(): + if self.machines[for_machine].is_darwin(): compiler_type = CompilerType.ICC_OSX - elif mesonlib.for_windows(want_cross, self): + elif self.machines[for_machine].is_windows(): # TODO: fix ICC on Windows compiler_type = CompilerType.ICC_WIN else: compiler_type = CompilerType.ICC_STANDARD cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler - return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap, full_version=full_version) + return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version) if 'ARM' in out: compiler_type = CompilerType.ARM_WIN cls = ArmCCompiler if lang == 'c' else ArmCPPCompiler - return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap, full_version=full_version) + return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version) if 'RX Family' in out: compiler_type = CompilerType.CCRX_WIN cls = CcrxCCompiler if lang == 'c' else CcrxCPPCompiler - return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap, full_version=full_version) + return cls(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version) self._handle_exceptions(popen_exceptions, compilers) - def detect_c_compiler(self, want_cross): - return self._detect_c_or_cpp_compiler('c', want_cross) + def detect_c_compiler(self, for_machine): + return self._detect_c_or_cpp_compiler('c', for_machine) - def detect_cpp_compiler(self, want_cross): - return self._detect_c_or_cpp_compiler('cpp', want_cross) + def detect_cpp_compiler(self, for_machine): + return self._detect_c_or_cpp_compiler('cpp', for_machine) - def detect_cuda_compiler(self, want_cross): + def detect_cuda_compiler(self, for_machine): popen_exceptions = {} - compilers, ccache, is_cross, exe_wrap = self._get_compilers('cuda', want_cross) + compilers, ccache, exe_wrap = self._get_compilers('cuda', for_machine) for compiler in compilers: if isinstance(compiler, str): compiler = [compiler] @@ -873,12 +850,13 @@ class Environment: # the full version: version = out.strip().split('V')[-1] cls = CudaCompiler - return cls(ccache + compiler, version, is_cross, exe_wrap) + return cls(ccache + compiler, version, for_machine, exe_wrap) raise EnvironmentException('Could not find suitable CUDA compiler: "' + ' '.join(compilers) + '"') - def detect_fortran_compiler(self, want_cross): + def detect_fortran_compiler(self, for_machine): popen_exceptions = {} - compilers, ccache, is_cross, exe_wrap = self._get_compilers('fortran', want_cross) + compilers, ccache, exe_wrap = self._get_compilers('fortran', for_machine) + is_cross = not self.machines.matches_build_machine(for_machine) for compiler in compilers: if isinstance(compiler, str): compiler = [compiler] @@ -910,14 +888,14 @@ class Environment: else: version = self.get_gnu_version_from_defines(defines) cls = GnuFortranCompiler - return cls(compiler, version, compiler_type, is_cross, exe_wrap, defines, full_version=full_version) + return cls(compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines, full_version=full_version) if 'G95' in out: - return G95FortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) + return G95FortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version) if 'Sun Fortran' in err: version = search_version(err) - return SunFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) + return SunFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version) if 'Intel(R) Visual Fortran' in err: version = search_version(err) @@ -925,36 +903,37 @@ class Environment: return IntelClFortranCompiler(compiler, version, is_cross, target, exe_wrap) if 'ifort (IFORT)' in out: - return IntelFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) + return IntelFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version) if 'PathScale EKOPath(tm)' in err: - return PathScaleFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) + return PathScaleFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version) if 'PGI Compilers' in out: - if self.machine[for_macine].is_darwin(): + if self.machine[for_machine].is_darwin(): compiler_type = CompilerType.PGI_OSX elif self.machines[for_machine].is_windows(): compiler_type = CompilerType.PGI_WIN else: compiler_type = CompilerType.PGI_STANDARD - return PGIFortranCompiler(compiler, version, compiler_type, is_cross, exe_wrap, full_version=full_version) + return PGIFortranCompiler(compiler, version, compiler_type, for_machine, is_cross, exe_wrap, full_version=full_version) if 'flang' in out or 'clang' in out: - return FlangFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) + return FlangFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version) if 'Open64 Compiler Suite' in err: - return Open64FortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) + return Open64FortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version) if 'NAG Fortran' in err: - return NAGFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) + return NAGFortranCompiler(compiler, version, for_machine, is_cross, exe_wrap, full_version=full_version) self._handle_exceptions(popen_exceptions, compilers) def get_scratch_dir(self): return self.scratch_dir - def detect_objc_compiler(self, want_cross): + def detect_objc_compiler(self, for_machine): popen_exceptions = {} - compilers, ccache, is_cross, exe_wrap = self._get_compilers('objc', want_cross) + compilers, ccache, exe_wrap = self._get_compilers('objc', for_machine) + is_cross = not self.machines.matches_build_machine(for_machine) for compiler in compilers: if isinstance(compiler, str): compiler = [compiler] @@ -972,18 +951,19 @@ class Environment: continue compiler_type = self.get_gnu_compiler_type(defines) version = self.get_gnu_version_from_defines(defines) - return GnuObjCCompiler(ccache + compiler, version, compiler_type, is_cross, exe_wrap, defines) + return GnuObjCCompiler(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines) if out.startswith('Apple LLVM'): - return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, is_cross, exe_wrap) + return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, for_machine, is_cross, exe_wrap) if 'windows' in out: - return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_MINGW, is_cross, exe_wrap) + return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_MINGW, for_machine, is_cross, exe_wrap) if out.startswith(('clang', 'OpenBSD clang')): - return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, is_cross, exe_wrap) + return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, for_machine, is_cross, exe_wrap) self._handle_exceptions(popen_exceptions, compilers) - def detect_objcpp_compiler(self, want_cross): + def detect_objcpp_compiler(self, for_machine): popen_exceptions = {} - compilers, ccache, is_cross, exe_wrap = self._get_compilers('objcpp', want_cross) + compilers, ccache, exe_wrap = self._get_compilers('objcpp', for_machine) + is_cross = not self.machines.matches_build_machine(for_machine) for compiler in compilers: if isinstance(compiler, str): compiler = [compiler] @@ -1001,16 +981,16 @@ class Environment: continue compiler_type = self.get_gnu_compiler_type(defines) version = self.get_gnu_version_from_defines(defines) - return GnuObjCPPCompiler(ccache + compiler, version, compiler_type, is_cross, exe_wrap, defines) + return GnuObjCPPCompiler(ccache + compiler, version, compiler_type, for_machine, is_cross, exe_wrap, defines) if out.startswith('Apple LLVM'): - return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, is_cross, exe_wrap) + return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, for_machine, is_cross, exe_wrap) if 'windows' in out: - return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_MINGW, is_cross, exe_wrap) + return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_MINGW, for_machine, is_cross, exe_wrap) if out.startswith(('clang', 'OpenBSD clang')): - return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, is_cross, exe_wrap) + return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, for_machine, is_cross, exe_wrap) self._handle_exceptions(popen_exceptions, compilers) - def detect_java_compiler(self): + def detect_java_compiler(self, for_machine): exelist = self.binaries.host.lookup_entry('java') if exelist is None: # TODO support fallback @@ -1026,11 +1006,11 @@ class Environment: parts = (err if 'javac' in err else out).split() if len(parts) > 1: version = parts[1] - return JavaCompiler(exelist, version) + return JavaCompiler(exelist, version, for_machine) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - def detect_cs_compiler(self): - compilers, ccache, is_cross, exe_wrap = self._get_compilers('cs', False) + def detect_cs_compiler(self, for_machine): + compilers, ccache, exe_wrap = self._get_compilers('cs', for_machine) popen_exceptions = {} for comp in compilers: if not isinstance(comp, list): @@ -1043,14 +1023,15 @@ class Environment: version = search_version(out) if 'Mono' in out: - return MonoCompiler(comp, version) + return MonoCompiler(comp, version, for_machine) elif "Visual C#" in out: - return VisualStudioCsCompiler(comp, version) + return VisualStudioCsCompiler(comp, version, for_machine) self._handle_exceptions(popen_exceptions, compilers) - def detect_vala_compiler(self): + def detect_vala_compiler(self, for_machine): exelist = self.binaries.host.lookup_entry('vala') + is_cross = not self.machines.matches_build_machine(for_machine) if exelist is None: # TODO support fallback exelist = [self.default_vala[0]] @@ -1061,12 +1042,13 @@ class Environment: raise EnvironmentException('Could not execute Vala compiler "%s"' % ' '.join(exelist)) version = search_version(out) if 'Vala' in out: - return ValaCompiler(exelist, version) + return ValaCompiler(exelist, version, for_machine, is_cross) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - def detect_rust_compiler(self, want_cross): + def detect_rust_compiler(self, for_machine): popen_exceptions = {} - compilers, ccache, is_cross, exe_wrap = self._get_compilers('rust', want_cross) + compilers, ccache, exe_wrap = self._get_compilers('rust', for_machine) + is_cross = not self.machines.matches_build_machine(for_machine) for compiler in compilers: if isinstance(compiler, str): compiler = [compiler] @@ -1080,13 +1062,12 @@ class Environment: version = search_version(out) if 'rustc' in out: - return RustCompiler(compiler, version, is_cross, exe_wrap) + return RustCompiler(compiler, version, for_machine, is_cross, exe_wrap) self._handle_exceptions(popen_exceptions, compilers) - def detect_d_compiler(self, want_cross): - is_cross = want_cross and self.is_cross_build() - exelist = self.binaries.host.lookup_entry('d') + def detect_d_compiler(self, for_machine: MachineChoice): + exelist = self.binaries[for_machine].lookup_entry('d') # Search for a D compiler. # We prefer LDC over GDC unless overridden with the DC # environment variable because LDC has a much more @@ -1115,22 +1096,23 @@ class Environment: c_compiler = {} is_msvc = mesonlib.is_windows() and 'VCINSTALLDIR' in os.environ if is_msvc: - c_compiler = {'c': self.detect_c_compiler(want_cross)} # MSVC compiler is required for correct platform detection. + c_compiler = {'c': self.detect_c_compiler(for_machine)} # MSVC compiler is required for correct platform detection. arch = detect_cpu_family(c_compiler) if is_msvc and arch == 'x86': arch = 'x86_mscoff' if 'LLVM D compiler' in out: - return compilers.LLVMDCompiler(exelist, version, is_cross, arch, full_version=full_version) + return compilers.LLVMDCompiler(exelist, version, for_machine, arch, full_version=full_version) elif 'gdc' in out: - return compilers.GnuDCompiler(exelist, version, is_cross, arch, full_version=full_version) + return compilers.GnuDCompiler(exelist, version, for_machine, arch, full_version=full_version) elif 'The D Language Foundation' in out or 'Digital Mars' in out: - return compilers.DmdDCompiler(exelist, version, is_cross, arch, full_version=full_version) + return compilers.DmdDCompiler(exelist, version, for_machine, arch, full_version=full_version) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - def detect_swift_compiler(self): + def detect_swift_compiler(self, for_machine): exelist = self.binaries.host.lookup_entry('swift') + is_cross = not self.machines.matches_build_machine(for_machine) if exelist is None: # TODO support fallback exelist = [self.default_swift[0]] @@ -1141,53 +1123,47 @@ class Environment: raise EnvironmentException('Could not execute Swift compiler "%s"' % ' '.join(exelist)) version = search_version(err) if 'Swift' in err: - return compilers.SwiftCompiler(exelist, version) + return compilers.SwiftCompiler(exelist, version, for_machine, is_cross) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - def compiler_from_language(self, lang: str, want_cross: bool): + def compiler_from_language(self, lang: str, for_machine: MachineChoice): if lang == 'c': - comp = self.detect_c_compiler(want_cross) + comp = self.detect_c_compiler(for_machine) elif lang == 'cpp': - comp = self.detect_cpp_compiler(want_cross) + comp = self.detect_cpp_compiler(for_machine) elif lang == 'objc': - comp = self.detect_objc_compiler(want_cross) + comp = self.detect_objc_compiler(for_machine) elif lang == 'cuda': - comp = self.detect_cuda_compiler(want_cross) + comp = self.detect_cuda_compiler(for_machine) elif lang == 'objcpp': - comp = self.detect_objcpp_compiler(want_cross) + comp = self.detect_objcpp_compiler(for_machine) elif lang == 'java': - comp = self.detect_java_compiler() # Java is platform independent. + comp = self.detect_java_compiler(for_machine) elif lang == 'cs': - comp = self.detect_cs_compiler() # C# is platform independent. + comp = self.detect_cs_compiler(for_machine) elif lang == 'vala': - comp = self.detect_vala_compiler() # Vala compiles to platform-independent C + comp = self.detect_vala_compiler(for_machine) elif lang == 'd': - comp = self.detect_d_compiler(want_cross) + comp = self.detect_d_compiler(for_machine) elif lang == 'rust': - comp = self.detect_rust_compiler(want_cross) + comp = self.detect_rust_compiler(for_machine) elif lang == 'fortran': - comp = self.detect_fortran_compiler(want_cross) + comp = self.detect_fortran_compiler(for_machine) elif lang == 'swift': - if want_cross: - raise EnvironmentException('Cross compilation with Swift is not working yet.') - comp = self.detect_swift_compiler() + comp = self.detect_swift_compiler(for_machine) else: comp = None return comp - def detect_compilers(self, lang: str, need_cross_compiler: bool): - comp = self.compiler_from_language(lang, False) - if need_cross_compiler: - cross_comp = self.compiler_from_language(lang, True) - else: - cross_comp = None + def detect_compiler_for(self, lang: str, for_machine: MachineChoice): + comp = self.compiler_from_language(lang, for_machine) if comp is not None: - self.coredata.process_new_compilers(lang, comp, cross_comp, self) - return comp, cross_comp + assert comp.for_machine == for_machine + self.coredata.process_new_compiler(lang, comp, self) + return comp def detect_static_linker(self, compiler): - for_machine = MachineChoice.HOST if compiler.is_cross else MachineChoice.BUILD - linker = self.binaries[for_machine].lookup_entry('ar') + linker = self.binaries[compiler.for_machine].lookup_entry('ar') if linker is not None: linkers = [linker] else: @@ -1255,9 +1231,6 @@ class Environment: def get_build_dir(self): return self.build_dir - def get_exe_suffix(self): - return self.exe_suffix - def get_import_lib_dir(self) -> str: "Install dir for the import library (library used for linking)" return self.get_libdir() @@ -1268,7 +1241,9 @@ class Environment: def get_shared_lib_dir(self) -> str: "Install dir for the shared library" - if self.win_libdir_layout: + m = self.machines.host + # Windows has no RPATH or similar, so DLLs must be next to EXEs. + if m.is_windows() or m.is_cygwin(): return self.get_bindir() return self.get_libdir() @@ -1276,9 +1251,6 @@ class Environment: "Install dir for the static library" return self.get_libdir() - def get_object_suffix(self): - return self.object_suffix - def get_prefix(self) -> str: return self.coredata.get_builtin_option('prefix') @@ -1300,8 +1272,8 @@ class Environment: def get_datadir(self) -> str: return self.coredata.get_builtin_option('datadir') - def get_compiler_system_dirs(self): - for comp in self.coredata.compilers.values(): + def get_compiler_system_dirs(self, for_machine: MachineChoice): + for comp in self.coredata.compilers[for_machine].values(): if isinstance(comp, compilers.ClangCompiler): index = 1 break diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 7c17e1cb3..5dddb2293 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -21,7 +21,7 @@ from . import optinterpreter from . import compilers from .wrap import wrap, WrapMode from . import mesonlib -from .mesonlib import FileMode, MachineChoice, Popen_safe, listify, extract_as_list, has_path_sep +from .mesonlib import FileMode, MachineChoice, PerMachine, Popen_safe, listify, extract_as_list, has_path_sep from .dependencies import ExternalProgram from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException from .interpreterbase import InterpreterBase @@ -738,7 +738,7 @@ class BuildTargetHolder(TargetHolder): return r.format(self.__class__.__name__, h.get_id(), h.filename) def is_cross(self): - return self.held_object.is_cross() + return not self.held_object.environment.machines.matches_build_machine(self.held_object.for_machine) @noPosargs @permittedKwargs({}) @@ -1696,8 +1696,10 @@ class ModuleHolder(InterpreterObject, ObjectHolder): data=self.interpreter.build.data, headers=self.interpreter.build.get_headers(), man=self.interpreter.build.get_man(), - global_args=self.interpreter.build.global_args, - project_args=self.interpreter.build.projects_args.get(self.interpreter.subproject, {}), + #global_args_for_build = self.interpreter.build.global_args.build, + global_args = self.interpreter.build.global_args.host, + #project_args_for_build = self.interpreter.build.projects_args.build.get(self.interpreter.subproject, {}), + project_args = self.interpreter.build.projects_args.host.get(self.interpreter.subproject, {}), build_machine=self.interpreter.builtin['build_machine'].held_object, host_machine=self.interpreter.builtin['host_machine'].held_object, target_machine=self.interpreter.builtin['target_machine'].held_object, @@ -1847,10 +1849,7 @@ class MesonMain(InterpreterObject): native = True if not isinstance(native, bool): raise InterpreterException('Type of "native" must be a boolean.') - if native: - clist = self.interpreter.coredata.compilers - else: - clist = self.interpreter.coredata.cross_compilers + clist = self.interpreter.coredata.compilers[MachineChoice.BUILD if native else MachineChoice.HOST] if cname in clist: return CompilerHolder(clist[cname], self.build.environment, self.interpreter.subproject) raise InterpreterException('Tried to access compiler for unspecified language "%s".' % cname) @@ -2085,7 +2084,7 @@ class Interpreter(InterpreterBase): # have the compilers needed to gain more knowledge, so wipe out old # inferrence and start over. machines = self.build.environment.machines.miss_defaulting() - machines.build = environment.detect_machine_info(self.coredata.compilers) + machines.build = environment.detect_machine_info(self.coredata.compilers.build) self.build.environment.machines = machines.default_missing() assert self.build.environment.machines.build.cpu is not None assert self.build.environment.machines.host.cpu is not None @@ -2237,10 +2236,10 @@ class Interpreter(InterpreterBase): def get_variables(self): return self.variables - def check_cross_stdlibs(self): - if self.build.environment.is_cross_build(): - props = self.build.environment.properties.host - for l in self.coredata.cross_compilers.keys(): + def check_stdlibs(self): + for for_machine in MachineChoice: + props = self.build.environment.properties[for_machine] + for l in self.coredata.compilers[for_machine].keys(): try: di = mesonlib.stringlistify(props.get_stdlib(l)) if len(di) != 2: @@ -2248,7 +2247,7 @@ class Interpreter(InterpreterBase): % l) projname, depname = di subproj = self.do_subproject(projname, 'meson', {}) - self.build.cross_stdlibs[l] = subproj.get_variable_method([depname], {}) + self.build.stdlibs.host[l] = subproj.get_variable_method([depname], {}) except KeyError: pass except InvalidArguments: @@ -2729,7 +2728,7 @@ external dependencies (including libraries) must go to "dependencies".''') mlog.log('Project version:', mlog.bold(self.project_version)) self.add_languages(proj_langs, True) if not self.is_subproject(): - self.check_cross_stdlibs() + self.check_stdlibs() @permittedKwargs(permitted_kwargs['add_languages']) @stringArgs @@ -2786,37 +2785,38 @@ external dependencies (including libraries) must go to "dependencies".''') raise Exception() def add_languages(self, args, required): + success = self.add_languages_for(args, required, MachineChoice.BUILD) + success &= self.add_languages_for(args, required, MachineChoice.HOST) + return success + + def add_languages_for(self, args, required, for_machine: MachineChoice): success = True - need_cross_compiler = self.environment.is_cross_build() for lang in sorted(args, key=compilers.sort_clink): lang = lang.lower() - if lang in self.coredata.compilers: - comp = self.coredata.compilers[lang] - cross_comp = self.coredata.cross_compilers.get(lang, None) + clist = self.coredata.compilers[for_machine] + machine_name = for_machine.get_lower_case_name() + if lang in clist: + comp = clist[lang] else: try: - (comp, cross_comp) = self.environment.detect_compilers(lang, need_cross_compiler) + comp = self.environment.detect_compiler_for(lang, for_machine) if comp is None: raise InvalidArguments('Tried to use unknown language "%s".' % lang) comp.sanity_check(self.environment.get_scratch_dir(), self.environment) - if cross_comp: - cross_comp.sanity_check(self.environment.get_scratch_dir(), self.environment) except Exception: if not required: - mlog.log('Compiler for language', mlog.bold(lang), 'not found.') + mlog.log('Compiler for language', + mlog.bold(lang), 'for the', machine_name, + 'machine not found.') success = False continue else: raise - mlog.log('Native', comp.get_display_language(), 'compiler:', + mlog.log(comp.get_display_language(), 'compiler for the', machine_name, 'machine:', mlog.bold(' '.join(comp.get_exelist())), comp.get_version_string()) self.build.ensure_static_linker(comp) - if need_cross_compiler: - mlog.log('Cross', cross_comp.get_display_language(), 'compiler:', - mlog.bold(' '.join(cross_comp.get_exelist())), cross_comp.get_version_string()) - self.build.ensure_static_cross_linker(cross_comp) - langs = self.coredata.compilers.keys() + langs = self.coredata.compilers[for_machine].keys() if 'vala' in langs: if 'c' not in langs: raise InterpreterException('Compiling Vala requires C. Add C to your project languages and rerun Meson.') @@ -2935,14 +2935,9 @@ external dependencies (including libraries) must go to "dependencies".''') ) def _find_cached_dep(self, name, kwargs): - # Check if we want this as a cross-dep or a native-dep - # FIXME: Not all dependencies support such a distinction right now, - # and we repeat this check inside dependencies that do. We need to - # consolidate this somehow. - if self.environment.is_cross_build() and kwargs.get('native', False): - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST + # Check if we want this as a build-time / build machine or runt-time / + # host machine dep. + for_machine = MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST identifier = dependencies.get_dep_identifier(name, kwargs) cached_dep = self.coredata.deps[for_machine].get(identifier) @@ -3097,10 +3092,7 @@ external dependencies (including libraries) must go to "dependencies".''') # cannot cache them. They must always be evaluated else # we won't actually read all the build files. if dep.found(): - if self.environment.is_cross_build() and kwargs.get('native', False): - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST + for_machine = MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST self.coredata.deps[for_machine].put(identifier, dep) return DependencyHolder(dep, self.subproject) @@ -3849,45 +3841,47 @@ different subdirectory. env = self.unpack_env_kwarg(kwargs) self.build.test_setups[setup_name] = build.TestSetup(exe_wrapper, gdb, timeout_multiplier, env) - def get_argdict_on_crossness(self, native_dict, cross_dict, kwargs): + # TODO make cross agnostic, just taking into account for_machine + # TODO PerMachine[T], Iterator[T] + def get_argdict_on_crossness(self, dicts_per_machine: PerMachine, kwargs) -> typing.Iterator: for_native = kwargs.get('native', not self.environment.is_cross_build()) if not isinstance(for_native, bool): raise InterpreterException('Keyword native must be a boolean.') - if for_native: - return native_dict + if self.environment.is_cross_build(): + if for_native: + return iter([dicts_per_machine[MachineChoice.BUILD]]) + else: + return iter([dicts_per_machine[MachineChoice.HOST]]) else: - return cross_dict + if for_native: + return iter([dicts_per_machine[MachineChoice.BUILD], + dicts_per_machine[MachineChoice.HOST]]) + else: + return iter([]) @permittedKwargs(permitted_kwargs['add_global_arguments']) @stringArgs def func_add_global_arguments(self, node, args, kwargs): - argdict = self.get_argdict_on_crossness(self.build.global_args, - self.build.cross_global_args, - kwargs) - self.add_global_arguments(node, argdict, args, kwargs) + for argdict in self.get_argdict_on_crossness(self.build.global_args, kwargs): + self.add_global_arguments(node, argdict, args, kwargs) @permittedKwargs(permitted_kwargs['add_global_link_arguments']) @stringArgs def func_add_global_link_arguments(self, node, args, kwargs): - argdict = self.get_argdict_on_crossness(self.build.global_link_args, - self.build.cross_global_link_args, - kwargs) - self.add_global_arguments(node, argdict, args, kwargs) + for argdict in self.get_argdict_on_crossness(self.build.global_link_args, kwargs): + self.add_global_arguments(node, argdict, args, kwargs) @permittedKwargs(permitted_kwargs['add_project_arguments']) @stringArgs def func_add_project_arguments(self, node, args, kwargs): - argdict = self.get_argdict_on_crossness(self.build.projects_args, - self.build.cross_projects_args, - kwargs) - self.add_project_arguments(node, argdict, args, kwargs) + for argdict in self.get_argdict_on_crossness(self.build.projects_args, kwargs): + self.add_project_arguments(node, argdict, args, kwargs) @permittedKwargs(permitted_kwargs['add_project_link_arguments']) @stringArgs def func_add_project_link_arguments(self, node, args, kwargs): - argdict = self.get_argdict_on_crossness(self.build.projects_link_args, - self.build.cross_projects_link_args, kwargs) - self.add_project_arguments(node, argdict, args, kwargs) + for argdict in self.get_argdict_on_crossness(self.build.projects_link_args, kwargs): + self.add_project_arguments(node, argdict, args, kwargs) def add_global_arguments(self, node, argsdict, args, kwargs): if self.is_subproject(): @@ -3940,7 +3934,8 @@ different subdirectory. self.print_extra_warnings() def print_extra_warnings(self): - for c in self.coredata.compilers.values(): + # TODO cross compilation + for c in self.coredata.compilers.host.values(): if c.get_id() == 'clang': self.check_clang_asan_lundef() break @@ -4091,13 +4086,10 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_s if not args: raise InterpreterException('Target does not have a name.') name, *sources = args - if self.environment.is_cross_build(): - if kwargs.get('native', False): - is_cross = False - else: - is_cross = True + if kwargs.get('native', False): + for_machine = MachineChoice.BUILD else: - is_cross = False + for_machine = MachineChoice.HOST if 'sources' in kwargs: sources += listify(kwargs['sources']) sources = self.source_strings_to_files(sources) @@ -4128,9 +4120,9 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_s kwargs = {k: v for k, v in kwargs.items() if k in targetclass.known_kwargs} kwargs['include_directories'] = self.extract_incdirs(kwargs) - target = targetclass(name, self.subdir, self.subproject, is_cross, sources, objs, self.environment, kwargs) + target = targetclass(name, self.subdir, self.subproject, for_machine, sources, objs, self.environment, kwargs) - if is_cross: + if not self.environment.machines.matches_build_machine(for_machine): self.add_cross_stdlib_info(target) l = targetholder(target, self) self.add_target(name, l.held_object) @@ -4157,18 +4149,21 @@ This will become a hard error in the future.''', location=self.current_node) def get_used_languages(self, target): result = {} for i in target.sources: - for lang, c in self.coredata.compilers.items(): + # TODO other platforms + for lang, c in self.coredata.compilers.host.items(): if c.can_compile(i): result[lang] = True break return result def add_cross_stdlib_info(self, target): + if target.for_machine != MachineChoice.HOST: + return for l in self.get_used_languages(target): props = self.environment.properties.host if props.has_stdlib(l) \ and self.subproject != props.get_stdlib(l)[0]: - target.add_deps(self.build.cross_stdlibs[l]) + target.add_deps(self.build.stdlibs.host[l]) def check_sources_exist(self, subdir, sources): for s in sources: diff --git a/mesonbuild/modules/cmake.py b/mesonbuild/modules/cmake.py index 8ce5aef89..a36d7485a 100644 --- a/mesonbuild/modules/cmake.py +++ b/mesonbuild/modules/cmake.py @@ -110,7 +110,7 @@ class CmakeModule(ExtensionModule): self.snippets.add('subproject') def detect_voidp_size(self, env): - compilers = env.coredata.compilers + compilers = env.coredata.compilers.host compiler = compilers.get('c', None) if not compiler: compiler = compilers.get('cpp', None) diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index a223b787b..fd9e063ee 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -1048,7 +1048,7 @@ This will become a hard error in the future.''') if state.environment.is_cross_build(): compiler = state.environment.coredata.cross_compilers.get('c') else: - compiler = state.environment.coredata.compilers.get('c') + compiler = state.environment.coredata.compilers.host.get('c') compiler_flags = self._get_langs_compilers_flags(state, [('c', compiler)]) cflags.extend(compiler_flags[0]) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index d4d062527..0284f3d7c 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -397,7 +397,7 @@ class PkgConfigModule(ExtensionModule): dversions = kwargs.get('d_module_versions', None) if dversions: - compiler = state.environment.coredata.compilers.get('d') + compiler = state.environment.coredata.compilers.host.get('d') if compiler: deps.add_cflags(compiler.get_feature_args({'versions': dversions}, None)) diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index 04941eaba..2f4e5d67f 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -211,7 +211,7 @@ class PythonDependency(ExternalDependency): if pyarch is None: self.is_found = False return - arch = detect_cpu_family(env.coredata.compilers) + arch = detect_cpu_family(env.coredata.compilers.host) if arch == 'x86': arch = '32' elif arch == 'x86_64': diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index 3b4eb1581..efc3218b2 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -18,7 +18,7 @@ import re from .. import mlog from .. import mesonlib, build -from ..mesonlib import MesonException, extract_as_list +from ..mesonlib import MachineChoice, MesonException, extract_as_list from . import get_include_args from . import ModuleReturnValue from . import ExtensionModule @@ -41,16 +41,17 @@ class WindowsModule(ExtensionModule): def _find_resource_compiler(self, state): # FIXME: Does not handle `native: true` executables, see # See https://github.com/mesonbuild/meson/issues/1531 - # But given a machine, we can un-hardcode `binaries.host` below. + # Take a parameter instead of the hardcoded definition below + for_machine = MachineChoice.HOST if hasattr(self, '_rescomp'): return self._rescomp # Will try cross / native file and then env var - rescomp = ExternalProgram.from_bin_list(state.environment.binaries.host, 'windres') + rescomp = ExternalProgram.from_bin_list(state.environment.binaries[for_machine], 'windres') if not rescomp or not rescomp.found(): - comp = self.detect_compiler(state.environment.coredata.compilers) + comp = self.detect_compiler(state.environment.coredata.compilers[for_machine]) if comp.id in {'msvc', 'clang-cl', 'intel-cl'}: rescomp = ExternalProgram('rc', silent=True) else: diff --git a/mesonbuild/munstable_coredata.py b/mesonbuild/munstable_coredata.py index 864df0411..d3cc1da50 100644 --- a/mesonbuild/munstable_coredata.py +++ b/mesonbuild/munstable_coredata.py @@ -14,6 +14,7 @@ from . import coredata as cdata +from .mesonlib import MachineChoice import os.path import pprint @@ -91,18 +92,11 @@ def run(options): if v: print('Native File: ' + ' '.join(v)) elif k == 'compilers': - print('Cached native compilers:') - dump_compilers(v) - elif k == 'cross_compilers': - print('Cached cross compilers:') - dump_compilers(v) + for for_machine in MachineChoice: + print('Cached {} machine compilers:'.format( + for_machine.get_lower_case_name())) + dump_compilers(v[for_machine]) elif k == 'deps': - native = list(sorted(v.build.items())) - if v.host is not v.build: - cross = list(sorted(v.host.items())) - else: - cross = [] - def print_dep(dep_key, dep): print(' ' + dep_key[0] + ": ") print(' compile args: ' + repr(dep.get_compile_args())) @@ -111,16 +105,13 @@ def run(options): print(' sources: ' + repr(dep.get_sources())) print(' version: ' + repr(dep.get_version())) - if native: - print('Cached native dependencies:') - for dep_key, deps in native: - for dep in deps: - print_dep(dep_key, dep) - if cross: - print('Cached dependencies:') - for dep_key, deps in cross: - for dep in deps: - print_dep(dep_key, dep) + for for_machine in iter(MachineChoice): + items_list = list(sorted(v[for_machine].items())) + if items_list: + print('Cached dependencies for {} machine' % for_machine.get_lower_case_name()) + for dep_key, deps in items_list: + for dep in deps: + print_dep(dep_key, dep) else: print(k + ':') print(textwrap.indent(pprint.pformat(v), ' ')) diff --git a/run_project_tests.py b/run_project_tests.py index 0f3e913ef..bbeb6ca3b 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -31,7 +31,7 @@ from mesonbuild import compilers from mesonbuild import mesonlib from mesonbuild import mlog from mesonbuild import mtest -from mesonbuild.mesonlib import stringlistify, Popen_safe +from mesonbuild.mesonlib import MachineChoice, stringlistify, Popen_safe from mesonbuild.coredata import backendlist import argparse import xml.etree.ElementTree as ET @@ -465,12 +465,12 @@ def have_objc_compiler(): with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: env = environment.Environment(None, build_dir, get_fake_options('/')) try: - objc_comp = env.detect_objc_compiler(False) + objc_comp = env.detect_objc_compiler(MachineChoice.HOST) except mesonlib.MesonException: return False if not objc_comp: return False - env.coredata.process_new_compilers('objc', objc_comp, None, env) + env.coredata.process_new_compiler('objc', objc_comp, env) try: objc_comp.sanity_check(env.get_scratch_dir(), env) except mesonlib.MesonException: @@ -481,12 +481,12 @@ def have_objcpp_compiler(): with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: env = environment.Environment(None, build_dir, get_fake_options('/')) try: - objcpp_comp = env.detect_objcpp_compiler(False) + objcpp_comp = env.detect_objcpp_compiler(MachineChoice.HOST) except mesonlib.MesonException: return False if not objcpp_comp: return False - env.coredata.process_new_compilers('objcpp', objcpp_comp, None, env) + env.coredata.process_new_compiler('objcpp', objcpp_comp, env) try: objcpp_comp.sanity_check(env.get_scratch_dir(), env) except mesonlib.MesonException: @@ -793,7 +793,7 @@ def detect_system_compiler(): print() for lang in sorted(compilers.all_languages): try: - comp = env.compiler_from_language(lang, env.is_cross_build()) + comp = env.compiler_from_language(lang, MachineChoice.HOST) details = '%s %s' % (' '.join(comp.get_exelist()), comp.get_version_string()) except mesonlib.MesonException: comp = None diff --git a/run_unittests.py b/run_unittests.py index 0a1317485..23b8f2c7a 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -46,9 +46,9 @@ import mesonbuild.modules.gnome from mesonbuild.interpreter import Interpreter, ObjectHolder from mesonbuild.ast import AstInterpreter from mesonbuild.mesonlib import ( + BuildDirLock, LibType, MachineChoice, PerMachine, Version, is_windows, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, windows_proof_rmtree, python_command, version_compare, - BuildDirLock, Version, PerMachine, LibType ) from mesonbuild.environment import detect_ninja from mesonbuild.mesonlib import MesonException, EnvironmentException @@ -184,10 +184,7 @@ def skip_if_not_language(lang): try: env = get_fake_env() f = getattr(env, 'detect_{}_compiler'.format(lang)) - if lang in ['cs', 'vala', 'java', 'swift']: - f() - else: - f(False) + f(MachineChoice.HOST) except EnvironmentException: raise unittest.SkipTest('No {} compiler found.'.format(lang)) return func(*args, **kwargs) @@ -223,7 +220,7 @@ def skip_if_not_base_option(feature): @functools.wraps(f) def wrapped(*args, **kwargs): env = get_fake_env() - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) if feature not in cc.base_options: raise unittest.SkipTest( '{} not available with {}'.format(feature, cc.id)) @@ -344,7 +341,7 @@ class InternalTests(unittest.TestCase): def test_compiler_args_class(self): cargsfunc = mesonbuild.compilers.CompilerArgs - cc = mesonbuild.compilers.CCompiler([], 'fake', False) + cc = mesonbuild.compilers.CCompiler([], 'fake', False, MachineChoice.HOST) # Test that bad initialization fails self.assertRaises(TypeError, cargsfunc, []) self.assertRaises(TypeError, cargsfunc, [], []) @@ -430,7 +427,7 @@ class InternalTests(unittest.TestCase): def test_compiler_args_class_gnuld(self): cargsfunc = mesonbuild.compilers.CompilerArgs ## Test --start/end-group - gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', mesonbuild.compilers.CompilerType.GCC_STANDARD, False) + gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', mesonbuild.compilers.CompilerType.GCC_STANDARD, False, MachineChoice.HOST) ## Test that 'direct' append and extend works l = cargsfunc(gcc, ['-Lfoodir', '-lfoo']) self.assertEqual(l.to_native(copy=True), ['-Lfoodir', '-Wl,--start-group', '-lfoo', '-Wl,--end-group']) @@ -764,7 +761,7 @@ class InternalTests(unittest.TestCase): '{}.dll.a', '{}.lib', '{}.dll'), 'static': msvc_static}} env = get_fake_env() - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) if is_osx(): self._test_all_naming(cc, env, patterns, 'darwin') elif is_cygwin(): @@ -807,8 +804,8 @@ class InternalTests(unittest.TestCase): with tempfile.TemporaryDirectory() as tmpdir: pkgbin = ExternalProgram('pkg-config', command=['pkg-config'], silent=True) env = get_fake_env() - compiler = env.detect_c_compiler(False) - env.coredata.compilers = {'c': compiler} + compiler = env.detect_c_compiler(MachineChoice.HOST) + env.coredata.compilers.host = {'c': compiler} env.coredata.compiler_options.host['c_link_args'] = FakeCompilerOptions() p1 = Path(tmpdir) / '1' p2 = Path(tmpdir) / '2' @@ -989,7 +986,7 @@ class InternalTests(unittest.TestCase): Ensure that the toolset version returns the correct value for this MSVC ''' env = get_fake_env() - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) if cc.get_argument_syntax() != 'msvc': raise unittest.SkipTest('Test only applies to MSVC-like compilers') toolset_ver = cc.get_toolset_version() @@ -1045,8 +1042,8 @@ class DataTests(unittest.TestCase): self.assertIsNotNone(md) env = get_fake_env() # FIXME: Support other compilers - cc = env.detect_c_compiler(False) - cpp = env.detect_cpp_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) + cpp = env.detect_cpp_compiler(MachineChoice.HOST) for comp in (cc, cpp): for opt in comp.get_options().keys(): self.assertIn(opt, md) @@ -1606,7 +1603,7 @@ class AllPlatformTests(BasePlatformTests): def test_clike_get_library_dirs(self): env = get_fake_env() - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) for d in cc.get_library_dirs(env): self.assertTrue(os.path.exists(d)) self.assertTrue(os.path.isdir(d)) @@ -1622,7 +1619,7 @@ class AllPlatformTests(BasePlatformTests): ''' testdir = os.path.join(self.common_test_dir, '3 static') env = get_fake_env(testdir, self.builddir, self.prefix) - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) static_linker = env.detect_static_linker(cc) if is_windows(): raise unittest.SkipTest('https://github.com/mesonbuild/meson/issues/1526') @@ -1977,7 +1974,7 @@ class AllPlatformTests(BasePlatformTests): for lang, evar in langs: # Detect with evar and do sanity checks on that if evar in os.environ: - ecc = getattr(env, 'detect_{}_compiler'.format(lang))(False) + ecc = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST) self.assertTrue(ecc.version) elinker = env.detect_static_linker(ecc) # Pop it so we don't use it for the next detection @@ -2005,7 +2002,7 @@ class AllPlatformTests(BasePlatformTests): # Check that we actually used the evalue correctly as the compiler self.assertEqual(ecc.get_exelist(), shlex.split(evalue)) # Do auto-detection of compiler based on platform, PATH, etc. - cc = getattr(env, 'detect_{}_compiler'.format(lang))(False) + cc = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST) self.assertTrue(cc.version) linker = env.detect_static_linker(cc) # Check compiler type @@ -2056,7 +2053,7 @@ class AllPlatformTests(BasePlatformTests): for w in wrappercc: wrappercc_s += shlex.quote(w) + ' ' os.environ[evar] = wrappercc_s - wcc = getattr(env, 'detect_{}_compiler'.format(lang))(False) + wcc = getattr(env, 'detect_{}_compiler'.format(lang))(MachineChoice.HOST) # Check static linker too wrapperlinker = python_command + [wrapper] + linker.get_exelist() + linker.get_always_args() wrapperlinker_s = '' @@ -2081,7 +2078,7 @@ class AllPlatformTests(BasePlatformTests): testdir = os.path.join(self.common_test_dir, '138 c cpp and asm') # Skip if building with MSVC env = get_fake_env(testdir, self.builddir, self.prefix) - if env.detect_c_compiler(False).get_id() == 'msvc': + if env.detect_c_compiler(MachineChoice.HOST).get_id() == 'msvc': raise unittest.SkipTest('MSVC can\'t compile assembly') self.init(testdir) commands = {'c-asm': {}, 'cpp-asm': {}, 'cpp-c-asm': {}, 'c-cpp-asm': {}} @@ -2224,7 +2221,7 @@ class AllPlatformTests(BasePlatformTests): testdir = os.path.join(self.common_test_dir, '5 linkstatic') env = get_fake_env(testdir, self.builddir, self.prefix) - if env.detect_c_compiler(False).get_id() == 'clang' and is_windows(): + if env.detect_c_compiler(MachineChoice.HOST).get_id() == 'clang' and is_windows(): raise unittest.SkipTest('LTO not (yet) supported by windows clang') self.init(testdir, extra_args='-Db_lto=true') @@ -2367,7 +2364,7 @@ int main(int argc, char **argv) { def detect_prebuild_env(self): env = get_fake_env() - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) stlinker = env.detect_static_linker(cc) if mesonbuild.mesonlib.is_windows(): object_suffix = 'obj' @@ -2852,7 +2849,7 @@ recommended as it is not supported on some platforms''') testdirlib = os.path.join(testdirbase, 'lib') extra_args = None env = get_fake_env(testdirlib, self.builddir, self.prefix) - if env.detect_c_compiler(False).get_id() not in {'msvc', 'clang-cl', 'intel-cl'}: + if env.detect_c_compiler(MachineChoice.HOST).get_id() not in {'msvc', 'clang-cl', 'intel-cl'}: # static libraries are not linkable with -l with msvc because meson installs them # as .a files which unix_args_to_native will not know as it expects libraries to use # .lib as extension. For a DLL the import library is installed as .lib. Thus for msvc @@ -3821,7 +3818,7 @@ class FailureTests(BasePlatformTests): raise unittest.SkipTest('wx-config, wx-config-3.0 or wx-config-gtk3 found') self.assertMesonRaises("dependency('wxwidgets')", self.dnf) self.assertMesonOutputs("dependency('wxwidgets', required : false)", - "Dependency .*WxWidgets.* found: .*NO.*") + "Run-time dependency .*WxWidgets.* found: .*NO.*") def test_wx_dependency(self): if not shutil.which('wx-config-3.0') and not shutil.which('wx-config') and not shutil.which('wx-config-gtk3'): @@ -3868,8 +3865,8 @@ class FailureTests(BasePlatformTests): ''' env = get_fake_env() try: - env.detect_objc_compiler(False) - env.detect_objcpp_compiler(False) + env.detect_objc_compiler(MachineChoice.HOST) + env.detect_objcpp_compiler(MachineChoice.HOST) except EnvironmentException: code = "add_languages('objc')\nadd_languages('objcpp')" self.assertMesonRaises(code, "Unknown compiler") @@ -4022,7 +4019,7 @@ class WindowsTests(BasePlatformTests): ''' testdir = os.path.join(self.platform_test_dir, '1 basic') env = get_fake_env(testdir, self.builddir, self.prefix) - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) if cc.get_argument_syntax() != 'msvc': raise unittest.SkipTest('Not using MSVC') # To force people to update this test, and also test @@ -4035,7 +4032,7 @@ class WindowsTests(BasePlatformTests): # resource compiler depfile generation is not yet implemented for msvc env = get_fake_env(testdir, self.builddir, self.prefix) - depfile_works = env.detect_c_compiler(False).get_id() not in {'msvc', 'clang-cl', 'intel-cl'} + depfile_works = env.detect_c_compiler(MachineChoice.HOST).get_id() not in {'msvc', 'clang-cl', 'intel-cl'} self.init(testdir) self.build() @@ -4066,7 +4063,7 @@ class WindowsTests(BasePlatformTests): testdir = os.path.join(self.unit_test_dir, '45 vscpp17') env = get_fake_env(testdir, self.builddir, self.prefix) - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) if cc.get_argument_syntax() != 'msvc': raise unittest.SkipTest('Test only applies to MSVC-like compilers') @@ -4100,7 +4097,7 @@ class DarwinTests(BasePlatformTests): # Try with bitcode enabled out = self.init(testdir, extra_args='-Db_bitcode=true') env = get_fake_env(testdir, self.builddir, self.prefix) - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) if cc.id != 'clang': raise unittest.SkipTest('Not using Clang on OSX') # Warning was printed @@ -4360,10 +4357,10 @@ class LinuxlikeTests(BasePlatformTests): mesonlog = self.get_meson_log() if qt4 == 0: self.assertRegex('\n'.join(mesonlog), - r'Dependency qt4 \(modules: Core\) found: YES 4.* \(pkg-config\)\n') + r'Run-time dependency qt4 \(modules: Core\) found: YES 4.* \(pkg-config\)\n') if qt5 == 0: self.assertRegex('\n'.join(mesonlog), - r'Dependency qt5 \(modules: Core\) found: YES 5.* \(pkg-config\)\n') + r'Run-time dependency qt5 \(modules: Core\) found: YES 5.* \(pkg-config\)\n') @skip_if_not_base_option('b_sanitize') def test_generate_gir_with_address_sanitizer(self): @@ -4394,7 +4391,7 @@ class LinuxlikeTests(BasePlatformTests): # Confirm that the dependency was found with qmake mesonlog = self.get_meson_log() self.assertRegex('\n'.join(mesonlog), - r'Dependency qt5 \(modules: Core\) found: YES .* \((qmake|qmake-qt5)\)\n') + r'Run-time dependency qt5 \(modules: Core\) found: YES .* \((qmake|qmake-qt5)\)\n') def _test_soname_impl(self, libpath, install): if is_cygwin() or is_osx(): @@ -4519,7 +4516,7 @@ class LinuxlikeTests(BasePlatformTests): ''' testdir = os.path.join(self.common_test_dir, '1 trivial') env = get_fake_env(testdir, self.builddir, self.prefix) - cc = env.detect_c_compiler(False) + cc = env.detect_c_compiler(MachineChoice.HOST) self._test_stds_impl(testdir, cc, 'c') def test_compiler_cpp_stds(self): @@ -4529,7 +4526,7 @@ class LinuxlikeTests(BasePlatformTests): ''' testdir = os.path.join(self.common_test_dir, '2 cpp') env = get_fake_env(testdir, self.builddir, self.prefix) - cpp = env.detect_cpp_compiler(False) + cpp = env.detect_cpp_compiler(MachineChoice.HOST) self._test_stds_impl(testdir, cpp, 'cpp') def test_unity_subproj(self): @@ -5196,7 +5193,10 @@ endian = 'little' @skipIfNoPkgconfig def test_pkg_config_option(self): testdir = os.path.join(self.unit_test_dir, '55 pkg_config_path option') - self.init(testdir, extra_args=['-Dpkg_config_path=' + os.path.join(testdir, 'host_extra_path')]) + self.init(testdir, extra_args=[ + '-Dbuild.pkg_config_path=' + os.path.join(testdir, 'build_extra_path'), + '-Dpkg_config_path=' + os.path.join(testdir, 'host_extra_path'), + ]) def test_std_remains(self): # C_std defined in project options must be in effect also when native compiling. @@ -5781,17 +5781,16 @@ class NativeFileTests(BasePlatformTests): f.write('@py -3 {} %*'.format(filename)) return batfile - def helper_for_compiler(self, lang, cb): + def helper_for_compiler(self, lang, cb, for_machine = MachineChoice.HOST): """Helper for generating tests for overriding compilers for langaugages with more than one implementation, such as C, C++, ObjC, ObjC++, and D. """ env = get_fake_env() getter = getattr(env, 'detect_{}_compiler'.format(lang)) - if lang not in ['cs']: - getter = functools.partial(getter, False) + getter = functools.partial(getter, for_machine) cc = getter() binary, newid = cb(cc) - env.binaries.host.binaries[lang] = binary + env.binaries[for_machine].binaries[lang] = binary compiler = getter() self.assertEqual(compiler.id, newid) @@ -5956,8 +5955,7 @@ class NativeFileTests(BasePlatformTests): wrapper = self.helper_create_binary_wrapper(binary, version=version_str) env = get_fake_env() getter = getattr(env, 'detect_{}_compiler'.format(lang)) - if lang in ['rust']: - getter = functools.partial(getter, False) + getter = functools.partial(getter, MachineChoice.HOST) env.binaries.host.binaries[lang] = wrapper compiler = getter() self.assertEqual(compiler.version, version) @@ -5985,7 +5983,7 @@ class NativeFileTests(BasePlatformTests): 'swiftc', version='Swift 1.2345', outfile='stderr') env = get_fake_env() env.binaries.host.binaries['swift'] = wrapper - compiler = env.detect_swift_compiler() + compiler = env.detect_swift_compiler(MachineChoice.HOST) self.assertEqual(compiler.version, '1.2345') def test_native_file_dirs(self): diff --git a/test cases/unit/55 pkg_config_path option/meson.build b/test cases/unit/55 pkg_config_path option/meson.build index 3af6164f1..f9ceead06 100644 --- a/test cases/unit/55 pkg_config_path option/meson.build +++ b/test cases/unit/55 pkg_config_path option/meson.build @@ -3,10 +3,5 @@ project('pkg_config_path option') build = dependency('totally_made_up_dep', native: true, method : 'pkg-config') host = dependency('totally_made_up_dep', native: false, method : 'pkg-config') -# TODO always test we can do this separately -if meson.is_cross_build() - assert(build.version() == '4.5.6', 'wrong version for build machine dependency') -else - assert(host.version() == '1.2.3', 'wrong version for host machine dependency') -endif +assert(build.version() == '4.5.6', 'wrong version for build machine dependency') assert(host.version() == '1.2.3', 'wrong version for host machine dependency') From 3b54f38c845e0b3330a2e1fe3985884eb005e856 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 25 Feb 2019 02:45:20 -0500 Subject: [PATCH 3/7] Add some type annotations Some things, like `method[...](...)` or `x: ... = ...` python 3.5 doesn't support, so I made a comment instead with the intention that it can someday be made into a real annotation. --- mesonbuild/build.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 763e5c9fb..7856fbdcc 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 @@ -30,6 +29,7 @@ from .mesonlib import ( 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']) @@ -113,16 +113,16 @@ class Build: self.environment = environment self.projects = {} self.targets = OrderedDict() - self.global_args = PerMachine({}, {}) - self.projects_args = PerMachine({}, {}) - self.global_link_args = PerMachine({}, {}) - self.projects_link_args = PerMachine({}, {}) + 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 = PerMachine(None, None) + self.static_linker = PerMachine(None, None) # type: PerMachine[StaticLinker] self.subprojects = {} self.subproject_dir = '' self.install_scripts = [] @@ -1144,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++ From 2ddb1af29462fb645d522aea31f4caba57311adf Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sun, 24 Feb 2019 14:32:29 -0500 Subject: [PATCH 4/7] Simplify and dedup machine kwarg -> MachineChoice logic in the interpreter --- mesonbuild/interpreter.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 5dddb2293..673644b4d 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1035,12 +1035,8 @@ class CompilerHolder(InterpreterObject): idir = os.path.join(self.environment.get_source_dir(), i.held_object.get_curdir(), idir) args += self.compiler.get_include_args(idir, False) - native = kwargs.get('native', None) - if native: - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST if not nobuiltins: + for_machine = Interpreter.machine_from_native_kwarg(kwargs) opts = self.environment.coredata.compiler_options[for_machine] args += self.compiler.get_option_compile_args(opts) if mode == 'link': @@ -1841,12 +1837,7 @@ class MesonMain(InterpreterObject): if len(args) != 1: raise InterpreterException('get_compiler_method must have one and only one argument.') cname = args[0] - native = kwargs.get('native', None) - if native is None: - if self.build.environment.is_cross_build(): - native = False - else: - native = True + native = kwargs.get('native', False) if not isinstance(native, bool): raise InterpreterException('Type of "native" must be a boolean.') clist = self.interpreter.coredata.compilers[MachineChoice.BUILD if native else MachineChoice.HOST] @@ -2937,7 +2928,7 @@ external dependencies (including libraries) must go to "dependencies".''') def _find_cached_dep(self, name, kwargs): # Check if we want this as a build-time / build machine or runt-time / # host machine dep. - for_machine = MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST + for_machine = Interpreter.machine_from_native_kwarg(kwargs) identifier = dependencies.get_dep_identifier(name, kwargs) cached_dep = self.coredata.deps[for_machine].get(identifier) @@ -4086,10 +4077,7 @@ Try setting b_lundef to false instead.'''.format(self.coredata.base_options['b_s if not args: raise InterpreterException('Target does not have a name.') name, *sources = args - if kwargs.get('native', False): - for_machine = MachineChoice.BUILD - else: - for_machine = MachineChoice.HOST + for_machine = Interpreter.machine_from_native_kwarg(kwargs) if 'sources' in kwargs: sources += listify(kwargs['sources']) sources = self.source_strings_to_files(sources) @@ -4231,3 +4219,7 @@ This will become a hard error in the future.''', location=self.current_node) raise InvalidCode('Is_variable takes two arguments.') varname = args[0] return varname in self.variables + + @staticmethod + def machine_from_native_kwarg(kwargs): + return MachineChoice.BUILD if kwargs.get('native', False) else MachineChoice.HOST From 8a09434cd4e171001bb649989d520112a58c9123 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 4 Oct 2018 20:52:08 -0400 Subject: [PATCH 5/7] remove `for_XXX` functions from mesonlib All uses now use `env.machines.YYY.is_XXX` instead. --- mesonbuild/mesonlib.py | 70 ------------------------------------------ 1 file changed, 70 deletions(-) diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 1b07d85a2..d052a2b69 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -463,76 +463,6 @@ def is_dragonflybsd() -> bool: def is_freebsd() -> bool: return platform.system().lower() == 'freebsd' -def for_windows(env): - """ - Host machine is windows? - - Deprecated: Please use `env.machines.host.is_windows()`. - - Note: 'host' is the machine on which compiled binaries will run - """ - return env.machines.host.is_windows() - -def for_cygwin(env): - """ - Host machine is cygwin? - - Deprecated: Please use `env.machines.host.is_cygwin()`. - - Note: 'host' is the machine on which compiled binaries will run - """ - return env.machines.host.is_cygwin() - -def for_linux(env): - """ - Host machine is linux? - - Deprecated: Please use `env.machines.host.is_linux()`. - - Note: 'host' is the machine on which compiled binaries will run - """ - return env.machines.host.is_linux() - -def for_darwin(env): - """ - Host machine is Darwin (iOS/OS X)? - - Deprecated: Please use `env.machines.host.is_darwin()`. - - Note: 'host' is the machine on which compiled binaries will run - """ - return env.machines.host.is_darwin() - -def for_android(env): - """ - Host machine is Android? - - Deprecated: Please use `env.machines.host.is_android()`. - - Note: 'host' is the machine on which compiled binaries will run - """ - return env.machines.host.is_android() - -def for_haiku(env): - """ - Host machine is Haiku? - - Deprecated: Please use `env.machines.host.is_haiku()`. - - Note: 'host' is the machine on which compiled binaries will run - """ - return env.machines.host.is_haiku() - -def for_openbsd(env): - """ - Host machine is OpenBSD? - - Deprecated: Please use `env.machines.host.is_openbsd()`. - - Note: 'host' is the machine on which compiled binaries will run - """ - return env.machines.host.is_openbsd() - def exe_exists(arglist: List[str]) -> bool: try: if subprocess.run(arglist, timeout=10).returncode == 0: From b9d7e98e599776f58590b0a81f343eb676c8393d Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 28 Nov 2018 23:03:00 -0500 Subject: [PATCH 6/7] Simplify `ConfigToolDependency` for_machine `native` kwarg is already handled --- mesonbuild/dependencies/base.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 4c0d410bc..21da8e24a 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -369,7 +369,6 @@ class ConfigToolDependency(ExternalDependency): def __init__(self, name, environment, language, kwargs): super().__init__('config-tool', environment, language, kwargs) self.name = name - self.native = kwargs.get('native', False) self.tools = listify(kwargs.get('tools', self.tools)) req_version = kwargs.get('version', None) @@ -423,12 +422,11 @@ class ConfigToolDependency(ExternalDependency): if not isinstance(versions, list) and versions is not None: versions = listify(versions) - for_machine = MachineChoice.BUILD if self.native else MachineChoice.HOST - tool = self.env.binaries[for_machine].lookup_entry(self.tool_name) + tool = self.env.binaries[self.for_machine].lookup_entry(self.tool_name) if tool is not None: tools = [tool] else: - if self.env.is_cross_build() and not self.native: + if not self.env.machines.matches_build_machine(self.for_machine): mlog.deprecation('No entry for {0} specified in your cross file. ' 'Falling back to searching PATH. This may find a ' 'native version of {0}! This will become a hard ' From 6d6af46edcb765d7046533fdad4d03b0c0c9cd64 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 10 Apr 2019 08:05:00 -0400 Subject: [PATCH 7/7] Make test for identity (cherry picked from commit ae6426cd8acfe0ccc5d7958d55edb613b4a5bf01) --- run_unittests.py | 12 +++++++++ .../unit/58 identity cross/build_wrapper.py | 5 ++++ .../unit/58 identity cross/host_wrapper.py | 5 ++++ test cases/unit/58 identity cross/meson.build | 15 +++++++++++ test cases/unit/58 identity cross/stuff.h | 27 +++++++++++++++++++ 5 files changed, 64 insertions(+) create mode 100755 test cases/unit/58 identity cross/build_wrapper.py create mode 100755 test cases/unit/58 identity cross/host_wrapper.py create mode 100644 test cases/unit/58 identity cross/meson.build create mode 100644 test cases/unit/58 identity cross/stuff.h diff --git a/run_unittests.py b/run_unittests.py index 23b8f2c7a..90d4a6289 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -5206,6 +5206,18 @@ endian = 'little' self.assertRegex(compdb[0]['command'], '-std=c99') self.build() + def test_identity_cross(self): + testdir = os.path.join(self.unit_test_dir, '58 identity cross') + crossfile = tempfile.NamedTemporaryFile(mode='w') + os.environ['CC'] = '"' + os.path.join(testdir, 'build_wrapper.py') + '"' + crossfile.write('''[binaries] +c = ['{0}'] +'''.format(os.path.join(testdir, 'host_wrapper.py'))) + crossfile.flush() + self.meson_cross_file = crossfile.name + # TODO should someday be explicit about build platform only here + self.init(testdir) + def should_run_cross_arm_tests(): return shutil.which('arm-linux-gnueabihf-gcc') and not platform.machine().lower().startswith('arm') diff --git a/test cases/unit/58 identity cross/build_wrapper.py b/test cases/unit/58 identity cross/build_wrapper.py new file mode 100755 index 000000000..22e8b5dc1 --- /dev/null +++ b/test cases/unit/58 identity cross/build_wrapper.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +import subprocess, sys + +subprocess.call(["cc", "-DEXTERNAL_BUILD"] + sys.argv[1:]) diff --git a/test cases/unit/58 identity cross/host_wrapper.py b/test cases/unit/58 identity cross/host_wrapper.py new file mode 100755 index 000000000..5b4eed8be --- /dev/null +++ b/test cases/unit/58 identity cross/host_wrapper.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +import subprocess, sys + +subprocess.call(["cc", "-DEXTERNAL_HOST"] + sys.argv[1:]) diff --git a/test cases/unit/58 identity cross/meson.build b/test cases/unit/58 identity cross/meson.build new file mode 100644 index 000000000..950137a18 --- /dev/null +++ b/test cases/unit/58 identity cross/meson.build @@ -0,0 +1,15 @@ +project('identity cross test', 'c') + +assert(meson.get_compiler('c', native: true).get_define( + 'GOT', + args : [ '-DARG_BUILD' ], + prefix : '#include "stuff.h"', + include_directories: include_directories('.'), +) == 'BUILD', 'did not get BUILD from native: true compiler') + +assert(meson.get_compiler('c', native: false).get_define( + 'GOT', + args : [ '-DARG_HOST' ], + prefix : '#include "stuff.h"', + include_directories: include_directories('.'), +) == 'HOST', 'did not get HOST from native: false compiler') diff --git a/test cases/unit/58 identity cross/stuff.h b/test cases/unit/58 identity cross/stuff.h new file mode 100644 index 000000000..62f1cc9e6 --- /dev/null +++ b/test cases/unit/58 identity cross/stuff.h @@ -0,0 +1,27 @@ +#ifdef EXTERNAL_BUILD + #ifndef ARG_BUILD + #error "External is build but arg_build is not set." + #elif defined(ARG_HOST) + #error "External is build but arg_host is set." + #else + #define GOT BUILD + #endif +#endif + +#ifdef EXTERNAL_HOST + #ifndef ARG_HOST + #error "External is host but arg_host is not set." + #elif defined(ARG_BUILD) + #error "External is host but arg_build is set." + #else + #define GOT HOST + #endif +#endif + +#if defined(EXTERNAL_BUILD) && defined(EXTERNAL_HOST) + #error "Both external build and external host set." +#endif + +#if !defined(EXTERNAL_BUILD) && !defined(EXTERNAL_HOST) + #error "Neither external build nor external host is set." +#endif