From a44a91ddb64230c99971ef8852e566f8e9bf3ae4 Mon Sep 17 00:00:00 2001 From: Jakub Panek Date: Mon, 5 Feb 2024 23:27:53 +0000 Subject: [PATCH] wip: add support for xx-dnf --- docker-bake.hcl | 10 +- src/Dockerfile | 4 + src/test-dnf.bats | 230 +++++++++++++++++++++++++++++++++++++++++++ src/test_helper.bash | 8 ++ src/xx-cargo | 3 + src/xx-cc | 29 +++++- src/xx-dnf | 177 +++++++++++++++++++++++++++++++++ src/xx-verify | 2 + 8 files changed, 460 insertions(+), 3 deletions(-) create mode 100755 src/test-dnf.bats create mode 100755 src/xx-dnf diff --git a/docker-bake.hcl b/docker-bake.hcl index 0452513..58059f9 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -7,7 +7,7 @@ variable "TEST_BASE_TYPE" { } variable "TEST_BASE_IMAGE" { - default = TEST_BASE_TYPE == "alpine" ? "alpine:3.19" : TEST_BASE_TYPE == "debian" ? "debian:bookworm" : null + default = TEST_BASE_TYPE == "alpine" ? "alpine:3.19" : TEST_BASE_TYPE == "debian" ? "debian:bookworm" : TEST_BASE_TYPE == "rhel" ? "fedora:39" : null } variable "DEV_SDK_PLATFORM" { @@ -55,6 +55,7 @@ group "test" { "test-info", "test-apk", "test-apt", + "test-dnf", "test-verify", "test-clang", "test-go", @@ -77,6 +78,11 @@ target "test-apt" { target = "test-apt" } +target "test-dnf" { + inherits = ["test-base"] + target = "test-dnf" +} + target "test-verify" { inherits = ["test-base"] target = "test-verify" @@ -356,4 +362,4 @@ target "sigtool" { "linux/arm64", "linux/arm/v7", ] -} \ No newline at end of file +} diff --git a/src/Dockerfile b/src/Dockerfile index abf8c96..41a2a80 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -76,6 +76,10 @@ FROM test-base AS test-apk COPY test-apk.bats . RUN --mount=type=cache,target=/pkg-cache,sharing=locked [ ! -f /etc/alpine-release ] || ./test-apk.bats +FROM test-base AS test-dnf +COPY test-dnf.bats . +RUN --mount=type=cache,target=/pkg-cache,sharing=locked [ ! -f /etc/fedora-release ] || ./test-dnf.bats + FROM test-base AS test-verify COPY test-verify.bats . RUN --mount=type=cache,target=/pkg-cache,sharing=locked ./test-verify.bats diff --git a/src/test-dnf.bats b/src/test-dnf.bats new file mode 100755 index 0000000..c02e8d6 --- /dev/null +++ b/src/test-dnf.bats @@ -0,0 +1,230 @@ +#!/usr/bin/env bats + +load 'assert' + +@test "no_cmd" { + run xx-dnf + assert_failure + assert_output --partial "usage: dnf [options] COMMAND" +} + +@test "native" { + run xx-dnf info file + assert_success + assert_line "Name : file" + + run xx-dnf info glibc-devel + assert_success + assert_line "Name : glibc-devel" + + run xx-dnf info gcc + assert_success + assert_line "Name : gcc" +} + +@test "essentials" { + run xx-dnf info xx-c-essentials + assert_success + + run xx-dnf info xx-cxx-essentials + assert_success +} + +@test "amd64" { + export TARGETARCH=amd64 + if ! xx-info is-cross; then skip; fi + + run xx-dnf info file + assert_success + assert_line "Architecture : x86_64" + + run xx-dnf info glibc-devel + assert_success + assert_line "Architecture : x86_64" + + export XX_dnf_PREFER_CROSS=1 + run xx-dnf info glibc-devel + assert_success + assert_line "Package: glibc-devel-amd64-cross" + unset XX_dnf_PREFER_CROSS + + run xx-dnf info gcc + assert_success + assert_line "Architecture : x86_64" +} + +@test "arm64" { + export TARGETARCH=arm64 + if ! xx-info is-cross; then return; fi + + run xx-dnf info file + assert_success + assert_line "Architecture : aarch64" + + run xx-dnf info glibc-devel + assert_success + assert_line "Architecture : aarch64" + + export XX_dnf_PREFER_CROSS=1 + run xx-dnf info glibc-devel + assert_success + assert_line "Name: glibc-devel-arm64-cross" + unset XX_dnf_PREFER_CROSS + + run xx-dnf info gcc + assert_success + assert_line "Architecture : aarch64" +} + +@test "arm" { + export TARGETARCH=arm + if ! xx-info is-cross; then return; fi + + run xx-dnf info file + assert_success + assert_line "Package: file:armhf" + + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev:armhf" + + export XX_dnf_PREFER_CROSS=1 + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev-armhf-cross" + unset XX_dnf_PREFER_CROSS + + run xx-dnf info gcc + assert_success + assert_line "Package: gcc-arm-linux-gnueabihf" +} + +@test "armv6" { + export TARGETARCH=arm + export TARGETVARIANT=v6 + if ! xx-info is-cross; then return; fi + if [ "$(xx-info vendor)" = "ubuntu" ]; then skip; fi + + run xx-dnf info file + assert_success + assert_line "Package: file:armel" + + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev:armel" + + export XX_dnf_PREFER_CROSS=1 + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev-armel-cross" + unset XX_dnf_PREFER_CROSS + + run xx-dnf info gcc + assert_success + assert_line "Package: gcc-arm-linux-gnueabi" + unset TARGETVARIANT +} + +@test "s390x" { + export TARGETARCH=s390x + if ! xx-info is-cross; then return; fi + + run xx-dnf info file + assert_success + assert_line "Package: file:s390x" + + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev:s390x" + + export XX_dnf_PREFER_CROSS=1 + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev-s390x-cross" + unset XX_dnf_PREFER_CROSS + + # buster has no gcc package for arm64 + if [ "$(uname -m)" == "aarch64" ] && [ "$(cat /etc/debian_version | cut -d. -f 1)" = "10" ]; then + return + fi + + run xx-dnf info gcc + assert_success + assert_line "Package: gcc-s390x-linux-gnu" +} + +@test "ppc64le" { + export TARGETARCH=ppc64le + if ! xx-info is-cross; then return; fi + + run xx-dnf info file + assert_success + assert_line "Package: file:ppc64el" + + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev:ppc64el" + + export XX_dnf_PREFER_CROSS=1 + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev-ppc64el-cross" + unset XX_dnf_PREFER_CROSS + + # buster has no gcc package for arm64 + if [ "$(uname -m)" == "aarch64" ] && [ "$(cat /etc/debian_version | cut -d. -f 1)" = "10" ]; then + return + fi + + run xx-dnf info gcc + assert_success + assert_line "Package: gcc-powerpc64le-linux-gnu" +} + +@test "386" { + export TARGETARCH=386 + if ! xx-info is-cross; then return; fi + + run xx-dnf info file + assert_success + assert_line "Package: file:i386" + + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev:i386" + + export XX_dnf_PREFER_CROSS=1 + run xx-dnf info libc6-dev + assert_success + assert_line "Package: libc6-dev-i386-cross" + unset XX_dnf_PREFER_CROSS + + run xx-dnf info gcc + assert_success + assert_line "Package: gcc-i686-linux-gnu" +} + +@test "skip-nolinux" { + export TARGETOS="darwin" + export TARGETARCH="amd64" + run xx-dnf install foo + assert_success + unset TARGETOS + unset TARGETARCH +} + +@test "checkpkg" { + run dnf show wget + assert_success + run dnf show wget-notexist + assert_failure +} + +@test "print-source-file" { + run xx-dnf --print-source-file + assert_success + assert_output --partial "/etc/dnf/sources.list" + + run test -e "$(xx-dnf --print-source-file)" + assert_success +} diff --git a/src/test_helper.bash b/src/test_helper.bash index 21c18f9..893bb20 100644 --- a/src/test_helper.bash +++ b/src/test_helper.bash @@ -3,6 +3,8 @@ add() { if [ -f /etc/alpine-release ]; then apk add "$@" + elif [ -f /etc/fedora-release ]; then + xxrun dnf install "$@" else xxrun apt install -y --no-install-recommends "$@" fi @@ -11,6 +13,8 @@ add() { del() { if [ -f /etc/alpine-release ]; then apk del "$@" 2>/dev/null || true + elif [ -f /etc/fedora-release ]; then + xxrun dnf remove "$@" else xxrun apt remove --autoremove -y "$@" 2>/dev/null || true fi @@ -19,6 +23,8 @@ del() { xxadd() { if [ -f /etc/alpine-release ]; then xx-apk add "$@" + elif [ -f /etc/fedora-release ]; then + xxrun xx-dnf install "$@" else xxrun xx-apt install -y --no-install-recommends "$@" fi @@ -27,6 +33,8 @@ xxadd() { xxdel() { if [ -f /etc/alpine-release ]; then xx-apk del "$@" 2>/dev/null || true + elif [ -f /etc/fedora-release ]; then + xxrun xx-dnf remove "$@" else xxrun xx-apt remove -y --autoremove "$@" 2>/dev/null || true fi diff --git a/src/xx-cargo b/src/xx-cargo index 1af1b1b..470db77 100755 --- a/src/xx-cargo +++ b/src/xx-cargo @@ -65,6 +65,9 @@ if [ ! -f "$done_file" ]; then elif [ -f /etc/alpine-release ]; then # XX_VENDOR overrided to match the distrib one to install packages XX_VENDOR=$vendor execSilent xx-apk add rust-stdlib + elif [ -f /etc/fedora-release ]; then + # XX_VENDOR overrided to match the distrib one to install packages + XX_VENDOR=$vendor execSilent xx-dnf install --assumeyes rust-std-static else # XX_VENDOR overrided to match the distrib one to install packages XX_VENDOR=$vendor execSilent xx-apt-get install -y libstd-rust-dev diff --git a/src/xx-cc b/src/xx-cc index d80db3c..71d5b9e 100755 --- a/src/xx-cc +++ b/src/xx-cc @@ -37,6 +37,9 @@ installwget() { if command -v apk >/dev/null 2>/dev/null; then apk add wget >/dev/null 2>/dev/null fi + if command -v dnf >/dev/null 2>/dev/null; then + dnf install wget >/dev/null 2>/dev/null + fi } writexcrun() { @@ -464,7 +467,20 @@ export PKG_CONFIG_LIBDIR=/${target}/usr/lib/pkgconfig/ exec pkg-config "\$@" EOT chmod +x "/usr/bin/${target}-pkg-config" + elif [ -f /etc/fedora-release ]; then + config="${config} --sysroot=/${target}/" + if [ -n "$is_bfd" ]; then + config="${config} -Wl,-rpath-link,/${target}/usr/lib" + fi + + cat <"/usr/bin/${target}-pkg-config" +#!/usr/bin/env sh +export PKG_CONFIG_SYSROOT_DIR=/${target} +export PKG_CONFIG_LIBDIR=/${target}/usr/lib/pkgconfig/ +exec pkg-config "\$@" +EOT + chmod +x "/usr/bin/${target}-pkg-config" fi elif [ ! -f "/usr/bin/${target}-pkg-config" ] && [ ! -h "/usr/bin/${target}-pkg-config" ]; then ln -s pkg-config "/usr/bin/${target}-pkg-config" @@ -530,6 +546,17 @@ EOT fi fi + if [ -f /etc/fedora-release ]; then + # if vendor is not fedora then sysroot needs to be linked to the custom vendor + fedoratriple=$(echo "$target" | sed s/-[[:alpha:]][[:alpha:]]*-/-fedora-/ | sed s/^riscv64gc-/riscv64-/) + if [ "$target" != "$fedoratriple" ]; then + # shellcheck disable=SC2044 + for f in $(find / -type d -name "$fedoratriple"); do + ln -s "$fedoratriple" "$(dirname "$f")/$target" + done + fi + fi + if [ "${targetos}" = "darwin" ]; then if ! command -v xcrun 2>/dev/null >/dev/null; then writexcrun @@ -637,7 +664,7 @@ if [ -n "${printSysroot}" ]; then setup if xx-info is-cross; then - if [ -f "/etc/alpine-release" ]; then + if [ -f "/etc/alpine-release" ] || [ -f "/etc/fedora-release" ]; then echo "/${target}/" exit 0 fi diff --git a/src/xx-dnf b/src/xx-dnf new file mode 100755 index 0000000..2834f99 --- /dev/null +++ b/src/xx-dnf @@ -0,0 +1,177 @@ +#!/usr/bin/env sh + +set -e + +if [ -z "$XX_DNF_NOLOCK" ]; then + lock="/var/lock/xx-dnf" + exec 9>$lock + flock -x 9 + export XX_DNF_NOLOCK=1 +fi + +if [ -n "$XX_DEBUG_DNF" ]; then + set -x +fi + +unset XX_VENDOR # vendor for installing packages is always fedora + +for l in $(xx-info env); do + export "${l?}" +done + +if [ "${TARGETOS}" != "linux" ]; then + echo >&2 "skipping packages installation on ${XX_OS}" + exit 0 +fi + +arg0="$(basename "$0")" +if [ "$arg0" = "xx-dnf" ]; then + arg0="dnf" +else + arg0="yum" +fi + +suffix=$XX_TRIPLE +if [ "$suffix" = "x86_64-linux-gnu" ]; then + suffix="x86-64-linux-gnu" +fi +if [ "$XX_OS" = "windows" ]; then + case "$XX_ARCH" in + amd64) suffix="mingw-w64-x86-64" ;; + 386) suffix="mingw-w64-i686" ;; + arm64) suffix="mingw-w64-aarch64" ;; + arm) suffix="mingw-w64-arm" ;; + esac +fi + +packages2= +for p in ${packages}; do + if [ "${p}" = "xx-c-essentials" ]; then + p="glibc-devel" + p="$p libgcc" + elif [ "${p}" = "xx-cxx-essentials" ]; then + p="libstdc++-devel" + fi + if [ -z "$packages2" ]; then + packages2="$p" + else + packages2="${packages2} $p" + fi +done + +empty=1 +for p in ${packages2}; do + n= + if [ -n "$nocross" ]; then + n=${p} + elif checkpkg "${p}-${suffix}" >/dev/null 2>/dev/null; then + n="${p}-${suffix}" + elif [ "${XX_OS}" = "linux" ] && [ -n "${XX_DNF_PREFER_CROSS}" ] && checkpkg "${p}.${XX_PKG_ARCH}-cross" >/dev/null 2>/dev/null; then + n="${p}-${XX_PKG_ARCH}-cross" + elif [ "${XX_OS}" = "linux" ]; then + n="${p}.${XX_PKG_ARCH}" + else + continue + fi + empty= + set -- "$@" "$n" +done + +setup() { + if ! xx-info is-cross; then + return + fi + done_file="/${XX_TRIPLE}/.xx-setup" + if [ -f "$done_file" ]; then + return + fi + yum_dir="/${XX_TRIPLE}/etc/yum.repos.d" + mkdir -p "$yum_dir" + + cp -r /etc/yum.repos.d/* "$yum_dir/" + + . /etc/os-release + dnf install --assumeyes --forcearch "$(xx-info rhel-arch)" --installroot "/${XX_TRIPLE}" --releasever "${VERSION_ID}" fedora-repos + + touch "$done_file" +} + +clean() { + if ! xx-info is-cross; then + return + fi + # safety first + if [ -z "${XX_TRIPLE}" ]; then + echo >&2 "invalid triple root $XX_TRIPLE" + exit 1 + fi + rm -rf "/${XX_TRIPLE:?}" +} + +cmd() { + setup + root="/" + if xx-info is-cross; then + root="/${XX_TRIPLE}" + fi + n=$# + iscompilerrt= + isrustlib= + for a in "$@"; do + if [ $# = $n ]; then set --; fi + case "$a" in + "xx-c-essentials") + set -- "$@" glibc-devel gcc + ;; + "xx-cxx-essentials") + set -- "$@" g++ + ;; + "compiler-rt" | "compiler-rt-static") + iscompilerrt="$a" + set -- "$@" "$a" + ;; + "rust-stdlib") + set -- "$@" rust-std-static + isrustlib=1 + ;; + *) + set -- "$@" "$a" + ;; + esac + done + if [ "$#" != "0" ]; then + set -- "--installroot" "$root" "--forcearch" "$(xx-info rhel-arch)" "$@" + echo "+ dnf " "$@" + fi + dnf "$@" + if xx-info is-cross; then + if [ -z "$XX_DNF_KEEP_BINARIES" ]; then + rm -rf "/${XX_TRIPLE:?}/usr/bin/*" + fi + if [ -n "$iscompilerrt" ]; then + for f in $(dnf --installroot "$root" info -qL "$iscompilerrt" | grep 'clang_rt.'); do + ff="/${f}" + if [ ! -f "${ff}" ]; then + mkdir -p "$(dirname "${ff}")" + ln -s "/$(xx-info)/${f}" "${ff}" + fi + done + fi + # rust stdlib is accessed from the real root + if [ -n "$isrustlib" ] && [ -d "$root/usr/lib/rustlib/$(xx-info)" ]; then + ln -s "$root/usr/lib/rustlib/$(xx-info)" "/usr/lib/rustlib/$(xx-info)" || true + fi + fi +} + +case "$1" in + "setup") + setup + ;; + "clean") + clean + ;; + *) + cmd "$@" + ;; +esac diff --git a/src/xx-verify b/src/xx-verify index 4951aa4..22af20d 100755 --- a/src/xx-verify +++ b/src/xx-verify @@ -23,6 +23,8 @@ setup() { apk add --no-cache file >"$1" elif command -v apt >/dev/null; then apt update && apt install -y file + elif command -v dnf >/dev/null; then + dnf install file else echo >&2 "file not installed and no package manager not found" exit 1