|
94 | 94 | run: | |
95 | 95 | make test |
96 | 96 |
|
| 97 | + - name: Symbol diagnostic (macOS Intel) |
| 98 | + if: always() && matrix.platform == 'macos-15-intel' |
| 99 | + continue-on-error: true |
| 100 | + env: |
| 101 | + GOFLAGS: "-mod=mod" |
| 102 | + run: | |
| 103 | + echo "=== building test packages for symbol analysis ===" |
| 104 | + go build -o /tmp/gopy_diag . |
| 105 | + DIAGDIR=$(mktemp -d) |
| 106 | + CWD=$(pwd) |
| 107 | + mkdir -p "$DIAGDIR/gilstring" "$DIAGDIR/simple" |
| 108 | + printf 'module dummy\nrequire github.com/go-python/gopy v0.0.0\nreplace github.com/go-python/gopy => %s\n' \ |
| 109 | + "$CWD" > "$DIAGDIR/gilstring/go.mod" |
| 110 | + printf 'module dummy\nrequire github.com/go-python/gopy v0.0.0\nreplace github.com/go-python/gopy => %s\n' \ |
| 111 | + "$CWD" > "$DIAGDIR/simple/go.mod" |
| 112 | + /tmp/gopy_diag build -vm=python3 -output="$DIAGDIR/gilstring" ./_examples/gilstring 2>&1 | tail -3 |
| 113 | + /tmp/gopy_diag build -vm=python3 -output="$DIAGDIR/simple" ./_examples/simple 2>&1 | tail -3 |
| 114 | +
|
| 115 | + GIL_SO=$(find "$DIAGDIR/gilstring" -name "_gilstring*.so" 2>/dev/null | head -1) |
| 116 | + SIM_SO=$(find "$DIAGDIR/simple" -name "_simple*.so" 2>/dev/null | head -1) |
| 117 | + echo "gilstring: $GIL_SO" |
| 118 | + echo "simple: $SIM_SO" |
| 119 | + [ -n "$GIL_SO" ] && [ -n "$SIM_SO" ] || { echo "SKIP: .so files not found"; exit 0; } |
| 120 | +
|
| 121 | + echo "" |
| 122 | + echo "=== shared dynamic symbols ===" |
| 123 | + nm "$GIL_SO" | awk '$2~/^[A-Z]$/{print $3}' | sort > /tmp/diag_g1.txt |
| 124 | + nm "$SIM_SO" | awk '$2~/^[A-Z]$/{print $3}' | sort > /tmp/diag_g2.txt |
| 125 | + echo "total shared: $(comm -12 /tmp/diag_g1.txt /tmp/diag_g2.txt | wc -l | tr -d ' ')" |
| 126 | + echo "critical CGo bridge symbols shared between both .so files:" |
| 127 | + comm -12 /tmp/diag_g1.txt /tmp/diag_g2.txt \ |
| 128 | + | grep -E "crosscall|cgo_topofstack|x_cgo_init|x_cgo_inittls|cgo_yield|cgo_panic" \ |
| 129 | + || echo " (none)" |
| 130 | +
|
| 131 | + echo "" |
| 132 | + echo "=== indirect symbol table / PLT stubs in gilstring (otool -Iv) ===" |
| 133 | + TOTAL=$(otool -Iv "$GIL_SO" | grep -c '0x' || true) |
| 134 | + echo "total indirect entries: $TOTAL" |
| 135 | + otool -Iv "$GIL_SO" \ |
| 136 | + | grep -E "crosscall|cgo_topofstack|x_cgo_init|x_cgo_inittls|cgo_yield|cgo_panic" \ |
| 137 | + || echo " (none of the critical CGo symbols appear as PLT stubs)" |
| 138 | +
|
| 139 | + echo "" |
| 140 | + echo "=== indirect symbol table / PLT stubs in simple (otool -Iv) ===" |
| 141 | + TOTAL=$(otool -Iv "$SIM_SO" | grep -c '0x' || true) |
| 142 | + echo "total indirect entries: $TOTAL" |
| 143 | + otool -Iv "$SIM_SO" \ |
| 144 | + | grep -E "crosscall|cgo_topofstack|x_cgo_init|x_cgo_inittls|cgo_yield|cgo_panic" \ |
| 145 | + || echo " (none of the critical CGo symbols appear as PLT stubs)" |
| 146 | +
|
| 147 | + echo "" |
| 148 | + echo "=== runtime: which library wins in the global namespace ===" |
| 149 | + GIL_SO="$GIL_SO" SIM_SO="$SIM_SO" python3 << 'PYEOF' |
| 150 | + import ctypes, os |
| 151 | + GLOBAL = getattr(ctypes, 'RTLD_GLOBAL', 8) |
| 152 | + gil = ctypes.CDLL(os.environ['GIL_SO'], mode=GLOBAL) |
| 153 | + sim = ctypes.CDLL(os.environ['SIM_SO'], mode=GLOBAL) |
| 154 | + glb = ctypes.CDLL(None) |
| 155 | + for s in ['crosscall2', '_cgo_topofstack', 'x_cgo_init', 'x_cgo_inittls', '_cgo_yield', 'x_cgo_mmap']: |
| 156 | + try: |
| 157 | + a1 = ctypes.cast(getattr(gil, s), ctypes.c_void_p).value |
| 158 | + a2 = ctypes.cast(getattr(sim, s), ctypes.c_void_p).value |
| 159 | + ag = ctypes.cast(getattr(glb, s), ctypes.c_void_p).value |
| 160 | + who = 'gilstring' if ag == a1 else ('simple' if ag == a2 else 'other') |
| 161 | + print(' %-35s -> %-12s (global=%s)' % (s, who, hex(ag) if ag else 'N/A')) |
| 162 | + except Exception as e: |
| 163 | + print(' %-35s error: %s' % (s, e)) |
| 164 | + PYEOF |
| 165 | +
|
97 | 166 | - name: Upload-Coverage |
98 | 167 | if: matrix.platform == 'ubuntu-latest' |
99 | 168 | uses: codecov/codecov-action@v4 |
0 commit comments