Skip to content

Commit 5611a7c

Browse files
committed
msvc-dev-cmd v1.8.0
2 parents 18f5f2c + 08b850b commit 5611a7c

File tree

5 files changed

+181
-39
lines changed

5 files changed

+181
-39
lines changed

.github/workflows/main.yml

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,42 @@ jobs:
1818
uses: actions/checkout@v2
1919
- name: Download Internet
2020
run: npm install
21-
- name: Enable Developer Command Prompt
21+
- name: Enable Developer Command Prompt (amd64)
2222
uses: ./
23-
- name: Compile and run some C code
23+
with:
24+
arch: amd64
25+
- name: Compile and run some C code (amd64)
26+
shell: cmd
27+
run: |
28+
cl.exe hello.c
29+
hello.exe
30+
- name: Enable Developer Command Prompt (amd64_x86)
31+
uses: ./
32+
with:
33+
arch: amd64_x86
34+
- name: Compile and run some C code (x86)
2435
shell: cmd
2536
run: |
2637
cl.exe hello.c
2738
hello.exe
39+
- name: Enable Developer Command Prompt (amd64_arm)
40+
uses: ./
41+
with:
42+
arch: amd64_arm
43+
- name: Compile some C code (arm)
44+
shell: cmd
45+
run: |
46+
cl.exe hello.c
47+
dumpbin /headers hello.exe
48+
- name: Enable Developer Command Prompt (amd64_arm64)
49+
uses: ./
50+
with:
51+
arch: amd64_arm64
52+
- name: Compile some C code (arm64)
53+
shell: cmd
54+
run: |
55+
cl.exe hello.c
56+
dumpbin /headers hello.exe
2857
audit:
2958
name: npm audit
3059
runs-on: windows-latest

README.md

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,57 @@ This sets up the environment for compiling C/C++ code from command line.
88

99
Supports Windows. Does nothing on Linux and macOS.
1010

11+
## Example usage
12+
13+
Basic usage for default compilation settings is like this:
14+
15+
```yaml
16+
jobs:
17+
test:
18+
steps:
19+
- uses: actions/checkout@v2
20+
- uses: ilammy/msvc-dev-cmd@v1
21+
- name: Build something requiring CL.EXE
22+
run: |
23+
cmake -G "NMake Makefiles" .
24+
nmake
25+
# ...
26+
```
27+
28+
If you want something non-default,
29+
like using a specific version of Visual Studio,
30+
or cross-compling for a differen target,
31+
you will need to configure those settings via inputs:
32+
33+
```yaml
34+
jobs:
35+
test:
36+
# Run a job for each of the specified target architectures:
37+
strategy:
38+
matrix:
39+
arch:
40+
- amd64
41+
- amd64_x86
42+
- amd64_arm64
43+
steps:
44+
- uses: actions/checkout@v2
45+
- uses: ilammy/msvc-dev-cmd@v1
46+
with:
47+
arch: ${{ matrix.arch }}
48+
- name: Build something requiring CL.EXE
49+
run: |
50+
cmake -G "NMake Makefiles" .
51+
nmake
52+
# ...
53+
```
54+
1155
## Inputs
1256

1357
- `arch` – target architecture
1458
- native compilation:
1559
- `x64` (default) or its synonyms: `amd64`, `win64`
1660
- `x86` or its synonyms: `win32`
17-
- cross-compilation: `x86_amd64`, `x86_arm`, `x86_arm64`,
18-
`amd64_x86`, `amd64_arm`, `amd64_arm64`
61+
- cross-compilation: `x86_amd64`, `x86_arm`, `x86_arm64`, `amd64_x86`, `amd64_arm`, `amd64_arm64`
1962
- `sdk` – Windows SDK to use
2063
- do not specify to use the default SDK
2164
- or specify full Windows 10 SDK number (e.g, `10.0.10240.0`)
@@ -28,20 +71,64 @@ Supports Windows. Does nothing on Linux and macOS.
2871
- `uwp` – set `true` to build for Universal Windows Platform (i.e., for Windows Store)
2972
- `spectre` – set `true` to use Visual Studio libraries with [Spectre](https://meltdownattack.com) mitigations
3073

31-
## Example usage
74+
## Caveats
75+
76+
### Name conflicts with `shell: bash`
77+
78+
Using `shell: bash` in Actions may shadow some of the paths added by MSVC.
79+
In particular, `link.exe` (Microsoft C linker) is prone to be shadowed by `/usr/bin/link` (GNU filesystem link tool).
80+
81+
Unfortunately, this happens because GitHub Actions unconditionally *prepend* GNU paths when `shell: bash` is used,
82+
on top of any paths set by `msvc-dev-cmd`, every time at the start of each new step.
83+
Hence, there aren't many non-destructive options here.
84+
85+
If you experience compilation errors where `link` complains about unreasonable command-line arguments,
86+
“extra operand *something-something*” – that's probably it.
87+
Recommended workaround is to remove `/usr/bin/link` if that interferes with your builds.
88+
If this is not acceptable, please file an issue, then we'll figure out something better.
89+
90+
### Reconfiguration
91+
92+
You can invoke `ilammy/msvc-dev-cmd` multiple times during your jobs with different inputs
93+
to reconfigure the environment for building with different settings
94+
(e.g., to target multiple architectures).
3295

3396
```yaml
3497
jobs:
35-
test:
36-
- uses: actions/checkout@v1
37-
- uses: ilammy/msvc-dev-cmd@v1
38-
- name: Build something requiring CL.EXE
39-
run: |
40-
cmake -G "NMake Makefiles" .
41-
nmake
42-
# ...
98+
release:
99+
steps:
100+
# ...
101+
- name: Configure build for amd64
102+
uses: ilammy/msvc-dev-cmd@v1
103+
with:
104+
arch: amd64
105+
106+
- run: build # (for amd64)
107+
108+
- name: Configure build for x86
109+
uses: ilammy/msvc-dev-cmd@v1
110+
with:
111+
arch: amd64_x86
112+
113+
- run: build # (for x86)
114+
115+
- name: Configure build for ARM64
116+
uses: ilammy/msvc-dev-cmd@v1
117+
with:
118+
arch: amd64_arm64
119+
120+
- run: build # (for ARM64)
121+
122+
# ...
43123
```
44124

125+
This mostly works but it's not really recommended
126+
since Developer Command Prompt was not meant for recursive reconfiguration.
127+
That said, if it does not work for you, please file an issue.
128+
129+
Consider using [`strategy.matrix`](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix)
130+
to execute different build configuration in parallel, independent environments.
131+
45132
## License
46133

47134
MIT, see [LICENSE](LICENSE).

index.js

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,6 @@ const VERSIONS = ['2019', '2017']
1111

1212
const VSWHERE_PATH = `${PROGRAM_FILES_X86}\\Microsoft Visual Studio\\Installer`
1313

14-
const InterestingVariables = [
15-
'INCLUDE',
16-
'LIB',
17-
'LIBPATH',
18-
'VCINSTALLDIR',
19-
'Path',
20-
'Platform',
21-
'VisualStudioVersion',
22-
'UCRTVersion',
23-
'UniversalCRTSdkDir',
24-
/^VCTools/,
25-
/^VSCMD_/,
26-
/^WindowsSDK/i,
27-
]
28-
2914
function findWithVswhere(pattern) {
3015
try {
3116
let installationPath = child_process.execSync(`vswhere -products * -latest -prerelease -property installationPath`).toString().trim()
@@ -70,6 +55,21 @@ function findVcvarsall() {
7055
throw new Error('Microsoft Visual Studio not found')
7156
}
7257

58+
function isPathVariable(name) {
59+
const pathLikeVariables = ['PATH', 'INCLUDE', 'LIB', 'LIBPATH']
60+
return pathLikeVariables.indexOf(name.toUpperCase()) != -1
61+
}
62+
63+
function filterPathValue(path) {
64+
let paths = path.split(';')
65+
// Remove duplicates by keeping the first occurance and preserving order.
66+
// This keeps path shadowing working as intended.
67+
function unique(value, index, self) {
68+
return self.indexOf(value) === index
69+
}
70+
return paths.filter(unique).join(';')
71+
}
72+
7373
function main() {
7474
if (process.platform != 'win32') {
7575
core.info('This is not a Windows virtual environment, bye!')
@@ -113,15 +113,17 @@ function main() {
113113
args.push('-vcvars_spectre_libs=spectre')
114114
}
115115

116-
const command = `"${findVcvarsall()}" ${args.join(' ')} && set`
117-
core.debug(`Running: ${command}`)
118-
const environment = child_process.execSync(command, {shell: "cmd"}).toString().split('\r\n')
116+
const vcvars = `"${findVcvarsall()}" ${args.join(' ')}`
117+
core.debug(`vcvars command-line: ${vcvars}`)
118+
119+
const old_environment = child_process.execSync(`set`, {shell: "cmd"}).toString().split('\r\n')
120+
const new_environment = child_process.execSync(`${vcvars} && set`, {shell: "cmd"}).toString().split('\r\n')
119121

120122
// If vsvars.bat is given an incorrect command line, it will print out
121123
// an error and *still* exit successfully. Parse out errors from output
122124
// which don't look like environment variables, and fail if appropriate.
123125
var failed = false
124-
for (let line of environment) {
126+
for (let line of new_environment) {
125127
if (line.match(/^\[ERROR.*\]/)) {
126128
failed = true
127129
// Don't print this particular line which will be confusing in output.
@@ -135,15 +137,39 @@ function main() {
135137
throw new Error('invalid parameters')
136138
}
137139

138-
for (let string of environment) {
140+
// Convert old environment lines into a dictionary for easier lookup.
141+
let old_env_vars = {}
142+
for (let string of old_environment) {
139143
const [name, value] = string.split('=')
140-
for (let pattern of InterestingVariables) {
141-
if (name.match(pattern)) {
142-
core.exportVariable(name, value)
143-
break
144+
old_env_vars[name] = value
145+
}
146+
147+
// Now look at the new environment and export everything that changed.
148+
// These are the variables set by vsvars.bat. Also export everything
149+
// that was not there during the first sweep: those are new variables.
150+
core.startGroup('Environment variables')
151+
for (let string of new_environment) {
152+
// vsvars.bat likes to print some fluff at the beginning.
153+
// Skip lines that don't look like environment variables.
154+
if (!string.includes('=')) {
155+
continue;
156+
}
157+
let [name, new_value] = string.split('=')
158+
let old_value = old_env_vars[name]
159+
// For new variables "old_value === undefined".
160+
if (new_value !== old_value) {
161+
core.info(`Setting ${name}`)
162+
// Special case for a bunch of PATH-like variables: vcvarsall.bat
163+
// just prepends its stuff without checking if its already there.
164+
// This makes repeated invocations of this action fail after some
165+
// point, when the environment variable overflows. Avoid that.
166+
if (isPathVariable(name)) {
167+
new_value = filterPathValue(new_value)
144168
}
169+
core.exportVariable(name, new_value)
145170
}
146171
}
172+
core.endGroup()
147173

148174
core.info(`Configured Developer Command Prompt`)
149175
}

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "msvc-dev-cmd",
3-
"version": "1.6.0",
3+
"version": "1.8.0",
44
"description": "GitHub Action to setup Developer Command Prompt for Microsoft Visual C++",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)