Skip to content

Commit 5f6259d

Browse files
committed
v: add VCACHE support for thirdparty object files and for v build-module
1 parent 89daec4 commit 5f6259d

File tree

6 files changed

+166
-35
lines changed

6 files changed

+166
-35
lines changed

vlib/v/builder/cc.v

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,21 @@ fn (mut v Builder) post_process_c_compiler_output(res os.Result) {
118118
verror(c_error_info)
119119
}
120120

121+
fn (mut v Builder) rebuild_cached_module(vexe string, imp_path string) string {
122+
res := v.pref.cache_manager.exists('.o', imp_path) or {
123+
println('Cached $imp_path .o file not found... Building .o file for $imp_path')
124+
boptions := v.pref.build_options.join(' ')
125+
rebuild_cmd := '$vexe $boptions build-module $imp_path'
126+
// eprintln('>> rebuild_cmd: $rebuild_cmd')
127+
os.system(rebuild_cmd)
128+
rebuilded_o := v.pref.cache_manager.exists('.o', imp_path) or {
129+
panic('could not rebuild cache module for $imp_path, error: $err')
130+
}
131+
return rebuilded_o
132+
}
133+
return res
134+
}
135+
121136
fn (mut v Builder) cc() {
122137
if os.executable().contains('vfmt') {
123138
return
@@ -260,14 +275,9 @@ fn (mut v Builder) cc() {
260275
linker_flags << '-nostdlib'
261276
}
262277
if v.pref.build_mode == .build_module {
263-
// Create the modules & out directory if it's not there.
264-
out_dir := os.join_path(pref.default_module_path, 'cache', v.pref.path)
265-
pdir := out_dir.all_before_last(os.path_separator)
266-
if !os.is_dir(pdir) {
267-
os.mkdir_all(pdir)
268-
}
269-
v.pref.out_name = '${out_dir}.o' // v.out_name
270-
println('Building ${v.pref.out_name}...')
278+
v.pref.out_name = v.pref.cache_manager.postfix_with_key2cpath('.o', v.pref.path) // v.out_name
279+
println('Building $v.pref.path to $v.pref.out_name ...')
280+
v.pref.cache_manager.save('.description.txt', v.pref.path, '${v.pref.path:-30} @ $v.pref.cache_manager.vopts\n')
271281
// println('v.table.imports:')
272282
// println(v.table.imports)
273283
}
@@ -349,10 +359,7 @@ fn (mut v Builder) cc() {
349359
args << '-c'
350360
} else if v.pref.use_cache {
351361
mut built_modules := []string{}
352-
builtin_obj_path := os.join_path(pref.default_module_path, 'cache', 'vlib', 'builtin.o')
353-
if !os.exists(builtin_obj_path) {
354-
os.system('$vexe build-module vlib/builtin')
355-
}
362+
builtin_obj_path := v.rebuild_cached_module(vexe, 'vlib/builtin')
356363
libs += ' ' + builtin_obj_path
357364
for ast_file in v.parsed_files {
358365
for imp_stmt in ast_file.imports {
@@ -382,14 +389,8 @@ fn (mut v Builder) cc() {
382389
// continue
383390
// }
384391
imp_path := os.join_path('vlib', mod_path)
385-
cache_path := os.join_path(pref.default_module_path, 'cache')
386-
obj_path := os.join_path(cache_path, '${imp_path}.o')
387-
if os.exists(obj_path) {
388-
libs += ' ' + obj_path
389-
} else {
390-
println('$obj_path not found... building module $imp')
391-
os.system('$vexe build-module $imp_path')
392-
}
392+
obj_path := v.rebuild_cached_module(vexe, imp_path)
393+
libs += ' ' + obj_path
393394
if obj_path.ends_with('vlib/ui.o') {
394395
args << '-framework Cocoa -framework Carbon'
395396
}
@@ -777,21 +778,19 @@ fn (mut v Builder) build_thirdparty_obj_file(path string, moduleflags []cflag.CF
777778
if v.pref.os == .windows {
778779
// Cross compiling for Windows
779780
$if !windows {
780-
if os.exists(obj_path) {
781-
os.rm(obj_path)
782-
}
783781
v.pref.ccompiler = mingw_cc
784782
}
785783
}
786-
if os.exists(obj_path) {
784+
opath := v.pref.cache_manager.postfix_with_key2cpath('.o', obj_path)
785+
if os.exists(opath) {
787786
return
788787
}
789-
println('$obj_path not found, building it...')
788+
println('$obj_path not found, building it in $opath ...')
790789
cfile := '${path[..path.len - 2]}.c'
791790
btarget := moduleflags.c_options_before_target()
792791
atarget := moduleflags.c_options_after_target()
793792
cppoptions := if v.pref.ccompiler.contains('++') { ' -fpermissive -w ' } else { '' }
794-
cmd := '$v.pref.ccompiler $cppoptions $v.pref.third_party_option $btarget -c -o "$obj_path" "$cfile" $atarget'
793+
cmd := '$v.pref.ccompiler $cppoptions $v.pref.third_party_option $btarget -c -o "$opath" "$cfile" $atarget'
795794
res := os.exec(cmd) or {
796795
eprintln('exec failed for thirdparty object build cmd:\n$cmd')
797796
verror(err)
@@ -802,6 +801,7 @@ fn (mut v Builder) build_thirdparty_obj_file(path string, moduleflags []cflag.CF
802801
verror(res.output)
803802
return
804803
}
804+
v.pref.cache_manager.save('.description.txt', obj_path, '${obj_path:-30} @ $cmd\n')
805805
println(res.output)
806806
}
807807

vlib/v/builder/cflags.v

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
module builder
22

3+
import os
34
import v.cflag
45

56
// get flags for current os
6-
fn (v &Builder) get_os_cflags() []cflag.CFlag {
7+
fn (mut v Builder) get_os_cflags() []cflag.CFlag {
78
mut flags := []cflag.CFlag{}
89
mut ctimedefines := []string{}
910
if v.pref.compile_defines.len > 0 {
1011
ctimedefines << v.pref.compile_defines
1112
}
12-
for flag in v.table.cflags {
13+
for mut flag in v.table.cflags {
14+
if flag.value.ends_with('.o') {
15+
flag.cached = v.pref.cache_manager.postfix_with_key2cpath('.o', os.real_path(flag.value))
16+
}
1317
if flag.os == '' ||
1418
(flag.os == 'linux' && v.pref.os == .linux) ||
1519
(flag.os == 'macos' && v.pref.os == .macos) ||
@@ -27,7 +31,7 @@ fn (v &Builder) get_os_cflags() []cflag.CFlag {
2731
return flags
2832
}
2933

30-
fn (v &Builder) get_rest_of_module_cflags(c &cflag.CFlag) []cflag.CFlag {
34+
fn (mut v Builder) get_rest_of_module_cflags(c &cflag.CFlag) []cflag.CFlag {
3135
mut flags := []cflag.CFlag{}
3236
cflags := v.get_os_cflags()
3337
for flag in cflags {

vlib/v/cflag/cflags.v

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,24 @@ import os
88
// parsed cflag
99
pub struct CFlag {
1010
pub:
11-
mod string // the module in which the flag was given
12-
os string // eg. windows | darwin | linux
13-
name string // eg. -I
14-
value string // eg. /path/to/include
11+
mod string // the module in which the flag was given
12+
os string // eg. windows | darwin | linux
13+
name string // eg. -I
14+
value string // eg. /path/to/include
15+
pub mut:
16+
cached string // eg. ~/.vmodules/cache/ea/ea9878886727367672163.o (for .o files)
1517
}
1618

1719
pub fn (c &CFlag) str() string {
18-
return 'CFlag{ name: "$c.name" value: "$c.value" mod: "$c.mod" os: "$c.os" }'
20+
return 'CFlag{ name: "$c.name" value: "$c.value" mod: "$c.mod" os: "$c.os" cached: "$c.cached" }'
1921
}
2022

2123
// format flag
2224
pub fn (cf &CFlag) format() string {
2325
mut value := cf.value
26+
if cf.cached != '' {
27+
value = cf.cached
28+
}
2429
if cf.name in ['-l', '-Wa', '-Wl', '-Wp'] && value.len > 0 {
2530
return '$cf.name$value'.trim_space()
2631
}

vlib/v/pref/default.v

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,17 @@ pub fn (mut p Preferences) fill_with_defaults() {
7171
}
7272
}
7373
}
74+
// Prepare the cache manager. All options that can affect the generated cached .c files
75+
// should go into res.cache_manager.vopts, which is used as a salt for the cache hash.
76+
p.cache_manager = new_cache_manager([
77+
'$p.backend | $p.os | $p.ccompiler',
78+
p.cflags.trim_space(),
79+
p.third_party_option.trim_space(),
80+
'$p.compile_defines_all',
81+
'$p.compile_defines',
82+
'$p.lookup_path',
83+
])
84+
// eprintln('prefs.cache_manager: $p')
7485
}
7586

7687
fn default_c_compiler() string {

vlib/v/pref/pref.v

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ pub mut:
129129
is_ios_simulator bool
130130
is_apk bool // build as Android .apk format
131131
cleanup_files []string // list of temporary *.tmp.c and *.tmp.c.rsp files. Cleaned up on successfull builds.
132+
build_options []string // list of options, that should be passed down to `build-module`, if needed for -usecache
133+
cache_manager CacheManager
132134
}
133135

134136
pub fn parse_args(args []string) (&Preferences, string) {
@@ -142,6 +144,7 @@ pub fn parse_args(args []string) (&Preferences, string) {
142144
match arg {
143145
'-apk' {
144146
res.is_apk = true
147+
res.build_options << arg
145148
}
146149
'-show-timings' {
147150
res.show_timings = true
@@ -167,10 +170,12 @@ pub fn parse_args(args []string) (&Preferences, string) {
167170
'-g' {
168171
res.is_debug = true
169172
res.is_vlines = true
173+
res.build_options << arg
170174
}
171175
'-cg' {
172176
res.is_debug = true
173177
res.is_vlines = false
178+
res.build_options << arg
174179
}
175180
'-repl' {
176181
res.is_repl = true
@@ -190,26 +195,31 @@ pub fn parse_args(args []string) (&Preferences, string) {
190195
}
191196
'-autofree' {
192197
res.autofree = true
198+
res.build_options << arg
193199
}
194200
'-compress' {
195201
res.compress = true
196202
}
197203
'-freestanding' {
198204
res.is_bare = true
205+
res.build_options << arg
199206
}
200207
'-no-preludes' {
201208
res.no_preludes = true
209+
res.build_options << arg
202210
}
203211
'-prof', '-profile' {
204212
res.profile_file = cmdline.option(current_args, '-profile', '-')
205213
res.is_prof = true
214+
res.build_options << '$arg $res.profile_file'
206215
i++
207216
}
208217
'-profile-no-inline' {
209218
res.profile_no_inline = true
210219
}
211220
'-prod' {
212221
res.is_prod = true
222+
res.build_options << arg
213223
}
214224
'-simulator' {
215225
res.is_ios_simulator = true
@@ -240,6 +250,7 @@ pub fn parse_args(args []string) (&Preferences, string) {
240250
}
241251
'-prealloc' {
242252
res.prealloc = true
253+
res.build_options << arg
243254
}
244255
'-keepc' {
245256
eprintln('-keepc is deprecated. V always keeps the generated .tmp.c files now.')
@@ -249,6 +260,7 @@ pub fn parse_args(args []string) (&Preferences, string) {
249260
}
250261
'-x64' {
251262
res.backend = .x64
263+
res.build_options << arg
252264
}
253265
'-W' {
254266
res.warns_are_errors = true
@@ -277,13 +289,15 @@ pub fn parse_args(args []string) (&Preferences, string) {
277289
exit(1)
278290
}
279291
res.os = target_os_kind
292+
res.build_options << '$arg $target_os'
280293
}
281294
'-printfn' {
282295
res.printfn_list << cmdline.option(current_args, '-printfn', '')
283296
i++
284297
}
285298
'-cflags' {
286299
res.cflags += ' ' + cmdline.option(current_args, '-cflags', '')
300+
res.build_options << '$arg "$res.cflags.trim_space()"'
287301
i++
288302
}
289303
'-define', '-d' {
@@ -295,26 +309,31 @@ pub fn parse_args(args []string) (&Preferences, string) {
295309
}
296310
'-cc' {
297311
res.ccompiler = cmdline.option(current_args, '-cc', 'cc')
312+
res.build_options << '$arg "$res.ccompiler"'
298313
i++
299314
}
300315
'-o' {
301316
res.out_name = cmdline.option(current_args, '-o', '')
302317
i++
303318
}
304319
'-b' {
305-
b := backend_from_string(cmdline.option(current_args, '-b', 'c')) or {
320+
sbackend := cmdline.option(current_args, '-b', 'c')
321+
res.build_options << '$arg $sbackend'
322+
b := backend_from_string(sbackend) or {
306323
continue
307324
}
308325
res.backend = b
309326
i++
310327
}
311328
'-path' {
312329
path := cmdline.option(current_args, '-path', '')
330+
res.build_options << '$arg "$path"'
313331
res.lookup_path = path.replace('|', os.path_delimiter).split(os.path_delimiter)
314332
i++
315333
}
316334
'-custom-prelude' {
317335
path := cmdline.option(current_args, '-custom-prelude', '')
336+
res.build_options << '$arg $path'
318337
prelude := os.read_file(path) or {
319338
eprintln('cannot open custom prelude file: $err')
320339
exit(1)
@@ -390,6 +409,13 @@ pub fn parse_args(args []string) (&Preferences, string) {
390409
res.build_mode = .build_module
391410
res.path = args[command_pos + 1]
392411
}
412+
// keep only the unique res.build_options:
413+
mut m := map[string]string{}
414+
for x in res.build_options {
415+
m[x] = ''
416+
}
417+
res.build_options = m.keys()
418+
// eprintln('>> res.build_options: $res.build_options')
393419
res.fill_with_defaults()
394420
return res, command
395421
}

0 commit comments

Comments
 (0)