From 551e5352578e1536c361b24d3918d6f12a41db79 Mon Sep 17 00:00:00 2001 From: Alexander Magola Date: Tue, 13 Apr 2021 13:36:15 +0700 Subject: [PATCH] remake and improve 'export-*', fix 'export-config-results' --- demos/c/05-startdir/project/src/prog/test.c | 3 +- demos/c/05-startdir/zenmake/buildconf.py | 5 +- demos/c/07-with spaces/buildconf.py | 4 +- demos/codegen/01-simple/buildconf.py | 2 +- demos/cpp/04-complex/buildconf.py | 3 +- demos/cpp/10-headeronly/buildconf.py | 2 +- demos/gtk3/03-withlib/buildconf.py | 2 +- demos/gtk3/04-withlib2/buildconf.py | 5 +- demos/subdirs/1-first/libs/core/buildconf.py | 2 +- .../subdirs/1-first/libs/engine/buildconf.py | 2 +- .../2-complex/libs/core/buildconf.yaml | 2 +- .../2-complex/libs/engine/buildconf.py | 3 +- docs/buildconf-taskparams.rst | 136 ++++++++++++------ docs/config-actions.rst | 11 +- src/zenmake/zm/buildconf/scheme.py | 31 +++- src/zenmake/zm/constants.py | 4 + src/zenmake/zm/waf/assist.py | 27 +--- src/zenmake/zm/waf/config_actions.py | 45 +++--- src/zenmake/zm/waf/configure.py | 130 +++++++++++++---- src/zenmake/zm/waf/wscriptimpl.py | 12 +- tests/test_buildconf_select.py | 51 +++++-- tests/test_waf_assist.py | 30 ++-- 22 files changed, 338 insertions(+), 174 deletions(-) diff --git a/demos/c/05-startdir/project/src/prog/test.c b/demos/c/05-startdir/project/src/prog/test.c index 99b6ae35..0d895946 100644 --- a/demos/c/05-startdir/project/src/prog/test.c +++ b/demos/c/05-startdir/project/src/prog/test.c @@ -1,8 +1,9 @@ #include #include "util.h" -int main(int argc, char **argv) +int main(int argc, char **argv) { foo(); + printf("hello from main\n"); return 0; } diff --git a/demos/c/05-startdir/zenmake/buildconf.py b/demos/c/05-startdir/zenmake/buildconf.py index dfea44e8..481cab4c 100644 --- a/demos/c/05-startdir/zenmake/buildconf.py +++ b/demos/c/05-startdir/zenmake/buildconf.py @@ -7,7 +7,7 @@ 'features' : 'cshlib', 'source' : 'src/shlib/**/*.c', 'includes' : 'includes', - 'export-includes': True, + 'export' : 'includes config-results', 'configure' : [ dict(do = 'check-headers', names = 'stdio.h'), ], @@ -16,9 +16,6 @@ 'features' : 'cprogram', 'source' : 'src/prog/**/*.c', 'use' : 'util', - 'configure' : [ - dict(do = 'check-headers', names = 'stdio.h'), - ], }, } diff --git a/demos/c/07-with spaces/buildconf.py b/demos/c/07-with spaces/buildconf.py index b86a89af..400eda6e 100644 --- a/demos/c/07-with spaces/buildconf.py +++ b/demos/c/07-with spaces/buildconf.py @@ -6,7 +6,7 @@ 'features' : 'cshlib', 'source' : '"my shlib/**/*.c"', 'includes' : '"my includes"', - 'export-includes' : True, + 'export' : 'includes', 'configure' : [ { 'do' : 'check-headers', 'names' : 'stdio.h' }, ], @@ -24,7 +24,7 @@ 'features' : 'cshlib', 'source' : '"my shlib/my util.c" "my shlib/my util2.c"', 'includes' : '"my includes"', - 'export-includes' : True, + 'export' : 'includes', 'configure' : [ { 'do' : 'check-headers', 'names' : 'stdio.h' }, ], diff --git a/demos/codegen/01-simple/buildconf.py b/demos/codegen/01-simple/buildconf.py index 05b16273..99637aac 100644 --- a/demos/codegen/01-simple/buildconf.py +++ b/demos/codegen/01-simple/buildconf.py @@ -4,7 +4,7 @@ 'configure' : [ dict(do = 'find-program', names = 'python'), ], 'run' : '${PYTHON} ${TOP_DIR}/gencode.py ${BUILDTYPE_DIR}/generated', 'target' : '', - 'export-config-results' : True, + 'export' : 'config-results', }, 'gen-code2' : { 'run' : '${PYTHON} ${TOP_DIR}/gencode.py ${BUILDTYPE_DIR}/generated step2', diff --git a/demos/cpp/04-complex/buildconf.py b/demos/cpp/04-complex/buildconf.py index 39e74658..d974e130 100644 --- a/demos/cpp/04-complex/buildconf.py +++ b/demos/cpp/04-complex/buildconf.py @@ -19,8 +19,7 @@ 'source' : 'shlib/**/*.cpp', 'includes' : 'include', 'defines' : 'ABC=1 DOIT MY_LONG_STRING="some long string"', - 'export-includes' : True, - 'export-defines' : True, + 'export' : 'includes defines', 'install-path' : False, 'configure' : [ { diff --git a/demos/cpp/10-headeronly/buildconf.py b/demos/cpp/10-headeronly/buildconf.py index 299d05f8..4658218c 100644 --- a/demos/cpp/10-headeronly/buildconf.py +++ b/demos/cpp/10-headeronly/buildconf.py @@ -2,7 +2,7 @@ tasks = { 'util' : { 'includes' : 'headers', - 'export-includes' : True, + 'export' : 'includes', }, 'program' : { 'features' : 'cxxprogram', diff --git a/demos/gtk3/03-withlib/buildconf.py b/demos/gtk3/03-withlib/buildconf.py index d00e63b5..4719b004 100644 --- a/demos/gtk3/03-withlib/buildconf.py +++ b/demos/gtk3/03-withlib/buildconf.py @@ -16,7 +16,7 @@ 'configure' : [ { 'do' : 'pkgconfig', 'packages' : 'gtk+-3.0' }, ], - 'export-config-results' : True, + 'export' : 'config-results', 'install-files' : [ { 'src' : '${BUILDTYPE_DIR}/builder.ui', diff --git a/demos/gtk3/04-withlib2/buildconf.py b/demos/gtk3/04-withlib2/buildconf.py index 34034b08..ef82ebbe 100644 --- a/demos/gtk3/04-withlib2/buildconf.py +++ b/demos/gtk3/04-withlib2/buildconf.py @@ -9,7 +9,8 @@ # find 'glib-compile-resources' by pkg-config { 'msg' : 'Looking for glib-compile-resources', - 'do' : 'toolconfig', 'toolname' : 'pkg-config', + 'do' : 'toolconfig', + 'toolname' : 'pkg-config', 'args' : '--variable=glib_compile_resources gio-2.0', 'parse-as' : 'entire', 'var' : 'COMPILE_RES', @@ -30,7 +31,7 @@ 'configure' : [ { 'do' : 'pkgconfig', 'packages' : 'gtk+-3.0' }, ], - 'export-config-results' : True, + 'export' : 'config-results', }, 'gtk3demo2' : { 'features' : 'cprogram', diff --git a/demos/subdirs/1-first/libs/core/buildconf.py b/demos/subdirs/1-first/libs/core/buildconf.py index 3b5cf11b..15b72df2 100644 --- a/demos/subdirs/1-first/libs/core/buildconf.py +++ b/demos/subdirs/1-first/libs/core/buildconf.py @@ -8,7 +8,7 @@ def check(**kwargs): 'features' : 'cshlib', 'source' : '**/*.c', 'includes' : 'src', - 'export-includes' : True, + 'export' : 'includes', 'ver-num' : '0.4.0', 'configure' : [ dict(do = 'check-headers', names = 'stdio.h'), diff --git a/demos/subdirs/1-first/libs/engine/buildconf.py b/demos/subdirs/1-first/libs/engine/buildconf.py index edc36480..6946286c 100644 --- a/demos/subdirs/1-first/libs/engine/buildconf.py +++ b/demos/subdirs/1-first/libs/engine/buildconf.py @@ -14,7 +14,7 @@ 'source' : dict( incl = 'src/**/*.cpp', excl = 'src/extra*' ), 'includes' : 'src', 'use' : 'extra', - 'export-includes' : True, + 'export' : 'includes', 'configure' : [ dict(do = 'check-headers', names = 'iostream'), ], diff --git a/demos/subdirs/2-complex/libs/core/buildconf.yaml b/demos/subdirs/2-complex/libs/core/buildconf.yaml index 5dc96e44..059efd8e 100644 --- a/demos/subdirs/2-complex/libs/core/buildconf.yaml +++ b/demos/subdirs/2-complex/libs/core/buildconf.yaml @@ -5,7 +5,7 @@ tasks: corelib : features : cshlib source : '**/*.c' - export-includes : true + export : includes ver-num : 0.4.0 configure : - do: check-headers diff --git a/demos/subdirs/2-complex/libs/engine/buildconf.py b/demos/subdirs/2-complex/libs/engine/buildconf.py index 4fef2b74..057241f3 100644 --- a/demos/subdirs/2-complex/libs/engine/buildconf.py +++ b/demos/subdirs/2-complex/libs/engine/buildconf.py @@ -30,7 +30,6 @@ def check2(**kwargs): 'includes' : 'src', 'use' : 'extra', 'ver-num' : '0.3.1', - 'export-includes' : True, 'configure' : [ dict( do = 'check-headers', names = 'stdio.h iostream' ), dict( do = 'parallel', actions = [ @@ -51,7 +50,7 @@ def check2(**kwargs): dict( do = 'write-config-header'), dict( do = 'check-headers', names = 'string vector' ), ], - 'export-config-results' : True, + 'export' : 'includes config-results', }, 'extra-test' : { 'features' : 'cxxprogram test', diff --git a/docs/buildconf-taskparams.rst b/docs/buildconf-taskparams.rst index 3964d3bc..54d39c4e 100644 --- a/docs/buildconf-taskparams.rst +++ b/docs/buildconf-taskparams.rst @@ -212,17 +212,7 @@ includes It's possible to use :ref:`selectable parameters` to set this parameter. -export-includes -""""""""""""""""""""" - If it's True then it exports value of ``includes`` for all build tasks - which depend on the current task. Also it can be one or more paths - for explicit exporting. By default it's False. - - If paths contain spaces and all these paths are listed - in one string then each such a path must be in quotes. - - It's possible to use :ref:`selectable parameters` - to set this parameter. + This parameter can be :ref:`exported`. .. _buildconf-taskparams-toolchain: @@ -351,23 +341,7 @@ defines And it's possible to use :ref:`selectable parameters` to set this parameter. -export-defines -""""""""""""""""""""" - If it's True then it exports value of - :ref:`defines` for all build tasks - which depend on the current task. Also it can be one or more defines - for explicit exporting. Defines from :ref:`configuration actions` - are not exported. - Use :ref:`export-config-results` - to export defines from configuration actions. - - By default it's False. - - You can use :ref:`substitution` - variables for this parameter. - - And it's possible to use :ref:`selectable parameters` - to set this parameter. + Also this parameter can be :ref:`exported`. .. _buildconf-taskparams-use: @@ -410,12 +384,12 @@ libs task you may need to specify the same libraries for all other tasks which depend on the current task. For example, you set library 'mylib' to the task A but the task B has parameter ``use`` with 'A', - then it's recommended to add 'mylib' to the parameter ``libs`` of the + then it's recommended to add 'mylib' to the parameter ``libs`` for the task B. Otherwise you can get link error ``... undefined reference to ...`` or something like that. - Some other ways to solve this problem includes using environment variable - ``LD_LIBRARY_PATH`` or changing of /etc/ld.so.conf file. But last way usually - is not recommended. + Some other ways to solve this problem include using environment variable + ``LD_LIBRARY_PATH`` or changing of /etc/ld.so.conf file. But usually last + method is not recommended. Example: @@ -646,17 +620,8 @@ configure It's possible to use :ref:`selectable parameters` to set this parameter. -.. _buildconf-taskparams-export-config-results: - -export-config-results -""""""""""""""""""""" - If it's True then it exports all results of actions in - :ref:`configure` for all - build tasks which depend on the current task. - By default it's False. - - It's possible to use :ref:`selectable parameters` - to set this parameter. + Results of these configuration actions + can be :ref:`exported` with the name `config-results`. .. _buildconf-taskparams-substvars: @@ -672,6 +637,82 @@ substvars It's possible to use :ref:`selectable parameters` to set this parameter. +.. _buildconf-taskparams-export: + +export- / export +"""""""""""""""""""""""" + + Some task parameters can be exported to all dependent build tasks. + + There two forms: ``export-`` and ``export``. + + In first form ```` is a name of task parameter that can be exported. + As value can be used True/False or specific value to export. + If value is True then ZenMake exports value of parameter from current task + to all dependent build tasks. If value is False then ZenMake + exports nothing. + + Supported names: ``includes``, ``defines``, ``config-results``. + + The parameter with ``config-results`` can not be used to export specific values. + It always must be True/False only. + + In second form it must be string or list with the names of parameters to export. + Second form is simplified form of the first form when all values are True. + This form can not be used to set specific value to export. + + By default ZenMake doesn't export anything (all values are False). + + Exported values are inserted in the beginning of the current parameter values + in dependent tasks. It was made to have ability to overwrite parent values. + For example, task A has ``defines`` with value ``AAA=q`` and task B depends + on task A and has ``defines`` with value ``BBB=v``. So if task A has + ``export-defines`` with True, then actual value of ``defines`` in task B will + be ``AAA=q BBB=v``. + + Examples in YAML format: + + .. code-block:: yaml + + # export all includes from current task + export-includes: true + # the same result: + export: includes + + # export all includes and defines from current task + export-includes: true + export-defines: true + # the same result: + export: includes defines + + # export specific includes, value of parameter 'includes' from current + # task is not used + export-includes: incl1 incl2 + + # export specific defines, value of parameter 'defines' from current + # task is not used + export-defines : 'ABC=1 DOIT AAA="some long string"' + + # export results of all configuration actions from current task + export-config-results: true + + # export all includes, defines and results of configuration actions + export: includes defines config-results + + Specific remarks: + + :includes: + If specified paths contain spaces and all these paths are listed + in one string then each such a path must be in quotes. + + :defines: + Defines from :ref:`configuration actions` + are not exported. Use ``export-config-results`` or + ``export`` with ``config-results`` for that. + + It's possible to use :ref:`selectable parameters` + to set this parameter. + install-path """"""""""""""""""""" String representing the installation path for the output files. @@ -679,6 +720,7 @@ install-path To disable installation, set it to False or empty string. If it's absent then general values of ``PREFIX``, ``BINDIR`` and ``LIBDIR`` will be used to detect path. + Path must be absolute. You can use any :ref:`substitution` variable including ``${PREFIX}``, ``${BINDIR}`` and ``${LIBDIR}`` here like this: @@ -828,7 +870,7 @@ group-dependent-tasks analyzing of the task dependencies and file paths in :ref:`source`. Such list of tasks is called `build group` and, by default, it's only one build group for each project which uses ZenMake. If this parameter is true, - ZenMake creates a new build group for all other tasks which depend on the current task and + ZenMake creates a new build group for all other dependent tasks and preparation for these dependent tasks will be run only when all jobs for current task, including all dependencies, are done. @@ -851,12 +893,12 @@ objfile-index build task. If you set this for one task but not for others in the same project and your - selected index number is matched with an one of automatic generated indexes - then it can cause compilation errors if different tasks uses the same files in + index number is matched with one of automatic generated indexes + then it can cause compilation errors if different tasks use the same files in parameter ``source``. Also you can set the same value for the all build tasks and often it's not a - problem while different tasks uses the different files in + problem while different tasks use the different files in parameter ``source``. Set this parameter only if you know what you do. diff --git a/docs/config-actions.rst b/docs/config-actions.rst index 16032f41..2b9e5030 100644 --- a/docs/config-actions.rst +++ b/docs/config-actions.rst @@ -310,10 +310,9 @@ These configuration actions in ``dict`` format: *Supported languages*: C, C++. - After some configuration actions are executed, write a - configuration header in the build directory. - The configuration header is used to limit the size of the - command-line. By default file name is ``_config.h``. + Write a configuration header in the build directory after some + configuration actions. + By default file name is ``_config.h``. Parameter ``guard`` can be used to change C/C++ header guard. Parameter ``remove-defines`` means removing the defines after they are added into configuration header file and it is True by default. @@ -354,8 +353,8 @@ for parallel actions and for the whole bundle of parallel actions as well. All results (defines and some other values) of configuration actions (excluding ``call-pyfunc``) in one build -task can be exported to all build tasks which depend on the current task. -Use :ref:`export-config-results` +task can be exported to all dependent build tasks. +Use :ref:`export` with the name `config-results` for this ability. It allows you to avoid writing the same config actions in tasks and reduce configuration actions time run. diff --git a/src/zenmake/zm/buildconf/scheme.py b/src/zenmake/zm/buildconf/scheme.py index f7710b63..39568be9 100644 --- a/src/zenmake/zm/buildconf/scheme.py +++ b/src/zenmake/zm/buildconf/scheme.py @@ -6,9 +6,10 @@ license: BSD 3-Clause License, see LICENSE for more details. """ +from copy import deepcopy import re -from zm.constants import KNOWN_PLATFORMS, TASK_TARGET_KINDS +from zm.constants import KNOWN_PLATFORMS, TASK_TARGET_KINDS, EXPORTING_TASK_PARAMS from zm.pyutils import stringtype from zm.error import ZenMakeConfValueError from zm.cli import config as cliConfig @@ -24,6 +25,14 @@ def _checkVerNum(value, fullkey): msg += " for the param %r." % fullkey raise ZenMakeConfValueError(msg) +def _checkExportParams(values, fullkey): + + for val in values: + if val not in EXPORTING_TASK_PARAMS: + msg = "Value %r is invalid" % val + msg += " for the param %r." % fullkey + raise ZenMakeConfValueError(msg) + def _genSameSchemeDict(keys, scheme): return { k:scheme for k in keys } @@ -239,6 +248,21 @@ def _genInstallFilesDictVarsScheme(confnode, fullkey): return schemeDictVars +def _addExportParamsToScheme(tscheme): + + tscheme['export'] = { + 'type': ('str', 'list-of-strs'), + 'allowed': _checkExportParams, + } + + for param in EXPORTING_TASK_PARAMS: + if param == 'config-results': + paramScheme = { 'type': 'bool' } + else: + paramScheme = deepcopy(tscheme[param]) + paramScheme['type'] = ('bool', ) + paramScheme['type'] + tscheme['export-%s' % param] = paramScheme + taskscheme = { 'target' : { 'type': 'str' }, 'features' : { 'type': ('str', 'list-of-strs') }, @@ -257,19 +281,18 @@ def _genInstallFilesDictVarsScheme(confnode, fullkey): 'linkflags' : { 'type': ('str', 'list-of-strs') }, 'ldflags' : { 'type': ('str', 'list-of-strs') }, 'defines' : { 'type': ('str', 'list-of-strs') }, - 'export-includes' : { 'type': ('bool', 'str', 'list-of-strs') }, - 'export-defines' : { 'type': ('bool', 'str', 'list-of-strs') }, 'substvars' : _SUBST_VARS_SCHEME, 'install-path' : { 'type': ('bool', 'str') }, 'install-files' : _genInstallFilesScheme, 'configure' : _genConfActionsScheme, - 'export-config-results' : { 'type': 'bool' }, 'group-dependent-tasks' : { 'type': 'bool' }, 'normalize-target-name' : { 'type': 'bool' }, 'enabled' : { 'type': 'bool' }, 'objfile-index' : { 'type': 'int' }, } +_addExportParamsToScheme(taskscheme) + addSelectToParams(taskscheme, [x for x in taskscheme if x != 'features']) taskscheme.update(ConfValidation.getTaskSchemeSpecs()) diff --git a/src/zenmake/zm/constants.py b/src/zenmake/zm/constants.py index e5b2fc1c..123787cf 100644 --- a/src/zenmake/zm/constants.py +++ b/src/zenmake/zm/constants.py @@ -56,3 +56,7 @@ SYSTEM_LIB_PATHS = [] else: SYSTEM_LIB_PATHS = ['/usr/lib64', '/usr/lib', '/usr/local/lib64', '/usr/local/lib'] + +EXPORTING_TASK_PARAMS = ( + 'includes', 'defines', 'config-results', +) diff --git a/src/zenmake/zm/waf/assist.py b/src/zenmake/zm/waf/assist.py index 4a76edea..fad88397 100644 --- a/src/zenmake/zm/waf/assist.py +++ b/src/zenmake/zm/waf/assist.py @@ -319,10 +319,10 @@ def convertTaskParamNamesForWaf(taskParams): ('libs', 'lib'), ('stlibs', 'stlib'), ('ver-num', 'vnum'), - ('export-includes', 'export_includes'), - ('export-defines', 'export_defines'), ('install-path', 'install_path'), ('objfile-index', 'idx'), + + # ZenMake doesn't use Waf 'export_includes' and 'export_defines' anymore ) for zmKey, wafKey in nameMap: @@ -393,14 +393,11 @@ def handleTaskLibPathParams(taskParams): def handleTaskIncludesParam(taskParams, startdir): """ - Make valid 'includes' and 'export-includes' for build task + Make valid 'includes' for build task """ # Includes paths must be relative to the startdir - ##################### - ### 'includes' - if 'includes' in taskParams: param = taskParams['includes'] includes = param.relpaths(startdir) @@ -413,24 +410,6 @@ def handleTaskIncludesParam(taskParams, startdir): includes.insert(0, '.') taskParams['includes'] = includes - ##################### - ### 'export-includes' - - if 'export-includes' not in taskParams: - return - - param = taskParams['export-includes'] - if isinstance(param, bool): - exportIncludes = includes if param else None - else: - exportIncludes = param.relpaths(startdir) - - if not exportIncludes: - taskParams.pop('export-includes', None) - return - - taskParams['export-includes'] = exportIncludes - def handleTaskSourceParam(ctx, taskParams): """ Get valid 'source' for build task diff --git a/src/zenmake/zm/waf/config_actions.py b/src/zenmake/zm/waf/config_actions.py index 33d06a38..a8b93df0 100644 --- a/src/zenmake/zm/waf/config_actions.py +++ b/src/zenmake/zm/waf/config_actions.py @@ -1480,24 +1480,36 @@ def _handleActions(actions, params): 'write-conf-header' : _applyWriteConfigHeaderResults, } -def _importConfigActions(cfgCtx, taskParams): +def _exportConfigActions(cfgCtx, taskParams): - allTasks = cfgCtx.allTasks - localDeps = taskParams.get('use', []) - assert isinstance(localDeps, list) + if not taskParams.get('export-config-results', False): + return - for name in localDeps: - depTaskParams = allTasks.get(name) - if not depTaskParams or not depTaskParams.get('export-config-results', False): - continue + exports = [] + storedActions = taskParams['$stored-actions'] + for actionData in storedActions: + func = _exportedActionsFuncs.get(actionData['type']) + assert func is not None + exports.append([func, actionData['data']]) + + def applyExports(rdeps, exports): + + for name in rdeps: + depTaskParams = cfgCtx.allTasks.get(name) + if not depTaskParams: + continue - storedActions = depTaskParams['$stored-actions'] - for actionData in storedActions: - func = _exportedActionsFuncs.get(actionData['type']) - assert func is not None - data = actionData['data'] - data['$task-params'] = taskParams - func(cfgCtx, data) + cfgCtx.setenv(depTaskParams['$task.variant']) + for func, data in exports: + data['$task-params'] = depTaskParams + func(cfgCtx, data) + + applyExports(depTaskParams.get('$ruse', []), exports) + + applyExports(taskParams.get('$ruse', []), exports) + + # return back the current task env + cfgCtx.setenv(taskParams['$task.variant']) def runActions(cfgCtx): """ @@ -1520,7 +1532,6 @@ def runActions(cfgCtx): #cfgCtx.path = cfgCtx.getPathNode(bconf.confdir) taskParams['$stored-actions'] = deque() - _importConfigActions(cfgCtx, taskParams) actions = taskParams.get('configure', []) if not actions: @@ -1545,6 +1556,8 @@ def runActions(cfgCtx): _handleActions(actions, params) + _exportConfigActions(cfgCtx, taskParams) + for taskParams in tasksList: taskParams.pop('$stored-actions') diff --git a/src/zenmake/zm/waf/configure.py b/src/zenmake/zm/waf/configure.py index 3895fd2c..ae0f64ed 100644 --- a/src/zenmake/zm/waf/configure.py +++ b/src/zenmake/zm/waf/configure.py @@ -21,9 +21,9 @@ from waflib.ConfigSet import ConfigSet from waflib.Configure import ConfigurationContext as WafConfContext from zm.constants import ZENMAKE_CONF_CACHE_PREFIX, WAF_CACHE_DIRNAME, WAF_CONFIG_LOG -from zm.constants import TASK_TARGET_KINDS +from zm.constants import TASK_TARGET_KINDS, EXPORTING_TASK_PARAMS from zm.pyutils import stringtype -from zm.pathutils import substPathsConf +from zm.pathutils import PathsParam, substPathsConf from zm import utils, log, toolchains, error, db, version, cli, edeps from zm.buildconf.select import handleOneTaskParamSelect, handleTaskParamSelects from zm.features import TASK_TARGET_FEATURES_TO_LANG, TASK_LANG_FEATURES @@ -64,6 +64,7 @@ def __init__(self, *args, **kwargs): self._confCache = None self.allTasks = None self.allOrderedTasks = None + self.cleanExportParams = True self.monitFiles = [] self.zmMetaConfAttrs = {} @@ -77,6 +78,91 @@ def _fixSysEnvVars(self): if val is not None: environ[var] = val.replace('"', '').replace("'", '') + def _adjustTaskExportParams(self, taskParams): + + # handle all export params in buildconf and bring to one form + export = taskParams.get('export', []) + exportCount = len(EXPORTING_TASK_PARAMS) + for param in EXPORTING_TASK_PARAMS: + exportName = 'export-%s' % param + exportParam = taskParams.get(exportName, bool(param in export)) + taskParams[exportName] = exportParam + if not exportParam and self.cleanExportParams: + taskParams.pop(exportName, None) + exportCount -= 1 + + if not exportCount: # optimization + taskParams['$no-exports'] = True + + # remove task param 'export' + taskParams.pop('export', None) + + def _handleTaskExportParams(self, taskParams): + + if taskParams.pop('$no-exports', False): + return + + startdir = taskParams['$bconf'].startdir + + pathParams = ('includes', 'libpath', 'stlibpath') + ignoreParams = set(['config-results']) + exportingParams = tuple(set(EXPORTING_TASK_PARAMS) - ignoreParams) + + # gather values for export + export = [] + for param in exportingParams: + exportName = 'export-%s' % param + + exportVal = taskParams.get(exportName, False) + if isinstance(exportVal, bool): + exportVal = taskParams.get(param) if exportVal else None + + if not exportVal: + if self.cleanExportParams: + taskParams.pop(exportName, None) + continue + + withPaths = param in pathParams + if withPaths and not isinstance(exportVal, PathsParam): + exportVal = PathsParam(exportVal, startdir) + + export.append((param, exportVal, withPaths)) + + if not export: + return + + # apply gathered values to all task where they are needed + def applyExports(rdeps, export): + + for name in rdeps: + depTaskParams = self.allTasks.get(name) + if not depTaskParams: + continue + + depStartdir = depTaskParams['$bconf'].startdir + + for param, exportVal, withPaths in export: + if withPaths: + exportVal = exportVal.relpaths(depStartdir) + depTaskParams.setdefault(param, []) + depTaskParams[param][0:0] = exportVal + + applyExports(depTaskParams.get('$ruse', []), export) + + applyExports(taskParams.get('$ruse', []), export) + + if self.cleanExportParams: + for param, _, _ in export: + # they are not needed anymore + exportName = 'export-%s' % param + taskParams.pop(exportName, None) + else: + for param, exportVal, _ in export: + exportName = 'export-%s' % param + if isinstance(exportVal, PathsParam): + exportVal = exportVal.relpaths(startdir) + taskParams[exportName] = exportVal + def _applySubstVars(self, taskParams): substEnv = self.all_envs[taskParams['$task.variant']] @@ -103,21 +189,6 @@ def apply(val, env): else: taskParams[name] = apply(param, substEnv) - def _handleTaskDefinesParam(self, taskParams): - """ - Get valid 'defines' and 'export-defines' for build task - """ - - exportDefines = taskParams.get('export-defines') - if exportDefines is True: - exportDefines = taskParams.get('defines', []) - - if not exportDefines: - taskParams.pop('export-defines', None) - return - - taskParams['export-defines'] = exportDefines - def _handleMonitLibs(self, taskParams): for libsparam in ('libs', 'stlibs'): @@ -634,21 +705,30 @@ def runConfigActions(self): """ configActions.runActions(self) - def configureTaskParams(self, bconf, taskParams): + def configureTaskParams(self): """ Handle some known task params that can be handled at configure stage. """ - self._applySubstVars(taskParams) + for taskParams in self.allOrderedTasks: + bconf = taskParams['$bconf'] - assist.handleTaskIncludesParam(taskParams, bconf.startdir) - assist.handleTaskLibPathParams(taskParams) + # should be called before handling of 'casual' params + self._adjustTaskExportParams(taskParams) - self._handleTaskDefinesParam(taskParams) - self._handleMonitLibs(taskParams) + self._applySubstVars(taskParams) - #counter for the object file extension - taskParams['objfile-index'] = self._calcObjectsIndex(bconf, taskParams) + assist.handleTaskIncludesParam(taskParams, bconf.startdir) + assist.handleTaskLibPathParams(taskParams) + + self._handleMonitLibs(taskParams) + + #counter for the object file extension + taskParams['objfile-index'] = self._calcObjectsIndex(bconf, taskParams) + + for taskParams in self.allOrderedTasks: + # should be called after handling of 'casual' params + self._handleTaskExportParams(taskParams) def _setupTaskTarget(self, taskParams, taskEnv, btypeDir): diff --git a/src/zenmake/zm/waf/wscriptimpl.py b/src/zenmake/zm/waf/wscriptimpl.py index 74fde686..7ba78169 100644 --- a/src/zenmake/zm/waf/wscriptimpl.py +++ b/src/zenmake/zm/waf/wscriptimpl.py @@ -73,18 +73,14 @@ def configure(conf): Implementation of wscript.configure """ - configs = conf.bconfManager.configs - tasksList = conf.allOrderedTasks - - for taskParams in tasksList: - # handle such task params as includes, libpath, ... - conf.configureTaskParams(taskParams['$bconf'], taskParams) + # handle such task params as includes, libpath, etc. + conf.configureTaskParams() # run conf actions conf.runConfigActions() # save envs - for taskParams in tasksList: + for taskParams in conf.allOrderedTasks: bconf = taskParams['$bconf'] @@ -106,7 +102,7 @@ def configure(conf): # switch current env to the root env conf.setenv('') - for bconf in configs: + for bconf in conf.bconfManager.configs: conf.addExtraMonitFiles(bconf) def _setupClean(bld, bconfPaths): diff --git a/tests/test_buildconf_select.py b/tests/test_buildconf_select.py index 2a4ed9af..e1648657 100644 --- a/tests/test_buildconf_select.py +++ b/tests/test_buildconf_select.py @@ -17,8 +17,9 @@ from waflib import Options, Context, Build from waflib.ConfigSet import ConfigSet from waflib.Errors import WafError -from zm.constants import PLATFORM, CPU_ARCH -from zm.pyutils import maptype +from zm.constants import PLATFORM, CPU_ARCH, EXPORTING_TASK_PARAMS +from zm.pyutils import maptype, stringtype +from zm.pathutils import PathsParam from zm.autodict import AutoDict from zm import cli, utils from zm.waf import assist @@ -58,6 +59,7 @@ def makeConfig(self, dirpath, parent = None): 'source' : ['test.c', 'test.c main.c', ['test.c', 'mmain.c']], 'includes' : ['inc1', 'inc1 inc2', ['inc1', 'inc3']], 'export-includes' : ['inc1', 'inc1 inc2', ['inc1', 'inc3']], + 'export' : [ 'defines', 'defines includes', ['defines', 'includes'] ], 'run' : [ {}, {'cmd': 'ls'}, {'cmd': 'ls -la'}], 'substvars' : [ {'VAR': 'ls'}, {'MYVAR': 'ls'}, {'MYVAR1': 'ls -la'}], 'objfile-index' : [1, 2, 3], @@ -89,6 +91,7 @@ def cfgctx(monkeypatch, mocker, tmpdir): monkeypatch.setattr(Options, 'options', AutoDict()) cfgCtx = ConfigurationContext(run_dir = rundir) + cfgCtx.cleanExportParams = False cfgCtx.fatal = mocker.MagicMock(side_effect = WafError) @@ -139,33 +142,59 @@ def execute(): def paramName(request): return request.param -def checkExpectedDefault(result, expected): +def checkExpectedDefault(taskParams, paramName, expected): + result = taskParams[paramName] assert utils.toList(result) == utils.toList(expected) -def checkExpectedToolchain(result, expected): +def checkExpectedToolchain(taskParams, paramName, expected): + result = taskParams[paramName] assert result == [expected] -def checkExpectedTarget(result, expected): +def checkExpectedTarget(taskParams, paramName, expected): + result = taskParams[paramName] assert os.path.basename(result) == expected -def checkExpectedSource(result, expected): +def checkExpectedSource(taskParams, paramName, expected): + result = taskParams[paramName] assert utils.toList(result[0]['paths']) == utils.toList(expected) -def checkExpectedIncludes(result, expected): +def checkExpectedIncludes(taskParams, paramName, expected): + result = taskParams[paramName] if isinstance(result, maptype): result = result['paths'] + elif isinstance(result, PathsParam): + result = result.relpaths() result = [x for x in utils.toList(result) if x != '.'] assert result == utils.toList(expected) checkExpectedExportIncludes = checkExpectedIncludes -def checkExpectedLibpath(result, expected): +def checkExpectedExport(taskParams, _, expected): + + if isinstance(expected, stringtype): + expectedParams = utils.toList(expected) + elif isinstance(expected, (list, tuple)): + expectedParams = expected + else: + assert False + + for param in EXPORTING_TASK_PARAMS: + exportName = 'export-%s' % param + if param in expectedParams: + assert taskParams[exportName] + else: + assert not taskParams.get(exportName) + +def checkExpectedLibpath(taskParams, paramName, expected): + result = taskParams[paramName] assert [os.path.basename(x) for x in result] == utils.toList(expected) -def checkExpectedStlibpath(result, expected): +def checkExpectedStlibpath(taskParams, paramName, expected): + result = taskParams[paramName] assert [os.path.basename(x) for x in result] == utils.toList(expected) -def checkExpectedRun(result, expected): +def checkExpectedRun(taskParams, paramName, expected): + result = taskParams[paramName] for name in expected: assert result[name] == expected[name] @@ -478,4 +507,4 @@ def testParam(cfgctx, monkeypatch, paramfixture): bconf = bconfManager.root for taskParams in bconf.tasks.values(): _expected = expected[taskParams['name']] - checkExpected(taskParams[paramname], _expected) + checkExpected(taskParams, paramname, _expected) diff --git a/tests/test_waf_assist.py b/tests/test_waf_assist.py index 1c7d07c3..e6dbf55e 100644 --- a/tests/test_waf_assist.py +++ b/tests/test_waf_assist.py @@ -190,11 +190,13 @@ def calcExpectedPaths(newStartdir, paramStartDir, paths): 'includes': PathsParam(incPaths, paramStartDir, kind = 'paths'), } - if isinstance(expPaths, bool): - taskParams['export-includes'] = expPaths - else: - taskParams['export-includes'] = \ - PathsParam(expPaths, paramStartDir, kind = 'paths') + # TODO: it's better to do new test with + # ConfigurationContext._handleTaskExportParams + #if isinstance(expPaths, bool): + # taskParams['export-includes'] = expPaths + #else: + # taskParams['export-includes'] = \ + # PathsParam(expPaths, paramStartDir, kind = 'paths') _taskParams = deepcopy(taskParams) assist.handleTaskIncludesParam(_taskParams, startdir) @@ -204,15 +206,15 @@ def calcExpectedPaths(newStartdir, paramStartDir, paths): expected.extend(includePaths) assert _taskParams['includes'] == expected - if isinstance(expPaths, bool): - if expPaths: - assert _taskParams['export-includes'] == expected - else: - assert 'export-includes' not in _taskParams - else: - exportPaths = calcExpectedPaths(startdir, paramStartDir, - expPaths) - assert _taskParams['export-includes'] == exportPaths + #if isinstance(expPaths, bool): + # if expPaths: + # assert _taskParams['export-includes'] == expected + # else: + # assert 'export-includes' not in _taskParams + #else: + # exportPaths = calcExpectedPaths(startdir, paramStartDir, + # expPaths) + # assert _taskParams['export-includes'] == exportPaths def testHandleTaskSourceParam(tmpdir, mocker):