Modernize C builds with offline dependencies and portable runtime helpers

This commit is contained in:
Max Lv
2026-09-11 00:00:40 +08:00
parent 8fe386b5c2
commit 4455d7f8f3
110 changed files with 4295 additions and 1480 deletions
+11 -41
View File
@@ -1,44 +1,14 @@
#!/usr/bin/env bash
set -e
archive() {
export TARBALL_NAME=$1
export TARBALL_OUTDIR=$2
# archive this repo
cd "$(git rev-parse --show-toplevel)"
git archive HEAD --format=tar --prefix="${TARBALL_NAME}/" \
-o "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar"
# archive submodules
git submodule update --init
git submodule foreach --quiet 'git archive HEAD --format=tar \
--prefix="${TARBALL_NAME}/${path}/" \
-o "${TARBALL_OUTDIR}/${TARBALL_NAME}-submodule-${path}-${sha1}.tar"
tar -n --concatenate --file="${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" \
"${TARBALL_OUTDIR}/${TARBALL_NAME}-submodule-${path}-${sha1}.tar"'
gzip -c "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar" > "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar.gz"
# clean-up
git submodule foreach --quiet 'rm ${TARBALL_OUTDIR}/${TARBALL_NAME}-submodule-${path}-${sha1}.tar'
rm "${TARBALL_OUTDIR}/${TARBALL_NAME}.tar"
}
TARGET_TARBALL_NAME=shadowsocks-libev
TARGET_TARBALL_DIR=$(git rev-parse --show-toplevel)
while getopts "n:o:" opt
do
case ${opt} in
o)
TARGET_TARBALL_DIR=$(readlink -f -- $OPTARG)
;;
n)
TARGET_TARBALL_NAME=$OPTARG
;;
\?)
exit 1
;;
# Backward-compatible maintainer entrypoint for the offline release archive.
set -euo pipefail
root=$(git rev-parse --show-toplevel)
name=shadowsocks-libev
directory=$root
while getopts "n:o:" opt; do
case "$opt" in
n) name=$OPTARG ;;
o) directory=$OPTARG ;;
*) exit 1 ;;
esac
done
archive "${TARGET_TARBALL_NAME}" "${TARGET_TARBALL_DIR}"
exec python3 "$root/scripts/source_archive.py" "$directory/$name.tar.gz" --prefix "$name"
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
"""Create an offline source archive from Git's tracked working-tree files.
Maintainer-only tool; building the resulting archive needs neither Git nor
Python (unless integration tests or generated documentation are requested).
"""
import argparse
import gzip
import io
import os
from pathlib import Path
import subprocess
import tarfile
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("output", type=Path)
parser.add_argument("--prefix", default="shadowsocks-libev-3.3.6")
args = parser.parse_args()
root = Path(__file__).resolve().parents[1]
if "/" in args.prefix or args.prefix in ("", ".", ".."):
parser.error("prefix must be a single directory name")
epoch = int(os.environ.get("SOURCE_DATE_EPOCH") or subprocess.check_output(
["git", "show", "-s", "--format=%ct", "HEAD"], cwd=root, text=True).strip())
entries = subprocess.check_output(["git", "ls-files", "--stage", "-z"], cwd=root).split(b"\0")
args.output.parent.mkdir(parents=True, exist_ok=True)
with args.output.open("wb") as raw, gzip.GzipFile(filename="", mode="wb", fileobj=raw, mtime=epoch) as compressed:
with tarfile.open(fileobj=compressed, mode="w|") as archive:
for entry in entries:
if not entry:
continue
metadata, encoded = entry.split(b"\t", 1)
mode, _, stage = metadata.split()
if stage != b"0" or mode == b"160000":
raise RuntimeError("Unmerged entry or submodule in source archive")
relative = os.fsdecode(encoded)
path = root / relative
info = tarfile.TarInfo(args.prefix + "/" + relative)
info.mtime = epoch
info.mode = int(mode, 8) & 0o777
if path.is_symlink():
info.type = tarfile.SYMTYPE
info.linkname = os.readlink(path)
archive.addfile(info)
else:
content = path.read_bytes()
info.size = len(content)
archive.addfile(info, io.BytesIO(content))
print(args.output)
if __name__ == "__main__":
main()