diff options
-rw-r--r-- | .travis.yml | 5 | ||||
-rw-r--r-- | docs/markdown/D.md | 10 | ||||
-rw-r--r-- | docs/markdown/Reference-manual.md | 3 | ||||
-rw-r--r-- | docs/markdown/Reference-tables.md | 5 | ||||
-rw-r--r-- | docs/markdown/Wrap-dependency-system-manual.md | 22 | ||||
-rw-r--r-- | mesonbuild/build.py | 6 | ||||
-rw-r--r-- | mesonbuild/compilers/c.py | 14 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 2 | ||||
-rw-r--r-- | mesonbuild/compilers/d.py | 50 | ||||
-rw-r--r-- | mesonbuild/dependencies/dev.py | 81 | ||||
-rwxr-xr-x | run_unittests.py | 21 | ||||
-rw-r--r-- | test cases/d/9 features/app.d | 24 | ||||
-rw-r--r-- | test cases/d/9 features/meson.build | 62 |
13 files changed, 251 insertions, 54 deletions
diff --git a/.travis.yml b/.travis.yml index dd5cebb..bd8d48c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ matrix: before_install: - python ./skip_ci.py --base-branch-env=TRAVIS_BRANCH --is-pull-env=TRAVIS_PULL_REQUEST - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt llvm; fi # # Run one macOS build without pkg-config available, and the other (unity=on) with pkg-config - if [[ "$TRAVIS_OS_NAME" == "osx" && "$MESON_ARGS" =~ .*unity=on.* ]]; then brew install pkg-config; fi # Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219 @@ -62,4 +62,5 @@ script: withgit \ /bin/sh -c "cd /root && mkdir -p tools; wget -c http://nirbheek.in/files/binaries/ninja/linux-amd64/ninja -O /root/tools/ninja; chmod +x /root/tools/ninja; CC=$CC CXX=$CXX OBJC=$CC OBJCXX=$CXX PATH=/root/tools:$PATH MESON_FIXED_NINJA=1 ./run_tests.py $RUN_TESTS_ARGS -- $MESON_ARGS && chmod -R a+rwX .coverage" fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:/usr/local/opt/qt/bin:$PATH MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi + # Ensure that llvm is added after $PATH, otherwise the clang from that llvm install will be used instead of the native apple clang. + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then SDKROOT=$(xcodebuild -version -sdk macosx Path) CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib OBJC=$CC OBJCXX=$CXX PATH=$HOME/tools:/usr/local/opt/qt/bin:$PATH:$(brew --prefix llvm)/bin MESON_FIXED_NINJA=1 ./run_tests.py --backend=ninja -- $MESON_ARGS ; fi diff --git a/docs/markdown/D.md b/docs/markdown/D.md index 15de2f7..2b0eaac 100644 --- a/docs/markdown/D.md +++ b/docs/markdown/D.md @@ -14,15 +14,21 @@ project('myapp', 'd') executable('myapp', 'app.d') ``` -## Compiling different versions +## [Conditional compilation](https://dlang.org/spec/version.html) -If you are using the [version()](https://dlang.org/spec/version.html) feature for conditional compilation, +If you are using the [version()](https://dlang.org/spec/version.html#version-specification) feature for conditional compilation, you can use it using the `d_module_versions` target property: ```meson project('myapp', 'd') executable('myapp', 'app.d', d_module_versions: ['Demo', 'FeatureA']) ``` +For debugging, [debug()](https://dlang.org/spec/version.html#debug) conditions are compiled automatically in debug builds, and extra identifiers can be added with the `d_debug` argument: +```meson +project('myapp', 'd') +executable('myapp', 'app.d', d_debug: [3, 'DebugFeatureA']) +``` + ## Using embedded unittests If you are using embedded [unittest functions](https://dlang.org/spec/unittest.html), your source code needs diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 7902f19..3bd2bfa 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -537,7 +537,8 @@ be passed to [shared and static libraries](#library). - `d_import_dirs` list of directories to look in for string imports used in the D programming language - `d_unittest`, when set to true, the D modules are compiled in debug mode -- `d_module_versions` list of module versions set when compiling D sources +- `d_module_versions` list of module version identifiers set when compiling D sources +- `d_debug` list of module debug identifiers set when compiling D sources The list of `sources`, `objects`, and `dependencies` is always flattened, which means you can freely nest and add lists while diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index ccdcb34..39ec1cd 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -65,6 +65,11 @@ set in the cross file. Any cpu family not listed in the above list is not guaranteed to remain stable in future releases. +Those porting from autotools should note that meson does not add +endianness to the name of the cpu_family. For example, autotools +will call little endian PPC64 "ppc64le", meson will not, you must +also check the `.endian()` value of the machine for this information. + ## Operating system names These are provided by the `.system()` method call. diff --git a/docs/markdown/Wrap-dependency-system-manual.md b/docs/markdown/Wrap-dependency-system-manual.md index 0977921..2e977b2 100644 --- a/docs/markdown/Wrap-dependency-system-manual.md +++ b/docs/markdown/Wrap-dependency-system-manual.md @@ -85,9 +85,9 @@ slightly different wrap file. ```ini [wrap-git] -directory=samplesubproject -url=https://github.com/jpakkane/samplesubproject.git -revision=head +directory = samplesubproject +url = https://github.com/jpakkane/samplesubproject.git +revision = head ``` The format is straightforward. The only thing to note is the revision @@ -106,14 +106,14 @@ these cases you can specify the upload URL by adding the following at the end of your wrap file: ```ini -push-url=git@git.example.com:projects/someproject.git # Supported since version 0.37.0 +push-url = git@git.example.com:projects/someproject.git # Supported since version 0.37.0 ``` If the git repo contains submodules, you can tell Meson to clone them automatically by adding the following *(since 0.48.0)*: ```ini -clone-recursive=true +clone-recursive = true ``` ## Using wrapped projects @@ -121,12 +121,12 @@ clone-recursive=true To use a subproject simply do this in your top level `meson.build`. ```meson -foobar_sp = subproject('foobar') +foobar_proj = subproject('foobar') ``` Usually dependencies consist of some header files plus a library to -link against. To do this you would declare this internal dependency -like this: +link against. To do this in a project so it can be used as a subproject you +would declare this internal dependency like this: ```meson foobar_dep = declare_dependency(link_with : mylib, @@ -137,7 +137,7 @@ Then in your main project you would use them like this: ```meson executable('toplevel_exe', 'prog.c', - dependencies : foobar_sp.get_variable('foobar_dep')) + dependencies : foobar_proj.get_variable('foobar_dep')) ``` Note that the subproject object is *not* used as the dependency, but @@ -160,10 +160,10 @@ available. foobar_dep = dependency('foobar', required : false) if not foobar_dep.found() - foobar_subproj = subproject('foobar') + foobar_proj = subproject('foobar') # the subproject defines an internal dependency with # the command declare_dependency(). - foobar_dep = foobar_subproj.get_variable('foobar_dep') + foobar_dep = foobar_proj.get_variable('foobar_dep') endif executable('toplevel_exe', 'prog.c', diff --git a/mesonbuild/build.py b/mesonbuild/build.py index eb0e294..ee99806 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -37,6 +37,7 @@ lang_arg_kwargs = set([ 'd_import_dirs', 'd_unittest', 'd_module_versions', + 'd_debug', 'fortran_args', 'java_args', 'objc_args', @@ -737,9 +738,12 @@ just like those detected with the dependency() function.''') dfeature_unittest = kwargs.get('d_unittest', False) if dfeature_unittest: dfeatures['unittest'] = dfeature_unittest - dfeature_versions = kwargs.get('d_module_versions', None) + dfeature_versions = kwargs.get('d_module_versions', []) if dfeature_versions: dfeatures['versions'] = dfeature_versions + dfeature_debug = kwargs.get('d_debug', []) + if dfeature_debug: + dfeatures['debug'] = dfeature_debug if 'd_import_dirs' in kwargs: dfeature_import_dirs = extract_as_list(kwargs, 'd_import_dirs', unholder=True) for d in dfeature_import_dirs: diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 2da627f..72b9f24 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -986,12 +986,12 @@ class CCompiler(Compiler): return self.find_library_impl(libname, env, extra_dirs, code, libtype) def thread_flags(self, env): - if for_haiku(self.is_cross, env): + if for_haiku(self.is_cross, env) or for_darwin(self.is_cross, env): return [] return ['-pthread'] def thread_link_flags(self, env): - if for_haiku(self.is_cross, env): + if for_haiku(self.is_cross, env) or for_darwin(self.is_cross, env): return [] return ['-pthread'] @@ -1076,16 +1076,6 @@ class ClangCCompiler(ClangCompiler, CCompiler): 'none')}) return opts - def thread_flags(self, env): - if for_darwin(self.is_cross, env): - return [] - return super().thread_flags() - - def thread_link_flags(self, env): - if for_darwin(self.is_cross, env): - return [] - return super().thread_link_flags() - def get_option_compile_args(self, options): args = [] std = options['c_std'] diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 87bf5af..26aeba7 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -299,7 +299,7 @@ msvc_optimization_args = {'0': [], 'g': ['/O0'], '1': ['/O1'], '2': ['/O2'], - '3': ['/O3'], + '3': ['/O2'], 's': ['/O1'], # Implies /Os. } diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index e9ceafb..2865b1f 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -30,14 +30,17 @@ from .compilers import ( ) d_feature_args = {'gcc': {'unittest': '-funittest', + 'debug': '-fdebug', 'version': '-fversion', 'import_dir': '-J' }, 'llvm': {'unittest': '-unittest', + 'debug': '-d-debug', 'version': '-d-version', 'import_dir': '-J' }, 'dmd': {'unittest': '-unittest', + 'debug': '-debug', 'version': '-version', 'import_dir': '-J' } @@ -168,16 +171,53 @@ class DCompiler(Compiler): if unittest: res.append(unittest_arg) + if 'debug' in kwargs: + debug_level = -1 + debugs = kwargs.pop('debug') + if not isinstance(debugs, list): + debugs = [debugs] + + debug_arg = d_feature_args[self.id]['debug'] + if not debug_arg: + raise EnvironmentException('D compiler %s does not support conditional debug identifiers.' % self.name_string()) + + # Parse all debug identifiers and the largest debug level identifier + for d in debugs: + if isinstance(d, int): + if d > debug_level: + debug_level = d + elif isinstance(d, str) and d.isdigit(): + if int(d) > debug_level: + debug_level = int(d) + else: + res.append('{0}={1}'.format(debug_arg, d)) + + if debug_level >= 0: + res.append('{0}={1}'.format(debug_arg, debug_level)) + if 'versions' in kwargs: + version_level = -1 versions = kwargs.pop('versions') if not isinstance(versions, list): versions = [versions] version_arg = d_feature_args[self.id]['version'] if not version_arg: - raise EnvironmentException('D compiler %s does not support the "feature versions" feature.' % self.name_string()) + raise EnvironmentException('D compiler %s does not support conditional version identifiers.' % self.name_string()) + + # Parse all version identifiers and the largest version level identifier for v in versions: - res.append('{0}={1}'.format(version_arg, v)) + if isinstance(v, int): + if v > version_level: + version_level = v + elif isinstance(v, str) and v.isdigit(): + if int(v) > version_level: + version_level = int(v) + else: + res.append('{0}={1}'.format(version_arg, v)) + + if version_level >= 0: + res.append('{0}={1}'.format(version_arg, version_level)) if 'import_dirs' in kwargs: import_dirs = kwargs.pop('import_dirs') @@ -378,7 +418,11 @@ class DCompiler(Compiler): return args def get_debug_args(self, is_debug): - return clike_debug_args[is_debug] + ddebug_args = [] + if is_debug: + ddebug_args = [d_feature_args[self.id]['debug']] + + return clike_debug_args[is_debug] + ddebug_args def get_crt_args(self, crt_val, buildtype): if not is_windows(): diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index d8289c5..1e7c3e8 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -16,6 +16,7 @@ # development purposes, such as testing, debugging, etc.. import functools +import glob import os import re @@ -27,6 +28,17 @@ from .base import ( ) +def get_shared_library_suffix(environment, native): + """This is only gauranteed to work for languages that compile to machine + code, not for languages like C# that use a bytecode and always end in .dll + """ + if mesonlib.for_windows(native, environment): + return '.dll' + elif mesonlib.for_darwin(native, environment): + return '.dylib' + return '.so' + + class GTestDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('gtest', environment, 'cpp', kwargs) @@ -235,7 +247,7 @@ class LLVMDependency(ConfigToolDependency): self.compile_args = list(cargs.difference(self.__cpp_blacklist)) if version_compare(self.version, '>= 3.9'): - self._set_new_link_args() + self._set_new_link_args(environment) else: self._set_old_link_args() self.link_args = strip_system_libdirs(environment, self.link_args) @@ -258,18 +270,63 @@ class LLVMDependency(ConfigToolDependency): new_args.append(arg) return new_args - def _set_new_link_args(self): + def __check_libfiles(self, shared): + """Use llvm-config's --libfiles to check if libraries exist.""" + mode = '--link-shared' if shared else '--link-static' + + # Set self.required to true to force an exception in get_config_value + # if the returncode != 0 + restore = self.required + self.required = True + + try: + # It doesn't matter what the stage is, the caller needs to catch + # the exception anyway. + self.link_args = self.get_config_value(['--libfiles', mode], '') + finally: + self.required = restore + + def _set_new_link_args(self, environment): """How to set linker args for LLVM versions >= 3.9""" - if ((mesonlib.is_dragonflybsd() or mesonlib.is_freebsd()) and not - self.static and version_compare(self.version, '>= 4.0')): - # llvm-config on DragonFly BSD and FreeBSD for versions 4.0, 5.0, - # and 6.0 have an error when generating arguments for shared mode - # linking, even though libLLVM.so is installed, because for some - # reason the tool expects to find a .so for each static library. - # This works around that. - self.link_args = self.get_config_value(['--ldflags'], 'link_args') - self.link_args.append('-lLLVM') - return + mode = self.get_config_value(['--shared-mode'], 'link_args')[0] + if not self.static and mode == 'static': + # If llvm is configured with LLVM_BUILD_LLVM_DYLIB but not with + # LLVM_LINK_LLVM_DYLIB and not LLVM_BUILD_SHARED_LIBS (which + # upstreams doesn't recomend using), then llvm-config will lie to + # you about how to do shared-linking. It wants to link to a a bunch + # of individual shared libs (which don't exist because llvm wasn't + # built with LLVM_BUILD_SHARED_LIBS. + # + # Therefore, we'll try to get the libfiles, if the return code is 0 + # or we get an empty list, then we'll try to build a working + # configuration by hand. + try: + self.__check_libfiles(True) + except DependencyException: + lib_ext = get_shared_library_suffix(environment, self.native) + libdir = self.get_config_value(['--libdir'], 'link_args')[0] + # Sort for reproducability + matches = sorted(glob.iglob(os.path.join(libdir, 'libLLVM*{}'.format(lib_ext)))) + if not matches: + if self.required: + raise + return + + self.link_args = self.get_config_value(['--ldflags'], 'link_args') + libname = os.path.basename(matches[0]).rstrip(lib_ext).lstrip('lib') + self.link_args.append('-l{}'.format(libname)) + return + elif self.static and mode == 'shared': + # If, however LLVM_BUILD_SHARED_LIBS is true # (*cough* gentoo *cough*) + # then this is correct. Building with LLVM_BUILD_SHARED_LIBS has a side + # effect, it stops the generation of static archives. Therefore we need + # to check for that and error out on static if this is the case + try: + self.__check_libfiles(False) + except DependencyException: + if self.required: + raise + link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared'] self.link_args = self.get_config_value( ['--libs', '--ldflags'] + link_args + list(self.required_modules), diff --git a/run_unittests.py b/run_unittests.py index 8fe1c11..8bea2d0 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -37,7 +37,7 @@ import mesonbuild.coredata import mesonbuild.modules.gnome from mesonbuild.interpreter import Interpreter, ObjectHolder from mesonbuild.mesonlib import ( - is_windows, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, + is_windows, is_osx, is_cygwin, is_dragonflybsd, is_openbsd, is_haiku, windows_proof_rmtree, python_command, version_compare, BuildDirLock, Version ) @@ -3270,17 +3270,17 @@ class LinuxlikeTests(BasePlatformTests): self.assertEqual(sorted(out), sorted(['libfoo >= 1.0'])) out = self._run(cmd + ['--cflags-only-other']).strip().split() - self.assertEqual(sorted(out), sorted(['-pthread', '-DCUSTOM'])) + self.check_pkg_flags_are_same(out, ['-pthread', '-DCUSTOM']) out = self._run(cmd + ['--libs-only-l', '--libs-only-other']).strip().split() - self.assertEqual(sorted(out), sorted(['-pthread', '-lcustom', - '-llibmain', '-llibexposed'])) + self.check_pkg_flags_are_same(out, ['-pthread', '-lcustom', + '-llibmain', '-llibexposed']) out = self._run(cmd + ['--libs-only-l', '--libs-only-other', '--static']).strip().split() - self.assertEqual(sorted(out), sorted(['-pthread', '-lcustom', - '-llibmain', '-llibexposed', - '-llibinternal', '-lcustom2', - '-lfoo'])) + self.check_pkg_flags_are_same(out, ['-pthread', '-lcustom', + '-llibmain', '-llibexposed', + '-llibinternal', '-lcustom2', + '-lfoo']) cmd = ['pkg-config', 'requires-test'] out = self._run(cmd + ['--print-requires']).strip().split('\n') @@ -3290,6 +3290,11 @@ class LinuxlikeTests(BasePlatformTests): out = self._run(cmd + ['--print-requires-private']).strip().split('\n') self.assertEqual(sorted(out), sorted(['libexposed', 'libfoo >= 1.0', 'libhello'])) + def check_pkg_flags_are_same(self, output, expected): + if is_osx() or is_haiku(): + expected = [x for x in expected if x != '-pthread'] + self.assertEqual(sorted(output), sorted(expected)) + def test_pkg_unfound(self): testdir = os.path.join(self.unit_test_dir, '23 unfound pkgconfig') self.init(testdir) diff --git a/test cases/d/9 features/app.d b/test cases/d/9 features/app.d index 6b43bf0..05c56ca 100644 --- a/test cases/d/9 features/app.d +++ b/test cases/d/9 features/app.d @@ -41,6 +41,30 @@ void main (string[] args) exit (1); } } + + version (With_VersionInteger) + version(3) exit(0); + + version (With_Debug) + debug exit(0); + + version (With_DebugInteger) + debug(3) exit(0); + + version (With_DebugIdentifier) + debug(DebugIdentifier) exit(0); + + version (With_DebugAll) { + int dbg = 0; + debug dbg++; + debug(2) dbg++; + debug(3) dbg++; + debug(4) dbg++; + debug(DebugIdentifier) dbg++; + + if (dbg == 5) + exit(0); + } // we fail here exit (1); diff --git a/test cases/d/9 features/meson.build b/test cases/d/9 features/meson.build index 694e488..06f0341 100644 --- a/test cases/d/9 features/meson.build +++ b/test cases/d/9 features/meson.build @@ -1,4 +1,4 @@ -project('D Features', 'd') +project('D Features', 'd', default_options : ['debug=false']) # ONLY FOR BACKWARDS COMPATIBILITY. # DO NOT DO THIS IN NEW CODE! @@ -44,3 +44,63 @@ e_test = executable('dapp_test', d_unittest: true ) test('dapp_test', e_test) + +# test version level +e_version_int = executable('dapp_version_int', + test_src, + d_import_dirs: [data_dir], + d_module_versions: ['With_VersionInteger', 3], +) +test('dapp_version_int_t', e_version_int, args: ['debug']) + +# test version level failure +e_version_int_fail = executable('dapp_version_int_fail', + test_src, + d_import_dirs: [data_dir], + d_module_versions: ['With_VersionInteger', 2], +) +test('dapp_version_int_t_fail', e_version_int_fail, args: ['debug'], should_fail: true) + +# test debug conditions: disabled +e_no_debug = executable('dapp_no_debug', + test_src, + d_import_dirs: [data_dir], + d_module_versions: ['With_Debug'], +) +test('dapp_no_debug_t_fail', e_no_debug, args: ['debug'], should_fail: true) + +# test debug conditions: enabled +e_debug = executable('dapp_debug', + test_src, + d_import_dirs: [data_dir], + d_module_versions: ['With_Debug'], + d_debug: 1, +) +test('dapp_debug_t', e_debug, args: ['debug']) + +# test debug conditions: integer +e_debug_int = executable('dapp_debug_int', + test_src, + d_import_dirs: [data_dir], + d_module_versions: ['With_DebugInteger'], + d_debug: 3, +) +test('dapp_debug_int_t', e_debug_int, args: ['debug']) + +# test debug conditions: identifier +e_debug_ident = executable('dapp_debug_ident', + test_src, + d_import_dirs: [data_dir], + d_module_versions: ['With_DebugIdentifier'], + d_debug: 'DebugIdentifier', +) +test('dapp_debug_ident_t', e_debug_ident, args: ['debug']) + +# test with all debug conditions at once, and with redundant values +e_debug_all = executable('dapp_debug_all', + test_src, + d_import_dirs: [data_dir], + d_module_versions: ['With_DebugAll'], + d_debug: ['4', 'DebugIdentifier', 2, 'DebugIdentifierUnused'], +) +test('dapp_debug_all_t', e_debug_all, args: ['debug']) |