Debian's filesystem layout has a nice advantage over Fedora which is
that it can install non-native RPMs in the main root filesystem. It is
thus possible to prepare an x86_64 filesystem containing -dev packages
for a foreign architecture, along with a GCC cross compiler.
QEMU has used this technique to facilitate developer build testing of
non-x86 architectures, since few people have access to physical
hardware for most of these architectures. For the same reason it would
be helpful to libvirt developers.
This patch extends the 'dockerfile' command to 'lcitool' so that it
accepts a '-x $ARCH' argument.
$ lcitool dockerfile -x s390x libvirt-debian-9 libvirt
This is only valid when using a 'deb' based distro.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
guests/host_vars/libvirt-debian-9/main.yml | 44 +++++++++++++
guests/host_vars/libvirt-debian-sid/main.yml | 45 ++++++++++++++
guests/lcitool | 65 +++++++++++++++++++-
guests/vars/mappings.yml | 59 ++++++++++++++++++
4 files changed, 211 insertions(+), 2 deletions(-)
diff --git a/guests/host_vars/libvirt-debian-9/main.yml
b/guests/host_vars/libvirt-debian-9/main.yml
index ec7e6b4..3bf4ae1 100644
--- a/guests/host_vars/libvirt-debian-9/main.yml
+++ b/guests/host_vars/libvirt-debian-9/main.yml
@@ -21,3 +21,47 @@ os_name: 'Debian'
os_version: '9'
ansible_python_interpreter: /usr/bin/python3
+
+arches:
+ aarch64:
+ package_arch: arm64
+ abi: aarch64-linux-gnu
+ cross_gcc: gcc-aarch64-linux-gnu
+ armv6l:
+ package_arch: armel
+ abi: arm-linux-gnueabi
+ cross_gcc: gcc-arm-linux-gnueabi
+ armv7l:
+ package_arch: armhf
+ abi: arm-linux-gnueabihf
+ cross_gcc: gcc-arm-linux-gnueabihf
+ i686:
+ package_arch: i386
+ abi: i386-linux-gnu
+ mips:
+ package_arch: mips
+ abi: mips-linux-gnu
+ cross_gcc: gcc-mips-linux-gnu
+ mipsel:
+ package_arch: mipsel
+ abi: mipsel-linux-gnu
+ cross_gcc: gcc-mipsel-linux-gnu
+ mips64:
+ package_arch: mips64
+ abi: mips64-linux-gnu
+ cross_gcc: gcc-mips64-linux-gnu
+ mips64el:
+ package_arch: mips64el
+ abi: mips64el-linux-gnu
+ cross_gcc: gcc-mips64el-linux-gnu
+ ppc64el:
+ package_arch: ppc64el
+ abi: ppc64el-linux-gnu
+ cross_gcc: gcc-ppc64el-linux-gnu
+ s390x:
+ package_arch: s390x
+ abi: s390x-linux-gnu
+ cross_gcc: gcc-s390x-linux-gnu
+ x86_64:
+ package_arch: amd64
+ abi: x86_64-linux-gnu
diff --git a/guests/host_vars/libvirt-debian-sid/main.yml
b/guests/host_vars/libvirt-debian-sid/main.yml
index 1c7a29b..b14a564 100644
--- a/guests/host_vars/libvirt-debian-sid/main.yml
+++ b/guests/host_vars/libvirt-debian-sid/main.yml
@@ -21,3 +21,48 @@ os_name: 'Debian'
os_version: 'Sid'
ansible_python_interpreter: /usr/bin/python3
+
+arches:
+ aarch64:
+ package_arch: arm64
+ abi: aarch64-linux-gnu
+ cross_gcc: gcc-aarch64-linux-gnu
+ armv6l:
+ package_arch: armel
+ abi: arm-linux-gnueabi
+ cross_gcc: gcc-arm-linux-gnueabi
+ armv7l:
+ package_arch: armhf
+ abi: arm-linux-gnueabihf
+ cross_gcc: gcc-arm-linux-gnueabihf
+ i686:
+ package_arch: i386
+ abi: i686-linux-gnu
+ cross_gcc: gcc-i686-linux-gnu
+ mips:
+ package_arch: mips
+ abi: mips-linux-gnu
+ cross_gcc: gcc-mips-linux-gnu
+ mipsel:
+ package_arch: mipsel
+ abi: mipsel-linux-gnu
+ cross_gcc: gcc-mipsel-linux-gnu
+ mips64:
+ package_arch: mips64
+ abi: mips64-linux-gnu
+ cross_gcc: gcc-mips64-linux-gnu
+ mips64el:
+ package_arch: mips64el
+ abi: mips64el-linux-gnu
+ cross_gcc: gcc-mips64el-linux-gnu
+ ppc64el:
+ package_arch: ppc64el
+ abi: ppc64el-linux-gnu
+ cross_gcc: gcc-ppc64el-linux-gnu
+ s390x:
+ package_arch: s390x
+ abi: s390x-linux-gnu
+ cross_gcc: gcc-s390x-linux-gnu
+ x86_64:
+ package_arch: amd64
+ abi: x86_64-linux-gnu
diff --git a/guests/lcitool b/guests/lcitool
index 263ab0d..0fb30a5 100755
--- a/guests/lcitool
+++ b/guests/lcitool
@@ -367,6 +367,10 @@ class Application:
add_hosts_arg(dockerfileparser)
add_projects_arg(dockerfileparser)
+ dockerfileparser.add_argument(
+ "-x", "--cross-arch",
+ help="cross compiler architecture",
+ )
def _execute_playbook(self, playbook, hosts, projects, git_revision):
base = Util.get_base()
@@ -537,10 +541,23 @@ class Application:
os_name = facts["os_name"]
os_version = facts["os_version"]
os_full = os_name + os_version
+ cross_facts = None
if package_format not in ["deb", "rpm"]:
raise Error("Host {} doesn't support
Dockerfiles".format(host))
+ if args.cross_arch is not None:
+ if "arches" not in facts:
+ raise Error("Non x86_64 arches not supported for this host")
+ if args.cross_arch not in facts["arches"]:
+ raise Error("Arch {} not supported for this host".format(
+ args.cross_arch))
+ if "cross_gcc" not in facts["arches"][args.cross_arch]:
+ raise Error("Arch {} cross compiler not supported for this
host".format
+ (args.cross_arch))
+
+ cross_build_facts = facts["arches"][args.cross_arch]
+
projects = self._projects.expand_pattern(args.projects)
for project in projects:
if project not in facts["projects"]:
@@ -552,25 +569,50 @@ class Application:
)
pkgs = {}
+ cross_pkgs = {}
base_keys = ["default", package_format, os_name, os_full]
- keys = base_keys + [k + "-" + self._native_arch for k in base_keys]
+ cross_keys = []
+ if args.cross_arch:
+ keys = base_keys + [k + "-" + args.cross_arch for k in base_keys]
+ cross_keys = [k + "-cross-arch" for k in base_keys]
+ else:
+ keys = base_keys + [k + "-" + self._native_arch for k in
base_keys]
+
# We need to add the base project manually here: the standard
# machinery hides it because it's an implementation detail
for project in projects + ["base"]:
for package in self._projects.get_packages(project):
+ policy = "native"
+ for key in cross_keys:
+ if key in mappings[package]:
+ policy = mappings[package][key]
+ if policy not in ["native", "foreign",
"skip"]:
+ raise Error("Unexpected policy {} for {}",
+ policy, package)
+
for key in keys:
if key in mappings[package]:
pkgs[package] = mappings[package][key]
if package not in pkgs:
continue
- if pkgs[package] is None:
+ if policy == "foreign" and pkgs[package] is not None:
+ cross_pkgs[package] = pkgs[package]
+ if pkgs[package] is None or policy in ["skip",
"foreign"]:
del pkgs[package]
print("FROM {}".format(facts["docker_base"]))
varmap = {}
varmap["pkgs"] = " \\\n
".join(sorted(set(pkgs.values())))
+ if args.cross_arch:
+ if package_format != "deb":
+ raise Error("Cannot install foreign {}
packages".format(package_format))
+ varmap["cross_arch"] = cross_build_facts["package_arch"]
+ pkg_names = [p + ":" + cross_build_facts["package_arch"]
for p in cross_pkgs.values()]
+ pkg_names.append(cross_build_facts["cross_gcc"])
+ varmap["cross_pkgs"] = " \\\n
".join(sorted(set(pkg_names)))
+ varmap["cross_target"] = cross_build_facts["abi"]
if package_format == "deb":
sys.stdout.write(textwrap.dedent("""
RUN export DEBIAN_FRONTEND=noninteractive && \\
@@ -581,6 +623,25 @@ class Application:
apt-get autoremove -y && \\
apt-get autoclean -y
""").format(**varmap))
+ if args.cross_arch:
+ # Intentionally a separate RUN command from the above
+ # so that the common packages of all cross-built images
+ # share a docker image layer.
+ sys.stdout.write(textwrap.dedent("""
+ RUN export DEBIAN_FRONTEND=noninteractive && \\
+ dpkg --add-architecture {cross_arch} && \\
+ apt-get update && \\
+ apt-get dist-upgrade -y && \\
+ apt-get install --no-install-recommends -y \\
+ {cross_pkgs} && \\
+ apt-get autoremove -y && \\
+ apt-get autoclean -y
+
+ ENV TARGET "{cross_target}"
+ ENV CONFIGURE_OPTS "--host={cross_target} \\
+ --target={cross_target}"
+ ENV PKG_CONFIG_LIBDIR "/usr/lib/{cross_target}/pkgconfig"
+ """).format(**varmap))
elif package_format == "rpm":
if os_name == "Fedora" and os_version == "Rawhide":
sys.stdout.write(textwrap.dedent("""
diff --git a/guests/vars/mappings.yml b/guests/vars/mappings.yml
index ea46ce4..ebf7e60 100644
--- a/guests/vars/mappings.yml
+++ b/guests/vars/mappings.yml
@@ -57,11 +57,15 @@
# deb-x86_64: libxen-dev
# Fedora-x86_64: xen-devel
#
+# In parallel with this 'cross-arch: native|foreign|skip' entries can
+# used to indicate the policy when setting up a cross-architecture
+# build environment. If omitted 'native' is assumed
mappings:
apparmor:
deb: libapparmor-dev
+ deb-cross-arch: foreign
augeas:
default: augeas
@@ -80,6 +84,7 @@ mappings:
avahi:
deb: libavahi-client-dev
+ deb-cross-arch: foreign
pkg: avahi
rpm: avahi-devel
@@ -106,6 +111,7 @@ mappings:
cyrus-sasl:
deb: libsasl2-dev
+ deb-cross-arch: foreign
pkg: cyrus-sasl
rpm: cyrus-sasl-devel
@@ -116,6 +122,7 @@ mappings:
device-mapper:
deb: libdevmapper-dev
+ deb-cross-arch: foreign
rpm: device-mapper-devel
dnsmasq:
@@ -124,6 +131,7 @@ mappings:
dtrace:
deb: systemtap-sdt-dev
+ deb-cross-arch: skip
rpm: systemtap-sdt-devel
dwarves:
@@ -144,6 +152,7 @@ mappings:
fuse:
deb: libfuse-dev
+ deb-cross-arch: foreign
pkg: fusefs-libs
rpm: fuse-devel
@@ -159,19 +168,23 @@ mappings:
glib2:
deb: libglib2.0-dev
+ deb-cross-arch: foreign
pkg: glib
rpm: glib2-devel
glibc:
deb: libc6-dev
+ deb-cross-arch: foreign
rpm: glibc-devel
glibc-static:
deb: libc6-dev
+ deb-cross-arch: foreign
rpm: glibc-static
glusterfs:
deb: libglusterfs-dev
+ deb-cross-arch: foreign
rpm: glusterfs-api-devel
Debian8: glusterfs-common
Debian9: glusterfs-common
@@ -183,6 +196,7 @@ mappings:
gnutls:
deb: libgnutls28-dev
+ deb-cross-arch: foreign
pkg: gnutls
rpm: gnutls-devel
@@ -192,11 +206,13 @@ mappings:
gobject-introspection:
deb: libgirepository1.0-dev
+ deb-cross-arch: foreign
pkg: gobject-introspection
rpm: gobject-introspection-devel
gtk3:
deb: libgtk-3-dev
+ deb-cross-arch: foreign
pkg: gtk3
rpm: gtk3-devel
@@ -211,6 +227,7 @@ mappings:
gtk-vnc2:
deb: libgtk-vnc-2.0-dev
+ deb-cross-arch: foreign
pkg: gtk-vnc
rpm: gtk-vnc2-devel
@@ -243,32 +260,39 @@ mappings:
json-glib:
deb: libjson-glib-dev
+ deb-cross-arch: foreign
pkg: json-glib
rpm: json-glib-devel
libacl:
deb: libacl1-dev
+ deb-cross-arch: foreign
rpm: libacl-devel
libarchive:
deb: libarchive-dev
+ deb-cross-arch: foreign
pkg: libarchive
rpm: libarchive-devel
libattr:
deb: libattr1-dev
+ deb-cross-arch: foreign
rpm: libattr-devel
libaudit:
deb: libaudit-dev
+ deb-cross-arch: foreign
rpm: audit-libs-devel
libblkid:
deb: libblkid-dev
+ deb-cross-arch: foreign
rpm: libblkid-devel
libcap-ng:
deb: libcap-ng-dev
+ deb-cross-arch: foreign
rpm: libcap-ng-devel
libcmpiutil:
@@ -276,67 +300,81 @@ mappings:
libconfig:
deb: libconfig-dev
+ deb-cross-arch: foreign
pkg: libconfig
rpm: libconfig-devel
libcurl:
deb: libcurl4-gnutls-dev
+ deb-cross-arch: foreign
pkg: curl
rpm: libcurl-devel
libdbus:
deb: libdbus-1-dev
+ deb-cross-arch: foreign
pkg: dbus
rpm: dbus-devel
libgovirt:
rpm: libgovirt-devel
Debian: libgovirt-dev
+ Debian-cross-arch: foreign
Debian8:
libiscsi:
deb: libiscsi-dev
+ deb-cross-arch: foreign
rpm: libiscsi-devel
libnl3:
deb: libnl-3-dev
+ deb-cross-arch: foreign
rpm: libnl3-devel
libnlroute3:
deb: libnl-route-3-dev
+ deb-cross-arch: foreign
rpm: libnl3-devel
libnuma:
deb: libnuma-dev
+ deb-cross-arch: foreign
deb-armv6l:
deb-armv7l:
rpm: numactl-devel
libparted:
deb: libparted-dev
+ deb-cross-arch: foreign
rpm: parted-devel
libpcap:
deb: libpcap0.8-dev
+ deb-cross-arch: foreign
pkg: libpcap
rpm: libpcap-devel
libpciaccess:
deb: libpciaccess-dev
+ deb-cross-arch: foreign
pkg: libpciaccess
rpm: libpciaccess-devel
librbd:
deb: librbd-dev
+ deb-cross-arch: foreign
Fedora: librbd-devel
CentOS7: librbd1-devel
libselinux:
deb: libselinux1-dev
+ deb-cross-arch: foreign
rpm: libselinux-devel
libsoup:
deb: libsoup2.4-dev
+ deb-cross-arch: foreign
pkg: libsoup
rpm: libsoup-devel
@@ -344,15 +382,18 @@ mappings:
pkg: libssh
rpm: libssh-devel
Debian: libssh-gcrypt-dev
+ Debian-cross-arch: foreign
Ubuntu: libssh-dev
libssh2:
deb: libssh2-1-dev
+ deb-cross-arch: foreign
pkg: libssh2
rpm: libssh2-devel
libtirpc:
deb: libtirpc-dev
+ deb-cross-arch: foreign
rpm: libtirpc-devel
libtool:
@@ -364,20 +405,24 @@ mappings:
libudev:
deb: libudev-dev
+ deb-cross-arch: foreign
rpm: libudev-devel
libuuid:
deb: uuid-dev
+ deb-cross-arch: foreign
pkg: e2fsprogs-libuuid
rpm: libuuid-devel
libxml2:
deb: libxml2-dev
+ deb-cross-arch: foreign
pkg: libxml2
rpm: libxml2-devel
libxslt:
deb: libxslt1-dev
+ deb-cross-arch: foreign
pkg: libxslt
rpm: libxslt-devel
@@ -554,6 +599,7 @@ mappings:
netcf:
deb: libnetcf-dev
+ deb-cross-arch: skip
rpm: netcf-devel
numad:
@@ -714,6 +760,7 @@ mappings:
python2-devel:
deb: python-dev
+ deb-cross-arch: foreign
pkg: python2
rpm: python2-devel
@@ -738,6 +785,7 @@ mappings:
python3-devel:
deb: python3-dev
+ deb-cross-arch: foreign
pkg: python3
Fedora: python3-devel
@@ -783,6 +831,7 @@ mappings:
readline:
deb: libreadline-dev
+ deb-cross-arch: foreign
pkg: readline
rpm: readline-devel
@@ -797,6 +846,7 @@ mappings:
sanlock:
deb: libsanlock-dev
+ deb-cross-arch: foreign
rpm: sanlock-devel
screen:
@@ -818,6 +868,7 @@ mappings:
spice-gtk3:
deb: libspice-client-gtk-3.0-dev
+ deb-cross-arch: foreign
pkg: spice-gtk
rpm: spice-gtk3-devel
@@ -849,10 +900,12 @@ mappings:
wireshark:
deb: wireshark-dev
+ deb-cross-arch: skip
Fedora: wireshark-devel
Debian8:
xen:
+ deb-cross-arch: foreign
deb-x86_64: libxen-dev
deb-armv7l: libxen-dev
deb-aarch64: libxen-dev
@@ -860,6 +913,7 @@ mappings:
xfsprogs:
deb: xfslibs-dev
+ deb-cross-arch: foreign
rpm: xfsprogs-devel
xmllint:
@@ -872,14 +926,17 @@ mappings:
xz:
deb: liblzma-dev
+ deb-cross-arch: foreign
rpm: xz-devel
xz-static:
deb: liblzma-dev
+ deb-cross-arch: foreign
Fedora: xz-static
yajl:
deb: libyajl-dev
+ deb-cross-arch: foreign
pkg: yajl
rpm: yajl-devel
@@ -890,8 +947,10 @@ mappings:
zlib:
deb: zlib1g-dev
+ deb-cross-arch: foreign
rpm: zlib-devel
zlib-static:
deb: zlib1g-dev
+ deb-cross-arch: foreign
rpm: zlib-static
--
2.20.1