Skip to content
Draft
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
47 changes: 47 additions & 0 deletions .github/probe/codepage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# TEMPORARY PROBE (do not merge): why Glob.EscapedSpellingIsUtf8WhateverTheName
# fails on some Windows machines. Prints; asserts nothing.
set -u
M="${MCPP_BUILT:?}"
section() { echo; echo "### $1"; }
REPO="$PWD"

section "the runner's code pages"
powershell -NoProfile -Command "[System.Text.Encoding]::Default.CodePage; (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\Nls\CodePage).ACP"

section "the unit test as CI runs it"
"$M" test test_modgraph 2>&1 | grep -E "EscapedSpelling|PASSED|FAILED|passed|failed|error" | head -20
echo "-- does the test binary embed the UTF-8 activeCodePage manifest? (mcpp.exe for comparison)"
for exe in $(find target -name 'test_modgraph*.exe' | head -1) $(find target -name 'mcpp.exe' -path '*/bin/*' | head -1); do
printf '%s: ' "$exe"; grep -a -c "activeCodePage" "$exe" || true
done

section "the same narrow-to-path conversion under each code page"
W="$RUNNER_TEMP/codepage"; rm -rf "$W"; mkdir -p "$W"
for v in legacy utf8; do
mkdir -p "$W/$v/src"; cd "$W/$v"
{ printf '[package]\nname = "cp_%s"\nversion = "0.1.0"\n\n[toolchain]\nwindows = "msvc@system"\n\n[targets.cp_%s]\nkind = "bin"\nmain = "src/main.cpp"\n' "$v" "$v"
[ "$v" = utf8 ] && printf 'windows_code_page = "utf-8"\n'; } > mcpp.toml
cat > src/main.cpp <<'EOF'
#include <windows.h>
#include <cstdio>
#include <exception>
#include <filesystem>
static void conv(unsigned cp) {
const int n = MultiByteToWideChar(cp, MB_ERR_INVALID_CHARS, "caf\xE9", -1, nullptr, 0);
std::printf(" MultiByteToWideChar(cp=%u, \"caf\\xE9\") -> %s\n", cp, n ? "ok" : "fails (no mapping)");
}
int main() {
std::printf("GetACP() = %u\n", GetACP());
try {
std::filesystem::path p("caf\xE9");
std::printf(" std::filesystem::path(\"caf\\xE9\") ok, %zu UTF-16 units\n", p.native().size());
} catch (const std::exception& e) {
std::printf(" std::filesystem::path(\"caf\\xE9\") throws: %s\n", e.what());
}
for (unsigned cp : {1252u, 936u, 65001u}) conv(cp);
}
EOF
echo "-- $v"; "$M" run 2>&1 | grep -v "^ *\(Resolved\|Target\|Inferred\|Compiling\|Finished\|Running\)" | head -12
done
cd "$REPO"
214 changes: 214 additions & 0 deletions .github/probe/mcpp_probes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#!/usr/bin/env bash
# TEMPORARY PROBE (do not merge): mcpp built from main, on the cases the design
# for #770 / #771 / #769 relies on. Prints; asserts nothing.
set -u
M="${MCPP_BUILT:?}"
W="$RUNNER_TEMP/mcpp-probes"; mkdir -p "$W"
run() { echo "\$ $*"; "$@" 2>&1; echo "rc=$?"; }
section() { echo; echo "### $1"; }
edges() { # the link edges of the generated build.ninja, with their link flags
local n; n=$(find target -name build.ninja | head -1)
[ -n "$n" ] || { echo "(no build.ninja)"; return; }
python - "$n" <<'PY'
import re, sys
glob, edges, cur = {}, {}, None
for line in open(sys.argv[1], encoding="utf-8", errors="replace"):
line = line.rstrip("\n")
if line.startswith("build "):
cur = line.split(" : ")[0][6:].strip()
rule = line.split(" : ", 1)[1].split()[0] if " : " in line else "?"
edges[cur] = {"_rule": rule}
continue
if line.startswith(" ") and cur:
k, _, v = line.strip().partition(" = "); edges[cur][k] = v; continue
cur = None
m = re.match(r"^(\w+)\s*=\s*(.*)$", line)
if m: glob[m.group(1)] = m.group(2)
for e, v in edges.items():
if v["_rule"] not in ("cxx_shared", "cxx_link"): continue
src = "group" if "ldflags" in v else "plan-global"
ld = v.get("ldflags", glob.get("ldflags", "")) + " | unit: " + v.get("unit_ldflags", "")
print(f"{e} [{v['_rule']}, {src}]\n {ld}")
PY
}
"$M" --version

MODE="${1:-all}"
if [ "$MODE" = msvc ] || [ "$MODE" = all ]; then
# ---------------------------------------------------------------- #771
section "771 workspace member's shared library and its build.mcpp link_lib (msvc@system)"
mkdir -p "$W/ws771/player/src" "$W/ws771/other/src"; cd "$W/ws771"
cat > mcpp.toml <<'EOF'
[workspace]
members = ["player", "other"]

[toolchain]
windows = "msvc@system"
EOF
cat > player/mcpp.toml <<'EOF'
[package]
name = "player"
version = "0.1.0"

[targets.player_dll]
kind = "shared"

[targets.player]
kind = "bin"
main = "src/main.cpp"
EOF
cat > player/build.mcpp <<'EOF'
import mcpp;
int main() { mcpp::link_lib("ws2_32"); return 0; }
EOF
cat > player/src/net.cpp <<'EOF'
#include <winsock2.h>
int player_err() { return WSAGetLastError(); }
EOF
cat > player/src/main.cpp <<'EOF'
int player_err();
int main() { return player_err() == 0 ? 0 : 0; }
EOF
cat > other/mcpp.toml <<'EOF'
[package]
name = "other"
version = "0.1.0"

[build]
ldflags = ["/IGNORE:4099"]

[targets.other]
kind = "bin"
main = "src/main.cpp"
EOF
printf 'int main() { return 0; }\n' > other/src/main.cpp
run "$M" build
edges
section "771 the same, selecting the member (-p player)"
rm -rf target; run "$M" build -p player
edges

# ---------------------------------------------------------------- #770 F6
section "770 F6 /GL in cxxflags + default windows_auto_export on a DLL (msvc@system)"
mkdir -p "$W/gl/src"; cd "$W/gl"
cat > mcpp.toml <<'EOF'
[package]
name = "glprobe"
version = "0.1.0"

[toolchain]
windows = "msvc@system"

[build]
cxxflags = ["/GL"]
ldflags = ["/LTCG"]

[targets.glprobe]
kind = "shared"
EOF
printf 'int gl_fn(int x) { return x + 1; }\n' > src/gl.cpp
run "$M" build

section "770 F6b /GL + windows_auto_export = false + __declspec(dllexport)"
mkdir -p "$W/gl2/src"; cd "$W/gl2"
cat > mcpp.toml <<'EOF'
[package]
name = "glprobe2"
version = "0.1.0"

[toolchain]
windows = "msvc@system"

[build]
cxxflags = ["/GL"]
ldflags = ["/LTCG"]

[targets.glprobe2]
kind = "shared"
windows_auto_export = false
EOF
printf '__declspec(dllexport) int gl_fn(int x) { return x + 1; }\n' > src/gl.cpp
run "$M" build
dll=$(find target -name 'glprobe2.dll' | head -1); [ -n "$dll" ] && MSYS2_ARG_CONV_EXCL='*' run dumpbin -nologo -exports "$dll"

section "770 lto = true on cl.exe today: what the build line says"
mkdir -p "$W/lto/src"; cd "$W/lto"
cat > mcpp.toml <<'EOF'
[package]
name = "ltoprobe"
version = "0.1.0"

[toolchain]
windows = "msvc@system"

[profile.release]
lto = true

[targets.ltoprobe]
kind = "bin"
main = "src/main.cpp"
EOF
printf 'int main() { return 0; }\n' > src/main.cpp
run "$M" build --release
n=$(find target -name build.ninja | head -1); grep -n "GL\|LTCG\|flto" "$n" | head -5; echo "(grep done)"

# ---------------------------------------------------------------- #769 / D2
fi
if [ "$MODE" = llvm ] || [ "$MODE" = all ]; then
section "D2 import std only: is std.compat compiled anyway? (std cache cleared first)"
echo "WindowsSdkDir=${WindowsSdkDir:-<unset>}"
rm -rf "${MCPP_HOME:-$HOME/.mcpp}/build-cache/v1/std"
rm -rf "$W/stdonly"; mkdir -p "$W/stdonly/src"; cd "$W/stdonly"
cat > mcpp.toml <<'EOF'
[package]
name = "std-only"
version = "0.1.0"
standard = "c++23"

[toolchain]
windows = "llvm@22.1.8"

[target.x86_64-windows-msvc]
sysroot = "msvc@system"

[targets.std-only]
kind = "bin"
main = "src/main.cpp"
EOF
printf 'import std;\nint main() { std::vector<int> v{1}; return v.size() == 1 ? 0 : 1; }\n' > src/main.cpp
run "$M" build
find "${MCPP_HOME:-$HOME/.mcpp}" -path '*std.compat*' \( -name '*.pcm' -o -name '*.o' -o -name '*.obj' \) 2>/dev/null | head -5
echo "(compat artefacts listed above, if any)"

section "769 llvm + MSVC STL: import std.compat"
rm -rf "$W/compat"; mkdir -p "$W/compat/src"; cd "$W/compat"
cat > mcpp.toml <<'EOF'
[package]
name = "std-compat-canary"
version = "0.1.0"
standard = "c++23"

[toolchain]
windows = "llvm@22.1.8"

[target.x86_64-windows-msvc]
sysroot = "msvc@system"

[targets.std-compat-canary]
kind = "bin"
main = "src/main.cpp"
EOF
cat > src/main.cpp <<'EOF'
import std.compat;
int main() {
auto* memory = ::malloc(32);
if (!memory) return 1;
::free(memory);
std::vector<int> values{1, 2, 3};
::printf("compat=%zu\n", values.size());
return values.size() == 3 ? 0 : 1;
}
EOF
run "$M" build
run "$M" run
fi
102 changes: 102 additions & 0 deletions .github/probe/msvc_facts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/env bash
# TEMPORARY PROBE (do not merge): facts about cl.exe /GL, /bigobj, link /LTCG
# and lib /LTCG that the design for #770 relies on. Every command prints its
# output and its exit code; nothing here asserts.
set -u
export MSYS2_ARG_CONV_EXCL='*' # keep /GL etc. away from MSYS path conversion
W="$RUNNER_TEMP/msvc-facts"; rm -rf "$W"; mkdir -p "$W"; cd "$W"

run() { echo "\$ $*"; "$@" 2>&1; echo "rc=$?"; }
# Git Bash ships /usr/bin/link (coreutils); name MSVC's linker by path.
LINK="$(cygpath -u "${VCToolsInstallDir}")bin/Hostx64/x64/link.exe"
link() { "$LINK" "$@"; }
section() { echo; echo "### $1"; }
hex() { od -A d -t x1 -N 64 "$1"; }

section "toolset"
cl 2>&1 | head -1
echo "VCToolsInstallDir=$VCToolsInstallDir"

cat > a.cpp <<'EOF'
extern "C" int probe_fn(int x) { return x + 1; }
int probe_var = 7;
EOF
cat > main.cpp <<'EOF'
extern "C" int probe_fn(int);
int main() { return probe_fn(-1); }
EOF

section "F1 object headers (first 64 bytes)"
run cl -nologo -c a.cpp -Fo:plain.obj
run cl -nologo -c -bigobj a.cpp -Fo:big.obj
run cl -nologo -c -GL a.cpp -Fo:gl.obj
run cl -nologo -c -GL -bigobj a.cpp -Fo:glbig.obj
for f in plain big gl glbig; do echo "-- $f.obj"; hex "$f.obj"; done
# A short import object: a member of an import library.
printf 'LIBRARY probe\nEXPORTS\n probe_fn\n' > probe.def
run lib -nologo -def:probe.def -machine:x64 -out:probe_imp.lib
run lib -nologo -list probe_imp.lib

section "F5 dumpbin on a /GL object"
run dumpbin -nologo -symbols gl.obj

section "F2 link /GL objects WITHOUT /LTCG"
run cl -nologo -c -GL main.cpp -Fo:main_gl.obj
run link -nologo main_gl.obj gl.obj -out:noltcg.exe
run ./noltcg.exe

section "F3 lib.exe on /GL objects, without and with /LTCG"
run lib -nologo gl.obj -out:gl_noltcg.lib
run lib -nologo -LTCG gl.obj -out:gl_ltcg.lib

section "F4 /GL with /Zi /FS, and /LTCG with /DEBUG"
run cl -nologo -c -GL -Zi -FS a.cpp -Fo:gl_zi.obj
run link -nologo -LTCG -DEBUG main_gl.obj gl_zi.obj -out:ltcg_debug.exe
run link -nologo -LTCG -DEBUG -INCREMENTAL main_gl.obj gl_zi.obj -out:ltcg_debug_inc.exe
run link -nologo -LTCG -DEBUG -INCREMENTAL:NO main_gl.obj gl_zi.obj -out:ltcg_debug_noinc.exe

section "F8 a /GL DLL exports through __declspec(dllexport)"
cat > dll.cpp <<'EOF'
extern "C" __declspec(dllexport) int dll_fn(int x) { return x * 2; }
EOF
run cl -nologo -c -GL dll.cpp -Fo:dll_gl.obj
run link -nologo -DLL -LTCG dll_gl.obj -out:gl.dll
run dumpbin -nologo -exports gl.dll

section "D5 per-target degrade: own objects plain + a /GL static library + .def"
cat > own.cpp <<'EOF'
extern "C" int helper(int);
extern "C" int own_fn(int x) { return helper(x) + 1; }
EOF
cat > helper.cpp <<'EOF'
extern "C" int helper(int x) { return x * 3; }
EOF
printf 'LIBRARY own\nEXPORTS\n own_fn\n' > own.def
run cl -nologo -c own.cpp -Fo:own.obj
run cl -nologo -c -GL helper.cpp -Fo:helper_gl.obj
run lib -nologo -LTCG helper_gl.obj -out:helper_gl.lib
echo "-- own.obj is ordinary COFF:"; hex own.obj | head -1
run link -nologo -DLL -LTCG own.obj helper_gl.lib -def:own.def -out:own.dll
run dumpbin -nologo -exports own.dll
run link -nologo -DLL own.obj helper_gl.lib -def:own.def -out:own_noltcg.dll

section "O2 import std across /GL boundaries"
STD_IXX="${VCToolsInstallDir}modules\\std.ixx"
cat > m.cpp <<'EOF'
import std;
int main() { std::vector<int> v{1, 2, 3}; return v.size() == 3 ? 0 : 1; }
EOF
mkdir -p plainstd glstd
echo "-- std built WITHOUT /GL, consumer WITH /GL"
run cl -nologo -std:c++latest -EHsc -c "$STD_IXX" -ifcOutput plainstd/std.ifc -Fo:plainstd/std.obj
run cl -nologo -std:c++latest -EHsc -GL -c m.cpp -reference std=plainstd/std.ifc -Fo:m_gl.obj
run link -nologo -LTCG m_gl.obj plainstd/std.obj -out:m1.exe
run ./m1.exe
echo "-- std built WITH /GL, consumer WITHOUT /GL"
run cl -nologo -std:c++latest -EHsc -GL -c "$STD_IXX" -ifcOutput glstd/std.ifc -Fo:glstd/std.obj
run cl -nologo -std:c++latest -EHsc -c m.cpp -reference std=glstd/std.ifc -Fo:m_plain.obj
run link -nologo -LTCG m_plain.obj glstd/std.obj -out:m2.exe
run ./m2.exe
echo "-- both WITH /GL"
run link -nologo -LTCG m_gl.obj glstd/std.obj -out:m3.exe
run ./m3.exe
Loading
Loading