Hi @Finagolfin I'm having another try at cross-compiling a dynamically linked binary for grpc-swift under Ubuntu Linux 24.04, and then running patchelf
to patch the binaries to run under Alpine Linux. My JSON file currently looks like this:
{ "version": 1, "target": "aarch64-unknown-linux-gnu", "toolchain-bin-dir": "/usr/aarch64-linux-gnu/bin", "sdk": "/root/aarch64/usr/lib/swift", "extra-cc-flags": [ "-fPIC" ], "extra-cpp-flags": [ "-lstdc++", "-I", "/usr/aarch64-linux-gnu/include/c++/13", "-I", "/usr/aarch64-linux-gnu/include/c++/13/aarch64-linux-gnu/" ], "extra-swiftc-flags": [ "-resource-dir", "/root/aarch64/usr/lib/swift" ] }
Build succeeds with no errors. When I try to run the resulting binary, I get this error:
protoc-gen-swift: error while loading shared libraries: libswiftCore.so: cannot open shared object file: No such file or directory
If I add a step to my build Dockerfile to run ldd
on the binary to see what patchelf is trying to patch in, I get the following result showing libswiftCore.so is indeed not found:
#23 [grpc_swift 5/5] RUN ldd /protoc-gen-swift/protoc-gen-swift #23 0.389 linux-vdso.so.1 (0x00007f2d30710000) #23 0.390 libswiftCore.so => not found #23 0.390 libswift_Concurrency.so => not found #23 0.390 libswift_StringProcessing.so => not found #23 0.390 libswift_RegexParser.so => not found #23 0.390 libswiftGlibc.so => not found #23 0.390 libBlocksRuntime.so => not found #23 0.390 libdispatch.so => not found #23 0.390 libswiftDispatch.so => not found #23 0.390 libFoundation.so => not found #23 0.390 libFoundationEssentials.so => not found #23 0.390 libFoundationInternationalization.so => not found #23 0.390 libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x00007f2d27af0000) #23 0.390 libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x00007f2d27930000) #23 0.390 /lib/ld-linux-aarch64.so.1 (0x00007f2d306b0000) #23 DONE 0.5s
Why doesn't the compiler error instead of building a binary that links to non-existent files? Stepping inside the build container, I have unpacked the swift-6.1-RELEASE-ubuntu24.04-aarch64.tar.gz
to /root/aarch64
. I can see all of the "not found" .so files located in /root/aarch64/usr/lib/swift/linux
. No matter how I mess around with the toolchain-bin-dir
, sdk
and resource-dir
variables, I cannot build a binary that correctly links to these files. In particular, I have tried setting /
, /root/aarch64
and every intermediate directory up to /root/aarch64/usr/lib/swift/linux
.
Ubuntu installs the aarch64 toolchain under /usr/aarch64-linux-gnu
, and I believe I'm pointing to it correctly. Any idea what I might be doing wrong? My full Dockerfile is below.
FROM --platform=$BUILDPLATFORM swift:${SWIFT_IMAGE_VERSION}-noble AS grpc_swift_builder ARG PROTOC_GEN_SWIFT_VERSION ARG SWIFT_IMAGE_VERSION ARG SWIFT_SDK_CHECKSUM RUN apt-get update && \ apt-get install -y build-essential curl file RUN mkdir -p /grpc-swift RUN curl -sSL https://api.github.com/repos/grpc/grpc-swift/tarball/${PROTOC_GEN_SWIFT_VERSION} | tar xz --strip 1 -C /grpc-swift WORKDIR /grpc-swift ARG TARGETOS TARGETARCH RUN <<EOF if [ "${TARGETARCH}" = "arm64" ]; then SWIFT_VERSION=$(echo ${SWIFT_IMAGE_VERSION} | sed -E 's/([0-9]+\.[0-9]+)\.0/\1/') mkdir -p /root/aarch64 curl -sSL https://download.swift.org/swift-$SWIFT_VERSION-release/ubuntu2404-aarch64/swift-$SWIFT_VERSION-RELEASE/swift-$SWIFT_VERSION-RELEASE-ubuntu24.04-aarch64.tar.gz | tar xz --strip 1 -C /root/aarch64 apt-get install -y \ gcc-aarch64-linux-gnu \ g++-aarch64-linux-gnu ln -sf /usr/bin/aarch64-linux-gnu-ld.gold /usr/bin/ld.gold fi EOF COPY ubuntu-24.04-aarch64.json /root/ubuntu-24.04-aarch64.json RUN <<EOF if [ "${TARGETARCH}" = "arm64" ]; then SWIFTBUILD="swift build --destination /root/ubuntu-24.04-aarch64.json" else SWIFTBUILD="swift build" fi $SWIFTBUILD -c release --product protoc-gen-swift EOF RUN mkdir -p /protoc-gen-swift RUN install -D /grpc-swift/.build/release/protoc-gen-swift /protoc-gen-swift/protoc-gen-swift FROM swift:${SWIFT_IMAGE_VERSION}-noble AS grpc_swift ARG TARGETARCH RUN apt-get update && \ apt-get install -y patchelf file COPY --from=grpc_swift_builder /protoc-gen-swift/ /protoc-gen-swift/ # Debug to check if linking worked before we try to run patchelf RUN ldd /protoc-gen-swift/protoc-gen-swift RUN <<EOF case ${TARGETARCH} in "amd64") SWIFT_LIB_DIR=/lib64 && SWIFT_LINKER=ld-linux-x86-64.so.2 ;; "arm64") SWIFT_LIB_DIR=/lib && SWIFT_LINKER=ld-linux-aarch64.so.1 ;; *) echo "ERROR: Machine arch ${TARGETARCH} not supported." ;; esac cp ${SWIFT_LIB_DIR}/${SWIFT_LINKER} \ $(ldd /protoc-gen-swift/protoc-gen-swift | awk '{print $3}' | grep /lib | sort | uniq) /protoc-gen-swift/ find /protoc-gen-swift/ -name 'lib*.so*' -exec patchelf --set-rpath /protoc-gen-swift {} \; for p in protoc-gen-swift; do patchelf --set-interpreter /protoc-gen-swift/${SWIFT_LINKER} /protoc-gen-swift/${p} done EOF