Skip to content

Commit 648d23d

Browse files
committed
measure-693 round 5: the encodings in which cl.exe, link.exe and lib.exe read a response file, and the same file written by Ninja
1 parent 20809f0 commit 648d23d

2 files changed

Lines changed: 150 additions & 3 deletions

File tree

‎.github/measure-693/rsp.ps1‎

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# Measurement for mcpp#693, round 5. TEMPORARY: this branch is never merged.
2+
#
3+
# Question:
4+
# R1 In which encodings do the MSVC tools read a response file whose content
5+
# is not ASCII? mcpp's compile, link and archive edges on Windows pass
6+
# their arguments through response files that Ninja writes with the bytes
7+
# of build.ninja, which are UTF-8 under the code page mcpp declares. The
8+
# earlier rounds produced no response file with non-ASCII content.
9+
#
10+
# Each case writes one response file in one encoding and runs the tool on it.
11+
# Directories: an ASCII control, a name inside code page 1252 (U+00E9) and a
12+
# name outside it (U+6D4B U+8BD5). Encodings: UTF-8 without a BOM, UTF-8 with
13+
# a BOM, UTF-16LE with a BOM, and code page 1252. The last case runs the same
14+
# UTF-8-with-BOM content through Ninja's `rspfile_content`, as mcpp would write
15+
# it.
16+
#
17+
# Every observation is one `READING <id>: ...` line. Source is ASCII only.
18+
19+
$ErrorActionPreference = 'Continue'
20+
$ProgressPreference = 'SilentlyContinue'
21+
[System.Text.Encoding]::RegisterProvider([System.Text.CodePagesEncodingProvider]::Instance)
22+
23+
function Reading([string]$id, [string]$text) {
24+
$line = "READING ${id}: $text"
25+
Write-Host $line
26+
if ($env:GITHUB_STEP_SUMMARY) {
27+
Add-Content -LiteralPath $env:GITHUB_STEP_SUMMARY -Value (" " + $line) -Encoding utf8
28+
}
29+
}
30+
31+
function Run([string]$exe, [string[]]$argv, [string]$cwd) {
32+
$psi = [System.Diagnostics.ProcessStartInfo]::new()
33+
$psi.FileName = $exe
34+
foreach ($a in $argv) { [void]$psi.ArgumentList.Add($a) }
35+
$psi.WorkingDirectory = $cwd
36+
$psi.UseShellExecute = $false
37+
$psi.RedirectStandardOutput = $true
38+
$psi.RedirectStandardError = $true
39+
$p = [System.Diagnostics.Process]::Start($psi)
40+
$o = $p.StandardOutput.ReadToEndAsync(); $e = $p.StandardError.ReadToEndAsync()
41+
$p.WaitForExit()
42+
return @{ code = $p.ExitCode; out = ($o.Result + $e.Result) }
43+
}
44+
45+
function FirstLine([string]$s) {
46+
$t = ($s -replace "`r", '' -split "`n" | Where-Object { $_ -match '\S' } | Select-Object -First 1)
47+
if ($null -eq $t) { return '(no output)' }
48+
if ($t.Length -gt 150) { $t = $t.Substring(0, 150) + '...' }
49+
return $t
50+
}
51+
52+
$Utf8 = [System.Text.UTF8Encoding]::new($false)
53+
$Ansi = [System.Text.Encoding]::GetEncoding(1252)
54+
function Bytes([string]$text, [string]$enc) {
55+
switch ($enc) {
56+
'u8' { return $Utf8.GetBytes($text) }
57+
'u8bom' { return [byte[]](@(0xEF, 0xBB, 0xBF) + $Utf8.GetBytes($text)) }
58+
'u16' { return [byte[]](@(0xFF, 0xFE) + [System.Text.Encoding]::Unicode.GetBytes($text)) }
59+
'ansi' { return $Ansi.GetBytes($text) }
60+
}
61+
}
62+
63+
# ---------------------------------------------------------------------------
64+
# The Visual Studio environment
65+
66+
$vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
67+
$vs = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
68+
Import-Module (Join-Path $vs 'Common7\Tools\Microsoft.VisualStudio.DevShell.dll')
69+
Enter-VsDevShell -VsInstallPath $vs -SkipAutomaticLocation -DevCmdArguments '-arch=x64 -host_arch=x64' | Out-Null
70+
$acp = (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Nls\CodePage').ACP
71+
$cl = (Get-Command cl.exe).Source
72+
$ninja = Get-Command ninja.exe -ErrorAction SilentlyContinue
73+
Reading 'env' "acp=$acp cl=$cl ninja=$(if ($ninja) { $ninja.Source } else { 'absent' })"
74+
$ver = Run $cl @() $env:TEMP
75+
Reading 'env.cl' (FirstLine $ver.out)
76+
77+
$Root = 'C:\m'
78+
New-Item -ItemType Directory -Force -Path (Join-Path $Root 'a') | Out-Null
79+
$A = Join-Path $Root 'a'
80+
[System.IO.File]::WriteAllText((Join-Path $A 't.c'), "#include `"h.h`"`nint main(void) { return H_OK - 1; }`n")
81+
[System.IO.File]::WriteAllText((Join-Path $A 't0.c'), "int main(void) { return 0; }`n")
82+
$r = Run $cl @('/nologo', '/c', 't0.c', '/Fot0.obj') $A
83+
Reading 'setup.t0' "exit=$($r.code)"
84+
85+
$Dirs = [ordered]@{
86+
ascii = 'plain'
87+
cafe = 'caf' + [char]0x00E9
88+
cjk = [string][char]0x6D4B + [char]0x8BD5
89+
}
90+
foreach ($k in $Dirs.Keys) {
91+
$d = Join-Path $Root $Dirs[$k]
92+
New-Item -ItemType Directory -Force -Path (Join-Path $d 'inc'), (Join-Path $d 'src') | Out-Null
93+
[System.IO.File]::WriteAllText((Join-Path $d 'inc\h.h'), "#define H_OK 1`n")
94+
[System.IO.File]::WriteAllText((Join-Path $d 'src\s.c'), "int s(void) { return 0; }`n")
95+
}
96+
97+
# ---------------------------------------------------------------------------
98+
# R1: one response file per tool, directory and encoding
99+
100+
foreach ($k in $Dirs.Keys) {
101+
$d = Join-Path $Root $Dirs[$k]
102+
foreach ($enc in @('u8', 'u8bom', 'u16', 'ansi')) {
103+
if ($enc -eq 'ansi' -and $k -eq 'cjk') { continue } # not representable
104+
$cases = [ordered]@{
105+
'cl-include' = @{ exe = 'cl.exe'; text = "/nologo /c /I`"$d\inc`" /Fo`"$A\t-$k-$enc.obj`" `"$A\t.c`"`r`n"; out = "$A\t-$k-$enc.obj" }
106+
'cl-source' = @{ exe = 'cl.exe'; text = "/nologo /c `"$d\src\s.c`" /Fo`"$A\s-$k-$enc.obj`"`r`n"; out = "$A\s-$k-$enc.obj" }
107+
'link-out' = @{ exe = 'link.exe'; text = "/nologo /OUT:`"$d\o-$enc.exe`" `"$A\t0.obj`"`r`n"; out = "$d\o-$enc.exe" }
108+
'lib-out' = @{ exe = 'lib.exe'; text = "/nologo /OUT:`"$d\l-$enc.lib`" `"$A\t0.obj`"`r`n"; out = "$d\l-$enc.lib" }
109+
}
110+
foreach ($c in $cases.Keys) {
111+
$rsp = Join-Path $A "$c-$k-$enc.rsp"
112+
[System.IO.File]::WriteAllBytes($rsp, (Bytes $cases[$c].text $enc))
113+
$r = Run $cases[$c].exe @("@$rsp") $A
114+
$made = Test-Path -LiteralPath $cases[$c].out
115+
$note = if ($r.code -eq 0) { '' } else { ' | ' + (FirstLine $r.out) }
116+
Reading "R1.$c.$k.$enc" "exit=$($r.code) output=$made$note"
117+
}
118+
}
119+
}
120+
121+
# ---------------------------------------------------------------------------
122+
# R1n: the same UTF-8-with-BOM content, written by Ninja from `rspfile_content`
123+
124+
if (-not $ninja) {
125+
$zip = Join-Path $env:TEMP 'ninja.zip'
126+
Invoke-WebRequest -Uri 'https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-win.zip' -OutFile $zip -UseBasicParsing
127+
Expand-Archive -LiteralPath $zip -DestinationPath (Join-Path $env:TEMP 'ninja') -Force
128+
$ninjaExe = Join-Path $env:TEMP 'ninja\ninja.exe'
129+
} else { $ninjaExe = $ninja.Source }
130+
$wcp = Run $ninjaExe @('-t', 'wincodepage') $A
131+
Reading 'R1n.wincodepage' (FirstLine $wcp.out)
132+
foreach ($k in $Dirs.Keys) {
133+
foreach ($bom in @('none', 'bom')) {
134+
$d = Join-Path $Root $Dirs[$k]
135+
$b = Join-Path $Root "n-$k-$bom"
136+
New-Item -ItemType Directory -Force -Path $b | Out-Null
137+
$prefix = if ($bom -eq 'bom') { [string][char]0xFEFF } else { '' }
138+
$text = "ninja_required_version = 1.11`n" +
139+
"rule cc`n command = cl.exe @`$out.rsp`n rspfile = `$out.rsp`n" +
140+
" rspfile_content = $prefix/nologo /c /I`"$($d -replace ':', '$$:')\inc`" `$in /Fo`$out`n" +
141+
"build t.obj: cc $($A -replace ':', '$$:')\t.c`n"
142+
[System.IO.File]::WriteAllBytes((Join-Path $b 'build.ninja'), $Utf8.GetBytes($text))
143+
$r = Run $ninjaExe @('-C', $b) $Root
144+
$note = if ($r.code -eq 0) { '' } else { ' | ' + (FirstLine ($r.out -replace '(?m)^\[.*\]\s*', '')) }
145+
Reading "R1n.$k.$bom" "exit=$($r.code) output=$(Test-Path -LiteralPath (Join-Path $b 't.obj'))$note"
146+
}
147+
}

‎.github/workflows/measure-693.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
timeout-minutes: 90
1717
steps:
1818
- uses: actions/checkout@v4
19-
- name: Readings
19+
- name: Readings (round 5, response-file encodings)
2020
shell: pwsh
21-
timeout-minutes: 85
22-
run: ./.github/measure-693/measure.ps1
21+
timeout-minutes: 30
22+
run: ./.github/measure-693/rsp.ps1

0 commit comments

Comments
 (0)