Skip to content

Commit 323f76b

Browse files
author
xlings-ci
committed
probe: measure MSVC /GL, /LTCG, bigobj and the #771 member DLL link (temporary, do not merge)
1 parent 8d9bde2 commit 323f76b

25 files changed

Lines changed: 372 additions & 7640 deletions

‎.github/probe/mcpp_probes.sh‎

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#!/usr/bin/env bash
2+
# TEMPORARY PROBE (do not merge): mcpp built from main, on the cases the design
3+
# for #770 / #771 / #769 relies on. Prints; asserts nothing.
4+
set -u
5+
M="${MCPP_BUILT:?}"
6+
W="$RUNNER_TEMP/mcpp-probes"; rm -rf "$W"; mkdir -p "$W"
7+
run() { echo "\$ $*"; "$@" 2>&1; echo "rc=$?"; }
8+
section() { echo; echo "### $1"; }
9+
edges() { # the link edges of the generated build.ninja, with their link flags
10+
local n; n=$(find target -name build.ninja | head -1)
11+
[ -n "$n" ] || { echo "(no build.ninja)"; return; }
12+
python - "$n" <<'PY'
13+
import re, sys
14+
glob, edges, cur = {}, {}, None
15+
for line in open(sys.argv[1], encoding="utf-8", errors="replace"):
16+
line = line.rstrip("\n")
17+
if line.startswith("build "):
18+
cur = line.split(" : ")[0][6:].strip()
19+
rule = line.split(" : ", 1)[1].split()[0] if " : " in line else "?"
20+
edges[cur] = {"_rule": rule}
21+
continue
22+
if line.startswith(" ") and cur:
23+
k, _, v = line.strip().partition(" = "); edges[cur][k] = v; continue
24+
cur = None
25+
m = re.match(r"^(\w+)\s*=\s*(.*)$", line)
26+
if m: glob[m.group(1)] = m.group(2)
27+
for e, v in edges.items():
28+
if v["_rule"] not in ("cxx_shared", "cxx_link"): continue
29+
src = "group" if "ldflags" in v else "plan-global"
30+
ld = v.get("ldflags", glob.get("ldflags", "")) + " | unit: " + v.get("unit_ldflags", "")
31+
print(f"{e} [{v['_rule']}, {src}]\n {ld}")
32+
PY
33+
}
34+
"$M" --version
35+
36+
# ---------------------------------------------------------------- #771
37+
section "771 workspace member's shared library and its build.mcpp link_lib (msvc@system)"
38+
mkdir -p "$W/ws771/player/src" "$W/ws771/other/src"; cd "$W/ws771"
39+
cat > mcpp.toml <<'EOF'
40+
[workspace]
41+
members = ["player", "other"]
42+
43+
[toolchain]
44+
windows = "msvc@system"
45+
EOF
46+
cat > player/mcpp.toml <<'EOF'
47+
[package]
48+
name = "player"
49+
version = "0.1.0"
50+
51+
[targets.player_dll]
52+
kind = "shared"
53+
54+
[targets.player]
55+
kind = "bin"
56+
main = "src/main.cpp"
57+
EOF
58+
cat > player/build.mcpp <<'EOF'
59+
import mcpp;
60+
int main() { mcpp::link_lib("ws2_32"); return 0; }
61+
EOF
62+
cat > player/src/net.cpp <<'EOF'
63+
#include <winsock2.h>
64+
int player_err() { return WSAGetLastError(); }
65+
EOF
66+
cat > player/src/main.cpp <<'EOF'
67+
int player_err();
68+
int main() { return player_err() == 0 ? 0 : 0; }
69+
EOF
70+
cat > other/mcpp.toml <<'EOF'
71+
[package]
72+
name = "other"
73+
version = "0.1.0"
74+
75+
[build]
76+
ldflags = ["/IGNORE:4099"]
77+
78+
[targets.other]
79+
kind = "bin"
80+
main = "src/main.cpp"
81+
EOF
82+
printf 'int main() { return 0; }\n' > other/src/main.cpp
83+
run "$M" build
84+
edges
85+
section "771 the same, selecting the member (-p player)"
86+
rm -rf target; run "$M" build -p player
87+
edges
88+
89+
# ---------------------------------------------------------------- #770 F6
90+
section "770 F6 /GL in cxxflags + default windows_auto_export on a DLL (msvc@system)"
91+
mkdir -p "$W/gl/src"; cd "$W/gl"
92+
cat > mcpp.toml <<'EOF'
93+
[package]
94+
name = "glprobe"
95+
version = "0.1.0"
96+
97+
[toolchain]
98+
windows = "msvc@system"
99+
100+
[build]
101+
cxxflags = ["/GL"]
102+
ldflags = ["/LTCG"]
103+
104+
[targets.glprobe]
105+
kind = "shared"
106+
EOF
107+
printf 'int gl_fn(int x) { return x + 1; }\n' > src/gl.cpp
108+
run "$M" build
109+
110+
section "770 F6b /GL + windows_auto_export = false + __declspec(dllexport)"
111+
mkdir -p "$W/gl2/src"; cd "$W/gl2"
112+
cat > mcpp.toml <<'EOF'
113+
[package]
114+
name = "glprobe2"
115+
version = "0.1.0"
116+
117+
[toolchain]
118+
windows = "msvc@system"
119+
120+
[build]
121+
cxxflags = ["/GL"]
122+
ldflags = ["/LTCG"]
123+
124+
[targets.glprobe2]
125+
kind = "shared"
126+
windows_auto_export = false
127+
EOF
128+
printf '__declspec(dllexport) int gl_fn(int x) { return x + 1; }\n' > src/gl.cpp
129+
run "$M" build
130+
dll=$(find target -name 'glprobe2.dll' | head -1); [ -n "$dll" ] && MSYS2_ARG_CONV_EXCL='*' run dumpbin -nologo -exports "$dll"
131+
132+
section "770 lto = true on cl.exe today: what the build line says"
133+
mkdir -p "$W/lto/src"; cd "$W/lto"
134+
cat > mcpp.toml <<'EOF'
135+
[package]
136+
name = "ltoprobe"
137+
version = "0.1.0"
138+
139+
[toolchain]
140+
windows = "msvc@system"
141+
142+
[profile.release]
143+
lto = true
144+
145+
[targets.ltoprobe]
146+
kind = "bin"
147+
main = "src/main.cpp"
148+
EOF
149+
printf 'int main() { return 0; }\n' > src/main.cpp
150+
run "$M" build --release
151+
n=$(find target -name build.ninja | head -1); grep -n "GL\|LTCG\|flto" "$n" | head -5; echo "(grep done)"
152+
153+
# ---------------------------------------------------------------- #769 / D2
154+
section "D2 import std only: is std.compat compiled anyway?"
155+
mkdir -p "$W/stdonly/src"; cd "$W/stdonly"
156+
cat > mcpp.toml <<'EOF'
157+
[package]
158+
name = "std-only"
159+
version = "0.1.0"
160+
standard = "c++23"
161+
162+
[toolchain]
163+
windows = "llvm@22.1.8"
164+
165+
[target.x86_64-windows-msvc]
166+
sysroot = "msvc@system"
167+
168+
[targets.std-only]
169+
kind = "bin"
170+
main = "src/main.cpp"
171+
EOF
172+
printf 'import std;\nint main() { std::vector<int> v{1}; return v.size() == 1 ? 0 : 1; }\n' > src/main.cpp
173+
run "$M" build
174+
find "${MCPP_HOME:-$HOME/.mcpp}" -path '*std.compat*' \( -name '*.pcm' -o -name '*.o' -o -name '*.obj' \) 2>/dev/null | head -5
175+
echo "(compat artefacts listed above, if any)"
176+
177+
section "769 llvm + MSVC STL: import std.compat"
178+
mkdir -p "$W/compat/src"; cd "$W/compat"
179+
cat > mcpp.toml <<'EOF'
180+
[package]
181+
name = "std-compat-canary"
182+
version = "0.1.0"
183+
standard = "c++23"
184+
185+
[toolchain]
186+
windows = "llvm@22.1.8"
187+
188+
[target.x86_64-windows-msvc]
189+
sysroot = "msvc@system"
190+
191+
[targets.std-compat-canary]
192+
kind = "bin"
193+
main = "src/main.cpp"
194+
EOF
195+
cat > src/main.cpp <<'EOF'
196+
import std.compat;
197+
int main() {
198+
auto* memory = ::malloc(32);
199+
if (!memory) return 1;
200+
::free(memory);
201+
std::vector<int> values{1, 2, 3};
202+
::printf("compat=%zu\n", values.size());
203+
return values.size() == 3 ? 0 : 1;
204+
}
205+
EOF
206+
run "$M" build
207+
run "$M" run

‎.github/probe/msvc_facts.sh‎

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env bash
2+
# TEMPORARY PROBE (do not merge): facts about cl.exe /GL, /bigobj, link /LTCG
3+
# and lib /LTCG that the design for #770 relies on. Every command prints its
4+
# output and its exit code; nothing here asserts.
5+
set -u
6+
export MSYS2_ARG_CONV_EXCL='*' # keep /GL etc. away from MSYS path conversion
7+
W="$RUNNER_TEMP/msvc-facts"; rm -rf "$W"; mkdir -p "$W"; cd "$W"
8+
9+
run() { echo "\$ $*"; "$@" 2>&1; echo "rc=$?"; }
10+
section() { echo; echo "### $1"; }
11+
hex() { od -A d -t x1 -N 64 "$1"; }
12+
13+
section "toolset"
14+
cl 2>&1 | head -1
15+
echo "VCToolsInstallDir=$VCToolsInstallDir"
16+
17+
cat > a.cpp <<'EOF'
18+
extern "C" int probe_fn(int x) { return x + 1; }
19+
int probe_var = 7;
20+
EOF
21+
cat > main.cpp <<'EOF'
22+
extern "C" int probe_fn(int);
23+
int main() { return probe_fn(-1); }
24+
EOF
25+
26+
section "F1 object headers (first 64 bytes)"
27+
run cl -nologo -c a.cpp -Fo:plain.obj
28+
run cl -nologo -c -bigobj a.cpp -Fo:big.obj
29+
run cl -nologo -c -GL a.cpp -Fo:gl.obj
30+
run cl -nologo -c -GL -bigobj a.cpp -Fo:glbig.obj
31+
for f in plain big gl glbig; do echo "-- $f.obj"; hex "$f.obj"; done
32+
# A short import object: a member of an import library.
33+
printf 'LIBRARY probe\nEXPORTS\n probe_fn\n' > probe.def
34+
run lib -nologo -def:probe.def -machine:x64 -out:probe_imp.lib
35+
run lib -nologo -list probe_imp.lib
36+
37+
section "F5 dumpbin on a /GL object"
38+
run dumpbin -nologo -symbols gl.obj
39+
40+
section "F2 link /GL objects WITHOUT /LTCG"
41+
run cl -nologo -c -GL main.cpp -Fo:main_gl.obj
42+
run link -nologo main_gl.obj gl.obj -out:noltcg.exe
43+
run ./noltcg.exe
44+
45+
section "F3 lib.exe on /GL objects, without and with /LTCG"
46+
run lib -nologo gl.obj -out:gl_noltcg.lib
47+
run lib -nologo -LTCG gl.obj -out:gl_ltcg.lib
48+
49+
section "F4 /GL with /Zi /FS, and /LTCG with /DEBUG"
50+
run cl -nologo -c -GL -Zi -FS a.cpp -Fo:gl_zi.obj
51+
run link -nologo -LTCG -DEBUG main_gl.obj gl_zi.obj -out:ltcg_debug.exe
52+
run link -nologo -LTCG -DEBUG -INCREMENTAL main_gl.obj gl_zi.obj -out:ltcg_debug_inc.exe
53+
run link -nologo -LTCG -DEBUG -INCREMENTAL:NO main_gl.obj gl_zi.obj -out:ltcg_debug_noinc.exe
54+
55+
section "F8 a /GL DLL exports through __declspec(dllexport)"
56+
cat > dll.cpp <<'EOF'
57+
extern "C" __declspec(dllexport) int dll_fn(int x) { return x * 2; }
58+
EOF
59+
run cl -nologo -c -GL dll.cpp -Fo:dll_gl.obj
60+
run link -nologo -DLL -LTCG dll_gl.obj -out:gl.dll
61+
run dumpbin -nologo -exports gl.dll
62+
63+
section "D5 per-target degrade: own objects plain + a /GL static library + .def"
64+
cat > own.cpp <<'EOF'
65+
extern "C" int helper(int);
66+
extern "C" int own_fn(int x) { return helper(x) + 1; }
67+
EOF
68+
cat > helper.cpp <<'EOF'
69+
extern "C" int helper(int x) { return x * 3; }
70+
EOF
71+
printf 'LIBRARY own\nEXPORTS\n own_fn\n' > own.def
72+
run cl -nologo -c own.cpp -Fo:own.obj
73+
run cl -nologo -c -GL helper.cpp -Fo:helper_gl.obj
74+
run lib -nologo -LTCG helper_gl.obj -out:helper_gl.lib
75+
echo "-- own.obj is ordinary COFF:"; hex own.obj | head -1
76+
run link -nologo -DLL -LTCG own.obj helper_gl.lib -def:own.def -out:own.dll
77+
run dumpbin -nologo -exports own.dll
78+
run link -nologo -DLL own.obj helper_gl.lib -def:own.def -out:own_noltcg.dll
79+
80+
section "O2 import std across /GL boundaries"
81+
STD_IXX="${VCToolsInstallDir}modules\\std.ixx"
82+
cat > m.cpp <<'EOF'
83+
import std;
84+
int main() { std::vector<int> v{1, 2, 3}; return v.size() == 3 ? 0 : 1; }
85+
EOF
86+
mkdir -p plainstd glstd
87+
echo "-- std built WITHOUT /GL, consumer WITH /GL"
88+
run cl -nologo -std:c++latest -EHsc -c "$STD_IXX" -ifcOutput plainstd/std.ifc -Fo:plainstd/std.obj
89+
run cl -nologo -std:c++latest -EHsc -GL -c m.cpp -reference std=plainstd/std.ifc -Fo:m_gl.obj
90+
run link -nologo -LTCG m_gl.obj plainstd/std.obj -out:m1.exe
91+
run ./m1.exe
92+
echo "-- std built WITH /GL, consumer WITHOUT /GL"
93+
run cl -nologo -std:c++latest -EHsc -GL -c "$STD_IXX" -ifcOutput glstd/std.ifc -Fo:glstd/std.obj
94+
run cl -nologo -std:c++latest -EHsc -c m.cpp -reference std=glstd/std.ifc -Fo:m_plain.obj
95+
run link -nologo -LTCG m_plain.obj glstd/std.obj -out:m2.exe
96+
run ./m2.exe
97+
echo "-- both WITH /GL"
98+
run link -nologo -LTCG m_gl.obj glstd/std.obj -out:m3.exe
99+
run ./m3.exe

0 commit comments

Comments
 (0)