mirror of https://github.com/ARMmbed/mbed-os.git
Configuration in header files - step 1
The current implementation of the configuration system "compiles" the configuration parameters to macros defined on the command line. This works, but has a few limitations: - it can bring back the maximum command line length issues in Windows. - depending on the type of the configuration parameter, it might require special quoting of its value in the command line. - various 3rd party IDE/tools seem to have some limitations regarding the total length of the macros that can be defined. This commit is the first step in replacing the current mechanism with one that generates configuration in header files that will be automatically included, instead of command line macro definitions. The commit only adds the method for generating the header file, it doesn't actually change the way config is used yet (that will happen in step 2), thus it is backwards compatible. The logic of the configuration system itself is unchanged (in fact, the whole change (not only this commit) is supposed to be completely transparent for the users of the configuration system). The commit also fixes an issue in tools/get_config.py that appeared as a result of a recent PR: the signature of "get_config" in tools/build_api.py changed, but tools/get_config.py was not updated.pull/1957/head
parent
135a4ee555
commit
ab0a5a53c2
|
@ -132,8 +132,10 @@ class ConfigMacro:
|
|||
if len(tmp) != 2:
|
||||
raise ValueError("Invalid macro definition '%s' in '%s'" % (name, self.defined_by))
|
||||
self.macro_name = tmp[0]
|
||||
self.macro_value = tmp[1]
|
||||
else:
|
||||
self.macro_name = name
|
||||
self.macro_value = None
|
||||
|
||||
# 'Config' implements the mbed configuration mechanism
|
||||
class Config:
|
||||
|
@ -343,13 +345,13 @@ class Config:
|
|||
|
||||
# Return the configuration data in two parts:
|
||||
# - params: a dictionary with (name, ConfigParam) entries
|
||||
# - macros: the list of macros defined with "macros" in libraries and in the application
|
||||
# - macros: the list of macros defined with "macros" in libraries and in the application (as ConfigMacro instances)
|
||||
def get_config_data(self):
|
||||
all_params = self.get_target_config_data()
|
||||
lib_params, macros = self.get_lib_config_data()
|
||||
all_params.update(lib_params)
|
||||
self.get_app_config_data(all_params, macros)
|
||||
return all_params, [m.name for m in macros.values()]
|
||||
return all_params, macros
|
||||
|
||||
# Helper: verify if there are any required parameters without a value in 'params'
|
||||
def _check_required_parameters(self, params):
|
||||
|
@ -363,11 +365,17 @@ class Config:
|
|||
def parameters_to_macros(params):
|
||||
return ['%s=%s' % (m.macro_name, m.value) for m in params.values() if m.value is not None]
|
||||
|
||||
# Return the macro definitions generated for a dictionary of ConfigMacros (as returned by get_config_data)
|
||||
# params: a dictionary of (name, ConfigMacro instance) mappings
|
||||
@staticmethod
|
||||
def config_macros_to_macros(macros):
|
||||
return [m.name for m in macros.values()]
|
||||
|
||||
# Return the configuration data converted to a list of C macros
|
||||
def get_config_data_macros(self):
|
||||
params, macros = self.get_config_data()
|
||||
self._check_required_parameters(params)
|
||||
return macros + self.parameters_to_macros(params)
|
||||
return self.config_macros_to_macros(macros) + self.parameters_to_macros(params)
|
||||
|
||||
# Returns any features in the configuration data
|
||||
def get_features(self):
|
||||
|
@ -387,4 +395,45 @@ class Config:
|
|||
if self.config_errors:
|
||||
raise self.config_errors[0]
|
||||
return True
|
||||
|
||||
|
||||
# Return the configuration data converted to the content of a C header file,
|
||||
# meant to be included to a C/C++ file. The content is returned as a string.
|
||||
# If 'fname' is given, the content is also written to the file called "fname".
|
||||
# WARNING: if 'fname' names an existing file, that file will be overwritten!
|
||||
def get_config_data_header(self, fname = None):
|
||||
params, macros = self.get_config_data()
|
||||
self._check_required_parameters(params)
|
||||
header_data = "// Automatically generated configuration file.\n"
|
||||
header_data += "// DO NOT EDIT, content will be overwritten.\n\n"
|
||||
header_data += "#ifndef __MBED_CONFIG_DATA__\n"
|
||||
header_data += "#define __MBED_CONFIG_DATA__\n\n"
|
||||
# Compute maximum length of macro names for proper alignment
|
||||
max_param_macro_name_len = max([len(m.macro_name) for m in params.values() if m.value is not None]) if params else 0
|
||||
max_direct_macro_name_len = max([len(m.macro_name) for m in macros.values()]) if macros else 0
|
||||
max_macro_name_len = max(max_param_macro_name_len, max_direct_macro_name_len)
|
||||
# Compute maximum length of macro values for proper alignment
|
||||
max_param_macro_val_len = max([len(str(m.value)) for m in params.values() if m.value is not None]) if params else 0
|
||||
max_direct_macro_val_len = max([len(m.macro_value or "") for m in macros.values()]) if macros else 0
|
||||
max_macro_val_len = max(max_param_macro_val_len, max_direct_macro_val_len)
|
||||
# Generate config parameters first
|
||||
if params:
|
||||
header_data += "// Configuration parameters\n"
|
||||
for m in params.values():
|
||||
if m.value is not None:
|
||||
header_data += "#define %s%s%s%s// set by %s\n" % (m.macro_name, " " * (max_macro_name_len - len(m.macro_name) + 1), str(m.value),
|
||||
" " * (max_macro_val_len - len(str(m.value)) + 1), m.set_by)
|
||||
# Then macros
|
||||
if macros:
|
||||
header_data += "// Macros\n"
|
||||
for m in macros.values():
|
||||
if m.macro_value:
|
||||
header_data += "#define %s%s%s%s// defined by %s\n" % (m.macro_name, " " * (max_macro_name_len - len(m.macro_name) + 1), str(m.macro_value),
|
||||
" " * (max_macro_val_len - len(str(m.macro_value)) + 1), m.defined_by)
|
||||
else:
|
||||
header_data += "#define %s%s// defined by %s\n" % (m.macro_name, " " * (max_macro_name_len + max_macro_val_len - len(m.macro_name) + 2), m.defined_by)
|
||||
header_data += "\n#endif\n"
|
||||
# If fname is given, write "header_data" to it
|
||||
if fname:
|
||||
with open(fname, "wt") as f:
|
||||
f.write(header_data)
|
||||
return header_data
|
||||
|
|
|
@ -62,7 +62,7 @@ if __name__ == '__main__':
|
|||
options.prefix = options.prefix or [""]
|
||||
|
||||
try:
|
||||
params, macros = get_config(options.source_dir, target, toolchain)
|
||||
params, macros, features = get_config(options.source_dir, target, toolchain)
|
||||
if not params and not macros:
|
||||
print "No configuration data available."
|
||||
_exit(0)
|
||||
|
@ -79,7 +79,7 @@ if __name__ == '__main__':
|
|||
print "Macros"
|
||||
print "------"
|
||||
if macros:
|
||||
print 'Defined with "macros":', macros
|
||||
print 'Defined with "macros":', Config.config_macros_to_macros(macros)
|
||||
print "Generated from configuration parameters:", Config.parameters_to_macros(params)
|
||||
|
||||
except KeyboardInterrupt, e:
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
"""
|
||||
|
||||
from tools.build_api import get_config
|
||||
from tools.config import ConfigException
|
||||
from tools.config import ConfigException, Config
|
||||
import os, sys
|
||||
|
||||
# Compare the output of config against a dictionary of known good results
|
||||
|
@ -44,6 +44,7 @@ def test_tree(full_name, name):
|
|||
err_msg = None
|
||||
try:
|
||||
cfg, macros, features = get_config(full_name, target, "GCC_ARM")
|
||||
macros = Config.config_macros_to_macros(macros)
|
||||
except ConfigException as e:
|
||||
err_msg = e.message
|
||||
if err_msg:
|
||||
|
|
Loading…
Reference in New Issue