Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Swift binary dynamically linked #425

Open
strophy opened this issue Jan 17, 2025 · 0 comments
Open

Make Swift binary dynamically linked #425

strophy opened this issue Jan 17, 2025 · 0 comments

Comments

@strophy
Copy link
Collaborator

strophy commented Jan 17, 2025

We currently build two large statically linked Swift binaries, which is not very space efficient.

Instead, we should build dynamically linked binaries so libraries and the Swift runtime can be shared between them.

https://forums.swift.org/t/cross-architecture-compilation-on-linux/66172/15

Potential Dockerfile for this:

FROM --platform=$BUILDPLATFORM swift:${SWIFT_IMAGE_VERSION}-noble AS grpc_swift_builder
ARG GRPC_SWIFT_VERSION SWIFT_IMAGE_VERSION
RUN apt-get update && \
    apt-get install -y \
        build-essential \
        curl \
        file 
RUN mkdir -p /root/aarch64-swift /protoc-gen-swift /grpc-swift
COPY ubuntu-24.04-aarch64.json /root/ubuntu-24.04-aarch64.json
RUN curl -sSL https://api.github.com/repos/grpc/grpc-swift/tarball/${GRPC_SWIFT_VERSION} | tar xz --strip 1 -C /grpc-swift
WORKDIR /grpc-swift
ARG TARGETOS TARGETARCH
RUN <<EOF
    if [ "${TARGETARCH}" = "arm64" ]; then
        mkdir -p /root/aarch64
        curl -sSL https://download.swift.org/swift-6.0.3-release/ubuntu2404-aarch64/swift-6.0.3-RELEASE/swift-6.0.3-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
        SWIFTBUILD="swift build --destination /root/ubuntu-24.04-aarch64.json"
    else
        SWIFTBUILD="swift build"
    fi
    $SWIFTBUILD -c release --product protoc-gen-swift
    $SWIFTBUILD -c release --product protoc-gen-grpc-swift
EOF
RUN install -D /grpc-swift/.build/release/protoc-gen-swift /protoc-gen-swift/protoc-gen-swift
RUN install -D /grpc-swift/.build/release/protoc-gen-grpc-swift /protoc-gen-swift/protoc-gen-grpc-swift
RUN file /protoc-gen-swift/protoc-gen-swift
RUN file /protoc-gen-swift/protoc-gen-grpc-swift


FROM swift:${SWIFT_IMAGE_VERSION}-noble AS grpc_swift
ARG TARGETOS TARGETARCH
COPY --from=grpc_swift_builder /protoc-gen-swift/ /protoc-gen-swift/
RUN apt-get update && \
    apt-get install -y \
        patchelf
# Under x86_64 the following files are copied into /protoc-gen-swift, but not on aarch64. Find out why.
# /lib/x86_64-linux-gnu/libgcc_s.so.1
# /lib/x86_64-linux-gnu/libstdc++.so.6
# /lib64/ld-linux-x86-64.so.2
# /protoc-gen-swift/libc.so.6
# /protoc-gen-swift/libm.so.6
# /usr/lib/swift/linux/libBlocksRuntime.so
# /usr/lib/swift/linux/libFoundation.so
# /usr/lib/swift/linux/libFoundationEssentials.so
# /usr/lib/swift/linux/libFoundationInternationalization.so
# /usr/lib/swift/linux/lib_FoundationICU.so
# /usr/lib/swift/linux/libdispatch.so
# /usr/lib/swift/linux/libswiftCore.so
# /usr/lib/swift/linux/libswiftDispatch.so
# /usr/lib/swift/linux/libswiftGlibc.so
# /usr/lib/swift/linux/libswiftSynchronization.so
# /usr/lib/swift/linux/libswift_Concurrency.so
# /usr/lib/swift/linux/libswift_RegexParser.so
# /usr/lib/swift/linux/libswift_StringProcessing.so
RUN <<EOF
    case ${TARGETARCH} in
      "amd64")  SWIFT_LIB_DIR=/lib64 && SWIFT_LINKER=ld-${TARGETOS}-x86-64.so.2  ;;
      "arm64")  SWIFT_LIB_DIR=/lib   && SWIFT_LINKER=ld-${TARGETOS}-aarch64.so.1 ;;
      *)        echo "ERROR: Machine arch ${TARGETARCH} not supported." ;;
    esac
    cp ${SWIFT_LIB_DIR}/${SWIFT_LINKER} \
      $(ldd /protoc-gen-swift/protoc-gen-swift /protoc-gen-swift/protoc-gen-grpc-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 protoc-gen-grpc-swift; do
      patchelf --set-interpreter /protoc-gen-swift/${SWIFT_LINKER} /protoc-gen-swift/${p}
    done
EOF

ubuntu-24.04-aarch64.json:

{
  "version": 1,
  "target": "aarch64-unknown-linux-gnu",
  "toolchain-bin-dir": "/usr/bin",
  "sdk": "/usr/aarch64-linux-gnu",
  "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"
  ]
}

The issue here is that the Swift runtime isn't present for patchelf in the final step.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant