diff options
-rw-r--r-- | docs/markdown/Builtin-options.md | 2 | ||||
-rw-r--r-- | docs/markdown/Reference-manual.md | 2 | ||||
-rw-r--r-- | docs/markdown/images/buildtime.png (renamed from docs/images/buildtime.png) | bin | 8764 -> 8764 bytes | |||
-rw-r--r-- | docs/markdown/images/conftime.png (renamed from docs/images/conftime.png) | bin | 10729 -> 10729 bytes | |||
-rw-r--r-- | docs/markdown/images/emptytime.png (renamed from docs/images/emptytime.png) | bin | 9960 -> 9960 bytes | |||
-rw-r--r-- | docs/markdown/images/glib_build.png (renamed from docs/images/glib_build.png) | bin | 10228 -> 10228 bytes | |||
-rw-r--r-- | docs/markdown/images/glib_conf.png (renamed from docs/images/glib_conf.png) | bin | 9186 -> 9186 bytes | |||
-rw-r--r-- | docs/markdown/images/glib_empty.png (renamed from docs/images/glib_empty.png) | bin | 8894 -> 8894 bytes | |||
-rw-r--r-- | docs/markdown/images/glib_link.png (renamed from docs/images/glib_link.png) | bin | 9057 -> 9057 bytes | |||
-rw-r--r-- | docs/markdown/images/gtksample.png (renamed from docs/images/gtksample.png) | bin | 3853 -> 3853 bytes | |||
-rw-r--r-- | docs/markdown/images/py3-install-1.png (renamed from docs/images/py3-install-1.png) | bin | 101763 -> 101763 bytes | |||
-rw-r--r-- | docs/markdown/images/py3-install-2.png (renamed from docs/images/py3-install-2.png) | bin | 99866 -> 99866 bytes | |||
-rw-r--r-- | docs/markdown/images/py3-install-3.png (renamed from docs/images/py3-install-3.png) | bin | 101063 -> 101063 bytes | |||
-rw-r--r-- | docs/markdown/snippets/version_comparison.md | 15 | ||||
-rw-r--r-- | docs/meson.build | 5 | ||||
-rw-r--r-- | mesonbuild/build.py | 1 | ||||
-rw-r--r-- | mesonbuild/compilers/__init__.py | 22 | ||||
-rw-r--r-- | mesonbuild/compilers/c.py | 40 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 137 | ||||
-rw-r--r-- | mesonbuild/compilers/cpp.py | 24 | ||||
-rw-r--r-- | mesonbuild/compilers/d.py | 35 | ||||
-rw-r--r-- | mesonbuild/compilers/fortran.py | 14 | ||||
-rw-r--r-- | mesonbuild/compilers/objc.py | 16 | ||||
-rw-r--r-- | mesonbuild/compilers/objcpp.py | 16 | ||||
-rw-r--r-- | mesonbuild/coredata.py | 2 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 65 | ||||
-rw-r--r-- | mesonbuild/environment.py | 87 | ||||
-rw-r--r-- | mesonbuild/linkers.py | 17 | ||||
-rw-r--r-- | mesonbuild/mesonlib.py | 157 | ||||
-rw-r--r-- | mesonbuild/mesonmain.py | 62 | ||||
-rwxr-xr-x | run_unittests.py | 163 | ||||
-rwxr-xr-x | test cases/unit/35 dist script/replacer.py | 2 | ||||
-rw-r--r-- | test cases/unit/41 featurenew subprojects/meson.build | 1 | ||||
-rw-r--r-- | test cases/unit/41 featurenew subprojects/subprojects/baz/meson.build | 3 | ||||
-rwxr-xr-x | tools/dircondenser.py | 2 |
35 files changed, 511 insertions, 379 deletions
diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index 05578c7..55352aa 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -36,7 +36,7 @@ Installation options are all relative to the prefix, except: | sysconfdir | etc | Sysconf data directory | | localstatedir | var | Localstate data directory | | sharedstatedir | com | Architecture-independent data directory | -| werror | false | Treat warnings as erros | +| werror | false | Treat warnings as errors | | warnlevel {1, 2, 3} | 1 | Set the warning level. From 1 = lowest to 3 = highest | | layout {mirror,flat} | mirror | Build directory layout. | | default-library {shared, static, both} | shared | Default library type. | diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 907ceda..b616d3e 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -1094,7 +1094,7 @@ Project supports the following keyword arguments. `meson.project_license()`. - `meson_version` takes a string describing which Meson version the - project requires. Usually something like `>0.28.0`. + project requires. Usually something like `>=0.28.0`. - `subproject_dir` specifies the top level directory name that holds Meson subprojects. This is only meant as a compatibility option diff --git a/docs/images/buildtime.png b/docs/markdown/images/buildtime.png Binary files differindex 2a44422..2a44422 100644 --- a/docs/images/buildtime.png +++ b/docs/markdown/images/buildtime.png diff --git a/docs/images/conftime.png b/docs/markdown/images/conftime.png Binary files differindex 63754db..63754db 100644 --- a/docs/images/conftime.png +++ b/docs/markdown/images/conftime.png diff --git a/docs/images/emptytime.png b/docs/markdown/images/emptytime.png Binary files differindex d80eab9..d80eab9 100644 --- a/docs/images/emptytime.png +++ b/docs/markdown/images/emptytime.png diff --git a/docs/images/glib_build.png b/docs/markdown/images/glib_build.png Binary files differindex ddb9947..ddb9947 100644 --- a/docs/images/glib_build.png +++ b/docs/markdown/images/glib_build.png diff --git a/docs/images/glib_conf.png b/docs/markdown/images/glib_conf.png Binary files differindex 5de60d5..5de60d5 100644 --- a/docs/images/glib_conf.png +++ b/docs/markdown/images/glib_conf.png diff --git a/docs/images/glib_empty.png b/docs/markdown/images/glib_empty.png Binary files differindex 5976e7f..5976e7f 100644 --- a/docs/images/glib_empty.png +++ b/docs/markdown/images/glib_empty.png diff --git a/docs/images/glib_link.png b/docs/markdown/images/glib_link.png Binary files differindex 23d9044..23d9044 100644 --- a/docs/images/glib_link.png +++ b/docs/markdown/images/glib_link.png diff --git a/docs/images/gtksample.png b/docs/markdown/images/gtksample.png Binary files differindex b6557c4..b6557c4 100644 --- a/docs/images/gtksample.png +++ b/docs/markdown/images/gtksample.png diff --git a/docs/images/py3-install-1.png b/docs/markdown/images/py3-install-1.png Binary files differindex 74f0819..74f0819 100644 --- a/docs/images/py3-install-1.png +++ b/docs/markdown/images/py3-install-1.png diff --git a/docs/images/py3-install-2.png b/docs/markdown/images/py3-install-2.png Binary files differindex 9a8f1fe..9a8f1fe 100644 --- a/docs/images/py3-install-2.png +++ b/docs/markdown/images/py3-install-2.png diff --git a/docs/images/py3-install-3.png b/docs/markdown/images/py3-install-3.png Binary files differindex b702910..b702910 100644 --- a/docs/images/py3-install-3.png +++ b/docs/markdown/images/py3-install-3.png diff --git a/docs/markdown/snippets/version_comparison.md b/docs/markdown/snippets/version_comparison.md new file mode 100644 index 0000000..861a3ee --- /dev/null +++ b/docs/markdown/snippets/version_comparison.md @@ -0,0 +1,15 @@ +## Version comparison + +`dependency(version:)` and other version constraints now handle versions +containing non-numeric characters better, comparing versions using the rpmvercmp +algorithm (as using the `pkg-config` autoconf macro `PKG_CHECK_MODULES` does). + +This is a breaking change for exact comparison constraints which rely on the +previous comparison behaviour of extending the compared versions with `'0'` +elements, up to the same length of `'.'`-separated elements. + +For example, a version of `'0.11.0'` would previously match a version constraint +of `'==0.11'`, but no longer does, being instead considered strictly greater. + +Instead, use a version constraint which exactly compares with the precise +version required, e.g. `'==0.11.0'`. diff --git a/docs/meson.build b/docs/meson.build index c83d5f8..32aab07 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -17,6 +17,5 @@ documentation = hotdoc.generate_doc(meson.project_name(), ) run_target('upload', - command: [find_program('hotdoc'), 'run', '--conf-file', documentation.config_path(), - '--git-upload'] -)
\ No newline at end of file + command: [find_program('hotdoc'), 'run', '--conf-file', documentation.config_path()] +) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index b86c84d..ec6e1e6 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -960,7 +960,6 @@ You probably should put it in link_with instead.''') raise InvalidArguments('Tried to mix cross built and native libraries in target {!r}'.format(self.name)) self.link_targets.append(t) - def link_whole(self, target): for t in listify(target, unholder=True): if not isinstance(t, StaticLibrary): diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py index bb6c9a9..677301e 100644 --- a/mesonbuild/compilers/__init__.py +++ b/mesonbuild/compilers/__init__.py @@ -14,16 +14,7 @@ # Public symbols for compilers sub-package when using 'from . import compilers' __all__ = [ - 'CLANG_OSX', - 'CLANG_STANDARD', - 'CLANG_WIN', - 'GCC_CYGWIN', - 'GCC_MINGW', - 'GCC_OSX', - 'GCC_STANDARD', - 'ICC_OSX', - 'ICC_STANDARD', - 'ICC_WIN', + 'CompilerType', 'all_languages', 'base_options', @@ -94,16 +85,7 @@ __all__ = [ # Bring symbols from each module into compilers sub-package namespace from .compilers import ( - GCC_OSX, - GCC_MINGW, - GCC_CYGWIN, - GCC_STANDARD, - CLANG_OSX, - CLANG_WIN, - CLANG_STANDARD, - ICC_OSX, - ICC_WIN, - ICC_STANDARD, + CompilerType, all_languages, base_options, clib_langs, diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 1d531a6..9b7ac68 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -30,7 +30,7 @@ from ..mesonlib import ( from .c_function_attributes import C_FUNC_ATTRIBUTES from .compilers import ( - GCC_MINGW, + CompilerType, get_largefile_args, gnu_winlibs, msvc_winlibs, @@ -121,7 +121,8 @@ class CCompiler(Compiler): # The default behavior is this, override in MSVC @functools.lru_cache(maxsize=None) def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): - if self.id == 'clang' and self.clang_type == compilers.CLANG_OSX: + if getattr(self, 'compiler_type', False) and self.compiler_type.is_osx_compiler: + # Clang, GCC and ICC on macOS all use the same rpath arguments return self.build_osx_rpath_args(build_dir, rpath_paths, build_rpath) return self.build_unix_rpath_args(build_dir, from_dir, rpath_paths, build_rpath, install_rpath) @@ -160,15 +161,8 @@ class CCompiler(Compiler): ''' Get args for allowing undefined symbols when linking to a shared library ''' - if self.id == 'clang': - if self.clang_type == compilers.CLANG_OSX: - # Apple ld - return ['-Wl,-undefined,dynamic_lookup'] - else: - # GNU ld and LLVM lld - return ['-Wl,--allow-shlib-undefined'] - elif self.id == 'gcc': - if self.gcc_type == compilers.GCC_OSX: + if self.id in ('clang', 'gcc'): + if self.compiler_type.is_osx_compiler: # Apple ld return ['-Wl,-undefined,dynamic_lookup'] else: @@ -1064,9 +1058,9 @@ class CCompiler(Compiler): class ClangCCompiler(ClangCompiler, CCompiler): - def __init__(self, exelist, version, clang_type, is_cross, exe_wrapper=None, **kwargs): + def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) - ClangCompiler.__init__(self, clang_type) + ClangCompiler.__init__(self, compiler_type) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], @@ -1092,7 +1086,7 @@ class ClangCCompiler(ClangCompiler, CCompiler): def get_linker_always_args(self): basic = super().get_linker_always_args() - if self.clang_type == compilers.CLANG_OSX: + if self.compiler_type.is_osx_compiler: return basic + ['-Wl,-headerpad_max_install_names'] return basic @@ -1126,9 +1120,9 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler): class GnuCCompiler(GnuCompiler, CCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs): + 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) - GnuCompiler.__init__(self, gcc_type, defines) + GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], @@ -1140,7 +1134,7 @@ class GnuCCompiler(GnuCompiler, CCompiler): ['none', 'c89', 'c99', 'c11', 'gnu89', 'gnu99', 'gnu11'], 'none')}) - if self.gcc_type == GCC_MINGW: + if self.compiler_type == CompilerType.GCC_MINGW: opts.update({ 'c_winlibs': coredata.UserArrayOption('c_winlibs', 'Standard Win libraries to link against', gnu_winlibs), }) @@ -1154,7 +1148,7 @@ class GnuCCompiler(GnuCompiler, CCompiler): return args def get_option_link_args(self, options): - if self.gcc_type == GCC_MINGW: + if self.compiler_type == CompilerType.GCC_MINGW: return options['c_winlibs'].value[:] return [] @@ -1166,9 +1160,9 @@ class GnuCCompiler(GnuCompiler, CCompiler): class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs): - GnuCCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs) - ElbrusCompiler.__init__(self, gcc_type, defines) + 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) + 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. def get_options(self): @@ -1190,9 +1184,9 @@ class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): class IntelCCompiler(IntelCompiler, CCompiler): - def __init__(self, exelist, version, icc_type, is_cross, exe_wrapper=None, **kwargs): + def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) - IntelCompiler.__init__(self, icc_type) + IntelCompiler.__init__(self, compiler_type) self.lang_header = 'c-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', '-Wpch-messages'] self.warn_args = {'1': default_warn_args, diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 40d6880..bf261a2 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import contextlib, os.path, re, tempfile, shlex +import contextlib, enum, os.path, re, tempfile, shlex import subprocess from ..linkers import StaticLinker @@ -1141,19 +1141,35 @@ class Compiler: raise EnvironmentException( 'Language {} does not support function attributes.'.format(self.get_display_language())) -GCC_STANDARD = 0 -GCC_OSX = 1 -GCC_MINGW = 2 -GCC_CYGWIN = 3 -CLANG_STANDARD = 0 -CLANG_OSX = 1 -CLANG_WIN = 2 -# Possibly clang-cl? +@enum.unique +class CompilerType(enum.Enum): + GCC_STANDARD = 0 + GCC_OSX = 1 + GCC_MINGW = 2 + GCC_CYGWIN = 3 + + CLANG_STANDARD = 10 + CLANG_OSX = 11 + CLANG_MINGW = 12 + # Possibly clang-cl? + + ICC_STANDARD = 20 + ICC_OSX = 21 + ICC_WIN = 22 + + @property + def is_standard_compiler(self): + return self.name in ('GCC_STANDARD', 'CLANG_STANDARD', 'ICC_STANDARD') + + @property + def is_osx_compiler(self): + return self.name in ('GCC_OSX', 'CLANG_OSX', 'ICC_OSX') + + @property + def is_windows_compiler(self): + return self.name in ('GCC_MINGW', 'GCC_CYGWIN', 'CLANG_MINGW', 'ICC_WIN') -ICC_STANDARD = 0 -ICC_OSX = 1 -ICC_WIN = 2 # GNU ld cannot be installed on macOS # https://github.com/Homebrew/homebrew-core/issues/17794#issuecomment-328174395 @@ -1169,14 +1185,14 @@ def get_macos_dylib_install_name(prefix, shlib_name, suffix, soversion): install_name += '.dylib' return '@rpath/' + install_name -def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, soversion, darwin_versions, is_shared_module): - if gcc_type == GCC_STANDARD: +def get_gcc_soname_args(compiler_type, prefix, shlib_name, suffix, soversion, darwin_versions, is_shared_module): + if compiler_type.is_standard_compiler: sostr = '' if soversion is None else '.' + soversion return ['-Wl,-soname,%s%s.%s%s' % (prefix, shlib_name, suffix, sostr)] - elif gcc_type in (GCC_MINGW, GCC_CYGWIN): + elif compiler_type.is_windows_compiler: # For PE/COFF the soname argument has no effect with GNU LD return [] - elif gcc_type == GCC_OSX: + elif compiler_type.is_osx_compiler: if is_shared_module: return [] name = get_macos_dylib_install_name(prefix, shlib_name, suffix, soversion) @@ -1188,20 +1204,21 @@ def get_gcc_soname_args(gcc_type, prefix, shlib_name, suffix, soversion, darwin_ raise RuntimeError('Not implemented yet.') def get_compiler_is_linuxlike(compiler): - if (getattr(compiler, 'gcc_type', None) == GCC_STANDARD) or \ - (getattr(compiler, 'clang_type', None) == CLANG_STANDARD) or \ - (getattr(compiler, 'icc_type', None) == ICC_STANDARD): - return True - return False + compiler_type = getattr(compiler, 'compiler_type', None) + return compiler_type and compiler_type.is_standard_compiler def get_compiler_uses_gnuld(c): # FIXME: Perhaps we should detect the linker in the environment? # FIXME: Assumes that *BSD use GNU ld, but they might start using lld soon - if (getattr(c, 'gcc_type', None) in (GCC_STANDARD, GCC_MINGW, GCC_CYGWIN)) or \ - (getattr(c, 'clang_type', None) in (CLANG_STANDARD, CLANG_WIN)) or \ - (getattr(c, 'icc_type', None) in (ICC_STANDARD, ICC_WIN)): - return True - return False + compiler_type = getattr(c, 'compiler_type', None) + return compiler_type in ( + CompilerType.GCC_STANDARD, + CompilerType.GCC_MINGW, + CompilerType.GCC_CYGWIN, + CompilerType.CLANG_STANDARD, + CompilerType.CLANG_MINGW, + CompilerType.ICC_STANDARD, + CompilerType.ICC_WIN) def get_largefile_args(compiler): ''' @@ -1262,13 +1279,13 @@ def gnulike_default_include_dirs(compiler, lang): class GnuCompiler: # Functionality that is common to all GNU family compilers. - def __init__(self, gcc_type, defines): + def __init__(self, compiler_type, defines): self.id = 'gcc' - self.gcc_type = gcc_type + self.compiler_type = compiler_type self.defines = defines or {} self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', 'b_colorout', 'b_ndebug', 'b_staticpic'] - if self.gcc_type == GCC_OSX: + if self.compiler_type.is_osx_compiler: self.base_options.append('b_bitcode') else: self.base_options.append('b_lundef') @@ -1279,7 +1296,7 @@ class GnuCompiler: # TODO: centralise this policy more globally, instead # of fragmenting it into GnuCompiler and ClangCompiler def get_asneeded_args(self): - if self.gcc_type == GCC_OSX: + if self.compiler_type.is_osx_compiler: return APPLE_LD_AS_NEEDED else: return GNU_LD_AS_NEEDED @@ -1305,7 +1322,7 @@ class GnuCompiler: return self.defines[define] def get_pic_args(self): - if self.gcc_type in (GCC_CYGWIN, GCC_MINGW, GCC_OSX): + if self.compiler_type in (CompilerType.GCC_CYGWIN, CompilerType.GCC_MINGW, CompilerType.GCC_OSX): return [] # On Window and OS X, pic is always on. return ['-fPIC'] @@ -1319,7 +1336,7 @@ class GnuCompiler: return clike_debug_args[is_debug] def get_buildtype_linker_args(self, buildtype): - if self.gcc_type == GCC_OSX: + if self.compiler_type.is_osx_compiler: return apple_buildtype_linker_args[buildtype] return gnulike_buildtype_linker_args[buildtype] @@ -1330,7 +1347,7 @@ class GnuCompiler: return os.path.dirname(fname), fname def get_soname_args(self, *args): - return get_gcc_soname_args(self.gcc_type, *args) + return get_gcc_soname_args(self.compiler_type, *args) def get_std_shared_lib_link_args(self): return ['-shared'] @@ -1343,13 +1360,13 @@ class GnuCompiler: raise RuntimeError('Module definitions file should be str') # On Windows targets, .def files may be specified on the linker command # line like an object file. - if self.gcc_type in (GCC_CYGWIN, GCC_MINGW): + if self.compiler_type in (CompilerType.GCC_CYGWIN, CompilerType.GCC_MINGW): return [defsfile] # For other targets, discard the .def file. return [] def get_gui_app_args(self, value): - if self.gcc_type in (GCC_CYGWIN, GCC_MINGW) and value: + if self.compiler_type in (CompilerType.GCC_CYGWIN, CompilerType.GCC_MINGW) and value: return ['-mwindows'] return [] @@ -1368,8 +1385,8 @@ class GnuCompiler: class ElbrusCompiler(GnuCompiler): # Elbrus compiler is nearly like GCC, but does not support # PCH, LTO, sanitizers and color output as of version 1.21.x. - def __init__(self, gcc_type, defines): - GnuCompiler.__init__(self, gcc_type, defines) + def __init__(self, compiler_type, defines): + GnuCompiler.__init__(self, compiler_type, defines) self.id = 'lcc' self.base_options = ['b_pgo', 'b_coverage', 'b_ndebug', 'b_staticpic', @@ -1404,12 +1421,12 @@ class ElbrusCompiler(GnuCompiler): return paths class ClangCompiler: - def __init__(self, clang_type): + def __init__(self, compiler_type): self.id = 'clang' - self.clang_type = clang_type + self.compiler_type = compiler_type self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', 'b_ndebug', 'b_staticpic', 'b_colorout'] - if self.clang_type == CLANG_OSX: + if self.compiler_type.is_osx_compiler: self.base_options.append('b_bitcode') else: self.base_options.append('b_lundef') @@ -1420,13 +1437,13 @@ class ClangCompiler: # TODO: centralise this policy more globally, instead # of fragmenting it into GnuCompiler and ClangCompiler def get_asneeded_args(self): - if self.clang_type == CLANG_OSX: + if self.compiler_type.is_osx_compiler: return APPLE_LD_AS_NEEDED else: return GNU_LD_AS_NEEDED def get_pic_args(self): - if self.clang_type in (CLANG_WIN, CLANG_OSX): + if self.compiler_type in (CompilerType.CLANG_MINGW, CompilerType.CLANG_OSX): return [] # On Window and OS X, pic is always on. return ['-fPIC'] @@ -1437,7 +1454,7 @@ class ClangCompiler: return gnulike_buildtype_args[buildtype] def get_buildtype_linker_args(self, buildtype): - if self.clang_type == CLANG_OSX: + if self.compiler_type.is_osx_compiler: return apple_buildtype_linker_args[buildtype] return gnulike_buildtype_linker_args[buildtype] @@ -1457,15 +1474,7 @@ class ClangCompiler: return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))] def get_soname_args(self, *args): - if self.clang_type == CLANG_STANDARD: - gcc_type = GCC_STANDARD - elif self.clang_type == CLANG_OSX: - gcc_type = GCC_OSX - elif self.clang_type == CLANG_WIN: - gcc_type = GCC_MINGW - else: - raise MesonException('Unreachable code when converting clang type to gcc type.') - return get_gcc_soname_args(gcc_type, *args) + return get_gcc_soname_args(self.compiler_type, *args) def has_multi_arguments(self, args, env): myargs = ['-Werror=unknown-warning-option', '-Werror=unused-command-line-argument'] @@ -1482,17 +1491,17 @@ class ClangCompiler: # visibility to obey OS X and iOS minimum version targets with # -mmacosx-version-min, -miphoneos-version-min, etc. # https://github.com/Homebrew/homebrew-core/issues/3727 - if self.clang_type == CLANG_OSX and version_compare(self.version, '>=8.0'): + if self.compiler_type.is_osx_compiler and version_compare(self.version, '>=8.0'): extra_args.append('-Wl,-no_weak_imports') return super().has_function(funcname, prefix, env, extra_args, dependencies) def get_std_shared_module_link_args(self, options): - if self.clang_type == CLANG_OSX: + if self.compiler_type.is_osx_compiler: return ['-bundle', '-Wl,-undefined,dynamic_lookup'] return ['-shared'] def get_link_whole_for(self, args): - if self.clang_type == CLANG_OSX: + if self.compiler_type.is_osx_compiler: result = [] for a in args: result += ['-Wl,-force_load', a] @@ -1593,9 +1602,9 @@ class ArmclangCompiler: # Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1 class IntelCompiler: - def __init__(self, icc_type): + def __init__(self, compiler_type): self.id = 'intel' - self.icc_type = icc_type + self.compiler_type = compiler_type self.lang_header = 'none' self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage', 'b_colorout', 'b_ndebug', 'b_staticpic', 'b_lundef', 'b_asneeded'] @@ -1625,27 +1634,19 @@ class IntelCompiler: return os.path.dirname(fname), fname def get_soname_args(self, *args): - if self.icc_type == ICC_STANDARD: - gcc_type = GCC_STANDARD - elif self.icc_type == ICC_OSX: - gcc_type = GCC_OSX - elif self.icc_type == ICC_WIN: - gcc_type = GCC_MINGW - else: - raise MesonException('Unreachable code when converting icc type to gcc type.') - return get_gcc_soname_args(gcc_type, *args) + return get_gcc_soname_args(self.compiler_type, *args) # TODO: centralise this policy more globally, instead # of fragmenting it into GnuCompiler and ClangCompiler def get_asneeded_args(self): - if self.icc_type == CLANG_OSX: + if self.compiler_type.is_osx_compiler: return APPLE_LD_AS_NEEDED else: return GNU_LD_AS_NEEDED def get_std_shared_lib_link_args(self): # FIXME: Don't know how icc works on OSX - # if self.icc_type == ICC_OSX: + # if self.compiler_type.is_osx_compiler: # return ['-bundle'] return ['-shared'] diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 2173655..004f65e 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -21,7 +21,7 @@ from ..mesonlib import MesonException, version_compare from .c import CCompiler, VisualStudioCCompiler from .compilers import ( - GCC_MINGW, + CompilerType, gnu_winlibs, msvc_winlibs, ClangCompiler, @@ -126,9 +126,9 @@ class CPPCompiler(CCompiler): class ClangCPPCompiler(ClangCompiler, CPPCompiler): - def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None, **kwargs): + def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) - ClangCompiler.__init__(self, cltype) + ClangCompiler.__init__(self, compiler_type) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], @@ -185,9 +185,9 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler): class GnuCPPCompiler(GnuCompiler, CPPCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrap, defines, **kwargs): + def __init__(self, exelist, version, compiler_type, is_cross, exe_wrap, defines, **kwargs): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) - GnuCompiler.__init__(self, gcc_type, defines) + GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], @@ -202,7 +202,7 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): 'cpp_debugstl': coredata.UserBooleanOption('cpp_debugstl', 'STL debug mode', False)}) - if self.gcc_type == GCC_MINGW: + if self.compiler_type == CompilerType.GCC_MINGW: opts.update({ 'cpp_winlibs': coredata.UserArrayOption('cpp_winlibs', 'Standard Win libraries to link against', gnu_winlibs), }) @@ -218,7 +218,7 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): return args def get_option_link_args(self, options): - if self.gcc_type == GCC_MINGW: + if self.compiler_type == CompilerType.GCC_MINGW: return options['cpp_winlibs'].value[:] return [] @@ -230,9 +230,9 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler): class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs): - GnuCPPCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs) - ElbrusCompiler.__init__(self, gcc_type, defines) + 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) + ElbrusCompiler.__init__(self, compiler_type, defines) # It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98. def get_options(self): @@ -253,9 +253,9 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): class IntelCPPCompiler(IntelCompiler, CPPCompiler): - def __init__(self, exelist, version, icc_type, is_cross, exe_wrap, **kwargs): + def __init__(self, exelist, version, compiler_type, is_cross, exe_wrap, **kwargs): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) - IntelCompiler.__init__(self, icc_type) + IntelCompiler.__init__(self, compiler_type) self.lang_header = 'c++-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', '-Wpch-messages', '-Wnon-virtual-dtor'] diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index 5433b36..6108e93 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -17,9 +17,7 @@ import os.path, subprocess from ..mesonlib import EnvironmentException, version_compare, is_windows, is_osx from .compilers import ( - GCC_STANDARD, - GCC_CYGWIN, - GCC_OSX, + CompilerType, d_dmd_buildtype_args, d_gdc_buildtype_args, d_ldc_buildtype_args, @@ -70,12 +68,12 @@ class DCompiler(Compiler): 'mtd': ['-mscrtlib=libcmtd'], } - def __init__(self, exelist, version, is_cross, is_64, **kwargs): + def __init__(self, exelist, version, is_cross, arch, **kwargs): self.language = 'd' super().__init__(exelist, version, **kwargs) self.id = 'unknown' self.is_cross = is_cross - self.is_64 = is_64 + self.arch = arch def sanity_check(self, work_dir, environment): source_name = os.path.join(work_dir, 'sanity.d') @@ -153,12 +151,12 @@ class DCompiler(Compiler): if is_windows(): return [] elif is_osx(): - soname_args = get_gcc_soname_args(GCC_OSX, *args) + soname_args = get_gcc_soname_args(CompilerType.GCC_OSX, *args) if soname_args: return ['-Wl,' + ','.join(soname_args)] return [] - return get_gcc_soname_args(GCC_STANDARD, *args) + return get_gcc_soname_args(CompilerType.GCC_STANDARD, *args) def get_feature_args(self, kwargs, build_to_src): res = [] @@ -276,7 +274,7 @@ class DCompiler(Compiler): # LDC2 on Windows targets to current OS architecture, but # it should follow the target specified by the MSVC toolchain. if is_windows(): - if self.is_64: + if self.arch == 'x86_64': return ['-m64'] return ['-m32'] return [] @@ -412,8 +410,8 @@ class DCompiler(Compiler): return [] class GnuDCompiler(DCompiler): - def __init__(self, exelist, version, is_cross, is_64, **kwargs): - DCompiler.__init__(self, exelist, version, is_cross, is_64, **kwargs) + def __init__(self, exelist, version, is_cross, arch, **kwargs): + DCompiler.__init__(self, exelist, version, is_cross, arch, **kwargs) self.id = 'gcc' default_warn_args = ['-Wall', '-Wdeprecated'] self.warn_args = {'1': default_warn_args, @@ -467,8 +465,8 @@ class GnuDCompiler(DCompiler): return gnu_optimization_args[optimization_level] class LLVMDCompiler(DCompiler): - def __init__(self, exelist, version, is_cross, is_64, **kwargs): - DCompiler.__init__(self, exelist, version, is_cross, is_64, **kwargs) + def __init__(self, exelist, version, is_cross, arch, **kwargs): + DCompiler.__init__(self, exelist, version, is_cross, arch, **kwargs) self.id = 'llvm' self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt'] @@ -503,11 +501,10 @@ class LLVMDCompiler(DCompiler): class DmdDCompiler(DCompiler): - def __init__(self, exelist, version, is_cross, is_64, **kwargs): - DCompiler.__init__(self, exelist, version, is_cross, is_64, **kwargs) + def __init__(self, exelist, version, is_cross, arch, **kwargs): + DCompiler.__init__(self, exelist, version, is_cross, arch, **kwargs) self.id = 'dmd' self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt'] - self.is_msvc = 'VCINSTALLDIR' in os.environ def get_colorout_args(self, colortype): if colortype == 'always': @@ -523,9 +520,9 @@ class DmdDCompiler(DCompiler): if is_windows(): # DMD links against D runtime only when main symbol is found, # so these needs to be inserted when linking static D libraries. - if self.is_64: + if self.arch == 'x86_64': return ['phobos64.lib'] - elif self.is_msvc: + elif self.arch == 'x86_mscoff': return ['phobos32mscoff.lib'] return ['phobos.lib'] return [] @@ -538,9 +535,9 @@ class DmdDCompiler(DCompiler): # Force the target to 64-bit in order to stay consistent # across the different platforms. if is_windows(): - if self.is_64: + if self.arch == 'x86_64': return ['-m64'] - elif self.is_msvc: + elif self.arch == 'x86_mscoff': return ['-m32mscoff'] return ['-m32'] return [] diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 3c7c2f9..b58c4e0 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -14,7 +14,7 @@ from .c import CCompiler from .compilers import ( - ICC_STANDARD, + CompilerType, apple_buildtype_linker_args, gnulike_buildtype_args, gnulike_buildtype_linker_args, @@ -257,9 +257,9 @@ end program prog class GnuFortranCompiler(GnuCompiler, FortranCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs): + 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) - GnuCompiler.__init__(self, gcc_type, defines) + GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], @@ -279,9 +279,9 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): class ElbrusFortranCompiler(GnuFortranCompiler, ElbrusCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None, **kwargs): - GnuFortranCompiler.__init__(self, exelist, version, gcc_type, is_cross, exe_wrapper, defines, **kwargs) - ElbrusCompiler.__init__(self, gcc_type, defines) + 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) + ElbrusCompiler.__init__(self, compiler_type, defines) class G95FortranCompiler(FortranCompiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): @@ -330,7 +330,7 @@ class IntelFortranCompiler(IntelCompiler, FortranCompiler): FortranCompiler.__init__(self, exelist, version, 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 - IntelCompiler.__init__(self, ICC_STANDARD) + IntelCompiler.__init__(self, CompilerType.ICC_STANDARD) self.id = 'intel' default_warn_args = ['-warn', 'general', '-warn', 'truncated_source'] self.warn_args = {'1': default_warn_args, diff --git a/mesonbuild/compilers/objc.py b/mesonbuild/compilers/objc.py index 388e83b..5b2b517 100644 --- a/mesonbuild/compilers/objc.py +++ b/mesonbuild/compilers/objc.py @@ -51,17 +51,21 @@ class ObjCCompiler(CCompiler): class GnuObjCCompiler(GnuCompiler, ObjCCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None): + def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None): ObjCCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) - GnuCompiler.__init__(self, gcc_type, defines) + GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} -class ClangObjCCompiler(ClangCompiler, GnuObjCCompiler): - def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None): - GnuObjCCompiler.__init__(self, exelist, version, cltype, is_cross, exe_wrapper) - ClangCompiler.__init__(self, cltype) +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) + ClangCompiler.__init__(self, compiler_type) + default_warn_args = ['-Wall', '-Winvalid-pch'] + self.warn_args = {'1': default_warn_args, + '2': default_warn_args + ['-Wextra'], + '3': default_warn_args + ['-Wextra', '-Wpedantic']} self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage'] diff --git a/mesonbuild/compilers/objcpp.py b/mesonbuild/compilers/objcpp.py index c2e4647..e1b7a7d 100644 --- a/mesonbuild/compilers/objcpp.py +++ b/mesonbuild/compilers/objcpp.py @@ -52,17 +52,21 @@ class ObjCPPCompiler(CPPCompiler): class GnuObjCPPCompiler(GnuCompiler, ObjCPPCompiler): - def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None): + def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, defines=None): ObjCPPCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) - GnuCompiler.__init__(self, gcc_type, defines) + GnuCompiler.__init__(self, compiler_type, defines) default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] self.warn_args = {'1': default_warn_args, '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic']} -class ClangObjCPPCompiler(ClangCompiler, GnuObjCPPCompiler): - def __init__(self, exelist, version, cltype, is_cross, exe_wrapper=None): - GnuObjCPPCompiler.__init__(self, exelist, version, cltype, is_cross, exe_wrapper) - ClangCompiler.__init__(self, cltype) +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) + ClangCompiler.__init__(self, compiler_type) + default_warn_args = ['-Wall', '-Winvalid-pch', '-Wnon-virtual-dtor'] + self.warn_args = {'1': default_warn_args, + '2': default_warn_args + ['-Wextra'], + '3': default_warn_args + ['-Wextra', '-Wpedantic']} self.base_options = ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage'] diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 4b32c19..4da5a6d 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -23,7 +23,7 @@ from .wrap import WrapMode import ast import argparse -version = '0.48.0.dev1' +version = '0.47.999' backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'xcode'] default_yielding = False diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index a34ebf7..a80423f 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -870,11 +870,8 @@ class DubDependency(ExternalDependency): mlog.debug('Determining dependency {!r} with DUB executable ' '{!r}'.format(name, self.dubbin.get_path())) - # we need to know the correct architecture on Windows - if self.compiler.is_64: - arch = 'x86_64' - else: - arch = 'x86' + # we need to know the target architecture + arch = self.compiler.arch # Ask dub for the package ret, res = self._call_dubbin(['describe', name, '--arch=' + arch]) @@ -885,8 +882,8 @@ class DubDependency(ExternalDependency): comp = self.compiler.get_id().replace('llvm', 'ldc').replace('gcc', 'gdc') packages = [] - j = json.loads(res) - for package in j['packages']: + description = json.loads(res) + for package in description['packages']: packages.append(package['name']) if package['name'] == name: self.is_found = True @@ -897,14 +894,24 @@ class DubDependency(ExternalDependency): not_lib = False if not_lib: - mlog.error(mlog.bold(name), 'found but it isn\'t a library') + mlog.error(mlog.bold(name), "found but it isn't a library") self.is_found = False return - self.module_path = self._find_right_lib_path(package['path'], comp, j, True, package['targetFileName']) - + self.module_path = self._find_right_lib_path(package['path'], comp, description, True, package['targetFileName']) if not os.path.exists(self.module_path): - mlog.error(mlog.bold(name), 'found but it wasn\'t compiled with', mlog.bold(comp)) + # check if the dependency was built for other archs + archs = [['x86_64'], ['x86'], ['x86', 'x86_mscoff']] + for a in archs: + description_a = copy.deepcopy(description) + description_a['architecture'] = a + arch_module_path = self._find_right_lib_path(package['path'], comp, description_a, True, package['targetFileName']) + if arch_module_path: + mlog.error(mlog.bold(name), "found but it wasn't compiled for", mlog.bold(arch)) + self.is_found = False + return + + mlog.error(mlog.bold(name), "found but it wasn't compiled with", mlog.bold(comp)) self.is_found = False return @@ -943,26 +950,29 @@ class DubDependency(ExternalDependency): for arg in pkgdep.get_link_args(raw=True): self.raw_link_args.append(arg) - for target in j['targets']: + for target in description['targets']: if target['rootPackage'] in packages: add_lib_args('libs', target) add_lib_args('libs-{}'.format(platform.machine()), target) for file in target['buildSettings']['linkerFiles']: - self.link_args.append(self._find_right_lib_path(file, comp, j)) + lib_path = self._find_right_lib_path(file, comp, description) + if lib_path: + self.link_args.append(lib_path) + else: + self.is_found = False def get_compiler(self): return self.compiler - def _find_right_lib_path(self, default_path, comp, j, folder_only=False, file_name=''): - path = '' - - module_build_path = lib_file_name = '' + def _find_right_lib_path(self, default_path, comp, description, folder_only=False, file_name=''): + module_path = lib_file_name = '' if folder_only: - module_build_path = default_path + module_path = default_path lib_file_name = file_name else: - module_build_path = os.path.dirname(default_path) + module_path = os.path.dirname(default_path) lib_file_name = os.path.basename(default_path) + module_build_path = os.path.join(module_path, '.dub', 'build') # Get D version implemented in the compiler # gdc doesn't support this @@ -970,7 +980,6 @@ class DubDependency(ExternalDependency): if ret != 0: mlog.error('Failed to run {!r}', mlog.bold(comp)) - self.is_found = False return d_ver = re.search('v[0-9].[0-9][0-9][0-9].[0-9]', res) # Ex.: v2.081.2 @@ -979,19 +988,21 @@ class DubDependency(ExternalDependency): else: d_ver = '' # gdc + if not os.path.isdir(module_build_path): + return '' + # Ex.: library-debug-linux.posix-x86_64-ldc_2081-EF934983A3319F8F8FF2F0E107A363BA - build_name = 'library-{}-{}-{}-{}_{}'.format(j['buildType'], '.'.join(j['platform']), j['architecture'][0], comp, d_ver) - for entry in os.listdir(os.path.join(module_build_path, '.dub', 'build')): + build_name = 'library-{}-{}-{}-{}_{}'.format(description['buildType'], '.'.join(description['platform']), '.'.join(description['architecture']), comp, d_ver) + for entry in os.listdir(module_build_path): if entry.startswith(build_name): - for file in os.listdir(os.path.join(module_build_path, '.dub', 'build', entry)): + for file in os.listdir(os.path.join(module_build_path, entry)): if file == lib_file_name: if folder_only: - path = os.path.join(module_build_path, '.dub', 'build', entry) + return os.path.join(module_build_path, entry) else: - path = os.path.join(module_build_path, '.dub', 'build', entry, lib_file_name) - break + return os.path.join(module_build_path, entry, lib_file_name) - return path + return '' def _call_dubbin(self, args, env=None): p, out = Popen_safe(self.dubbin.get_command() + args, env=env)[0:2] diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 9e9b5fc..81ba54c 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -15,21 +15,14 @@ import configparser, os, platform, re, shlex, shutil, subprocess from . import coredata -from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, LDCLinker +from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker from . import mesonlib from .mesonlib import EnvironmentException, Popen_safe from . import mlog from . import compilers from .compilers import ( - CLANG_OSX, - CLANG_STANDARD, - CLANG_WIN, - GCC_CYGWIN, - GCC_MINGW, - GCC_OSX, - GCC_STANDARD, - ICC_STANDARD, + CompilerType, is_assembly, is_header, is_library, @@ -341,7 +334,6 @@ class Environment: self.vs_static_linker = ['lib'] self.gcc_static_linker = ['gcc-ar'] self.clang_static_linker = ['llvm-ar'] - self.ldc2_static_linker = ['ldc2'] # Various prefixes and suffixes for import libraries, shared libraries, # static libraries, and executables. @@ -452,12 +444,12 @@ class Environment: def get_gnu_compiler_type(defines): # Detect GCC type (Apple, MinGW, Cygwin, Unix) if '__APPLE__' in defines: - return GCC_OSX + return CompilerType.GCC_OSX elif '__MINGW32__' in defines or '__MINGW64__' in defines: - return GCC_MINGW + return CompilerType.GCC_MINGW elif '__CYGWIN__' in defines: - return GCC_CYGWIN - return GCC_STANDARD + return CompilerType.GCC_CYGWIN + return CompilerType.GCC_STANDARD def warn_about_lang_pointing_to_cross(self, compiler_exe, evar): evar_str = os.environ.get(evar, 'WHO_WOULD_CALL_THEIR_COMPILER_WITH_THIS_NAME') @@ -561,14 +553,14 @@ This is probably wrong, it should always point to the native compiler.''' % evar if not defines: popen_exceptions[' '.join(compiler)] = 'no pre-processor defines' continue - gtype = self.get_gnu_compiler_type(defines) + compiler_type = self.get_gnu_compiler_type(defines) if guess_gcc_or_lcc == 'lcc': version = self.get_lcc_version_from_defines(defines) cls = ElbrusCCompiler if lang == 'c' else ElbrusCPPCompiler else: version = self.get_gnu_version_from_defines(defines) cls = GnuCCompiler if lang == 'c' else GnuCPPCompiler - return cls(ccache + compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version) + return cls(ccache + compiler, version, compiler_type, 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, @@ -588,13 +580,13 @@ This is probably wrong, it should always point to the native compiler.''' % evar return cls(ccache + compiler, version, is_cross, exe_wrap, full_version=full_version) if 'clang' in out: if 'Apple' in out or mesonlib.for_darwin(want_cross, self): - cltype = CLANG_OSX + compiler_type = CompilerType.CLANG_OSX elif 'windows' in out or mesonlib.for_windows(want_cross, self): - cltype = CLANG_WIN + compiler_type = CompilerType.CLANG_MINGW else: - cltype = CLANG_STANDARD + compiler_type = CompilerType.CLANG_STANDARD cls = ClangCCompiler if lang == 'c' else ClangCPPCompiler - return cls(ccache + compiler, version, cltype, is_cross, exe_wrap, full_version=full_version) + return cls(ccache + compiler, version, compiler_type, 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 @@ -611,9 +603,9 @@ This is probably wrong, it should always point to the native compiler.''' % evar return cls(compiler, version, is_cross, exe_wrap, is_64) if '(ICC)' in out: # TODO: add microsoft add check OSX - inteltype = ICC_STANDARD + compiler_type = CompilerType.ICC_STANDARD cls = IntelCCompiler if lang == 'c' else IntelCPPCompiler - return cls(ccache + compiler, version, inteltype, is_cross, exe_wrap, full_version=full_version) + return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap, full_version=full_version) if 'ARM' in out: cls = ArmCCompiler if lang == 'c' else ArmCPPCompiler return cls(ccache + compiler, version, is_cross, exe_wrap, full_version=full_version) @@ -652,14 +644,14 @@ This is probably wrong, it should always point to the native compiler.''' % evar if not defines: popen_exceptions[' '.join(compiler)] = 'no pre-processor defines' continue - gtype = self.get_gnu_compiler_type(defines) + compiler_type = self.get_gnu_compiler_type(defines) if guess_gcc_or_lcc == 'lcc': version = self.get_lcc_version_from_defines(defines) cls = ElbrusFortranCompiler else: version = self.get_gnu_version_from_defines(defines) cls = GnuFortranCompiler - return cls(compiler, version, gtype, is_cross, exe_wrap, defines, full_version=full_version) + return cls(compiler, version, compiler_type, 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) @@ -705,13 +697,13 @@ This is probably wrong, it should always point to the native compiler.''' % evar if not defines: popen_exceptions[' '.join(compiler)] = 'no pre-processor defines' continue - gtype = self.get_gnu_compiler_type(defines) + compiler_type = self.get_gnu_compiler_type(defines) version = self.get_gnu_version_from_defines(defines) - return GnuObjCCompiler(ccache + compiler, version, gtype, is_cross, exe_wrap, defines) + return GnuObjCCompiler(ccache + compiler, version, compiler_type, is_cross, exe_wrap, defines) if out.startswith('Apple LLVM'): - return ClangObjCCompiler(ccache + compiler, version, CLANG_OSX, is_cross, exe_wrap) + return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, is_cross, exe_wrap) if out.startswith('clang'): - return ClangObjCCompiler(ccache + compiler, version, CLANG_STANDARD, is_cross, exe_wrap) + return ClangObjCCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, is_cross, exe_wrap) self._handle_exceptions(popen_exceptions, compilers) def detect_objcpp_compiler(self, want_cross): @@ -732,13 +724,13 @@ This is probably wrong, it should always point to the native compiler.''' % evar if not defines: popen_exceptions[' '.join(compiler)] = 'no pre-processor defines' continue - gtype = self.get_gnu_compiler_type(defines) + compiler_type = self.get_gnu_compiler_type(defines) version = self.get_gnu_version_from_defines(defines) - return GnuObjCPPCompiler(ccache + compiler, version, gtype, is_cross, exe_wrap, defines) + return GnuObjCPPCompiler(ccache + compiler, version, compiler_type, is_cross, exe_wrap, defines) if out.startswith('Apple LLVM'): - return ClangObjCPPCompiler(ccache + compiler, version, CLANG_OSX, is_cross, exe_wrap) + return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_OSX, is_cross, exe_wrap) if out.startswith('clang'): - return ClangObjCPPCompiler(ccache + compiler, version, CLANG_STANDARD, is_cross, exe_wrap) + return ClangObjCPPCompiler(ccache + compiler, version, CompilerType.CLANG_STANDARD, is_cross, exe_wrap) self._handle_exceptions(popen_exceptions, compilers) def detect_java_compiler(self): @@ -837,22 +829,22 @@ This is probably wrong, it should always point to the native compiler.''' % evar version = search_version(out) full_version = out.split('\n', 1)[0] - # Detect which MSVC build environment is currently active. - is_64 = False + # Detect the target architecture, required for proper architecture handling on Windows. c_compiler = {} - if mesonlib.is_windows() and 'VCINSTALLDIR' in os.environ: - # MSVC compiler is required for correct platform detection. - c_compiler = {'c': self.detect_c_compiler(want_cross)} + 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. - if detect_cpu_family(c_compiler) == 'x86_64': - is_64 = True + 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, is_64, full_version=full_version) + return compilers.LLVMDCompiler(exelist, version, is_cross, arch, full_version=full_version) elif 'gdc' in out: - return compilers.GnuDCompiler(exelist, version, is_cross, is_64, full_version=full_version) + return compilers.GnuDCompiler(exelist, version, is_cross, arch, full_version=full_version) elif 'The D Language Foundation' in out or 'Digital Mars' in out: - return compilers.DmdDCompiler(exelist, version, is_cross, is_64, full_version=full_version) + return compilers.DmdDCompiler(exelist, version, is_cross, arch, full_version=full_version) raise EnvironmentException('Unknown compiler "' + ' '.join(exelist) + '"') def detect_swift_compiler(self): @@ -885,10 +877,11 @@ This is probably wrong, it should always point to the native compiler.''' % evar # Use llvm-ar if available; needed for LTO linkers = [self.clang_static_linker, self.default_static_linker] elif isinstance(compiler, compilers.DCompiler): + # Prefer static linkers over linkers used by D compilers if mesonlib.is_windows(): - linkers = [self.vs_static_linker, self.ldc2_static_linker] + linkers = [self.vs_static_linker, compiler.get_linker_exelist()] else: - linkers = [self.default_static_linker, self.ldc2_static_linker] + linkers = [self.default_static_linker, compiler.get_linker_exelist()] else: linkers = [self.default_static_linker] popen_exceptions = {} @@ -906,8 +899,12 @@ This is probably wrong, it should always point to the native compiler.''' % evar return VisualStudioLinker(linker) if p.returncode == 0 and ('armar' in linker or 'armar.exe' in linker): return ArmarLinker(linker) + if 'DMD32 D Compiler' in out or 'DMD64 D Compiler' in out: + return DLinker(linker, compiler.is_64, compiler.is_msvc) if 'LDC - the LLVM D compiler' in out: - return LDCLinker(linker) + return DLinker(linker, compiler.is_64, compiler.is_msvc) + if 'GDC' in out and ' based on D ' in out: + return DLinker(linker, compiler.is_64, compiler.is_msvc) if p.returncode == 0: return ArLinker(linker) if p.returncode == 1 and err.startswith('usage'): # OSX diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index 93106b3..30ca5d8 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .mesonlib import Popen_safe +from .mesonlib import Popen_safe, is_windows from . import mesonlib class StaticLinker: @@ -138,11 +138,12 @@ class ArmarLinker(ArLinker): # armar cann't accept arguments using the @rsp syntax return False -class LDCLinker(StaticLinker): - - def __init__(self, exelist): +class DLinker(StaticLinker): + def __init__(self, exelist, is_64, is_msvc): self.exelist = exelist - self.id = 'ldc2' + self.id = exelist[0] + self.is_64 = is_64 + self.is_msvc = is_msvc def can_linker_accept_rsp(self): return mesonlib.is_windows() @@ -163,6 +164,12 @@ class LDCLinker(StaticLinker): return [] def get_linker_always_args(self): + if is_windows(): + if self.is_64: + return ['-m64'] + elif self.is_msvc and self.id == 'dmd': + return ['-m32mscoff'] + return ['-m32'] return [] def get_coverage_link_args(self): diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 1b9cb42..bbab2ef 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -14,6 +14,7 @@ """A library of random helper functionality.""" +import functools import sys import stat import time @@ -390,33 +391,59 @@ def detect_vcs(source_dir): return vcs return None -def grab_leading_numbers(vstr, strict=False): - result = [] - for x in vstr.rstrip('.').split('.'): - try: - result.append(int(x)) - except ValueError as e: - if strict: - msg = 'Invalid version to compare against: {!r}; only ' \ - 'numeric digits separated by "." are allowed: ' + str(e) - raise MesonException(msg.format(vstr)) - break - return result +# a helper class which implements the same version ordering as RPM +@functools.total_ordering +class Version: + def __init__(self, s): + self._s = s -def make_same_len(listA, listB): - maxlen = max(len(listA), len(listB)) - for i in listA, listB: - for n in range(len(i), maxlen): - i.append(0) + # split into numeric, alphabetic and non-alphanumeric sequences + sequences = re.finditer(r'(\d+|[a-zA-Z]+|[^a-zA-Z\d]+)', s) + # non-alphanumeric separators are discarded + sequences = [m for m in sequences if not re.match(r'[^a-zA-Z\d]+', m.group(1))] + # numeric sequences have leading zeroes discarded + sequences = [re.sub(r'^0+(\d)', r'\1', m.group(1), 1) for m in sequences] + + self._v = sequences + + def __str__(self): + return '%s (V=%s)' % (self._s, str(self._v)) -numpart = re.compile('[0-9.]+') + def __lt__(self, other): + return self.__cmp__(other) == -1 -def version_compare(vstr1, vstr2, strict=False): - match = numpart.match(vstr1.strip()) - if match is None: - msg = 'Uncomparable version string {!r}.' - raise MesonException(msg.format(vstr1)) - vstr1 = match.group(0) + def __eq__(self, other): + return self.__cmp__(other) == 0 + + def __cmp__(self, other): + def cmp(a, b): + return (a > b) - (a < b) + + # compare each sequence in order + for i in range(0, min(len(self._v), len(other._v))): + # sort a non-digit sequence before a digit sequence + if self._v[i].isdigit() != other._v[i].isdigit(): + return 1 if self._v[i].isdigit() else -1 + + # compare as numbers + if self._v[i].isdigit(): + # because leading zeros have already been removed, if one number + # has more digits, it is greater + c = cmp(len(self._v[i]), len(other._v[i])) + if c != 0: + return c + # fallthrough + + # compare lexicographically + c = cmp(self._v[i], other._v[i]) + if c != 0: + return c + + # if equal length, all components have matched, so equal + # otherwise, the version with a suffix remaining is greater + return cmp(len(self._v), len(other._v)) + +def _version_extract_cmpop(vstr2): if vstr2.startswith('>='): cmpop = operator.ge vstr2 = vstr2[2:] @@ -440,10 +467,12 @@ def version_compare(vstr1, vstr2, strict=False): vstr2 = vstr2[1:] else: cmpop = operator.eq - varr1 = grab_leading_numbers(vstr1, strict) - varr2 = grab_leading_numbers(vstr2, strict) - make_same_len(varr1, varr2) - return cmpop(varr1, varr2) + + return (cmpop, vstr2) + +def version_compare(vstr1, vstr2): + (cmpop, vstr2) = _version_extract_cmpop(vstr2) + return cmpop(Version(vstr1), Version(vstr2)) def version_compare_many(vstr1, conditions): if not isinstance(conditions, (list, tuple, frozenset)): @@ -451,28 +480,22 @@ def version_compare_many(vstr1, conditions): found = [] not_found = [] for req in conditions: - if not version_compare(vstr1, req, strict=True): + if not version_compare(vstr1, req): not_found.append(req) else: found.append(req) return not_found == [], not_found, found - +# determine if the minimum version satisfying the condition |condition| exceeds +# the minimum version for a feature |minimum| def version_compare_condition_with_min(condition, minimum): - match = numpart.match(minimum.strip()) - if match is None: - msg = 'Uncomparable version string {!r}.' - raise MesonException(msg.format(minimum)) - minimum = match.group(0) if condition.startswith('>='): cmpop = operator.le condition = condition[2:] elif condition.startswith('<='): - return True - condition = condition[2:] + return False elif condition.startswith('!='): - return True - condition = condition[2:] + return False elif condition.startswith('=='): cmpop = operator.le condition = condition[2:] @@ -483,49 +506,25 @@ def version_compare_condition_with_min(condition, minimum): cmpop = operator.lt condition = condition[1:] elif condition.startswith('<'): - return True - condition = condition[2:] - else: - cmpop = operator.le - varr1 = grab_leading_numbers(minimum, True) - varr2 = grab_leading_numbers(condition, True) - make_same_len(varr1, varr2) - return cmpop(varr1, varr2) - -def version_compare_condition_with_max(condition, maximum): - match = numpart.match(maximum.strip()) - if match is None: - msg = 'Uncomparable version string {!r}.' - raise MesonException(msg.format(maximum)) - maximum = match.group(0) - if condition.startswith('>='): - return False - condition = condition[2:] - elif condition.startswith('<='): - cmpop = operator.ge - condition = condition[2:] - elif condition.startswith('!='): return False - condition = condition[2:] - elif condition.startswith('=='): - cmpop = operator.ge - condition = condition[2:] - elif condition.startswith('='): - cmpop = operator.ge - condition = condition[1:] - elif condition.startswith('>'): - return False - condition = condition[1:] - elif condition.startswith('<'): - cmpop = operator.gt - condition = condition[2:] else: - cmpop = operator.ge - varr1 = grab_leading_numbers(maximum, True) - varr2 = grab_leading_numbers(condition, True) - make_same_len(varr1, varr2) - return cmpop(varr1, varr2) + cmpop = operator.le + + # Declaring a project(meson_version: '>=0.46') and then using features in + # 0.46.0 is valid, because (knowing the meson versioning scheme) '0.46.0' is + # the lowest version which satisfies the constraint '>=0.46'. + # + # But this will fail here, because the minimum version required by the + # version constraint ('0.46') is strictly less (in our version comparison) + # than the minimum version needed for the feature ('0.46.0'). + # + # Map versions in the constraint of the form '0.46' to '0.46.0', to embed + # this knowledge of the meson versioning scheme. + condition = condition.strip() + if re.match('^\d+.\d+$', condition): + condition += '.0' + return cmpop(Version(minimum), Version(condition)) def default_libdir(): if is_debianlike(): diff --git a/mesonbuild/mesonmain.py b/mesonbuild/mesonmain.py index b150731..cd925e5 100644 --- a/mesonbuild/mesonmain.py +++ b/mesonbuild/mesonmain.py @@ -43,6 +43,10 @@ def create_parser(): help=argparse.SUPPRESS) p.add_argument('--fatal-meson-warnings', action='store_true', dest='fatal_warnings', help='Make all Meson warnings fatal') + p.add_argument('--reconfigure', action='store_true', + help='Set options and reconfigure the project. Useful when new ' + + 'options have been added to the project and the default value ' + + 'is not working.') p.add_argument('builddir', nargs='?', default=None) p.add_argument('sourcedir', nargs='?', default=None) return p @@ -57,8 +61,10 @@ def wrapmodetype(string): class MesonApp: - def __init__(self, dir1, dir2, handshake, options): - (self.source_dir, self.build_dir) = self.validate_dirs(dir1, dir2, handshake) + def __init__(self, options): + (self.source_dir, self.build_dir) = self.validate_dirs(options.builddir, + options.sourcedir, + options.reconfigure) self.options = options def has_build_file(self, dirname): @@ -66,6 +72,15 @@ class MesonApp: return os.path.exists(fname) def validate_core_dirs(self, dir1, dir2): + if dir1 is None: + if dir2 is None: + if not os.path.exists('meson.build') and os.path.exists('../meson.build'): + dir2 = '..' + else: + raise MesonException('Must specify at least one directory name.') + dir1 = os.getcwd() + if dir2 is None: + dir2 = os.getcwd() ndir1 = os.path.abspath(os.path.realpath(dir1)) ndir2 = os.path.abspath(os.path.realpath(dir2)) if not os.path.exists(ndir1): @@ -86,21 +101,23 @@ class MesonApp: return ndir2, ndir1 raise MesonException('Neither directory contains a build file %s.' % environment.build_filename) - def validate_dirs(self, dir1, dir2, handshake): + def validate_dirs(self, dir1, dir2, reconfigure): (src_dir, build_dir) = self.validate_core_dirs(dir1, dir2) priv_dir = os.path.join(build_dir, 'meson-private/coredata.dat') if os.path.exists(priv_dir): - if not handshake: - print('Directory already configured, exiting Meson. Just run your build command\n' - '(e.g. ninja) and Meson will regenerate as necessary. If ninja fails, run ninja\n' - 'reconfigure to force Meson to regenerate.\n' + if not reconfigure: + print('Directory already configured.\n' + '\nJust run your build command (e.g. ninja) and Meson will regenerate as necessary.\n' + 'If ninja fails, run "ninja reconfigure" or "meson --reconfigure"\n' + 'to force Meson to regenerate.\n' '\nIf build failures persist, manually wipe your build directory to clear any\n' 'stored system data.\n' - '\nTo change option values, run meson configure instead.') - sys.exit(0) + '\nTo change option values, run "meson configure" instead.') + sys.exit(1) else: - if handshake: - raise RuntimeError('Something went terribly wrong. Please file a bug.') + if reconfigure: + print('Directory does not contain a valid build tree:\n{}'.format(build_dir)) + sys.exit(1) return src_dir, build_dir def check_pkgconfig_envvar(self, env): @@ -317,7 +334,11 @@ def run(original_args, mainfile): # No special command? Do the basic setup/reconf. if len(args) >= 2 and args[0] == '--internal': - if args[1] != 'regenerate': + if args[1] == 'regenerate': + # Rewrite "meson --internal regenerate" command line to + # "meson --reconfigure" + args = ['--reconfigure'] + args[2:] + else: script = args[1] try: sys.exit(run_script_command(args[1:])) @@ -325,29 +346,14 @@ def run(original_args, mainfile): mlog.error('\nError in {} helper script:'.format(script)) mlog.exception(e) sys.exit(1) - args = args[2:] - handshake = True - else: - handshake = False parser = create_parser() args = mesonlib.expand_arguments(args) options = parser.parse_args(args) coredata.parse_cmd_line_options(options) - dir1 = options.builddir - dir2 = options.sourcedir try: - if dir1 is None: - if dir2 is None: - if not os.path.exists('meson.build') and os.path.exists('../meson.build'): - dir2 = '..' - else: - raise MesonException('Must specify at least one directory name.') - dir1 = os.getcwd() - if dir2 is None: - dir2 = os.getcwd() - app = MesonApp(dir1, dir2, handshake, options) + app = MesonApp(options) except Exception as e: # Log directory does not exist, so just print # to stdout. diff --git a/run_unittests.py b/run_unittests.py index 79bafcd..a355b0f 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -39,7 +39,7 @@ from mesonbuild.interpreter import Interpreter, ObjectHolder from mesonbuild.mesonlib import ( is_windows, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, windows_proof_rmtree, python_command, version_compare, - grab_leading_numbers, BuildDirLock + BuildDirLock, Version ) from mesonbuild.environment import detect_ninja from mesonbuild.mesonlib import MesonException, EnvironmentException @@ -265,7 +265,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', 0, False) + gcc = mesonbuild.compilers.GnuCCompiler([], 'fake', mesonbuild.compilers.CompilerType.GCC_STANDARD, False) ## 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']) @@ -691,6 +691,114 @@ class InternalTests(unittest.TestCase): PkgConfigDependency.pkgbin_cache = {} PkgConfigDependency.class_pkgbin = None + def test_version_compare(self): + comparefunc = mesonbuild.mesonlib.version_compare_many + for (a, b, result) in [ + ('0.99.beta19', '>= 0.99.beta14', True), + ]: + self.assertEqual(comparefunc(a, b)[0], result) + + for (a, b, result) in [ + # examples from https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison + ("1.0010", "1.9", 1), + ("1.05", "1.5", 0), + ("1.0", "1", 1), + ("2.50", "2.5", 1), + ("fc4", "fc.4", 0), + ("FC5", "fc4", -1), + ("2a", "2.0", -1), + ("1.0", "1.fc4", 1), + ("3.0.0_fc", "3.0.0.fc", 0), + # from RPM tests + ("1.0", "1.0", 0), + ("1.0", "2.0", -1), + ("2.0", "1.0", 1), + ("2.0.1", "2.0.1", 0), + ("2.0", "2.0.1", -1), + ("2.0.1", "2.0", 1), + ("2.0.1a", "2.0.1a", 0), + ("2.0.1a", "2.0.1", 1), + ("2.0.1", "2.0.1a", -1), + ("5.5p1", "5.5p1", 0), + ("5.5p1", "5.5p2", -1), + ("5.5p2", "5.5p1", 1), + ("5.5p10", "5.5p10", 0), + ("5.5p1", "5.5p10", -1), + ("5.5p10", "5.5p1", 1), + ("10xyz", "10.1xyz", -1), + ("10.1xyz", "10xyz", 1), + ("xyz10", "xyz10", 0), + ("xyz10", "xyz10.1", -1), + ("xyz10.1", "xyz10", 1), + ("xyz.4", "xyz.4", 0), + ("xyz.4", "8", -1), + ("8", "xyz.4", 1), + ("xyz.4", "2", -1), + ("2", "xyz.4", 1), + ("5.5p2", "5.6p1", -1), + ("5.6p1", "5.5p2", 1), + ("5.6p1", "6.5p1", -1), + ("6.5p1", "5.6p1", 1), + ("6.0.rc1", "6.0", 1), + ("6.0", "6.0.rc1", -1), + ("10b2", "10a1", 1), + ("10a2", "10b2", -1), + ("1.0aa", "1.0aa", 0), + ("1.0a", "1.0aa", -1), + ("1.0aa", "1.0a", 1), + ("10.0001", "10.0001", 0), + ("10.0001", "10.1", 0), + ("10.1", "10.0001", 0), + ("10.0001", "10.0039", -1), + ("10.0039", "10.0001", 1), + ("4.999.9", "5.0", -1), + ("5.0", "4.999.9", 1), + ("20101121", "20101121", 0), + ("20101121", "20101122", -1), + ("20101122", "20101121", 1), + ("2_0", "2_0", 0), + ("2.0", "2_0", 0), + ("2_0", "2.0", 0), + ("a", "a", 0), + ("a+", "a+", 0), + ("a+", "a_", 0), + ("a_", "a+", 0), + ("+a", "+a", 0), + ("+a", "_a", 0), + ("_a", "+a", 0), + ("+_", "+_", 0), + ("_+", "+_", 0), + ("_+", "_+", 0), + ("+", "_", 0), + ("_", "+", 0), + # other tests + ('0.99.beta19', '0.99.beta14', 1), + ("1.0.0", "2.0.0", -1), + (".0.0", "2.0.0", -1), + ("alpha", "beta", -1), + ("1.0", "1.0.0", -1), + ("2.456", "2.1000", -1), + ("2.1000", "3.111", -1), + ("2.001", "2.1", 0), + ("2.34", "2.34", 0), + ("6.1.2", "6.3.8", -1), + ("1.7.3.0", "2.0.0", -1), + ("2.24.51", "2.25", -1), + ("2.1.5+20120813+gitdcbe778", "2.1.5", 1), + ("3.4.1", "3.4b1", 1), + ("041206", "200090325", -1), + ("0.6.2+git20130413", "0.6.2", 1), + ("2.6.0+bzr6602", "2.6.0", 1), + ("2.6.0", "2.6b2", 1), + ("2.6.0+bzr6602", "2.6b2x", 1), + ("0.6.7+20150214+git3a710f9", "0.6.7", 1), + ("15.8b", "15.8.0.1", -1), + ("1.2rc1", "1.2.0", -1), + ]: + ver_a = Version(a) + ver_b = Version(b) + self.assertEqual(ver_a.__cmp__(ver_b), result) + self.assertEqual(ver_b.__cmp__(ver_a), -result) @unittest.skipIf(is_tarball(), 'Skipping because this is a tarball release') class DataTests(unittest.TestCase): @@ -1534,30 +1642,30 @@ class AllPlatformTests(BasePlatformTests): if isinstance(cc, gnu): self.assertIsInstance(linker, ar) if is_osx(): - self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_OSX) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.GCC_OSX) elif is_windows(): - self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_MINGW) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.GCC_MINGW) elif is_cygwin(): - self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_CYGWIN) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.GCC_CYGWIN) else: - self.assertEqual(cc.gcc_type, mesonbuild.compilers.GCC_STANDARD) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.GCC_STANDARD) if isinstance(cc, clang): self.assertIsInstance(linker, ar) if is_osx(): - self.assertEqual(cc.clang_type, mesonbuild.compilers.CLANG_OSX) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.CLANG_OSX) elif is_windows(): # Not implemented yet - self.assertEqual(cc.clang_type, mesonbuild.compilers.CLANG_WIN) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.CLANG_MINGW) else: - self.assertEqual(cc.clang_type, mesonbuild.compilers.CLANG_STANDARD) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.CLANG_STANDARD) if isinstance(cc, intel): self.assertIsInstance(linker, ar) if is_osx(): - self.assertEqual(cc.icc_type, mesonbuild.compilers.ICC_OSX) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.ICC_OSX) elif is_windows(): - self.assertEqual(cc.icc_type, mesonbuild.compilers.ICC_WIN) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.ICC_WIN) else: - self.assertEqual(cc.icc_type, mesonbuild.compilers.ICC_STANDARD) + self.assertEqual(cc.compiler_type, mesonbuild.compilers.CompilerType.ICC_STANDARD) if isinstance(cc, msvc): self.assertTrue(is_windows()) self.assertIsInstance(linker, lib) @@ -2552,13 +2660,14 @@ recommended as it is not supported on some platforms''') out = self.init(testdir) # Parent project warns correctly self.assertRegex(out, "WARNING: Project targetting '>=0.45'.*'0.47.0': dict") - # Subproject warns correctly - self.assertRegex(out, "|WARNING: Project targetting '>=0.40'.*'0.44.0': disabler") + # Subprojects warn correctly + self.assertRegex(out, r"\|WARNING: Project targetting '>=0.40'.*'0.44.0': disabler") + self.assertRegex(out, r"\|WARNING: Project targetting '!=0.40'.*'0.44.0': disabler") # Subproject has a new-enough meson_version, no warning self.assertNotRegex(out, "WARNING: Project targetting.*Python") # Ensure a summary is printed in the subproject and the outer project - self.assertRegex(out, "|WARNING: Project specifies a minimum meson_version '>=0.40'") - self.assertRegex(out, "| * 0.44.0: {'disabler'}") + self.assertRegex(out, r"\|WARNING: Project specifies a minimum meson_version '>=0.40'") + self.assertRegex(out, r"\| \* 0.44.0: {'disabler'}") self.assertRegex(out, "WARNING: Project specifies a minimum meson_version '>=0.45'") self.assertRegex(out, " * 0.47.0: {'dict'}") @@ -2656,7 +2765,7 @@ class FailureTests(BasePlatformTests): super().tearDown() windows_proof_rmtree(self.srcdir) - def assertMesonRaises(self, contents, match, extra_args=None, langs=None): + def assertMesonRaises(self, contents, match, extra_args=None, langs=None, meson_version=None): ''' Assert that running meson configure on the specified @contents raises a error message matching regex @match. @@ -2664,7 +2773,10 @@ class FailureTests(BasePlatformTests): if langs is None: langs = [] with open(self.mbuild, 'w') as f: - f.write("project('failure test', 'c', 'cpp')\n") + f.write("project('failure test', 'c', 'cpp'") + if meson_version: + f.write(", meson_version: '{}'".format(meson_version)) + f.write(")\n") for lang in langs: f.write("add_languages('{}', required : false)\n".format(lang)) f.write(contents) @@ -2674,13 +2786,14 @@ class FailureTests(BasePlatformTests): # Must run in-process or we'll get a generic CalledProcessError self.init(self.srcdir, extra_args=extra_args, inprocess=True) - def obtainMesonOutput(self, contents, match, extra_args, langs, meson_version): + def obtainMesonOutput(self, contents, match, extra_args, langs, meson_version=None): if langs is None: langs = [] with open(self.mbuild, 'w') as f: - core_version = '.'.join([str(component) for component in grab_leading_numbers(mesonbuild.coredata.version)]) - meson_version = meson_version or core_version - f.write("project('output test', 'c', 'cpp', meson_version: '{}')\n".format(meson_version)) + f.write("project('output test', 'c', 'cpp'") + if meson_version: + f.write(", meson_version: '{}'".format(meson_version)) + f.write(")\n") for lang in langs: f.write("add_languages('{}', required : false)\n".format(lang)) f.write(contents) @@ -2860,7 +2973,7 @@ class FailureTests(BasePlatformTests): # Same as above, except the meson version is now appropriate self.assertMesonDoesNotOutput("dict = {}", ".*WARNING.*Project targetting.*but.*", - meson_version='>= 0.47.0') + meson_version='>= 0.47') def test_using_too_recent_feature_dependency(self): self.assertMesonOutputs("dependency('pcap', required: false)", @@ -3344,11 +3457,11 @@ class LinuxlikeTests(BasePlatformTests): for v in compiler.get_options()[lang_std].choices: if (compiler.get_id() == 'clang' and '17' in v and (version_compare(compiler.version, '<5.0.0') or - (compiler.clang_type == mesonbuild.compilers.CLANG_OSX and version_compare(compiler.version, '<9.1')))): + (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<9.1')))): continue if (compiler.get_id() == 'clang' and '2a' in v and (version_compare(compiler.version, '<6.0.0') or - (compiler.clang_type == mesonbuild.compilers.CLANG_OSX and version_compare(compiler.version, '<9.1')))): + (compiler.compiler_type == mesonbuild.compilers.CompilerType.CLANG_OSX and version_compare(compiler.version, '<9.1')))): continue if (compiler.get_id() == 'gcc' and '2a' in v and version_compare(compiler.version, '<8.0.0')): continue diff --git a/test cases/unit/35 dist script/replacer.py b/test cases/unit/35 dist script/replacer.py index 92bcef0..adda365 100755 --- a/test cases/unit/35 dist script/replacer.py +++ b/test cases/unit/35 dist script/replacer.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -import os, sys +import os import pathlib source_root = pathlib.Path(os.environ['MESON_DIST_ROOT']) diff --git a/test cases/unit/41 featurenew subprojects/meson.build b/test cases/unit/41 featurenew subprojects/meson.build index 27898cd..d136bed 100644 --- a/test cases/unit/41 featurenew subprojects/meson.build +++ b/test cases/unit/41 featurenew subprojects/meson.build @@ -4,3 +4,4 @@ foo = {} subproject('foo') subproject('bar') +subproject('baz') diff --git a/test cases/unit/41 featurenew subprojects/subprojects/baz/meson.build b/test cases/unit/41 featurenew subprojects/subprojects/baz/meson.build new file mode 100644 index 0000000..811e7aa --- /dev/null +++ b/test cases/unit/41 featurenew subprojects/subprojects/baz/meson.build @@ -0,0 +1,3 @@ +project('baz subproject', meson_version: '!=0.40') + +disabler() diff --git a/tools/dircondenser.py b/tools/dircondenser.py index c87b967..58c44a2 100755 --- a/tools/dircondenser.py +++ b/tools/dircondenser.py @@ -67,7 +67,7 @@ def condense(dirname): i = _i + 1 if e[0] != i: old_name = str(e[0]) + ' ' + e[1] - new_name = str(i) + ' ' + e[1] + new_name = str(i) + ' ' + e[1] #print('git mv "%s" "%s"' % (old_name, new_name)) subprocess.check_call(['git', 'mv', old_name, new_name]) replacements.append((old_name, new_name)) |