I have a simple cli written in Swift that I want to run on Alpine. I want the binary to be self-contained. How can I do that? I have tried:
swift run and swift build with --static-swift-stdlib (but that has no musl support?)docker run -v "$PWD:/sources" -w /sources --platform linux/amd64 swift:latest swiftc -emit-executable -static-executable -O main.swift testit, but then the executable testit when running it on Alpine, says it is Unable to obtain Swift runtime path Aborted.The code of the program:
// The Swift Programming Language
// https://docs.swift.org/swift-book
func getSecret() -> String {
let CharArr: [Character] = ["T", "h", "i", "s", " ", "a", " ", "s", "e", "c", "r", "e", "t"]
let newStr = String(CharArr)
return newStr
}
if(CommandLine.arguments.count == 2){
if (CommandLine.arguments[1] == "spoil"){
print(getSecret())
} else {
if (CommandLine.arguments[1] == getSecret()){
print("This is correct! Congrats!");
}else{
print("This is incorrect. Try again");
}
}
} else if (CommandLine.arguments.count==1) {
print("Welcome to the wrongsecrets Swift binary which hides a secret.");
print("Use args spoil or a string to guess the password.");
} else {
print("Too many arguments supplied.");
}
Can you help me please?
Update (2024-06): Swift 6 will support static Linux builds (which use musl). Instructions on (cross-compiling) static Linux binaries can be found on the Swift page (although the instructions use incorrect flags at the time of writing, but I reckon this will be fixed by the final release of Swift 6)
As you figured out in the meantime, Swift doesn't run on musl-based systems, and can't generate musl binaries.
While waiting for Alpine Linux support in Swift, the following 2 alternatives work for me:
Install a glibc-based distribution in a chroot, and set up the loader using symlinks, as described on the Alpine wiki article on running Glibc programs. When this is done, binaries that have been built with Swift (using --static-swift-stdlib) on a glibc system run on Alpine.
Use --static-swift-stdlib -Xlinker --dynamic-linker=/usr/lib/my-package/ld-linux-x86-64.so.2 -Xlinker -rpath='$ORIGIN'/../lib/my-package
to let the resulting binary use its own private version of the ld linker, and bundle the linker and all the dynamic library dependencies in /usr/lib/my-package/. This allows you to create a distributable package that works on Alpine, without relying on anything special in the Alpine installation (since the binary uses its own private linker and version of its libraries). I use a script that does all this, which in turn is used in an Alpine package script to create the final packages.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With