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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list