|
14 | 14 | ##===----------------------------------------------------------------------===## |
15 | 15 | set -eu |
16 | 16 |
|
17 | | -# Validate that we're running on Linux |
18 | | -if [[ "$(uname -s)" != "Linux" ]]; then |
| 17 | +DRY_RUN=false |
| 18 | +for arg in "$@"; do |
| 19 | + case "$arg" in |
| 20 | + --dry-run) |
| 21 | + DRY_RUN=true |
| 22 | + ;; |
| 23 | + -h|--help) |
| 24 | + cat <<'EOF' |
| 25 | +Usage: run-linkage-test.sh [--dry-run] |
| 26 | +
|
| 27 | +Verifies that the linkage test package and its source files cover every |
| 28 | +runtime library product exported from swift-java, then (on Linux) builds |
| 29 | +those executables and confirms none of them link libFoundation.so. |
| 30 | +
|
| 31 | + --dry-run Only run the imports-in-sync check. |
| 32 | + Skips the Linux-only build + ldd steps. |
| 33 | +EOF |
| 34 | + exit 0 |
| 35 | + ;; |
| 36 | + *) |
| 37 | + echo "Error: unknown argument: $arg" >&2 |
| 38 | + echo "Run with --help for usage." >&2 |
| 39 | + exit 1 |
| 40 | + ;; |
| 41 | + esac |
| 42 | +done |
| 43 | + |
| 44 | +# Validate that we're running on Linux (unless we're only doing the |
| 45 | +# imports-in-sync check). |
| 46 | +if ! $DRY_RUN && [[ "$(uname -s)" != "Linux" ]]; then |
19 | 47 | echo "Error: This script must be run on Linux. Current OS: $(uname -s)" >&2 |
| 48 | + echo "Hint: pass --dry-run to run the imports-in-sync check on any OS." >&2 |
20 | 49 | exit 1 |
21 | 50 | fi |
22 | 51 |
|
23 | | -echo "Detected JAVA_HOME=${JAVA_HOME}" |
| 52 | +if ! $DRY_RUN; then |
| 53 | + echo "Detected JAVA_HOME=${JAVA_HOME}" |
| 54 | +fi |
| 55 | + |
| 56 | +# Verify that Tests/LinkageTest/Package.swift and tests include all the runtime libraries. |
| 57 | +# This is because if any of them accidentally pulls Foundation, that'd be bad. |
| 58 | +# |
| 59 | +# We inspect: |
| 60 | +# - any library product whose name starts with "Java" |
| 61 | +# - "SwiftJava" |
| 62 | +# - "SwiftRuntimeFunctions" |
| 63 | +# Anything else (tooling, docs, samples, `*Static` linkage variants) is |
| 64 | +# ignored on purpose. |
| 65 | +# |
| 66 | +# The expected list is derived from `swift package describe --type json` on |
| 67 | +# the root package so it stays honest as products are added or renamed. |
| 68 | +verify_linkage_test_covers_runtime_products() { |
| 69 | + local linkage_pkg="Tests/LinkageTest/Package.swift" |
| 70 | + |
| 71 | + if [[ ! -f "Package.swift" || ! -f "$linkage_pkg" ]]; then |
| 72 | + echo "Error: cannot find Package.swift or $linkage_pkg from $(pwd)" >&2 |
| 73 | + exit 1 |
| 74 | + fi |
| 75 | + |
| 76 | + if ! command -v jq >/dev/null 2>&1; then |
| 77 | + echo "Error: 'jq' is required to parse 'swift package describe --type json'." >&2 |
| 78 | + echo "Install it with your package manager (e.g. 'apt-get install -y jq') and re-run." >&2 |
| 79 | + exit 1 |
| 80 | + fi |
| 81 | + |
| 82 | + local expected |
| 83 | + expected=$( |
| 84 | + swift package --disable-sandbox describe --type json \ |
| 85 | + | jq -r ' |
| 86 | + .products[] |
| 87 | + | select(.type.library != null) |
| 88 | + | .name |
| 89 | + | select(startswith("Java") or . == "SwiftJava" or . == "SwiftRuntimeFunctions") |
| 90 | + ' \ |
| 91 | + | sort -u |
| 92 | + ) |
| 93 | + |
| 94 | + if [[ -z "$expected" ]]; then |
| 95 | + echo "Error: could not extract runtime library products from 'swift package describe'." >&2 |
| 96 | + echo "The parser in run-linkage-test.sh likely needs updating." >&2 |
| 97 | + exit 1 |
| 98 | + fi |
| 99 | + |
| 100 | + # Actual list, between the markers in Tests/LinkageTest/Package.swift. |
| 101 | + local actual |
| 102 | + actual=$( |
| 103 | + awk ' |
| 104 | + /RUNTIME_LIBRARY_PRODUCTS:START/ { collecting = 1; next } |
| 105 | + /RUNTIME_LIBRARY_PRODUCTS:END/ { collecting = 0 } |
| 106 | + collecting && match($0, /"[^"]+"/) { |
| 107 | + name = substr($0, RSTART + 1, RLENGTH - 2) |
| 108 | + print name |
| 109 | + } |
| 110 | + ' "$linkage_pkg" | sort -u |
| 111 | + ) |
| 112 | + |
| 113 | + if [[ -z "$actual" ]]; then |
| 114 | + echo "Error: no entries found between RUNTIME_LIBRARY_PRODUCTS:START/END in $linkage_pkg." >&2 |
| 115 | + echo "The linkage test would silently under-cover the runtime libraries." >&2 |
| 116 | + exit 1 |
| 117 | + fi |
| 118 | + |
| 119 | + local missing extra |
| 120 | + missing=$(comm -23 <(printf '%s\n' "$expected") <(printf '%s\n' "$actual")) |
| 121 | + extra=$(comm -13 <(printf '%s\n' "$expected") <(printf '%s\n' "$actual")) |
| 122 | + |
| 123 | + if [[ -n "$missing" || -n "$extra" ]]; then |
| 124 | + echo "Error: $linkage_pkg RUNTIME_LIBRARY_PRODUCTS list is out of sync with the root package." >&2 |
| 125 | + if [[ -n "$missing" ]]; then |
| 126 | + echo " Missing from linkage test (add these):" >&2 |
| 127 | + printf '%s\n' "$missing" | sed 's/^/ /' >&2 |
| 128 | + fi |
| 129 | + if [[ -n "$extra" ]]; then |
| 130 | + echo " Present in linkage test but not a runtime library product:" >&2 |
| 131 | + printf '%s\n' "$extra" | sed 's/^/ /' >&2 |
| 132 | + fi |
| 133 | + echo "Update the RUNTIME_LIBRARY_PRODUCTS list and re-run." >&2 |
| 134 | + exit 1 |
| 135 | + fi |
| 136 | + |
| 137 | + # Every linkage-test source file that imports the runtime products must also stay in sync. |
| 138 | + # Sources delimit their `import` block with `IMPORT_RUNTIME_LIBRARY_PRODUCTS:START` / `:END`. |
| 139 | + local import_source |
| 140 | + for import_source in \ |
| 141 | + Tests/LinkageTest/Sources/LinkageTest/main.swift \ |
| 142 | + Tests/LinkageTest/Sources/JExtractLinkageTest/main.swift |
| 143 | + do |
| 144 | + if [[ ! -f "$import_source" ]]; then |
| 145 | + echo "Error: expected linkage-test source $import_source not found." >&2 |
| 146 | + exit 1 |
| 147 | + fi |
| 148 | + |
| 149 | + local imported |
| 150 | + imported=$( |
| 151 | + awk ' |
| 152 | + /IMPORT_RUNTIME_LIBRARY_PRODUCTS:START/ { collecting = 1; next } |
| 153 | + /IMPORT_RUNTIME_LIBRARY_PRODUCTS:END/ { collecting = 0 } |
| 154 | + collecting && match($0, /^[[:space:]]*import[[:space:]]+[A-Za-z_][A-Za-z0-9_]*/) { |
| 155 | + line = substr($0, RSTART, RLENGTH) |
| 156 | + sub(/^[[:space:]]*import[[:space:]]+/, "", line) |
| 157 | + print line |
| 158 | + } |
| 159 | + ' "$import_source" | sort -u |
| 160 | + ) |
| 161 | + |
| 162 | + if [[ -z "$imported" ]]; then |
| 163 | + echo "Error: no imports found between IMPORT_RUNTIME_LIBRARY_PRODUCTS:START/END in $import_source." >&2 |
| 164 | + exit 1 |
| 165 | + fi |
| 166 | + |
| 167 | + local src_missing src_extra |
| 168 | + src_missing=$(comm -23 <(printf '%s\n' "$expected") <(printf '%s\n' "$imported")) |
| 169 | + src_extra=$(comm -13 <(printf '%s\n' "$expected") <(printf '%s\n' "$imported")) |
| 170 | + |
| 171 | + if [[ -n "$src_missing" || -n "$src_extra" ]]; then |
| 172 | + echo "Error: imports in $import_source are out of sync with the root package." >&2 |
| 173 | + if [[ -n "$src_missing" ]]; then |
| 174 | + echo " Missing imports (add these):" >&2 |
| 175 | + printf '%s\n' "$src_missing" | sed 's/^/ import /' >&2 |
| 176 | + fi |
| 177 | + if [[ -n "$src_extra" ]]; then |
| 178 | + echo " Imports not backed by a runtime library product:" >&2 |
| 179 | + printf '%s\n' "$src_extra" | sed 's/^/ import /' >&2 |
| 180 | + fi |
| 181 | + echo "Update the import block between the IMPORT_RUNTIME_LIBRARY_PRODUCTS markers and re-run." >&2 |
| 182 | + exit 1 |
| 183 | + fi |
| 184 | + done |
| 185 | + |
| 186 | + echo "Linkage test covers all runtime library products:" |
| 187 | + printf '%s\n' "$expected" | sed 's/^/ /' |
| 188 | +} |
| 189 | + |
| 190 | +verify_linkage_test_covers_runtime_products |
| 191 | + |
| 192 | +if $DRY_RUN; then |
| 193 | + echo "--dry-run: imports-in-sync check passed; skipping Linux build + ldd." |
| 194 | + exit 0 |
| 195 | +fi |
24 | 196 |
|
25 | 197 | echo "Running on Linux - proceeding with linkage test..." |
26 | 198 |
|
|
0 commit comments