Merge ~ubuntu-release/autopkgtest/+git/development:cross-arch-testing into ~ubuntu-release/autopkgtest/+git/development:master

Proposed by Steve Langasek
Status: Merged
Merge reported by: Brian Murray
Merged at revision: c4fc7003a2447e07d4e44083757dfe3458b26e2e
Proposed branch: ~ubuntu-release/autopkgtest/+git/development:cross-arch-testing
Merge into: ~ubuntu-release/autopkgtest/+git/development:master
Diff against target: 533 lines (+247/-69)
8 files modified
.gitlab-ci.yml (+2/-2)
debian/control (+26/-24)
debian/tests/control (+6/-9)
lib/adt_testbed.py (+119/-2)
lib/autopkgtest_args.py (+5/-0)
lib/testdesc.py (+28/-10)
runner/autopkgtest (+55/-22)
runner/autopkgtest.1 (+6/-0)
Reviewer Review Type Date Requested Status
Julian Andres Klode (community) Approve
Iain Lane Pending
Review via email: mp+376169@code.launchpad.net

Description of the change

A first pass at implementing a -a $arch argument to autopkgtest to support cross-arch testing

To post a comment you must log in.
c4fc700... by Steve Langasek

coding style

Revision history for this message
Julian Andres Klode (juliank) wrote :

The commits look good to me from reading them, except that one comment below. Not performed any real-world testing yet.

Revision history for this message
Steve Langasek (vorlon) :
Revision history for this message
Julian Andres Klode (juliank) :
Revision history for this message
Julian Andres Klode (juliank) :
Revision history for this message
Julian Andres Klode (juliank) wrote :

The code seems to do the right thing when testing it, but see the previous note about the missing = in the man page.

review: Approve
Revision history for this message
Brian Murray (brian-murray) wrote :

All the commit ids in this merge proposal exist in the master branch of autopkgtest so I'm setting this to merged.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
2index f28fa86..b9e1492 100644
3--- a/.gitlab-ci.yml
4+++ b/.gitlab-ci.yml
5@@ -17,9 +17,9 @@ tests-sid:
6 - apt-get install -y apt-utils autodep8 build-essential debhelper libdpkg-perl procps python3 python3-debian
7 - tests/autopkgtest NullRunner NullRunnerRoot ChrootRunner
8
9-tests-stretch:
10+tests-stable:
11 stage: test
12- image: debian:stretch
13+ image: debian:stable
14 script:
15 - apt-get update
16 - apt-get install -y apt-utils autodep8 build-essential debhelper libdpkg-perl procps python3 python3-debian
17diff --git a/debian/control b/debian/control
18index 6b347f0..c37b4ee 100644
19--- a/debian/control
20+++ b/debian/control
21@@ -1,39 +1,41 @@
22 Source: autopkgtest
23 Maintainer: Debian CI team <team+ci@tracker.debian.org>
24-Uploaders: Ian Jackson <ijackson@chiark.greenend.org.uk>, Martin Pitt <mpitt@debian.org>, Antonio Terceiro <terceiro@debian.org>, Paul Gevers <elbrus@debian.org>
25+Uploaders: Ian Jackson <ijackson@chiark.greenend.org.uk>,
26+ Martin Pitt <mpitt@debian.org>,
27+ Antonio Terceiro <terceiro@debian.org>,
28+ Paul Gevers <elbrus@debian.org>
29 Section: devel
30 Priority: optional
31 Standards-Version: 4.4.0
32 Build-Depends: debhelper (>= 9),
33- python3 (>= 3.1),
34- python3-mock,
35- python3-debian,
36- python3-docutils,
37- pyflakes3 | pyflakes,
38- procps,
39- pycodestyle | pep8,
40+ procps,
41+ pycodestyle | pep8,
42+ pyflakes3 | pyflakes,
43+ python3 (>= 3.1),
44+ python3-debian,
45+ python3-docutils,
46+ python3-mock
47 Vcs-Git: https://salsa.debian.org/ci-team/autopkgtest.git
48 Vcs-Browser: https://salsa.debian.org/ci-team/autopkgtest
49
50 Package: autopkgtest
51 Architecture: all
52-Depends: python3,
53- python3-debian,
54- apt-utils,
55- libdpkg-perl,
56- procps,
57- ${misc:Depends}
58+Depends: apt-utils,
59+ libdpkg-perl,
60+ procps,
61+ python3,
62+ python3-debian,
63+ ${misc:Depends}
64 Recommends: autodep8
65-Suggests:
66- lxc,
67- lxd,
68- ovmf,
69- qemu-efi-aarch64,
70- qemu-efi-arm,
71- qemu-system,
72- qemu-utils,
73- schroot,
74- vmdb2,
75+Suggests: lxc,
76+ lxd,
77+ ovmf,
78+ qemu-efi-aarch64,
79+ qemu-efi-arm,
80+ qemu-system,
81+ qemu-utils,
82+ schroot,
83+ vmdb2
84 Breaks: debci (<< 1.7~)
85 Description: automatic as-installed testing for Debian packages
86 autopkgtest runs tests on binary packages. The tests are run on the
87diff --git a/debian/tests/control b/debian/tests/control
88index a59b3ef..26f4a18 100644
89--- a/debian/tests/control
90+++ b/debian/tests/control
91@@ -1,8 +1,5 @@
92 Tests: autopkgtest
93-Depends: autopkgtest,
94- autodep8,
95- build-essential,
96- debhelper (>= 7)
97+Depends: autodep8, autopkgtest, build-essential, debhelper (>= 7)
98 Restrictions: needs-root
99 Tests-Directory: tests
100
101@@ -15,9 +12,9 @@ Depends: autopkgtest
102
103 Tests: lxd
104 Depends: autopkgtest,
105- lxd,
106- build-essential,
107- debhelper (>= 7),
108- fakeroot,
109- iptables
110+ build-essential,
111+ debhelper (>= 7),
112+ fakeroot,
113+ iptables,
114+ lxd
115 Restrictions: isolation-machine, needs-root, allow-stderr
116diff --git a/lib/adt_testbed.py b/lib/adt_testbed.py
117index 4fe8874..ff1a0ff 100644
118--- a/lib/adt_testbed.py
119+++ b/lib/adt_testbed.py
120@@ -395,7 +395,8 @@ class Testbed:
121 self._opened(pl)
122 self.modified = False
123
124- def install_deps(self, deps_new, recommends, shell_on_failure=False, synth_deps=[]):
125+ def install_deps(self, deps_new, recommends, shell_on_failure=False,
126+ synth_deps=[], cross_arch=None):
127 '''Install dependencies into testbed'''
128 adtlog.debug('install_deps: deps_new=%s, recommends=%s' % (deps_new, recommends))
129
130@@ -403,7 +404,24 @@ class Testbed:
131 self.recommends_installed = recommends
132 if not deps_new:
133 return
134- self.satisfy_dependencies_string(', '.join(deps_new), 'install-deps', recommends, shell_on_failure=shell_on_failure, synth_deps=synth_deps)
135+ if cross_arch:
136+ # mock up a .dsc with our dependencies string as our build-deps
137+ dsc = TempPath(self, 'autopkgtest-satdep.dsc')
138+ with open(dsc.host, 'w', encoding='UTF-8') as f_dsc:
139+ f_dsc.write("Source: autopkgtest-satdep\n"
140+ "Binary: autopkgtest-satdep\n"
141+ "Architecture: any all\n"
142+ "Build-Depends: " + ', '.join(deps_new) + "\n")
143+ dsc.copydown()
144+
145+ # feed the result to apt-get build-dep
146+ self.satisfy_build_deps(dsc.tb, cross_arch,
147+ recommends, shell_on_failure)
148+ # Now handle the synthetic deps as well
149+ self.install_apt('', recommends, shell_on_failure, synth_deps)
150+
151+ else:
152+ self.satisfy_dependencies_string(', '.join(deps_new), 'install-deps', recommends, shell_on_failure=shell_on_failure, synth_deps=synth_deps)
153
154 def needs_reset(self):
155 # show what caused a reset
156@@ -1021,6 +1039,105 @@ fi
157 if self.execute(['sh', adtlog.verbosity >= 2 and '-exc' or '-ec', script], kind='install')[0] != 0:
158 self.bomb('Failed to update click AppArmor rules')
159
160+ def _run_apt_build_dep(self, what, prefix, recommends, ignorerc=False):
161+ '''actually run apt-get build-dep'''
162+
163+ # capture status-fd to stderr
164+ (rc, _, serr) = self.execute(['/bin/sh', '-ec', '%s apt-get build-dep '
165+ '--assume-yes %s '
166+ '-o APT::Status-Fd=3 '
167+ '-o APT::Install-Recommends=%s '
168+ '-o Dpkg::Options::=--force-confnew '
169+ '-o Debug::pkgProblemResolver=true 3>&2 2>&1' %
170+ (prefix, what, recommends)],
171+ kind='install', stderr=subprocess.PIPE)
172+ if not ignorerc and rc != 0:
173+ adtlog.debug('apt-get build-dep %s failed; status-fd:\n%s' % (what, serr))
174+ # check if apt failed during package download, which might be a
175+ # transient error, so retry
176+ if 'dlstatus:' in serr and 'pmstatus:' not in serr:
177+ raise adtlog.AptDownloadError
178+ else:
179+ raise adtlog.AptPermanentError
180+
181+ def satisfy_build_deps(self, source_pkg, architecture=None,
182+ recommends=False, shell_on_failure=False):
183+ '''Install build-dependencies into testbed with apt-get build-dep
184+
185+ This requires root privileges and a writable file system.
186+ '''
187+ # check if we can use apt-get
188+ can_apt_get = False
189+ if 'root-on-testbed' in self.caps:
190+ rc = self.execute(['test', '-w', '/var/lib/dpkg/status'])[0]
191+ if rc == 0:
192+ can_apt_get = True
193+ adtlog.debug('can use apt-get on testbed: %s' % can_apt_get)
194+
195+ if not can_apt_get:
196+ self.bomb('no root on testbed, unsupported when specifying target architecture')
197+
198+ what = source_pkg
199+ if architecture:
200+ what += ' -a ' + architecture
201+ # install the build-dependencies for the specified source (which can
202+ # be a source package name, or a path); our apt pinning is not
203+ # very clever wrt. resolving transitional dependencies in the pocket,
204+ # so we might need to retry without pinning
205+ download_fail_retries = 3
206+ while True:
207+ rc = 0
208+ try:
209+ self._run_apt_build_dep(what, ' '.join(self.eatmydata_prefix), recommends)
210+
211+ # check if apt failed during package download, which might be a
212+ # transient error, so retry
213+ except adtlog.AptDownloadError:
214+ download_fail_retries -= 1
215+ if download_fail_retries > 0:
216+ adtlog.warning('apt failed to download packages, retrying in 10s...')
217+ time.sleep(10)
218+ continue
219+ else:
220+ self.bomb('apt repeatedly failed to download packages')
221+
222+ except adtlog.AptPermanentError:
223+ rc = -1
224+ if shell_on_failure:
225+ self.run_shell()
226+
227+ if rc != 0:
228+ if self.apt_pin_for_releases and self.enable_apt_fallback:
229+ release = self.apt_pin_for_releases.pop()
230+ adtlog.warning('Test dependencies are unsatisfiable using apt pinning. '
231+ 'Retrying using all packages from %s' % release)
232+ self.check_exec(['/bin/sh', '-ec', 'rm /etc/apt/preferences.d/autopkgtest-' + release])
233+ if not self.apt_pin_for_releases:
234+ self.check_exec(['/bin/sh', '-ec', 'rm -f /etc/apt/preferences.d/autopkgtest-default-release'])
235+ continue
236+
237+ adtlog.warning('Test dependencies are unsatisfiable - calling '
238+ 'apt install on test deps directly for further '
239+ 'data about failing dependencies in test logs')
240+ self._run_apt_build_dep('--simulate ' + what,
241+ ' '.join(self.eatmydata_prefix),
242+ recommends, ignorerc=True)
243+
244+ if shell_on_failure:
245+ self.run_shell()
246+ if self.enable_apt_fallback:
247+ self.badpkg('Test dependencies are unsatisfiable. A common reason is '
248+ 'that your testbed is out of date with respect to the '
249+ 'archive, and you need to use a current testbed or run '
250+ 'apt-get update or use -U.')
251+ else:
252+ self.badpkg('Test dependencies are unsatisfiable. A common reason is '
253+ 'that the requested apt pinning prevented dependencies '
254+ 'from the non-default suite to be installed. In that '
255+ 'case you need to add those dependencies to the pinning '
256+ 'list.')
257+ break
258+
259 def satisfy_dependencies_string(self, deps, what, recommends=False,
260 build_dep=False, shell_on_failure=False, synth_deps=[]):
261 '''Install dependencies from a string into the testbed'''
262diff --git a/lib/autopkgtest_args.py b/lib/autopkgtest_args.py
263index 7fea2d8..9edb4a8 100644
264--- a/lib/autopkgtest_args.py
265+++ b/lib/autopkgtest_args.py
266@@ -210,6 +210,11 @@ for details.'''
267 help='Run tests from already installed click package '
268 '(e. g. "com.example.myapp"), from specified click '
269 'source directory or manifest\'s x-source.')
270+ g_test.add_argument('-a', '--architecture', metavar='ARCH',
271+ help='run tests for (and when asked, build binaries '
272+ 'for) ARCH instead of the testbed host architecture. '
273+ 'Assumes ARCH is available as a foreign architecture '
274+ 'on the testbed.')
275 g_test.add_argument('packages', nargs='*',
276 help='testsrc source package and testbinary packages as above')
277
278diff --git a/lib/testdesc.py b/lib/testdesc.py
279index 84d24db..eb2ffd4 100644
280--- a/lib/testdesc.py
281+++ b/lib/testdesc.py
282@@ -239,7 +239,7 @@ def _debian_check_unknown_fields(name, record):
283 raise Unsupported(name, 'unknown field %s' % unknown_keys.pop())
284
285
286-def _debian_packages_from_source(srcdir):
287+def _debian_packages_from_source(srcdir, cross_arch=None):
288 packages = []
289 packages_no_arch = []
290
291@@ -252,10 +252,17 @@ def _debian_packages_from_source(srcdir):
292 st.get('Package-type', 'deb') != 'deb':
293 continue
294 arch = st['Architecture']
295- if arch in ('all', 'any'):
296+ qual_pkg = st['Package']
297+ # take care to emit an arch qualifier only for arch-dependent
298+ # packages, not for arch: all ones
299+ if cross_arch:
300+ qual_pkg += ':' + cross_arch
301+ if arch == 'all':
302 packages.append(st['Package'])
303+ elif arch == 'any':
304+ packages.append(qual_pkg)
305 else:
306- packages.append('%s [%s]' % (st['Package'], arch))
307+ packages.append('%s [%s]' % (qual_pkg, arch))
308 packages_no_arch.append(st['Package'])
309
310 return (packages, packages_no_arch)
311@@ -353,7 +360,8 @@ def _synthesize_deps(dep, testbed_arch):
312 return None
313
314
315-def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch):
316+def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch,
317+ cross_arch=None):
318 '''Parse Depends: line in a Debian package
319
320 Split dependencies (comma separated), validate their syntax, and expand @
321@@ -364,7 +372,12 @@ def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch):
322 '''
323 deps = []
324 synthdeps = []
325- (my_packages, my_packages_no_arch) = _debian_packages_from_source(srcdir)
326+ (my_packages, my_packages_no_arch) = _debian_packages_from_source(srcdir,
327+ cross_arch=cross_arch)
328+ if cross_arch:
329+ target_arch = cross_arch
330+ else:
331+ target_arch = testbed_arch
332 for alt_group_str in dep_str.split(','):
333 alt_group_str = alt_group_str.strip()
334 if not alt_group_str:
335@@ -375,7 +388,7 @@ def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch):
336 for d in my_packages:
337 adtlog.debug('synthesised dependency %s' % d)
338 deps.append(d)
339- s = _synthesize_deps(d, testbed_arch)
340+ s = _synthesize_deps(d, target_arch)
341 if s:
342 synthdeps.append(s)
343 elif alt_group_str == '@builddeps@':
344@@ -389,8 +402,10 @@ def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch):
345 if pkg not in my_packages_no_arch:
346 synthdep_alternatives = []
347 break
348- s = _synthesize_deps(dep, testbed_arch)
349+ s = _synthesize_deps(dep, target_arch)
350 if s:
351+ if cross_arch:
352+ s += ':' + cross_arch
353 synthdep_alternatives.append(s)
354 if synthdep_alternatives:
355 adtlog.debug('marked alternatives %s as a synthesised dependency' % synthdep_alternatives)
356@@ -398,6 +413,9 @@ def _parse_debian_depends(testname, dep_str, srcdir, testbed_arch):
357 synthdeps.append(synthdep_alternatives)
358 else:
359 synthdeps.append(synthdep_alternatives[0])
360+ if cross_arch and alt_group_str + ':' + cross_arch in my_packages:
361+ adtlog.debug('%s is from our source package, adding arch qualifier for cross-testing' % s)
362+ alt_group_str += ':' + cross_arch
363 deps.append(alt_group_str)
364
365 return (deps, synthdeps)
366@@ -429,7 +447,7 @@ def _autodep8(srcdir):
367
368
369 def parse_debian_source(srcdir, testbed_caps, testbed_arch, control_path=None,
370- auto_control=True):
371+ auto_control=True, cross_arch=None):
372 '''Parse test descriptions from a Debian DEP-8 source dir
373
374 You can specify an alternative path for the control file (default:
375@@ -503,7 +521,7 @@ def parse_debian_source(srcdir, testbed_caps, testbed_arch, control_path=None,
376 test_names[0],
377 record.get('Depends', '@'),
378 srcdir,
379- testbed_arch)
380+ testbed_arch, cross_arch=cross_arch)
381 if 'Test-command' in record:
382 raise InvalidControl('*', 'Only one of "Tests" or '
383 '"Test-Command" may be given')
384@@ -529,7 +547,7 @@ def parse_debian_source(srcdir, testbed_caps, testbed_arch, control_path=None,
385 command,
386 record.get('Depends', '@'),
387 srcdir,
388- testbed_arch)
389+ testbed_arch, cross_arch=cross_arch)
390 if feature_test_name is None:
391 command_counter += 1
392 name = 'command%i' % command_counter
393diff --git a/runner/autopkgtest b/runner/autopkgtest
394index 93c6e61..f1e2e8f 100755
395--- a/runner/autopkgtest
396+++ b/runner/autopkgtest
397@@ -159,7 +159,10 @@ def run_tests(tests, tree):
398 binaries.publish()
399 doTest = True
400 try:
401- testbed.install_deps(t.depends, 'needs-recommends' in t.restrictions, opts.shell_fail, t.synth_depends)
402+ testbed.install_deps(t.depends,
403+ 'needs-recommends' in t.restrictions,
404+ opts.shell_fail, t.synth_depends,
405+ opts.architecture)
406 except adtlog.BadPackageError as e:
407 if 'skip-not-installable' in t.restrictions:
408 errorcode |= 2
409@@ -388,6 +391,12 @@ def build_source(kind, arg, built_binaries):
410 return tests_tree
411
412 elif kind == 'apt-source':
413+ # Make sure we are selecting the binaries based on the actual target
414+ # architecture, not necessarily the testbed architecture
415+ if opts.architecture:
416+ arch = opts.architecture
417+ else:
418+ arch = testbed.dpkg_arch
419 # The default is to determine the version for "apt-get source
420 # pkg=version" that conforms to the current apt pinning. We only
421 # consider binaries which are shipped in all available versions,
422@@ -443,7 +452,7 @@ pkgs=$(echo "$pkgs\n" | awk "
423 if (foundarch == 0 || archmatch == 1) thissrc[\\$1] = 1;
424 next }
425 { if (!inlist) next;
426- inlist=0;''' % {'src': arg, 'arch': testbed.dpkg_arch}
427+ inlist=0;''' % {'src': arg, 'arch': arch}
428
429 create_command_part2_check_all_pkgs = '''
430 remaining=0;
431@@ -580,24 +589,8 @@ dpkg-source -x %(src)s_*.dsc src >/dev/null''' % {'src': arg}
432 if kind not in ['dsc', 'apt-source']:
433 testbed.install_deps([], False)
434
435- if kind in ('apt-source', 'git-source'):
436- # we need to get the downloaded debian/control from the testbed, so
437- # that we can avoid calling "apt-get build-dep" and thus
438- # introducing a second mechanism for installing build deps
439- pkg_control = adt_testbed.Path(testbed,
440- os.path.join(tmp, 'apt-control'),
441- os.path.join(result_pwd, 'debian/control'), False)
442- pkg_control.copyup()
443- dsc = pkg_control.host
444-
445- with open(dsc, encoding='UTF-8') as f:
446- d = deb822.Deb822(sequence=f)
447- bd = d.get('Build-Depends', '')
448- bdi = d.get('Build-Depends-Indep', '')
449- bda = d.get('Build-Depends-Arch', '')
450-
451 # determine build command and build-essential packages
452- build_essential = ['build-essential']
453+ build_essential = ['build-essential:native']
454 assert testbed.nproc
455 dpkg_buildpackage = 'DEB_BUILD_OPTIONS="parallel=%s $DEB_BUILD_OPTIONS" dpkg-buildpackage -us -uc -b' % (
456 opts.build_parallel or testbed.nproc)
457@@ -607,8 +600,47 @@ dpkg-source -x %(src)s_*.dsc src >/dev/null''' % {'src': arg}
458 if testbed.user or 'root-on-testbed' not in testbed.caps:
459 build_essential += ['fakeroot']
460
461- testbed.satisfy_dependencies_string(bd + ', ' + bdi + ', ' + bda + ', ' + ', '.join(build_essential), arg,
462- build_dep=True, shell_on_failure=opts.shell_fail)
463+ if opts.architecture:
464+ dpkg_buildpackage += ' -a' + opts.architecture
465+ build_essential += ['crossbuild-essential-%s:native' % opts.architecture]
466+ # apt-get build-dep is the best option here, but we don't call
467+ # it unconditionally because it doesn't take a path to a source
468+ # package as an option in very old releases; so for compatibility
469+ # only use it when we need its multiarch build-dep resolution
470+ # support.
471+ # This is supported in apt 1.1~exp2 and newer, which covers
472+ # Debian oldstable (at time of writing) and Ubuntu 16.04 and
473+ # newer, so once we can rely on this version of apt everywhere,
474+ # the old build-dep resolver code should be deprecated.
475+ all_build_deps = ''
476+ testbed.satisfy_build_deps(result_pwd,
477+ architecture=opts.architecture,
478+ shell_on_failure=opts.shell_fail)
479+ else:
480+ if kind in ('apt-source', 'git-source'):
481+ # we need to get the downloaded debian/control from the
482+ # testbed, so that we can avoid calling "apt-get build-dep"
483+ # and thus introducing a second mechanism for installing
484+ # build deps
485+ pkg_control = adt_testbed.Path(testbed,
486+ os.path.join(tmp, 'apt-control'),
487+ os.path.join(result_pwd, 'debian/control'), False)
488+ pkg_control.copyup()
489+ dsc = pkg_control.host
490+
491+ with open(dsc, encoding='UTF-8') as f:
492+ d = deb822.Deb822(sequence=f)
493+ bd = d.get('Build-Depends', '')
494+ bdi = d.get('Build-Depends-Indep', '')
495+ bda = d.get('Build-Depends-Arch', '')
496+
497+ all_build_deps = bd + ', ' + bdi + ', ' + bda + ', '
498+
499+ testbed.satisfy_dependencies_string(all_build_deps +
500+ ', '.join(build_essential),
501+ arg,
502+ build_dep=True,
503+ shell_on_failure=opts.shell_fail)
504
505 # keep patches applied for tests
506 source_rules_command([dpkg_buildpackage, 'dpkg-source --before-build .'], 'build', cwd=result_pwd)
507@@ -733,7 +765,8 @@ def process_actions():
508 (tests, skipped) = testdesc.parse_debian_source(
509 tests_tree.host, testbed.caps, testbed.dpkg_arch,
510 control_path=control_override,
511- auto_control=opts.auto_control)
512+ auto_control=opts.auto_control,
513+ cross_arch=opts.architecture)
514 except testdesc.InvalidControl as e:
515 adtlog.badpkg(str(e))
516
517diff --git a/runner/autopkgtest.1 b/runner/autopkgtest.1
518index ce4a1bf..abf181b 100644
519--- a/runner/autopkgtest.1
520+++ b/runner/autopkgtest.1
521@@ -136,6 +136,12 @@ autopkgtest --installed-click com.example.myclick -- [...]
522 .SH TEST OPTIONS
523
524 .TP
525+.BR -a " | " --architecture ARCH
526+Run tests for the specified architecture, rather than for the host
527+architecture as defined by dpkg \-\-print-architecture. When building
528+packages from source, cross-build for the target architecture as well.
529+
530+.TP
531 .BR -B " | " --no-built-binaries
532 Binaries from unbuilt source packages (see above)
533 will not be built or ignored, and dependencies are satisfied with packages from

Subscribers

People subscribed via source and target branches