diff --git a/docs/markdown/D.md b/docs/markdown/D.md index 15de2f72e..2b0eaac5a 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 7902f1985..3bd2bfa24 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/mesonbuild/build.py b/mesonbuild/build.py index eb0e2946b..ee99806f9 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/d.py b/mesonbuild/compilers/d.py index e9ceafb97..2865b1f2a 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/test cases/d/9 features/app.d b/test cases/d/9 features/app.d index 6b43bf055..05c56ca5f 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 694e48891..06f03414d 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'])