Repository navigation
Expand file tree
/
Copy pathsetup.vsh
More file actions
294 lines (275 loc) · 9.33 KB
/
Copy pathsetup.vsh
File metadata and controls
294 lines (275 loc) · 9.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#!/usr/bin/env -S v run
// Installs optional native tooling and verifies the bundled build inputs.
// Running without arguments performs the installation. Use --check for a
// read-only diagnostic pass suitable for support requests and CI.
import os
const usage = 'Usage: v run setup.vsh [--install|--check]\n\n' +
' --install Install native Vulkan tools and this V module (default).\n' + ' --check Report whether the compiler, bundled headers, loader and device work.\n'
fn command_exists(name string) bool {
os.find_abs_path_of_executable(name) or { return false }
return true
}
fn run(command string) ! {
println('\n> ${command}')
result := os.execute(command)
if result.output.trim_space() != '' {
println(result.output.trim_right('\r\n'))
}
if result.exit_code != 0 {
return error('command failed with exit code ${result.exit_code}')
}
}
fn install_linux() ! {
if command_exists('apt-get') {
run('sudo apt-get update')!
run('sudo apt-get install -y build-essential libvulkan1 mesa-vulkan-drivers vulkan-tools')!
return
}
if command_exists('dnf') {
run('sudo dnf install -y gcc gcc-c++ vulkan-loader vulkan-tools mesa-vulkan-drivers')!
return
}
if command_exists('pacman') {
run('sudo pacman -S --needed --noconfirm base-devel vulkan-icd-loader vulkan-tools')!
return
}
if command_exists('zypper') {
run('sudo zypper --non-interactive install -y gcc gcc-c++ vulkan-tools')!
return
}
return error('unsupported Linux package manager; install a C compiler, the Vulkan loader, vulkaninfo and a Vulkan ICD, then rerun with --check')
}
fn install_macos() ! {
if !command_exists('curl') || !command_exists('ditto') {
return error('curl and ditto are required for automatic macOS setup')
}
cache_root := os.join_path(os.cache_dir(), 'antono2', 'vulkan-sdk')
archive := os.join_path(cache_root, 'vulkan_sdk.zip')
unpacked := os.join_path(cache_root, 'unpacked')
os.mkdir_all(unpacked)!
run('curl --fail --location --output ${os.quoted_path(archive)} https://sdk.lunarg.com/sdk/download/latest/mac/vulkan_sdk.zip')!
run('ditto -x -k ${os.quoted_path(archive)} ${os.quoted_path(unpacked)}')!
found :=
os.execute('find ${os.quoted_path(unpacked)} -type f -path "*/InstallVulkan*.app/Contents/MacOS/InstallVulkan*" -print -quit')
installer := found.output.trim_space()
if found.exit_code != 0 || installer == '' {
return error('the downloaded Vulkan SDK did not contain the expected macOS installer')
}
install_root := os.join_path(os.home_dir(), 'VulkanSDK')
run('sudo ${os.quoted_path(installer)} --root ${os.quoted_path(install_root)} --accept-licenses --default-answer --confirm-command install com.lunarg.vulkan.core com.lunarg.vulkan.usr com.lunarg.vulkan.volk')!
}
fn windows_vulkan_sdk() string {
mut candidates := [os.getenv('VULKAN_SDK')]
machine_value :=
os.execute('powershell -NoProfile -Command "[Environment]::GetEnvironmentVariable(\'VULKAN_SDK\', \'Machine\')"')
if machine_value.exit_code == 0 {
candidates << machine_value.output.trim_space()
}
for candidate in candidates {
if candidate == '' {
continue
}
for relative in ['include/vulkan/vulkan.h', 'Include/vulkan/vulkan.h'] {
if os.is_file(os.join_path(candidate, relative)) {
return candidate
}
}
}
return ''
}
fn install_windows() ! {
installed_sdk := windows_vulkan_sdk()
if installed_sdk != '' {
os.setenv('VULKAN_SDK', installed_sdk, true)
println('Using the installed Vulkan SDK at ${installed_sdk}.')
return
}
if !command_exists('winget') {
return error('winget is required for automatic Windows setup; install Microsoft App Installer, then try again')
}
run('winget install --id KhronosGroup.VulkanSDK --exact --accept-package-agreements --accept-source-agreements')!
sdk_root := windows_vulkan_sdk()
if sdk_root == '' {
return error('the Vulkan SDK installer completed, but no installation containing Vulkan headers was found')
}
os.setenv('VULKAN_SDK', sdk_root, true)
println('\nThe Vulkan SDK installer updates VULKAN_SDK and PATH for new terminals.')
}
fn install_native() ! {
$if linux {
install_linux()!
} $else $if macos {
install_macos()!
} $else $if windows {
install_windows()!
} $else {
return error('automatic setup is not supported on this operating system')
}
}
fn find_vulkan_header() string {
return os.join_path(os.dir(@FILE), 'c', 'vendor', 'include', 'vulkan', 'vulkan.h')
}
fn find_volk_header() string {
return os.join_path(os.dir(@FILE), 'c', 'vendor', 'volk', 'volk.h')
}
struct HeaderVersion {
mut:
major int
minor int
patch int
}
fn (version HeaderVersion) str() string {
return '${version.major}.${version.minor}.${version.patch}'
}
fn parse_registry_version(text string) ?HeaderVersion {
parts := text.trim_space().trim_string_left('v').split('.')
if parts.len != 3 {
return none
}
version := HeaderVersion{
major: parts[0].int()
minor: parts[1].int()
patch: parts[2].int()
}
if version.major == 0 || version.patch == 0 {
return none
}
return version
}
fn installed_header_version(header string) ?HeaderVersion {
core := os.read_file(os.join_path(os.dir(header), 'vulkan_core.h')) or { return none }
mut version := HeaderVersion{
minor: -1
}
for line in core.split_into_lines() {
trimmed := line.trim_space()
if trimmed.starts_with('#define VK_HEADER_VERSION ') {
version.patch = trimmed.all_after('#define VK_HEADER_VERSION ').trim_space().int()
} else if trimmed.starts_with('#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(') {
parts := trimmed.all_after('VK_MAKE_API_VERSION(').all_before(')').split(',')
if parts.len == 4 {
version.major = parts[1].trim_space().int()
version.minor = parts[2].trim_space().int()
}
}
}
if version.major == 0 || version.minor < 0 || version.patch == 0 {
return none
}
return version
}
fn (version HeaderVersion) older_than(other HeaderVersion) bool {
if version.major != other.major {
return version.major < other.major
}
if version.minor != other.minor {
return version.minor < other.minor
}
return version.patch < other.patch
}
fn report_command(name string, required bool) bool {
if path := os.find_abs_path_of_executable(name) {
println('[ok] ${name}: ${path}')
return true
}
label := if required { 'missing' } else { 'optional' }
println('[${label}] ${name}')
return !required
}
fn check() bool {
println('\nVulkan setup check')
println('------------------')
mut ok := true
ok = report_command('v', true) && ok
$if windows {
report_command('cl', false)
} $else {
ok = report_command('cc', true) && ok
}
header := find_vulkan_header()
if !os.is_file(header) {
println('[missing] Bundled Vulkan header: ${header}')
ok = false
} else {
println('[ok] Bundled Vulkan header: ${header}')
required_text := os.read_file(os.join_path(os.dir(@FILE), 'VERSION')) or { '' }
required := parse_registry_version(required_text) or {
println('[warning] Could not read the binding registry version from VERSION')
ok = false
HeaderVersion{}
}
bundled := installed_header_version(header) or {
println('[warning] Could not determine the bundled Vulkan header version')
ok = false
HeaderVersion{}
}
if required.major > 0 && bundled.major > 0 {
if bundled.older_than(required) {
println('[outdated] Bundled Vulkan headers ${bundled}; bindings use registry ${required}')
ok = false
} else {
println('[ok] Bundled Vulkan headers ${bundled} cover registry ${required}')
}
}
}
volk := find_volk_header()
if !os.is_file(volk) || !os.is_file(os.join_path(os.dir(volk), 'volk.c')) {
println('[missing] Bundled Volk sources: ${os.dir(volk)}')
ok = false
} else {
println('[ok] Bundled Volk sources: ${os.dir(volk)}')
}
if command_exists('vulkaninfo') {
// Some SDK builds write their update manifest into the process working
// directory. Keep diagnostics from leaving residue in the user's repo.
original_directory := os.getwd()
os.chdir(os.temp_dir()) or {
println('[warning] Could not enter the temporary directory for Vulkan diagnostics: ${err}')
return ok
}
defer {
os.chdir(original_directory) or {}
}
// V's Windows os.execute rejects shell command chaining. Change the
// directory through the OS API so the probe actually runs on Windows.
result := os.execute('vulkaninfo --summary')
if result.exit_code == 0 {
println('[ok] Vulkan loader enumerated a physical device')
} else {
println('[warning] vulkaninfo is installed, but no usable device was enumerated')
println(' Install or update the GPU vendor driver; the SDK does not provide a hardware driver.')
}
} else {
println('[warning] vulkaninfo is unavailable; Vulkan loader/device verification was skipped')
}
return ok
}
fn main() {
if os.args.len > 2
|| (os.args.len == 2 && os.args[1] !in ['--install', '--check', '-h', '--help']) {
eprintln(usage)
exit(2)
}
if os.args.len == 2 && os.args[1] in ['-h', '--help'] {
println(usage)
return
}
install := os.args.len == 1 || os.args[1] == '--install'
if install {
install_native() or {
eprintln('Setup failed: ${err}')
exit(1)
}
if command_exists('v') {
run('v install antono2.vulkan') or {
eprintln('Could not install the V module: ${err}')
exit(1)
}
}
}
if !check() {
eprintln('\nSetup is incomplete. Resolve the missing items above and rerun with --check.')
exit(1)
}
println('\nVulkan module build prerequisites are ready; check runtime warnings above.')
}