Skip to content

Commit 343f94c

Browse files
builder: fix Windows pkgconfig paths and MSVC flags (#26631)
1 parent 849edf4 commit 343f94c

3 files changed

Lines changed: 134 additions & 5 deletions

File tree

‎vlib/v/builder/msvc_windows.v‎

Lines changed: 131 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -523,13 +523,116 @@ mut:
523523
other_flags []string
524524
}
525525

526+
fn strip_quotes(value string) string {
527+
if value.len >= 2 && value[0] == `"` && value[value.len - 1] == `"` {
528+
return value[1..value.len - 1]
529+
}
530+
return value
531+
}
532+
533+
fn apply_gnu_flag_to_msvc(value string, mut inc_paths []string, mut lib_paths []string, mut real_libs []string) bool {
534+
v := strip_quotes(value)
535+
if v.starts_with('-I') && v.len > 2 {
536+
path := v[2..]
537+
inc_paths << '/I"${os.real_path(path)}"'
538+
return true
539+
}
540+
if v.starts_with('-L') && v.len > 2 {
541+
path := v[2..]
542+
lib_paths << path
543+
lib_paths << path + os.path_separator + 'msvc'
544+
return true
545+
}
546+
if v.starts_with('-l') && v.len > 2 {
547+
mut lib := v[2..]
548+
if lib.starts_with(':') && lib.len > 1 {
549+
lib = lib[1..]
550+
}
551+
if !lib.ends_with('.lib') {
552+
lib += '.lib'
553+
}
554+
real_libs << lib
555+
return true
556+
}
557+
if v.starts_with('-Wl,') {
558+
mut consumed := false
559+
for part in v[4..].split(',') {
560+
if apply_gnu_flag_to_msvc(part, mut inc_paths, mut lib_paths, mut real_libs) {
561+
consumed = true
562+
}
563+
}
564+
return consumed
565+
}
566+
return false
567+
}
568+
569+
fn split_and_apply_gnu_flags(value string, mut inc_paths []string, mut lib_paths []string, mut real_libs []string) (bool, string) {
570+
if !value.contains(' ') {
571+
if apply_gnu_flag_to_msvc(value, mut inc_paths, mut lib_paths, mut real_libs) {
572+
return true, ''
573+
}
574+
return false, value
575+
}
576+
parts := split_quoted_flags(value)
577+
mut consumed := false
578+
mut leftovers := []string{}
579+
for part in parts {
580+
if part == '' {
581+
continue
582+
}
583+
if apply_gnu_flag_to_msvc(part, mut inc_paths, mut lib_paths, mut real_libs) {
584+
consumed = true
585+
} else {
586+
leftovers << strip_quotes(part)
587+
}
588+
}
589+
if consumed {
590+
return true, leftovers.join(' ')
591+
}
592+
return false, value
593+
}
594+
595+
fn split_quoted_flags(value string) []string {
596+
mut parts := []string{}
597+
mut buf := []u8{}
598+
mut in_quote := false
599+
for ch in value {
600+
if ch == `"` {
601+
in_quote = !in_quote
602+
continue
603+
}
604+
if !in_quote && ch == ` ` {
605+
if buf.len > 0 {
606+
parts << buf.bytestr()
607+
buf = []u8{}
608+
}
609+
continue
610+
}
611+
buf << ch
612+
}
613+
if buf.len > 0 {
614+
parts << buf.bytestr()
615+
}
616+
return parts
617+
}
618+
526619
pub fn (mut v Builder) msvc_string_flags(cflags []cflag.CFlag) MsvcStringFlags {
527620
mut real_libs := []string{}
528621
mut inc_paths := []string{}
529622
mut lib_paths := []string{}
530623
mut defines := []string{}
531624
mut other_flags := []string{}
532625
for flag in cflags {
626+
if flag.name == '' {
627+
consumed, leftover := split_and_apply_gnu_flags(flag.value, mut inc_paths, mut
628+
lib_paths, mut real_libs)
629+
if consumed {
630+
if leftover != '' {
631+
other_flags << strip_quotes(leftover)
632+
}
633+
continue
634+
}
635+
}
533636
// println('fl: ${flag.name} | flag arg: ${flag.value}')
534637
// We need to see if the flag contains -l
535638
// -l isnt recognised and these libs will be passed straight to the linker
@@ -540,14 +643,29 @@ pub fn (mut v Builder) msvc_string_flags(cflags []cflag.CFlag) MsvcStringFlags {
540643
}
541644
// MSVC has no method of linking against a .dll
542645
// TODO: we should look for .defs aswell
543-
lib_lib := flag.value + '.lib'
544-
real_libs << lib_lib
646+
parts := split_quoted_flags(flag.value)
647+
if parts.len > 0 {
648+
mut lib := strip_quotes(parts[0])
649+
if lib.starts_with(':') && lib.len > 1 {
650+
lib = lib[1..]
651+
}
652+
if !lib.ends_with('.lib') {
653+
lib += '.lib'
654+
}
655+
real_libs << lib
656+
if parts.len > 1 {
657+
_, leftover := split_and_apply_gnu_flags(parts[1..].join(' '), mut
658+
inc_paths, mut lib_paths, mut real_libs)
659+
if leftover != '' {
660+
other_flags << strip_quotes(leftover)
661+
}
662+
}
663+
}
545664
} else if flag.name == '-I' {
546-
inc_paths << flag.format() or { continue }
665+
inc_paths << '/I"${os.real_path(flag.value)}"'
547666
} else if flag.name == '-D' {
548667
defines << '/D${flag.value}'
549668
} else if flag.name == '-L' {
550-
// TODO: use flag.format() here as well; `#flag -L$when_first_existing(...)` is a more explicit way to achieve the same
551669
lib_paths << flag.value
552670
lib_paths << flag.value + os.path_separator + 'msvc'
553671
// The above allows putting msvc specific .lib files in a subfolder msvc/ ,
@@ -567,7 +685,15 @@ pub fn (mut v Builder) msvc_string_flags(cflags []cflag.CFlag) MsvcStringFlags {
567685
} else if flag.value.starts_with('-D') {
568686
defines << '/D${flag.value[2..]}'
569687
} else {
570-
other_flags << flag.value
688+
consumed, leftover := split_and_apply_gnu_flags(flag.value, mut inc_paths, mut
689+
lib_paths, mut real_libs)
690+
if consumed {
691+
if leftover != '' {
692+
other_flags << strip_quotes(leftover)
693+
}
694+
continue
695+
}
696+
other_flags << strip_quotes(flag.value)
571697
}
572698
}
573699
mut lpaths := []string{}

‎vlib/v/pkgconfig/pkgconfig.v‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ fn (mut pc PkgConfig) setvar(line string) {
100100

101101
fn (mut pc PkgConfig) parse(file string) bool {
102102
pc.file_path = file
103+
pc.vars['pcfiledir'] = os.real_path(os.dir(file))
103104
data := os.read_file(file) or { return false }
104105
if pc.options.debug {
105106
eprintln(data)

‎vlib/v/pkgconfig/pkgconfig_test.v‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ fn test_samples() {
5757
assert x.cflags == ['-I/usr/include', '-pthread', '-I/usr/include/glib-2.0',
5858
'-I/usr/lib/x86_64-linux-gnu/glib-2.0/include']
5959
assert x.vars == {
60+
'pcfiledir': samples_dir
6061
'prefix': '/usr'
6162
'libdir': '/usr/lib/x86_64-linux-gnu'
6263
'includedir': '/usr/include'
@@ -76,6 +77,7 @@ fn test_samples() {
7677
assert x.cflags == ['-I/usr/include/glib-2.0',
7778
'-I/usr/lib/x86_64-linux-gnu/glib-2.0/include', '-I/usr/include']
7879
assert x.vars == {
80+
'pcfiledir': samples_dir
7981
'prefix': '/usr'
8082
'libdir': '/usr/lib/x86_64-linux-gnu'
8183
'includedir': '/usr/include'

0 commit comments

Comments
 (0)