Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 10 additions & 85 deletions .github/workflows/regenerate-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ jobs:
detect:
runs-on: ubuntu-latest
outputs:
llvm-version: ${{ steps.detect.outputs.llvm-version }}
libllvm: ${{ steps.detect.outputs.libllvm }}
libllvmsharp: ${{ steps.detect.outputs.libllvmsharp }}
steps:
Expand All @@ -54,96 +53,22 @@ jobs:
shell: bash
run: |
set -euo pipefail

parse_version() { sed -n 's/^project(LLVMSharp VERSION \([0-9.]*\)).*/\1/p' "$1"; }

# The top-level CMakeLists.txt is the source of truth for the tracked LLVM version.
version="$(parse_version CMakeLists.txt)"
if [ -z "${version}" ]; then echo "could not parse LLVM version from CMakeLists.txt" >&2; exit 1; fi
echo "llvm-version=${version}" >> "$GITHUB_OUTPUT"

libllvm=false
libllvmsharp=false

if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
if [ "${{ inputs.libllvm }}" = "true" ]; then libllvm=true; fi
if [ "${{ inputs.libllvmsharp }}" = "true" ]; then libllvmsharp=true; fi
# Manual runs pick the families explicitly.
echo "libllvm=${{ inputs.libllvm }}" >> "$GITHUB_OUTPUT"
echo "libllvmsharp=${{ inputs.libllvmsharp }}" >> "$GITHUB_OUTPUT"
else
before="${{ github.event.before }}"
if [ -z "${before}" ] || [ "${before}" = "0000000000000000000000000000000000000000" ] || ! git cat-file -e "${before}^{commit}" 2>/dev/null; then
# No usable baseline to diff against (new/recreated branch, force-push,
# unfetched history); regenerate everything conservatively.
libllvm=true
libllvmsharp=true
else
# libLLVM regenerates when the tracked LLVM version changes. The libLLVM package
# version tracks the full patch (e.g. 21.1.8), so compare the full version.
prev_version="$(git show "${before}:CMakeLists.txt" 2>/dev/null | sed -n 's/^project(LLVMSharp VERSION \([0-9.]*\)).*/\1/p')"
if [ "${version}" != "${prev_version}" ]; then
libllvm=true
fi

# libLLVMSharp regenerates for the same reason or when its sources change.
if [ "${libllvm}" = "true" ] || ! git diff --quiet "${before}" HEAD -- sources/libLLVMSharp/; then
libllvmsharp=true
fi
fi
# Pushes diff against the prior commit; the script owns the change-detection
# logic so it stays reproducible and testable locally.
./scripts/build.sh --detectchanges --base "${{ github.event.before }}" | tee -a "$GITHUB_OUTPUT"
fi

echo "libllvm=${libllvm}" >> "$GITHUB_OUTPUT"
echo "libllvmsharp=${libllvmsharp}" >> "$GITHUB_OUTPUT"
echo "Resolved: llvm=${version} (major.minor=${major_minor}) libllvm=${libllvm} libllvmsharp=${libllvmsharp}"
- name: Verify package versions match the tracked LLVM version
# Guards against bumping CMakeLists.txt without updating the nuspec/runtime.json
# versions. libLLVM versions must equal the LLVM version exactly; libLLVMSharp
# versions must be that version plus an independent build revision (e.g. 21.1.8.1).
# versions before regenerating. The check lives in the build script so it is
# reproducible locally (./scripts/build.sh --verifypackages).
if: steps.detect.outputs.libllvm == 'true' || steps.detect.outputs.libllvmsharp == 'true'
shell: bash
run: |
set -euo pipefail
version="${{ steps.detect.outputs.llvm-version }}"
rc=0

nuspec_version() { sed -n 's:.*<version>\([^<]*\)</version>.*:\1:p' "$1" | head -n1; }
nuspec_branch() { sed -n 's:.*<repository[^>]*branch="\([^"]*\)".*:\1:p' "$1" | head -n1; }
json_versions() { grep -oE '"[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?"' "$1" | tr -d '"'; }

fail() { echo "::error file=$1::$2"; rc=1; }

if [ "${{ steps.detect.outputs.libllvm }}" = "true" ]; then
for f in packages/libLLVM/libLLVM/libLLVM.nuspec packages/libLLVM/libLLVM.runtime.*/*.nuspec; do
v="$(nuspec_version "$f")"
[ "${v}" = "${version}" ] || fail "$f" "version '${v}' does not match LLVM version '${version}'"
b="$(nuspec_branch "$f")"
if [ -n "${b}" ] && [ "${b}" != "llvmorg-${version}" ]; then
fail "$f" "repository branch '${b}' does not match 'llvmorg-${version}'"
fi
done
for v in $(json_versions packages/libLLVM/libLLVM/runtime.json); do
[ "${v}" = "${version}" ] || fail "packages/libLLVM/libLLVM/runtime.json" "mapped version '${v}' does not match LLVM version '${version}'"
done
fi

if [ "${{ steps.detect.outputs.libllvmsharp }}" = "true" ]; then
for f in packages/libLLVMSharp/libLLVMSharp/libLLVMSharp.nuspec packages/libLLVMSharp/libLLVMSharp.runtime.*/*.nuspec; do
v="$(nuspec_version "$f")"
case "${v}" in
"${version}".*) : ;;
*) fail "$f" "version '${v}' is not 'llvm-version.<revision>' (expected '${version}.<n>')" ;;
esac
done
for v in $(json_versions packages/libLLVMSharp/libLLVMSharp/runtime.json); do
case "${v}" in
"${version}".*) : ;;
*) fail "packages/libLLVMSharp/libLLVMSharp/runtime.json" "mapped version '${v}' is not '${version}.<revision>'" ;;
esac
done
fi

if [ "${rc}" -ne 0 ]; then
echo "Update the package versions to match the tracked LLVM version (${version}) before regenerating." >&2
exit 1
fi
echo "Package versions verified against LLVM ${version}"
run: ./scripts/build.sh --verifypackages

# -------- libLLVM: lift the shared libLLVM from the most-official prebuilt source --------

Expand Down
148 changes: 148 additions & 0 deletions scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ done
ScriptRoot="$( cd -P "$( dirname "$SOURCE" )" && pwd )"

architecture=''
base=''
build=false
ci=false
configuration='Debug'
detectchanges=false
help=false
llvm=''
pack=false
Expand All @@ -22,6 +24,7 @@ solution=''
target=''
test=false
verbosity='minimal'
verifypackages=false
properties=''

while [[ $# -gt 0 ]]; do
Expand All @@ -31,6 +34,10 @@ while [[ $# -gt 0 ]]; do
architecture=$2
shift 2
;;
--base)
base=$2
shift 2
;;
--build)
build=true
shift 1
Expand All @@ -43,6 +50,10 @@ while [[ $# -gt 0 ]]; do
configuration=$2
shift 2
;;
--detectchanges)
detectchanges=true
shift 1
;;
--help)
help=true
shift 1
Expand Down Expand Up @@ -83,6 +94,10 @@ while [[ $# -gt 0 ]]; do
verbosity=$2
shift 2
;;
--verifypackages)
verifypackages=true
shift 1
;;
*)
properties="$properties $1"
shift 1
Expand Down Expand Up @@ -127,6 +142,8 @@ function Help {
echo " --pack Package build artifacts"
echo " --regeneratenative Stage a native binary from the matching LLVM release"
echo " (use with --target and --rid)"
echo " --verifypackages Verify the libLLVM/libLLVMSharp package versions match CMakeLists.txt"
echo " --detectchanges Print which native packages need regenerating since --base <ref>"
echo ""
echo "Advanced settings:"
echo " --solution <value> Path to solution to build"
Expand Down Expand Up @@ -205,6 +222,121 @@ function GetLlvmVersion {
LASTEXITCODE=0
}

function VerifyPackages {
GetLlvmVersion

if [ "$LASTEXITCODE" != 0 ]; then
return "$LASTEXITCODE"
fi

rc=0

# libLLVM packages track the LLVM version exactly, including the repository branch.
for f in "$RepoRoot"/packages/libLLVM/libLLVM/libLLVM.nuspec "$RepoRoot"/packages/libLLVM/libLLVM.runtime.*/*.nuspec; do
v="$(sed -n 's:.*<version>\([^<]*\)</version>.*:\1:p' "$f" | head -n1)"

if [ "$v" != "$llvm" ]; then
echo "$f: version '$v' does not match LLVM version '$llvm'"
rc=1
fi

b="$(sed -n 's:.*<repository[^>]*branch="\([^"]*\)".*:\1:p' "$f" | head -n1)"

if [ -n "$b" ] && [ "$b" != "llvmorg-$llvm" ]; then
echo "$f: repository branch '$b' does not match 'llvmorg-$llvm'"
rc=1
fi
done

for v in $(grep -oE '"[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?"' "$RepoRoot/packages/libLLVM/libLLVM/runtime.json" | tr -d '"'); do
if [ "$v" != "$llvm" ]; then
echo "packages/libLLVM/libLLVM/runtime.json: mapped version '$v' does not match LLVM version '$llvm'"
rc=1
fi
done

# libLLVMSharp packages are the LLVM version plus an independent build revision.
for f in "$RepoRoot"/packages/libLLVMSharp/libLLVMSharp/libLLVMSharp.nuspec "$RepoRoot"/packages/libLLVMSharp/libLLVMSharp.runtime.*/*.nuspec; do
v="$(sed -n 's:.*<version>\([^<]*\)</version>.*:\1:p' "$f" | head -n1)"

case "$v" in
"$llvm".*) : ;;
*)
echo "$f: version '$v' is not 'llvm-version.<revision>' (expected '$llvm.<n>')"
rc=1
;;
esac
done

for v in $(grep -oE '"[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?"' "$RepoRoot/packages/libLLVMSharp/libLLVMSharp/runtime.json" | tr -d '"'); do
case "$v" in
"$llvm".*) : ;;
*)
echo "packages/libLLVMSharp/libLLVMSharp/runtime.json: mapped version '$v' is not '$llvm.<revision>'"
rc=1
;;
esac
done

# The managed libLLVM pin consumes the native package. Native may be updated ahead of managed,
# but managed must never lead native (managed <= native).
managedLibLLVM="$(sed -n 's:.*Include="libLLVM"[[:space:]]\{1,\}Version="\([0-9.]*\)".*:\1:p' "$RepoRoot/Directory.Packages.props" | head -n1)"

if [ -n "$managedLibLLVM" ] && [ "$(printf '%s\n%s\n' "$managedLibLLVM" "$llvm" | sort -V | head -n1)" != "$managedLibLLVM" ]; then
echo "Directory.Packages.props: managed libLLVM pin '$managedLibLLVM' leads the native libLLVM version '$llvm' (managed must be <= native)"
rc=1
fi

if [ "$rc" != 0 ]; then
echo "Update the package versions to match the tracked LLVM version ($llvm) before regenerating."
LASTEXITCODE=1
return "$LASTEXITCODE"
fi

echo "Package versions verified against LLVM $llvm"
LASTEXITCODE=0
}

function DetectChanges {
if [[ -z "$base" ]]; then
echo "--base <ref> is required with --detectchanges"
LASTEXITCODE=1
return "$LASTEXITCODE"
fi

GetLlvmVersion

if [ "$LASTEXITCODE" != 0 ]; then
return "$LASTEXITCODE"
fi

detectLibllvm=false
detectLibllvmsharp=false

if ! git -C "$RepoRoot" cat-file -e "$base^{commit}" 2>/dev/null; then
# No resolvable baseline to diff against, so regenerate everything conservatively.
detectLibllvm=true
detectLibllvmsharp=true
else
# libLLVM regenerates when the tracked LLVM version changes. The libLLVM package
# version tracks the full patch (e.g. 21.1.8), so compare the full version.
prevVersion="$(git -C "$RepoRoot" show "$base:CMakeLists.txt" 2>/dev/null | sed -n 's/^project(LLVMSharp VERSION \([0-9.]*\)).*/\1/p')"

if [ "$llvm" != "$prevVersion" ]; then
detectLibllvm=true
fi

# libLLVMSharp regenerates for that same reason or when its sources change.
if [ "$detectLibllvm" = true ] || ! git -C "$RepoRoot" diff --quiet "$base" HEAD -- sources/libLLVMSharp/; then
detectLibllvmsharp=true
fi
fi

echo "libllvm=$detectLibllvm"
echo "libllvmsharp=$detectLibllvmsharp"
LASTEXITCODE=0
}

function DownloadLlvm {
runtime="$1"
destination="$2"
Expand Down Expand Up @@ -512,3 +644,19 @@ if $regeneratenative; then
return "$LASTEXITCODE"
fi
fi

if $verifypackages; then
VerifyPackages

if [ "$LASTEXITCODE" != 0 ]; then
exit "$LASTEXITCODE"
fi
fi

if $detectchanges; then
DetectChanges

if [ "$LASTEXITCODE" != 0 ]; then
exit "$LASTEXITCODE"
fi
fi
Loading