Skip to content

Commit 080770a

Browse files
authored
Merge pull request #17 from gilles-peskine-arm/prepare-build-3.0
mbedtls-prepare-build: support generated files
2 parents 323c207 + 46cec4f commit 080770a

File tree

1 file changed

+110
-35
lines changed

1 file changed

+110
-35
lines changed

tools/bin/mbedtls-prepare-build

+110-35
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,8 @@ _environment_options = [
7070
'Options to always pass to ${CC} when compiling or linking'),
7171
EnvironmentOption('DLLFLAGS', '-shared',
7272
'Options to pass to ${CC} when building a shared library'),
73-
# TODO: allow linking extra libraries. This requires passing -l options
74-
# _after_ the objects to link. But LDFLAGS and xxx_EXTRA_LDFLAGS are
75-
# currently passed before. Should they be moved after? Or should there be
76-
# different variables?
73+
EnvironmentOption('EXTRA_LIBS', '',
74+
'Extra libraries to link programs (including tests) with'),
7775
EnvironmentOption('LDFLAGS', '',
7876
'Options to always pass to ${CC} when linking'),
7977
EnvironmentOption('LIBRARY_EXTRA_CFLAGS', '',
@@ -465,7 +463,7 @@ class MakefileMaker:
465463
for com in commands:
466464
self.format('\t{}{}',
467465
('' if short is None else '$(Q)'),
468-
com.replace('\n', ' \\\n\t'))
466+
com.strip('\n').replace('\n', ' \\\n\t'))
469467
if help is not None:
470468
self.help[name] = help
471469
if phony:
@@ -779,7 +777,7 @@ class MakefileMaker:
779777
"""
780778
self.comment('Library targets')
781779
self.assign('LIBRARY_CFLAGS',
782-
'-I include/mbedtls', # must come first, for "config.h"
780+
'-I include/mbedtls', # must come first, for the config header
783781
'-I include',
784782
self.include_path_options('library/*'),
785783
'$(LIBRARY_EXTRA_CFLAGS)')
@@ -972,6 +970,7 @@ class MakefileMaker:
972970
'$(LDFLAGS)',
973971
'$(PROGRAMS_LDFLAGS)',
974972
sjoin(*(dash_l_libs + self.extra_link_flags(base))),
973+
'$(EXTRA_LIBS)',
975974
'-o $@')],
976975
clean=False,
977976
short='LD $@')
@@ -1026,17 +1025,24 @@ class MakefileMaker:
10261025
tests_common_objects.append(object_file)
10271026
self.assign('test_common_objects', *tests_common_objects)
10281027

1029-
def test_subsection(self, src, executables):
1028+
def test_subsection(self, src, executables, groups):
10301029
"""Emit the makefile rules to build one test suite.
10311030
10321031
src is a SourceFile object for a .data file.
10331032
10341033
This function appens the path to the test executable to the list
1035-
executables.)"""
1034+
executables.
1035+
1036+
If the .data file is part of a group (*.*.data where the part before the
1037+
first '.' identifies a group), add it to the groups dictionary. The
1038+
keys in this dictionary are group names (base names of .function files)
1039+
and the values are lists of dependencies.
1040+
"""
10361041
base = os.path.basename(src.base())
10371042
source_dir = src.source_dir()
10381043
try:
10391044
function_base = base[:base.index('.')]
1045+
groups.setdefault(function_base, [])
10401046
except ValueError:
10411047
function_base = base
10421048
data_file = src.relative_path()
@@ -1045,6 +1051,8 @@ class MakefileMaker:
10451051
c_file = os.path.join('tests', base + '.c')
10461052
exe_basename = base + self.executable_extension
10471053
exe_file = os.path.join('tests', exe_basename)
1054+
if function_base in groups:
1055+
groups[function_base].append(exe_file)
10481056
generate_command = self.test_generator.command(function_file, data_file)
10491057
self.target(self.test_generator.target(c_file),
10501058
['$(SOURCE_DIR)/' + base
@@ -1098,6 +1106,28 @@ class MakefileMaker:
10981106
short='VALGRIND tests/' + exe_basename,
10991107
phony=True)
11001108

1109+
def test_group_targets(self, groups):
1110+
"""Emit run targets for test groups.
1111+
1112+
A test group is a group of test executables that share the same
1113+
.function file. The groups parameter is a dictionary mapping group
1114+
names to the list of executables that they contain.
1115+
"""
1116+
use_run_test_suites = False
1117+
for base, executables in groups.items():
1118+
shell_code = '''
1119+
failures=;
1120+
for x in {}; do
1121+
./$$x || failures="$$failures $$x";
1122+
done;
1123+
if [ -n "$$failures" ]; then echo; echo "Failures:$$failures"; false; fi
1124+
'''.format(' '.join([re.sub(r'.*/', r'', exe) for exe in executables]))
1125+
self.target('tests/' + base + '.run',
1126+
groups[base] + ['tests/seedfile'],
1127+
['$(SETENV)cd tests && ' + shell_code],
1128+
short='',
1129+
phony=True)
1130+
11011131
def tests_section(self):
11021132
"""Emit makefile rules to build and run test suites."""
11031133
self.comment('Test targets')
@@ -1111,7 +1141,8 @@ class MakefileMaker:
11111141
'$(TESTS_EXTRA_LDFLAGS)')
11121142
self.assign('TESTS_EXTRA_OBJECTS')
11131143
self.assign('test_libs',
1114-
*[self.dash_l_lib(lib) for lib in reversed(self.static_libraries)])
1144+
*[self.dash_l_lib(lib) for lib in reversed(self.static_libraries)],
1145+
'$(EXTRA_LIBS)')
11151146
self.assign('test_build_deps',
11161147
'$(test_common_objects)', *self.static_libraries)
11171148
self.add_clean(*['tests' + sub + '/*' + ext
@@ -1122,9 +1153,11 @@ class MakefileMaker:
11221153
data_files = self.list_source_files(self.options.source,
11231154
'tests/suites/*.data')
11241155
executables = []
1156+
groups = {}
11251157
for src in data_files:
1126-
self.test_subsection(src, executables)
1158+
self.test_subsection(src, executables, groups)
11271159
self.assign('test_apps', *executables)
1160+
self.test_group_targets(groups)
11281161
self.target('tests', ['$(test_apps)'],
11291162
[],
11301163
help='Build the host tests.',
@@ -1147,7 +1180,7 @@ class MakefileMaker:
11471180
[],
11481181
help='Run all the test suites with Valgrind.',
11491182
phony=True)
1150-
self.help['tests/test_suite_%.run'] = 'Run one test suite.'
1183+
self.help['tests/test_suite_%.run'] = 'Run one test suite (or a group).'
11511184
self.help['tests/test_suite_%.valgrind'] = 'Run one test suite with valgrind.'
11521185
self.add_clean('$(test_apps)')
11531186
# TODO: test_psa_constant_names.py
@@ -1224,25 +1257,31 @@ class MakefileMaker:
12241257
os.replace(temp_file, destination)
12251258

12261259
class ConfigMaker:
1227-
"""Parent class for config.h builders.
1260+
"""Parent class for config.h or mbedtls_config.h builders.
12281261
12291262
Typical usage: ChildClass(options).run()
12301263
"""
12311264

12321265
def __init__(self, options):
1233-
"""Initialize a config.h builder with the given command line options."""
1266+
"""Initialize a config header builder with the given command line options."""
12341267
self.options = options
12351268
self.source_file = options.config_file
1269+
include_dir = os.path.join(options.source, 'include', 'mbedtls')
1270+
if os.path.exists(os.path.join(include_dir, 'build_info.h')):
1271+
self.version = 3
1272+
basename = 'mbedtls_config.h'
1273+
else:
1274+
self.version = 2
1275+
basename = 'config.h'
12361276
if self.source_file is None:
1237-
self.source_file = os.path.join(options.source,
1238-
'include', 'mbedtls', 'config.h')
1239-
self.source_file_path = 'include/mbedtls/config.h'
1277+
self.source_file = os.path.join(include_dir, basename)
1278+
self.source_file_path = 'include/mbedtls/' + basename
12401279
if not options.in_tree_build:
12411280
self.source_file_path = 'source/' + self.source_file_path
12421281
else:
12431282
self.source_file_path = os.path.abspath(self.source_file)
12441283
self.target_file = os.path.join(options.dir,
1245-
'include', 'mbedtls', 'config.h')
1284+
'include', 'mbedtls', basename)
12461285

12471286
def start(self):
12481287
"""Builder-specific method which is called first."""
@@ -1268,7 +1307,7 @@ class ConfigMaker:
12681307
raise NotImplementedError
12691308

12701309
def run(self):
1271-
"""Go ahead and generate config.h."""
1310+
"""Go ahead and generate the config header."""
12721311
self.start()
12731312
if self.options.config_name is not None:
12741313
self.batch(self.options.config_name)
@@ -1293,16 +1332,20 @@ class ConfigMaker:
12931332
_config_classes = {}
12941333

12951334
class ConfigCopy(ConfigMaker):
1296-
"""ConfigMaker implementation that copies config.h and runs config.pl."""
1335+
"""ConfigMaker implementation that copies the config header and runs the config script."""
12971336

12981337
def start(self):
12991338
if not are_same_existing_files(self.source_file, self.target_file):
13001339
shutil.copyfile(self.source_file, self.target_file)
13011340

13021341
def run_config_script(self, *args):
1303-
cmd = ['perl', 'scripts/config.pl',
1304-
'-f', os.path.abspath(self.target_file)] + list(args)
1305-
subprocess.check_call(cmd, cwd=self.options.dir)
1342+
if os.path.exists(os.path.join(self.options.source,
1343+
'scripts', 'config.py')):
1344+
cmd = [sys.executable, 'scripts/config.py']
1345+
else:
1346+
cmd = ['perl', 'scripts/config.pl']
1347+
cmd += ['-f', os.path.abspath(self.target_file)] + list(args)
1348+
subprocess.check_call(cmd, cwd=self.options.source)
13061349

13071350
def set(self, name, value=None):
13081351
if value is None:
@@ -1321,7 +1364,7 @@ class ConfigCopy(ConfigMaker):
13211364
_config_classes['copy'] = ConfigCopy
13221365

13231366
class ConfigInclude(ConfigMaker):
1324-
"""ConfigMaker implementation that makes a config.h that #includes the base one."""
1367+
"""ConfigMaker implementation that makes a config script that #includes the base one."""
13251368

13261369
def __init__(self, *args):
13271370
super().__init__(*args)
@@ -1345,12 +1388,13 @@ class ConfigInclude(ConfigMaker):
13451388
self.lines.append('#undef ' + name)
13461389

13471390
def finish(self):
1348-
self.lines.append('')
1349-
self.lines.append('#undef MBEDTLS_CHECK_CONFIG_H')
1350-
# Avoid a redefinition of this typedef
1351-
self.lines.append('#define mbedtls_iso_c_forbids_empty_translation_units mbedtls_iso_c_forbids_empty_translation_units2')
1352-
self.lines.append('#include "mbedtls/check_config.h"')
1353-
self.lines.append('#undef mbedtls_iso_c_forbids_empty_translation_units')
1391+
if self.version < 3:
1392+
self.lines.append('')
1393+
self.lines.append('#undef MBEDTLS_CHECK_CONFIG_H')
1394+
# Avoid a redefinition of this typedef
1395+
self.lines.append('#define mbedtls_iso_c_forbids_empty_translation_units mbedtls_iso_c_forbids_empty_translation_units2')
1396+
self.lines.append('#include "mbedtls/check_config.h"')
1397+
self.lines.append('#undef mbedtls_iso_c_forbids_empty_translation_units')
13541398
self.lines.append('#endif')
13551399
with open(self.target_file, 'w') as out:
13561400
for line in self.lines:
@@ -1362,7 +1406,7 @@ class BuildTreeMaker:
13621406
13631407
* Create a directory structure.
13641408
* Create symbolic links to some files and directories from the source.
1365-
* Create a config.h.
1409+
* Create a config.h or mbedtls_config.h.
13661410
* Create a Makefile.
13671411
13681412
Typical usage: BuildTreeMaker(options).run()
@@ -1440,6 +1484,29 @@ class BuildTreeMaker:
14401484
# in a submodule.
14411485
self.make_link('source/tests/suites', 'suites')
14421486

1487+
def prepare_source(self):
1488+
"""Generate extra source files in the source tree.
1489+
1490+
This is necessary in the Mbed TLS development branch since before 3.0:
1491+
some source files are not checked into version control. Ideally this
1492+
script would know how to generate them in the target directory, but
1493+
this is not implemented yet. As an easier-to-implement stopgap measure,
1494+
generate the files in the source tree.
1495+
1496+
This implementation relies on the official Makefile, so it won't work
1497+
when re-running mbedtls-prepare-build for an in-tree build.
1498+
"""
1499+
if not os.path.exists(os.path.join(self.source_path,
1500+
'library', 'error.c')):
1501+
for name in ('gnumake', 'gmake', 'make'):
1502+
make_command = shutil.which(name)
1503+
if make_command is not None:
1504+
break
1505+
else:
1506+
raise Exception('No "make" command found to run "make generated_files"')
1507+
subprocess.check_call([make_command, 'generated_files'],
1508+
cwd=self.source_path)
1509+
14431510
def run(self):
14441511
"""Go ahead and prepate the build tree."""
14451512
for subdir in ([['include', 'mbedtls'],
@@ -1459,6 +1526,7 @@ class BuildTreeMaker:
14591526
['tests', 'ssl-opt.sh']]:
14601527
self.link_to_source_maybe(link)
14611528
self.link_test_suites()
1529+
self.prepare_source()
14621530
self.makefile.generate()
14631531
self.config.run()
14641532

@@ -1526,6 +1594,13 @@ _preset_options = {
15261594
CFLAGS='-Os',
15271595
COMMON_FLAGS='-mthumb -mcpu=cortex-m0plus',
15281596
),
1597+
'mingw': argparse.Namespace(
1598+
_help='MinGW-w64',
1599+
AR='x86_64-w64-mingw32-ar',
1600+
CC='x86_64-w64-mingw32-gcc',
1601+
EXTRA_LIBS='-lws2_32',
1602+
CFLAGS='-O1',
1603+
),
15291604
'msan': argparse.Namespace(
15301605
_help='Clang Memory sanitizer (MSan), current configuration',
15311606
config_unset=['MBEDTLS_AESNI_C',
@@ -1642,18 +1717,18 @@ def main():
16421717
parser.add_argument('--assembly-extension',
16431718
help='File extension for assembly files')
16441719
parser.add_argument('--config-file',
1645-
help='Base config.h to use')
1720+
help='Base config header (config.h or mbedtls_config.h) to use')
16461721
parser.add_argument('--config-mode',
16471722
choices=_config_classes.keys(),
1648-
help='What to do with config.h')
1723+
help='What to do with the config header')
16491724
parser.add_argument('--config-name',
1650-
help='Configuration to set with scripts/config.pl')
1725+
help='Configuration to set with scripts/config.{pl,py}')
16511726
parser.add_argument('--config-set',
16521727
action='append', default=[],
1653-
help='Additional symbol to set in config.h')
1728+
help='Additional symbol to set in the config header')
16541729
parser.add_argument('--config-unset',
16551730
action='append', default=[],
1656-
help='Symbol to unset in config.h')
1731+
help='Symbol to unset in the config header')
16571732
parser.add_argument('--cross',
16581733
help='Run tests on a different architecture with Qemu. Forces an out-of-tree build.')
16591734
parser.add_argument('--default-target',

0 commit comments

Comments
 (0)