diff options
25 files changed, 315 insertions, 136 deletions
diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 483f1eb..3d04ffc 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -57,6 +57,29 @@ jobs: architecture: 'x64' - template: ci/azure-steps.yml +- job: vs2019 + pool: + vmImage: windows-2019 + + strategy: + matrix: + vc2019x64ninja: + arch: x64 + compiler: msvc2019 + backend: ninja + vc2019x64vs: + arch: x64 + compiler: msvc2019 + backend: vs2019 + + steps: + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.7' + addToPath: true + architecture: 'x64' + - template: ci/azure-steps.yml + - job: cygwin pool: vmImage: VS2017-Win2016 @@ -73,6 +96,7 @@ jobs: - script: | %CYGWIN_ROOT%\cygwinsetup.exe -qnNdO -R "%CYGWIN_ROOT%" -s "%CYGWIN_MIRROR%" -g -P ^ cmake,^ + gcc-fortran,^ gcc-objc++,^ gcc-objc,^ git,^ @@ -154,7 +178,7 @@ jobs: set BOOST_ROOT= set PATH=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem set PATHEXT=%PATHEXT%;.py - if %compiler%==clang ( set CC=clang && set CXX=clang++ ) + if %compiler%==clang ( set CC=clang && set CXX=clang++ && set OBJC=clang && set OBJCXX=clang++ ) %MSYS2_ROOT%\usr\bin\bash -lc "MSYSTEM= python3 run_tests.py --backend=ninja" env: CHERE_INVOKING: yes diff --git a/ci/azure-steps.yml b/ci/azure-steps.yml index d0f6d09..abbed65 100644 --- a/ci/azure-steps.yml +++ b/ci/azure-steps.yml @@ -5,8 +5,8 @@ steps: exit 0 } - # remove MinGW from path, so we don't find gfortran and try to use it - $env:Path = ($env:Path.Split(';') | Where-Object { $_ -notlike '*mingw*' }) -join ';' + # remove Chocolately, MinGW, Strawberry Perl from path, so we don't find gcc/gfortran and try to use it + $env:Path = ($env:Path.Split(';') | Where-Object { $_ -notmatch 'mingw|Strawberry|Chocolatey' }) -join ';' # download and install prerequisites function DownloadFile([String] $Source, [String] $Destination) { @@ -99,6 +99,8 @@ steps: # import visual studio variables if ($env:compiler -eq 'msvc2015') { $vcvars = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" + } elseif($env:compiler -eq 'msvc2019') { + $vcvars = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" } else { $vcvars = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" } @@ -154,7 +156,10 @@ steps: echo "" echo "=== Start running tests ===" - python run_tests.py --backend $(backend) + # Starting from VS2019 Powershell(?) will fail the test run + # if it prints anything to stderr. Python's test runner + # does that by default so we need to forward it. + cmd /c 'python 2>&1' run_tests.py --backend $(backend) - task: PublishTestResults@2 inputs: diff --git a/docs/markdown/Configuring-a-build-directory.md b/docs/markdown/Configuring-a-build-directory.md index 73585e2..b0fb574 100644 --- a/docs/markdown/Configuring-a-build-directory.md +++ b/docs/markdown/Configuring-a-build-directory.md @@ -24,7 +24,7 @@ sample output for a simple project. Option Current Value Possible Values Description ------ ------------- --------------- ----------- auto_features auto [enabled, disabled, auto] Override value of all 'auto' features - backend ninja [ninja, vs, vs2010, vs2015, vs2017, xcode] Backend to use + backend ninja [ninja, vs, vs2010, vs2015, vs2017, vs2019, xcode] Backend to use buildtype release [plain, debug, debugoptimized, release, minsize, custom] Build type to use debug false [true, false] Debug default_library shared [shared, static, both] Default library type diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index 2789ee0..50dbcf5 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -394,7 +394,7 @@ The `language` keyword may used. *(added 0.51.0)* -`method` may be `auto` or `config-tool`. +`method` may be `auto`, `config-tool` or `pkg-config`. ## Python3 diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 5825004..056612d 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1066,8 +1066,9 @@ res2 = foo / bar ``` Builds a library that is either static, shared or both depending on -the value of `default_library` user option. You should use this -instead of [`shared_library`](#shared_library), +the value of `default_library` +user [option](https://mesonbuild.com/Builtin-options.html). +You should use this instead of [`shared_library`](#shared_library), [`static_library`](#static_library) or [`both_libraries`](#both_libraries) most of the time. This allows you to toggle your entire project (including subprojects) from shared to @@ -1552,7 +1553,8 @@ the following methods. `MESON_SOURCE_ROOT` and `MESON_BUILD_ROOT` set. - `backend()` *(added 0.37.0)* returns a string representing the - current backend: `ninja`, `vs2010`, `vs2015`, `vs2017`, or `xcode`. + current backend: `ninja`, `vs2010`, `vs2015`, `vs2017`, `vs2019`, + or `xcode`. - `build_root()` returns a string with the absolute path to the build root directory. Note: this function will return the build root of diff --git a/docs/markdown/snippets/gpgme-config.md b/docs/markdown/snippets/gpgme-config.md index 08a7d38..65569fb 100644 --- a/docs/markdown/snippets/gpgme-config.md +++ b/docs/markdown/snippets/gpgme-config.md @@ -1,3 +1,3 @@ ## gpgme dependency now supports gpgme-config -Previously, we could only detect GPGME with custom invocations of `gpgme-config`. Now we added support to Meson allowing us to use `dependency('gpgme')` instead. +Previously, we could only detect GPGME with custom invocations of `gpgme-config` or when the GPGME version was recent enough (>=1.13.0) to install pkg-config files. Now we added support to Meson allowing us to use `dependency('gpgme')` and fall back on `gpgme-config` parsing. diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index a3b9ce8..08b14c8 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1757,7 +1757,7 @@ rule FORTRAN_DEP_HACK%s exe_arr = self.exe_object_to_cmd_array(exe) infilelist = genlist.get_inputs() outfilelist = genlist.get_outputs() - extra_dependencies = [os.path.join(self.build_to_src, i) for i in genlist.extra_depends] + extra_dependencies = self.get_custom_target_depend_files(genlist) for i in range(len(infilelist)): curfile = infilelist[i] if len(generator.outputs) == 1: @@ -2418,7 +2418,7 @@ rule FORTRAN_DEP_HACK%s guessed_dependencies = [] # TODO The get_library_naming requirement currently excludes link targets that use d or fortran as their main linker if hasattr(linker, 'get_library_naming'): - search_dirs = tuple(search_dirs) + linker.get_library_dirs(self.environment) + search_dirs = tuple(search_dirs) + tuple(linker.get_library_dirs(self.environment)) static_patterns = linker.get_library_naming(self.environment, LibType.STATIC, strict=True) shared_patterns = linker.get_library_naming(self.environment, LibType.SHARED, strict=True) for libname in libs: diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 2ef8187..d1bf1e5 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -126,6 +126,7 @@ class Vs2010Backend(backends.Backend): sole_output = '' curfile = infilelist[i] infilename = os.path.join(down, curfile.rel_to_builddir(self.build_to_src)) + deps = self.get_custom_target_depend_files(genlist, True) base_args = generator.get_arglist(infilename) outfiles_rel = genlist.get_outputs_for(curfile) outfiles = [os.path.join(target_private_dir, of) for of in outfiles_rel] @@ -156,6 +157,8 @@ class Vs2010Backend(backends.Backend): cbs = ET.SubElement(idgroup, 'CustomBuild', Include=infilename) ET.SubElement(cbs, 'Command').text = ' '.join(self.quote_arguments(cmd)) ET.SubElement(cbs, 'Outputs').text = ';'.join(outfiles) + if deps: + ET.SubElement(cbs, 'AdditionalInputs').text = ';'.join(deps) return generator_output_files, custom_target_output_files, custom_target_include_dirs def generate(self, interp): @@ -207,7 +210,7 @@ class Vs2010Backend(backends.Backend): if 'VCINSTALLDIR' in os.environ: vs_version = os.environ['VisualStudioVersion'] \ if 'VisualStudioVersion' in os.environ else None - relative_path = 'Auxiliary\\Build\\' if vs_version == '15.0' else '' + relative_path = 'Auxiliary\\Build\\' if vs_version >= '15.0' else '' script_path = os.environ['VCINSTALLDIR'] + relative_path + 'vcvarsall.bat' if os.path.exists(script_path): if has_arch_values: @@ -507,7 +510,6 @@ class Vs2010Backend(backends.Backend): def gen_run_target_vcxproj(self, target, ofname, guid): root = self.create_basic_crap(target, guid) - action = ET.SubElement(root, 'ItemDefinitionGroup') cmd_raw = [target.command] + target.args cmd = python_command + \ [os.path.join(self.environment.get_script_dir(), 'commandrunner.py'), diff --git a/mesonbuild/backend/vs2019backend.py b/mesonbuild/backend/vs2019backend.py new file mode 100644 index 0000000..c6e78cb --- /dev/null +++ b/mesonbuild/backend/vs2019backend.py @@ -0,0 +1,34 @@ +# Copyright 2014-2019 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import xml.etree.ElementTree as ET + +from .vs2010backend import Vs2010Backend + + +class Vs2019Backend(Vs2010Backend): + def __init__(self, build): + super().__init__(build) + self.name = 'vs2019' + self.platform_toolset = 'v142' + self.vs_version = '2019' + # WindowsSDKVersion should be set by command prompt. + sdk_version = os.environ.get('WindowsSDKVersion', None) + if sdk_version: + self.windows_target_platform_version = sdk_version.rstrip('\\') + + def generate_debug_information(self, link): + # valid values for vs2019 is 'false', 'true', 'DebugFastLink', 'DebugFull' + ET.SubElement(link, 'GenerateDebugInformation').text = 'DebugFull' diff --git a/mesonbuild/build.py b/mesonbuild/build.py index dae94b6..66f08d8 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1365,8 +1365,17 @@ class GeneratedList: self.outfilelist = [] self.outmap = {} self.extra_depends = [] + self.depend_files = [] self.preserve_path_from = preserve_path_from self.extra_args = extra_args + if isinstance(generator.exe, dependencies.ExternalProgram): + if not generator.exe.found(): + raise InvalidArguments('Tried to use not-found external program as generator') + path = generator.exe.get_path() + if os.path.isabs(path): + # Can only add a dependency on an external program which we + # know the absolute path of + self.depend_files.append(File.from_absolute_file(path)) def add_preserved_path_segment(self, infile, outfiles, state): result = [] @@ -1962,8 +1971,7 @@ class CustomTarget(Target): final_cmd.append(c) elif isinstance(c, dependencies.ExternalProgram): if not c.found(): - m = 'Tried to use not-found external program {!r} in "command"' - raise InvalidArguments(m.format(c.name)) + raise InvalidArguments('Tried to use not-found external program in "command"') path = c.get_path() if os.path.isabs(path): # Can only add a dependency on an external program which we diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 12f7838..da9a5dc 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -1674,6 +1674,9 @@ class VisualStudioCCompiler(CCompiler): return '14.0' # (Visual Studio 2015) elif version < 1920: return '14.1' # (Visual Studio 2017) + elif version < 1930: + return '14.2' # (Visual Studio 2019) + mlog.warning('Could not find toolset for version {!r}'.format(self.version)) return None def get_default_include_dirs(self): diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index e29ca55..2239aa8 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -914,6 +914,12 @@ class Compiler: def get_id(self): return self.id + def get_version_string(self): + details = [self.id, self.version] + if self.full_version: + details += ['"%s"' % (self.full_version)] + return '(%s)' % (' '.join(details)) + def get_language(self): return self.language @@ -1736,7 +1742,7 @@ class ElbrusCompiler(GnuCompiler): # FIXME: use _build_wrapper to call this so that linker flags from the env # get applied - def get_library_dirs(self, env): + def get_library_dirs(self, env, elf_class = None): os_env = os.environ.copy() os_env['LC_ALL'] = 'C' stdo = Popen_safe(self.exelist + ['--print-search-dirs'], env=os_env)[1] diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 67de684..87e6ffc 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -115,8 +115,8 @@ class CPPCompiler(CCompiler): 'gnu++17': 'gnu++1z' } - # Currently, remapping is only supported for Clang and GCC - assert(self.id in frozenset(['clang', 'gcc'])) + # Currently, remapping is only supported for Clang, Elbrus and GCC + assert(self.id in frozenset(['clang', 'lcc', 'gcc'])) if cpp_std not in CPP_FALLBACKS: # 'c++03' and 'c++98' don't have fallback types @@ -251,10 +251,13 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): # It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98. def get_options(self): opts = CPPCompiler.get_options(self) - opts['cpp_std'] = coredata.UserComboOption('cpp_std', 'C++ language standard to use', - ['none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y', - 'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y'], - 'none') + opts.update({'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', + ['none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y', + 'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y'], + 'none'), + 'cpp_debugstl': coredata.UserBooleanOption('cpp_debugstl', + 'STL debug mode', + False)}) return opts # Elbrus C++ compiler does not have lchmod, but there is only linker warning, not compiler error. diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 6b86529..51b36f0 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -773,39 +773,41 @@ class BuiltinOption(Generic[_U]): kwargs['dest'] = 'cross_' + name parser.add_argument(self.argparse_name_to_arg('cross_' + name), help=h + ' (for host in cross compiles)', **kwargs) - -builtin_options = { - 'buildtype': BuiltinOption(UserComboOption, 'Build type to use', 'debug', - choices=['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom']), - 'strip': BuiltinOption(UserBooleanOption, 'Strip targets on install', False), - 'unity': BuiltinOption(UserComboOption, 'Unity build', 'off', choices=['on', 'off', 'subprojects']), - 'prefix': BuiltinOption(UserStringOption, 'Installation prefix', default_prefix()), - 'libdir': BuiltinOption(UserStringOption, 'Library directory', default_libdir()), - 'libexecdir': BuiltinOption(UserStringOption, 'Library executable directory', default_libexecdir()), - 'bindir': BuiltinOption(UserStringOption, 'Executable directory', 'bin'), - 'sbindir': BuiltinOption(UserStringOption, 'System executable directory', 'sbin'), - 'includedir': BuiltinOption(UserStringOption, 'Header file directory', 'include'), - 'datadir': BuiltinOption(UserStringOption, 'Data file directory', 'share'), - 'mandir': BuiltinOption(UserStringOption, 'Manual page directory', 'share/man'), - 'infodir': BuiltinOption(UserStringOption, 'Info page directory', 'share/info'), - 'localedir': BuiltinOption(UserStringOption, 'Locale data directory', 'share/locale'), - 'sysconfdir': BuiltinOption(UserStringOption, 'Sysconf data directory', 'etc'), - 'localstatedir': BuiltinOption(UserStringOption, 'Localstate data directory', 'var'), - 'sharedstatedir': BuiltinOption(UserStringOption, 'Architecture-independent data directory', 'com'), - 'werror': BuiltinOption(UserBooleanOption, 'Treat warnings as errors', False), - 'warning_level': BuiltinOption(UserComboOption, 'Compiler warning level to use', '1', choices=['0', '1', '2', '3']), - 'layout': BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat']), - 'default_library': BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both']), - 'backend': BuiltinOption(UserComboOption, 'Backend to use', 'ninja', choices=backendlist), - 'stdsplit': BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True), - 'errorlogs': BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True), - 'install_umask': BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022'), - 'auto_features': BuiltinOption(UserFeatureOption, "Override value of all 'auto' features", 'auto'), - 'optimization': BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['0', 'g', '1', '2', '3', 's']), - 'debug': BuiltinOption(UserBooleanOption, 'Debug', True), - 'wrap_mode': BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback']), - 'pkg_config_path': BuiltinOption(UserArrayOption, 'List of additional paths for pkg-config to search', [], separate_cross=True), -} +# Update `docs/markdown/Builtin-options.md` after changing the options below +builtin_options = OrderedDict([ + # Directories + ('prefix', BuiltinOption(UserStringOption, 'Installation prefix', default_prefix())), + ('bindir', BuiltinOption(UserStringOption, 'Executable directory', 'bin')), + ('datadir', BuiltinOption(UserStringOption, 'Data file directory', 'share')), + ('includedir', BuiltinOption(UserStringOption, 'Header file directory', 'include')), + ('infodir', BuiltinOption(UserStringOption, 'Info page directory', 'share/info')), + ('libdir', BuiltinOption(UserStringOption, 'Library directory', default_libdir())), + ('libexecdir', BuiltinOption(UserStringOption, 'Library executable directory', default_libexecdir())), + ('localedir', BuiltinOption(UserStringOption, 'Locale data directory', 'share/locale')), + ('localstatedir', BuiltinOption(UserStringOption, 'Localstate data directory', 'var')), + ('mandir', BuiltinOption(UserStringOption, 'Manual page directory', 'share/man')), + ('sbindir', BuiltinOption(UserStringOption, 'System executable directory', 'sbin')), + ('sharedstatedir', BuiltinOption(UserStringOption, 'Architecture-independent data directory', 'com')), + ('sysconfdir', BuiltinOption(UserStringOption, 'Sysconf data directory', 'etc')), + # Core options + ('auto_features', BuiltinOption(UserFeatureOption, "Override value of all 'auto' features", 'auto')), + ('backend', BuiltinOption(UserComboOption, 'Backend to use', 'ninja', choices=backendlist)), + ('buildtype', BuiltinOption(UserComboOption, 'Build type to use', 'debug', + choices=['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom'])), + ('debug', BuiltinOption(UserBooleanOption, 'Debug', True)), + ('default_library', BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both'])), + ('errorlogs', BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)), + ('install_umask', BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')), + ('layout', BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])), + ('pkg_config_path', BuiltinOption(UserArrayOption, 'List of additional paths for pkg-config to search', [], separate_cross=True)), + ('optimization', BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['0', 'g', '1', '2', '3', 's'])), + ('stdsplit', BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)), + ('strip', BuiltinOption(UserBooleanOption, 'Strip targets on install', False)), + ('unity', BuiltinOption(UserComboOption, 'Unity build', 'off', choices=['on', 'off', 'subprojects'])), + ('warning_level', BuiltinOption(UserComboOption, 'Compiler warning level to use', '1', choices=['0', '1', '2', '3'])), + ('werror', BuiltinOption(UserBooleanOption, 'Treat warnings as errors', False)), + ('wrap_mode', BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback'])), +]) # Special prefix-dependent defaults for installation directories that reside in # a path outside of the prefix in FHS and common usage. diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 219b3d6..55cb569 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -680,6 +680,9 @@ class GpgmeDependency(ExternalDependency): methods = cls._process_method_kw(kwargs) candidates = [] + if DependencyMethods.PKGCONFIG in methods: + candidates.append(functools.partial(PkgConfigDependency, 'gpgme', environment, kwargs)) + if DependencyMethods.CONFIG_TOOL in methods: candidates.append(functools.partial(ConfigToolDependency.factory, 'gpgme', environment, None, kwargs, ['gpgme-config'], @@ -696,7 +699,7 @@ class GpgmeDependency(ExternalDependency): @staticmethod def get_methods(): - return [DependencyMethods.CONFIG_TOOL] + return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL] class ShadercDependency(ExternalDependency): @@ -732,12 +735,25 @@ class ShadercDependency(ExternalDependency): methods = cls._process_method_kw(kwargs) candidates = [] + if DependencyMethods.PKGCONFIG in methods: + # ShaderC packages their shared and static libs together + # and provides different pkg-config files for each one. We + # smooth over this difference by handling the static + # keyword before handing off to the pkg-config handler. + shared_libs = ['shaderc'] + static_libs = ['shaderc_combined', 'shaderc_static'] + + if kwargs.get('static', False): + c = [functools.partial(PkgConfigDependency, name, environment, kwargs) + for name in static_libs + shared_libs] + else: + c = [functools.partial(PkgConfigDependency, name, environment, kwargs) + for name in shared_libs + static_libs] + candidates.exend(c) + if DependencyMethods.SYSTEM in methods: candidates.append(functools.partial(ShadercDependency, environment, kwargs)) - if DependencyMethods.PKGCONFIG in methods: - candidates.append(functools.partial(PkgConfigDependency, 'shaderc', environment, kwargs)) - return candidates @staticmethod diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 2241089..f85decd 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -921,6 +921,8 @@ class Environment: return GnuObjCCompiler(ccache + compiler, version, compiler_type, is_cross, exe_wrap, defines) if out.startswith('Apple LLVM'): return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, is_cross, exe_wrap) + if 'windows' in out: + return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_MINGW, is_cross, exe_wrap) if out.startswith(('clang', 'OpenBSD clang')): return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, is_cross, exe_wrap) self._handle_exceptions(popen_exceptions, compilers) @@ -948,6 +950,8 @@ class Environment: return GnuObjCPPCompiler(ccache + compiler, version, compiler_type, is_cross, exe_wrap, defines) if out.startswith('Apple LLVM'): return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, is_cross, exe_wrap) + if 'windows' in out: + return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_MINGW, is_cross, exe_wrap) if out.startswith(('clang', 'OpenBSD clang')): return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, is_cross, exe_wrap) self._handle_exceptions(popen_exceptions, compilers) @@ -1084,65 +1088,43 @@ class Environment: return compilers.SwiftCompiler(exelist, version) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') - def compilers_from_language(self, lang: str, need_cross_compiler: bool): - comp = None - cross_comp = None + def compiler_from_language(self, lang: str, want_cross: bool): if lang == 'c': - comp = self.detect_c_compiler(False) - if need_cross_compiler: - cross_comp = self.detect_c_compiler(True) + comp = self.detect_c_compiler(want_cross) elif lang == 'cpp': - comp = self.detect_cpp_compiler(False) - if need_cross_compiler: - cross_comp = self.detect_cpp_compiler(True) + comp = self.detect_cpp_compiler(want_cross) elif lang == 'objc': - comp = self.detect_objc_compiler(False) - if need_cross_compiler: - cross_comp = self.detect_objc_compiler(True) + comp = self.detect_objc_compiler(want_cross) elif lang == 'cuda': - comp = self.detect_cuda_compiler(False) - if need_cross_compiler: - cross_comp = self.detect_cuda_compiler(True) + comp = self.detect_cuda_compiler(want_cross) elif lang == 'objcpp': - comp = self.detect_objcpp_compiler(False) - if need_cross_compiler: - cross_comp = self.detect_objcpp_compiler(True) + comp = self.detect_objcpp_compiler(want_cross) elif lang == 'java': - comp = self.detect_java_compiler() - if need_cross_compiler: - cross_comp = comp # Java is platform independent. + comp = self.detect_java_compiler() # Java is platform independent. elif lang == 'cs': - comp = self.detect_cs_compiler() - if need_cross_compiler: - cross_comp = comp # C# is platform independent. + comp = self.detect_cs_compiler() # C# is platform independent. elif lang == 'vala': - comp = self.detect_vala_compiler() - if need_cross_compiler: - cross_comp = comp # Vala compiles to platform-independent C + comp = self.detect_vala_compiler() # Vala compiles to platform-independent C elif lang == 'd': - comp = self.detect_d_compiler(False) - if need_cross_compiler: - cross_comp = self.detect_d_compiler(True) + comp = self.detect_d_compiler(want_cross) elif lang == 'rust': - comp = self.detect_rust_compiler(False) - if need_cross_compiler: - cross_comp = self.detect_rust_compiler(True) + comp = self.detect_rust_compiler(want_cross) elif lang == 'fortran': - comp = self.detect_fortran_compiler(False) - if need_cross_compiler: - cross_comp = self.detect_fortran_compiler(True) + comp = self.detect_fortran_compiler(want_cross) elif lang == 'swift': - comp = self.detect_swift_compiler() - if need_cross_compiler: + if want_cross: raise EnvironmentException('Cross compilation with Swift is not working yet.') - # cross_comp = self.environment.detect_fortran_compiler(True) + comp = self.detect_swift_compiler() else: - return None, None - - return comp, cross_comp + comp = None + return comp def detect_compilers(self, lang: str, need_cross_compiler: bool): - (comp, cross_comp) = self.compilers_from_language(lang, need_cross_compiler) + comp = self.compiler_from_language(lang, False) + if need_cross_compiler: + cross_comp = self.compiler_from_language(lang, True) + else: + cross_comp = None if comp is not None: self.coredata.process_new_compilers(lang, comp, cross_comp, self) return comp, cross_comp diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 993ebbd..3a3fb81 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -2575,6 +2575,12 @@ external dependencies (including libraries) must go to "dependencies".''') if ':' in proj_name: raise InvalidArguments("Project name {!r} must not contain ':'".format(proj_name)) + if 'meson_version' in kwargs: + cv = coredata.version + pv = kwargs['meson_version'] + if not mesonlib.version_compare(cv, pv): + raise InterpreterException('Meson version is %s but project requires %s' % (cv, pv)) + if os.path.exists(self.option_file): oi = optinterpreter.OptionInterpreter(self.subproject) oi.process(self.option_file) @@ -2621,11 +2627,8 @@ external dependencies (including libraries) must go to "dependencies".''') mesonlib.project_meson_versions[self.subproject] = '' if 'meson_version' in kwargs: - cv = coredata.version - pv = kwargs['meson_version'] - mesonlib.project_meson_versions[self.subproject] = pv - if not mesonlib.version_compare(cv, pv): - raise InterpreterException('Meson version is %s but project requires %s.' % (cv, pv)) + mesonlib.project_meson_versions[self.subproject] = kwargs['meson_version'] + self.build.projects[self.subproject] = proj_name mlog.log('Project name:', mlog.bold(proj_name)) mlog.log('Project version:', mlog.bold(self.project_version)) @@ -2710,17 +2713,12 @@ external dependencies (including libraries) must go to "dependencies".''') continue else: raise - if comp.full_version is not None: - version_string = '(%s %s "%s")' % (comp.id, comp.version, comp.full_version) - else: - version_string = '(%s %s)' % (comp.id, comp.version) mlog.log('Native', comp.get_display_language(), 'compiler:', - mlog.bold(' '.join(comp.get_exelist())), version_string) + mlog.bold(' '.join(comp.get_exelist())), comp.get_version_string()) self.build.ensure_static_linker(comp) if need_cross_compiler: - version_string = '(%s %s)' % (cross_comp.id, cross_comp.version) mlog.log('Cross', cross_comp.get_display_language(), 'compiler:', - mlog.bold(' '.join(cross_comp.get_exelist())), version_string) + 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() diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index 91a52b1..e7005e9 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -81,14 +81,18 @@ class CommandLineParser: self.commands[i] = p def add_runpython_arguments(self, parser): + parser.add_argument('-c', action='store_true', dest='eval_arg', default=False) parser.add_argument('script_file') parser.add_argument('script_args', nargs=argparse.REMAINDER) def run_runpython_command(self, options): import runpy - sys.argv[1:] = options.script_args - sys.path.insert(0, os.path.dirname(options.script_file)) - runpy.run_path(options.script_file, run_name='__main__') + if options.eval_arg: + exec(options.script_file) + else: + sys.argv[1:] = options.script_args + sys.path.insert(0, os.path.dirname(options.script_file)) + runpy.run_path(options.script_file, run_name='__main__') return 0 def add_help_arguments(self, parser): diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index bd69244..a0ebe0e 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -42,9 +42,8 @@ mod_kwargs -= set(['name_prefix', 'name_suffix']) def run_command(python, command): - _, stdout, _ = mesonlib.Popen_safe(python.get_command() + [ - '-c', - command]) + cmd = python.get_command() + ['-c', command] + _, stdout, _ = mesonlib.Popen_safe(cmd) return stdout.strip() @@ -265,8 +264,7 @@ class PythonDependency(ExternalDependency): return super().get_pkgconfig_variable(variable_name, kwargs) -INTROSPECT_COMMAND = ''' -import sysconfig +INTROSPECT_COMMAND = '''import sysconfig import json import sys diff --git a/msi/createmsi.py b/msi/createmsi.py index a7a9c3c..4eb5111 100755 --- a/msi/createmsi.py +++ b/msi/createmsi.py @@ -84,6 +84,28 @@ class PackageGenerator: modules = ['mesonbuild.' + modname + '.' + x for x in modules if not x.startswith('_')] return modules + def get_more_modules(self): + # Python packagers want to minimal and only copy the things that + # they can see that are used. They are blind to many things. + return ['distutils.archive_util', + 'distutils.cmd', + 'distutils.config', + 'distutils.core', + 'distutils.debug', + 'distutils.dep_util', + 'distutils.dir_util', + 'distutils.dist', + 'distutils.errors', + 'distutils.extension', + 'distutils.fancy_getopt', + 'distutils.file_util', + 'distutils.spawn', + 'distutils.util', + 'distutils.version', + 'distutils.command.build_ext', + 'distutils.command.build', + ] + def build_dist(self): for sdir in self.staging_dirs: if os.path.exists(sdir): @@ -91,7 +113,7 @@ class PackageGenerator: main_stage, ninja_stage = self.staging_dirs modules = self.get_all_modules_from_dir('mesonbuild/modules') modules += self.get_all_modules_from_dir('mesonbuild/scripts') - modules += ['distutils.version'] + modules += self.get_more_modules() modulestr = ','.join(modules) python = shutil.which('python') cxfreeze = os.path.join(os.path.dirname(python), "Scripts", "cxfreeze") diff --git a/run_project_tests.py b/run_project_tests.py index fdb5f48..c1d42fc 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -27,6 +27,7 @@ import tempfile from pathlib import Path, PurePath from mesonbuild import build from mesonbuild import environment +from mesonbuild import compilers from mesonbuild import mesonlib from mesonbuild import mlog from mesonbuild import mtest @@ -564,8 +565,8 @@ def detect_tests_to_run(): ('vala', 'vala', backend is not Backend.ninja or not shutil.which('valac')), ('rust', 'rust', backend is not Backend.ninja or not shutil.which('rustc')), ('d', 'd', backend is not Backend.ninja or not have_d_compiler()), - ('objective c', 'objc', backend not in (Backend.ninja, Backend.xcode) or mesonlib.is_windows() or not have_objc_compiler()), - ('objective c++', 'objcpp', backend not in (Backend.ninja, Backend.xcode) or mesonlib.is_windows() or not have_objcpp_compiler()), + ('objective c', 'objc', backend not in (Backend.ninja, Backend.xcode) or not have_objc_compiler()), + ('objective c++', 'objcpp', backend not in (Backend.ninja, Backend.xcode) or not have_objcpp_compiler()), ('fortran', 'fortran', backend is not Backend.ninja or not shutil.which('gfortran')), ('swift', 'swift', backend not in (Backend.ninja, Backend.xcode) or not shutil.which('swiftc')), ('cuda', 'cuda', backend not in (Backend.ninja, Backend.xcode) or not shutil.which('nvcc')), @@ -768,11 +769,23 @@ def detect_system_compiler(): with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: env = environment.Environment(None, build_dir, get_fake_options('/')) - try: - comp = env.detect_c_compiler(env.is_cross_build()) - except: - raise RuntimeError("Could not find C compiler.") - system_compiler = comp.get_id() + print() + for lang in sorted(compilers.all_languages): + try: + comp = env.compiler_from_language(lang, env.is_cross_build()) + details = '%s %s' % (' '.join(comp.get_exelist()), comp.get_version_string()) + except: + comp = None + details = 'not found' + print('%-7s: %s' % (lang, details)) + + # note C compiler for later use by platform_fix_name() + if lang == 'c': + if comp: + system_compiler = comp.get_id() + else: + raise RuntimeError("Could not find C compiler.") + print() if __name__ == '__main__': parser = argparse.ArgumentParser(description="Run the test suite of Meson.") diff --git a/run_tests.py b/run_tests.py index d72546b..fb3bc28 100755 --- a/run_tests.py +++ b/run_tests.py @@ -292,7 +292,7 @@ def main(): os.environ.pop('platform') # Run tests print(mlog.bold('Running unittests.').get_text(mlog.colorize_console)) - print() + print(flush=True) # Can't pass arguments to unit tests, so set the backend to use in the environment env = os.environ.copy() env['MESON_UNIT_TEST_BACKEND'] = backend.name @@ -325,7 +325,7 @@ def main(): else: cross_test_args = mesonlib.python_command + ['run_cross_test.py'] print(mlog.bold('Running armhf cross tests.').get_text(mlog.colorize_console)) - print() + print(flush=True) cmd = cross_test_args + ['cross/ubuntu-armhf.txt'] if options.failfast: cmd += ['--failfast'] @@ -334,7 +334,7 @@ def main(): return returncode print(mlog.bold('Running mingw-w64 64-bit cross tests.') .get_text(mlog.colorize_console)) - print() + print(flush=True) cmd = cross_test_args + ['cross/linux-mingw-w64-64bit.txt'] if options.failfast: cmd += ['--failfast'] diff --git a/run_unittests.py b/run_unittests.py index 156e4b8..faef00f 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -958,6 +958,25 @@ class InternalTests(unittest.TestCase): self.assertEqual(ver_a.__cmp__(ver_b), result) self.assertEqual(ver_b.__cmp__(ver_a), -result) + def test_msvc_toolset_version(self): + ''' + Ensure that the toolset version returns the correct value for this MSVC + ''' + env = get_fake_env() + cc = env.detect_c_compiler(False) + if cc.get_argument_syntax() != 'msvc': + raise unittest.SkipTest('Test only applies to MSVC-like compilers') + toolset_ver = cc.get_toolset_version() + self.assertIsNotNone(toolset_ver) + # Visual Studio 2015 and older versions do not define VCToolsVersion + if int(''.join(cc.version.split('.')[0:2])) < 1910: + return + self.assertIn('VCToolsVersion', os.environ) + vctools_ver = os.environ['VCToolsVersion'] + self.assertTrue(vctools_ver.startswith(toolset_ver), + msg='{!r} does not start with {!r}'.format(vctools_ver, toolset_ver)) + + @unittest.skipIf(is_tarball(), 'Skipping because this is a tarball release') class DataTests(unittest.TestCase): @@ -2144,6 +2163,20 @@ class AllPlatformTests(BasePlatformTests): self.utime(os.path.join(testdir, f)) self.assertRebuiltTarget('prog') + def test_source_generator_program_cause_rebuild(self): + ''' + Test that changes to generator programs in the source tree cause + a rebuild. + ''' + testdir = os.path.join(self.common_test_dir, '95 gen extra') + self.init(testdir) + self.build() + # Immediately rebuilding should not do anything + self.assertBuildIsNoop() + # Changing mtime of generator should rebuild the executable + self.utime(os.path.join(testdir, 'srcgen.py')) + self.assertRebuiltTarget('basic') + def test_static_library_lto(self): ''' Test that static libraries can be built with LTO and linked to @@ -3611,12 +3644,13 @@ class FailureTests(BasePlatformTests): super().setUp() self.srcdir = os.path.realpath(tempfile.mkdtemp()) self.mbuild = os.path.join(self.srcdir, 'meson.build') + self.moptions = os.path.join(self.srcdir, 'meson_options.txt') def tearDown(self): super().tearDown() windows_proof_rmtree(self.srcdir) - def assertMesonRaises(self, contents, match, extra_args=None, langs=None, meson_version=None): + def assertMesonRaises(self, contents, match, extra_args=None, langs=None, meson_version=None, options=None): ''' Assert that running meson configure on the specified @contents raises a error message matching regex @match. @@ -3631,6 +3665,9 @@ class FailureTests(BasePlatformTests): for lang in langs: f.write("add_languages('{}', required : false)\n".format(lang)) f.write(contents) + if options is not None: + with open(self.moptions, 'w') as f: + f.write(options) # Force tracebacks so we can detect them properly os.environ['MESON_FORCE_BACKTRACE'] = '1' with self.assertRaisesRegex(MesonException, match, msg=contents): @@ -3863,6 +3900,14 @@ class FailureTests(BasePlatformTests): "sub1.get_variable('naaa')", """Subproject "subprojects/not-found-subproject" disabled can't get_variable on it.""") + def test_version_checked_before_parsing_options(self): + ''' + https://github.com/mesonbuild/meson/issues/5281 + ''' + options = "option('some-option', type: 'foo', value: '')" + match = 'Meson version is.*but project requires >=2000' + self.assertMesonRaises("", match, meson_version='>=2000', options=options) + @unittest.skipUnless(is_windows() or is_cygwin(), "requires Windows (or Windows via Cygwin)") class WindowsTests(BasePlatformTests): @@ -5796,7 +5841,11 @@ class NativeFileTests(BasePlatformTests): @skip_if_env_set('FC') def test_fortran_compiler(self): def cb(comp): - if comp.id == 'gcc': + if comp.id == 'lcc': + if shutil.which('lfortran'): + return 'lfortran', 'lcc' + raise unittest.SkipTest('No alternate Fortran implementation.') + elif comp.id == 'gcc': if shutil.which('ifort'): return 'ifort', 'intel' elif shutil.which('flang'): diff --git a/test cases/failing/96 dependency not config-tool/96 unknown config tool/meson.build b/test cases/failing/96 dependency not config-tool/96 unknown config tool/meson.build new file mode 100644 index 0000000..536976e --- /dev/null +++ b/test cases/failing/96 dependency not config-tool/96 unknown config tool/meson.build @@ -0,0 +1,2 @@ +project('no-such-config-tool') +dependency('no-such-config-tool', method:'config-tool') diff --git a/test cases/frameworks/27 gpgme/meson.build b/test cases/frameworks/27 gpgme/meson.build index 220a4c0..91b1aaa 100644 --- a/test cases/frameworks/27 gpgme/meson.build +++ b/test cases/frameworks/27 gpgme/meson.build @@ -19,3 +19,9 @@ dependency('gpgme', method: 'config-tool') # Check we can apply a version constraint dependency('gpgme', version: '>=@0@'.format(gpgme_dep.version()), method: 'config-tool') + +# If gpgme is new enough, make sure it picks up pkg-config by default: + +if gpgme_ver.version_compare('>=1.13.0') + assert(gpgme_dep.type_name() == 'pkgconfig', 'dependency found via pkg-config') +endif |
