Skip to content

Commit abdc7de

Browse files
Support cross-compilation and execution via Qemu on Linux
Assume that qemu-user is installed and registered for automatic execution through binfmt_misc, and that a cross-compiler is available in /usr/bin following the gcc-multilib-* naming convention (/usr/bin/$ARCH-gcc). Mbed-TLS/mbedtls#3795 (comment) Signed-off-by: Gilles Peskine <[email protected]>
1 parent d1521d2 commit abdc7de

File tree

2 files changed

+49
-6
lines changed

2 files changed

+49
-6
lines changed

tools/bin/mbedtls-prepare-build

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ _environment_options = [
8686
'Options to pass to ${CC} when linking sample programs'),
8787
EnvironmentOption('PYTHON', 'python3',
8888
'Python3 interpreter'),
89+
EnvironmentOption('QEMU_LD_PREFIX', '',
90+
'Path to a runtime for Qemu'),
8991
EnvironmentOption('RM', 'rm -f',
9092
'Program to remove files (e.g. "rm -f")'),
9193
EnvironmentOption('RUN', '',
@@ -308,6 +310,9 @@ class MakefileMaker:
308310
self.static_libraries = None
309311
self.help = {}
310312
self.clean = []
313+
self.variables_to_export = set()
314+
if options.QEMU_LD_PREFIX:
315+
self.variables_to_export.add('QEMU_LD_PREFIX')
311316
self.dependency_cache = {
312317
# TODO: arrange to find dependencies of this generated file.
313318
# They're hard-coded for now, but that won't work if the
@@ -478,6 +483,21 @@ class MakefileMaker:
478483
if clean:
479484
self.add_clean(name)
480485

486+
def setenv_command(self):
487+
"""Generate a shell command to export some environment variables.
488+
489+
The values of these variables must not contain the character ``'``
490+
(single quote).
491+
492+
Return an empty string if there are no variables to export.
493+
"""
494+
if not self.variables_to_export:
495+
return ''
496+
return (' export ' +
497+
' '.join(['{}=\'$({})\''.format(name, name)
498+
for name in sorted(self.variables_to_export)]) +
499+
'; ')
500+
481501
def environment_option_subsection(self):
482502
"""Generate the assignments to customizable options."""
483503
self.comment('Tool settings')
@@ -524,6 +544,7 @@ class MakefileMaker:
524544
self.line('AUX_Q_$(V) = @')
525545
self.line('ECHO_IF_QUIET = $(AUX_ECHO_IF_QUIET_)')
526546
self.line('Q = $(AUX_Q_)')
547+
self.assign('SETENV', self.setenv_command())
527548
self.line('')
528549
self.comment('Auxiliary paths')
529550
self.assign('SOURCE_DIR_FROM_TESTS', '../$(SOURCE_DIR)')
@@ -898,11 +919,11 @@ class MakefileMaker:
898919
executable = program + self.executable_extension
899920
self.target(program + '.run',
900921
[executable],
901-
['$(RUN) ' + executable + ' $(RUNS)'],
922+
['$(SETENV)$(RUN) ' + executable + ' $(RUNS)'],
902923
phony=True)
903924
self.target(program + '.gmon',
904925
[executable],
905-
['$(RUN) ' + executable + ' $(RUNS)',
926+
['$(SETENV)$(RUN) ' + executable + ' $(RUNS)',
906927
'mv gmon.out $@'])
907928

908929
def program_subsection(self, src, executables):
@@ -1057,12 +1078,12 @@ class MakefileMaker:
10571078
# so is the .datax file.
10581079
self.target('tests/' + base + '.run',
10591080
[exe_file, 'tests/seedfile'],
1060-
['cd tests && $(RUN) ./' + exe_basename + ' $(RUNS)'],
1081+
['$(SETENV)cd tests && $(RUN) ./' + exe_basename + ' $(RUNS)'],
10611082
short='RUN tests/' + exe_basename,
10621083
phony=True)
10631084
self.target('tests/' + base + '.gmon',
10641085
[exe_file, 'tests/seedfile'],
1065-
['cd tests && $(RUN) ./' + exe_basename + ' $(RUNS)',
1086+
['$(SETENV)cd tests && $(RUN) ./' + exe_basename + ' $(RUNS)',
10661087
'mv tests/gmon.out $@'],
10671088
short='RUN tests/' + exe_basename)
10681089
valgrind_log_basename = 'MemoryChecker.{}.log'.format(base)
@@ -1111,7 +1132,7 @@ class MakefileMaker:
11111132
self.target('tests/seedfile', [],
11121133
['dd bs=64 count=1 </dev/urandom >$@'])
11131134
self.target('check', ['$(test_apps)', 'tests/seedfile'],
1114-
['cd tests && $(PERL) scripts/run-test-suites.pl --skip=$(SKIP_TEST_SUITES)'],
1135+
['$(SETENV)cd tests && $(PERL) scripts/run-test-suites.pl --skip=$(SKIP_TEST_SUITES)'],
11151136
help='Run all the test suites.',
11161137
short='',
11171138
phony=True)
@@ -1550,6 +1571,16 @@ def set_default_option(options, attr, value):
15501571
elif isinstance(value, list):
15511572
setattr(options, attr, value + getattr(options, attr))
15521573

1574+
def handle_cross(options):
1575+
"""Update settings to handle --cross."""
1576+
if options.cross is None:
1577+
return
1578+
# Paths for Ubuntu 18.04 with the packages qemu-user and either
1579+
# gcc-multilib-<ARCH> or gcc-<ARCH> installed.
1580+
set_default_option(options, 'QEMU_LD_PREFIX', '/usr/' + options.cross)
1581+
set_default_option(options, 'CC', options.cross + '-gcc')
1582+
set_default_option(options, 'dir', 'build-' + options.cross)
1583+
15531584
def set_default_options(options):
15541585
"""Apply the preset if any and set default for remaining options.
15551586
@@ -1571,7 +1602,9 @@ def set_default_options(options):
15711602
continue
15721603
set_default_option(options, attr, value)
15731604
set_default_option(options, 'dir', 'build-' + options.preset)
1574-
# Step 2: set remaining defaults.
1605+
# Step 2: handle multi-effect options
1606+
handle_cross(options)
1607+
# Step 3: set remaining defaults.
15751608
for attr, value in _default_options.items():
15761609
set_default_option(options, attr, value)
15771610
for envopt in _environment_options:
@@ -1621,6 +1654,8 @@ def main():
16211654
parser.add_argument('--config-unset',
16221655
action='append', default=[],
16231656
help='Symbol to unset in config.h')
1657+
parser.add_argument('--cross',
1658+
help='Run tests on a different architecture with Qemu. Forces an out-of-tree build.')
16241659
parser.add_argument('--default-target',
16251660
help='Default makefile target (default: all)')
16261661
parser.add_argument('--dir', '-d',

tools/zsh/_mbedtls-prepare-build

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#compdef mbedtls-prepare-build
22

3+
_mbedtls_prepare_build_cross () {
4+
local architectures
5+
architectures=(/usr/*(/Ne['REPLY=$REPLY:t; [[ -e /usr/bin/$REPLY-gcc ]]']))
6+
_call_function ret _describe -t architectures 'Architectures' architectures
7+
}
8+
39
_mbedtls_prepare_build_symbols () {
410
local -a identifiers
511
identifiers=("${(@f)$(_call_program _config_pl_symbols sed -n \''s!^/*\**#define \(MBEDTLS_[0-9A-Z_a-z][0-9A-Z_a-z]*\).*!\1!p'\' \$source_dir/include/mbedtls/config.h)}")
@@ -90,6 +96,8 @@ _mbedtls_prepare_build () {
9096
_call_function ret _describe -t config_name 'Preset configuration name' config_names;;
9197
(--config-set|--config-unset)
9298
_call_function ret _mbedtls_prepare_build_symbols;;
99+
(--cross)
100+
_call_function ret _mbedtls_prepare_build_cross;;
93101
(--dir|--source)
94102
_call_function ret _files -/;;
95103
(--preset)

0 commit comments

Comments
 (0)