Skip to content

Commit 492e918

Browse files
authored
builder,pref: allow thirdparty objects compilation with CPP compiler (#19124)
1 parent 9543123 commit 492e918

File tree

9 files changed

+107
-12
lines changed

9 files changed

+107
-12
lines changed

cmd/tools/modules/testing/common.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ pub fn new_test_session(_vargs string, will_compile bool) TestSession {
187187
skip_files << 'examples/coroutines/simple_coroutines.v'
188188
$if msvc {
189189
skip_files << 'vlib/v/tests/const_comptime_eval_before_vinit_test.v' // _constructor used
190+
skip_files << 'vlib/v/tests/project_with_cpp_code/compiling_cpp_files_with_a_cplusplus_compiler_test.v'
190191
}
191192
$if solaris {
192193
skip_files << 'examples/gg/gg2.v'

cmd/tools/vtest-self.v

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ const (
170170
'vlib/orm/orm_insert_reserved_name_test.v',
171171
'vlib/v/tests/orm_sub_array_struct_test.v',
172172
'vlib/v/tests/orm_handle_error_for_select_from_not_created_table_test.v',
173+
'vlib/v/tests/project_with_cpp_code/compiling_cpp_files_with_a_cplusplus_compiler_test.v', // fails compilation with: undefined reference to vtable for __cxxabiv1::__function_type_info'
173174
]
174175
skip_with_werror = [
175176
'do_not_remove',
@@ -243,6 +244,7 @@ const (
243244
'vlib/v/tests/const_fixed_array_containing_references_to_itself_test.v', // error C2099: initializer is not a constant
244245
'vlib/v/tests/const_and_global_with_same_name_test.v', // error C2099: initializer is not a constant
245246
'vlib/v/tests/sumtype_as_cast_test.v', // error: cannot support compound statement expression ({expr; expr; expr;})
247+
'vlib/v/tests/project_with_cpp_code/compiling_cpp_files_with_a_cplusplus_compiler_test.v', // TODO
246248
]
247249
skip_on_windows = [
248250
'do_not_remove',
@@ -333,6 +335,7 @@ fn main() {
333335
}
334336

335337
if github_job == 'windows-tcc' {
338+
tsession.skip_files << 'vlib/v/tests/project_with_cpp_code/compiling_cpp_files_with_a_cplusplus_compiler_test.v'
336339
// TODO: fix these ASAP
337340
tsession.skip_files << 'vlib/net/tcp_test.v'
338341
tsession.skip_files << 'vlib/net/udp_test.v'

vlib/v/builder/cc.v

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ import v.util
1010
import v.vcache
1111
import term
1212

13+
const (
14+
c_std = 'c99'
15+
c_std_gnu = 'gnu99'
16+
cpp_std = 'c++17'
17+
cpp_std_gnu = 'gnu++17'
18+
)
19+
1320
const c_verror_message_marker = 'VERROR_MESSAGE '
1421

1522
const c_error_info = '
@@ -131,13 +138,6 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
131138
// arguments for the C compiler
132139
ccoptions.args = [v.pref.cflags]
133140
ccoptions.ldflags = [v.pref.ldflags]
134-
if !v.pref.no_std {
135-
if v.pref.os == .linux {
136-
ccoptions.args << '-std=gnu99 -D_DEFAULT_SOURCE'
137-
} else {
138-
ccoptions.args << '-std=c99 -D_DEFAULT_SOURCE'
139-
}
140-
}
141141
ccoptions.wargs = [
142142
'-Wall',
143143
'-Wextra',
@@ -343,6 +343,14 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
343343
if v.pref.os == .macos {
344344
ccoptions.source_args << '-x none'
345345
}
346+
if !v.pref.no_std {
347+
if v.pref.os == .linux {
348+
ccoptions.source_args << '-std=${builder.c_std_gnu}'
349+
} else {
350+
ccoptions.source_args << '-std=${builder.c_std}'
351+
}
352+
ccoptions.source_args << '-D_DEFAULT_SOURCE'
353+
}
346354
// Min macos version is mandatory I think?
347355
if v.pref.os == .macos {
348356
ccoptions.post_args << '-mmacosx-version-min=10.7'
@@ -396,7 +404,7 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
396404
// setup the cache too, so that different compilers/options do not interfere:
397405
v.pref.cache_manager.set_temporary_options(v.thirdparty_object_args(v.ccoptions, [
398406
ccoptions.guessed_compiler,
399-
]))
407+
], false))
400408
}
401409

402410
fn (v &Builder) all_args(ccoptions CcompilerOptions) []string {
@@ -437,8 +445,26 @@ fn (v &Builder) all_args(ccoptions CcompilerOptions) []string {
437445
return all
438446
}
439447

440-
fn (v &Builder) thirdparty_object_args(ccoptions CcompilerOptions, middle []string) []string {
448+
fn (v &Builder) thirdparty_object_args(ccoptions CcompilerOptions, middle []string, cpp_file bool) []string {
441449
mut all := []string{}
450+
451+
if !v.pref.no_std {
452+
if v.pref.os == .linux {
453+
if cpp_file {
454+
all << '-std=${builder.cpp_std_gnu}'
455+
} else {
456+
all << '-std=${builder.c_std_gnu}'
457+
}
458+
} else {
459+
if cpp_file {
460+
all << '-std=${builder.cpp_std}'
461+
} else {
462+
all << '-std=${builder.c_std}'
463+
}
464+
}
465+
all << '-D_DEFAULT_SOURCE'
466+
}
467+
442468
all << ccoptions.env_cflags
443469
all << ccoptions.args
444470
all << middle
@@ -888,7 +914,13 @@ fn (mut b Builder) build_thirdparty_obj_files() {
888914

889915
fn (mut v Builder) build_thirdparty_obj_file(mod string, path string, moduleflags []cflag.CFlag) {
890916
obj_path := os.real_path(path)
891-
cfile := '${obj_path[..obj_path.len - 2]}.c'
917+
mut cfile := '${obj_path[..obj_path.len - 2]}.c'
918+
mut cpp_file := false
919+
if !os.exists(cfile) {
920+
// Guessed C file does not exist, so it may be a CPP file
921+
cfile += 'pp'
922+
cpp_file = true
923+
}
892924
opath := v.pref.cache_manager.mod_postfix_with_key2cpath(mod, '.o', obj_path)
893925
mut rebuild_reason_message := '${obj_path} not found, building it in ${opath} ...'
894926
if os.exists(opath) {
@@ -918,8 +950,17 @@ fn (mut v Builder) build_thirdparty_obj_file(mod string, path string, moduleflag
918950
all_options << moduleflags.c_options_before_target()
919951
all_options << '-o ${os.quoted_path(opath)}'
920952
all_options << '-c ${os.quoted_path(cfile)}'
921-
cc_options := v.thirdparty_object_args(v.ccoptions, all_options).join(' ')
922-
cmd := '${v.quote_compiler_name(v.pref.ccompiler)} ${cc_options}'
953+
cc_options := v.thirdparty_object_args(v.ccoptions, all_options, cpp_file).join(' ')
954+
955+
// If the third party object file requires a CPP file compilation, switch to a CPP compiler
956+
mut ccompiler := v.pref.ccompiler
957+
if cpp_file {
958+
$if trace_thirdparty_obj_files ? {
959+
println('>>> build_thirdparty_obj_files switched from compiler "${ccompiler}" to "${v.pref.cppcompiler}"')
960+
}
961+
ccompiler = v.pref.cppcompiler
962+
}
963+
cmd := '${v.quote_compiler_name(ccompiler)} ${cc_options}'
923964
$if trace_thirdparty_obj_files ? {
924965
println('>>> build_thirdparty_obj_files cmd: ${cmd}')
925966
}

vlib/v/pref/default.v

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ pub fn (mut p Preferences) fill_with_defaults() {
119119
if p.ccompiler == '' {
120120
p.default_c_compiler()
121121
}
122+
if p.cppcompiler == '' {
123+
p.default_cpp_compiler()
124+
}
122125
p.find_cc_if_cross_compiling()
123126
p.ccompiler_type = cc_from_string(p.ccompiler)
124127
p.is_test = p.path.ends_with('_test.v') || p.path.ends_with('_test.vv')
@@ -244,6 +247,14 @@ pub fn (mut p Preferences) default_c_compiler() {
244247
return
245248
}
246249

250+
pub fn (mut p Preferences) default_cpp_compiler() {
251+
if p.ccompiler.contains('clang') {
252+
p.cppcompiler = 'clang++'
253+
return
254+
}
255+
p.cppcompiler = 'c++'
256+
}
257+
247258
pub fn vexe_path() string {
248259
vexe := os.getenv('VEXE')
249260
if vexe != '' {

vlib/v/pref/pref.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ pub mut:
163163
m64 bool // true = generate 64-bit code, defaults to x64
164164
ccompiler string // the name of the C compiler used
165165
ccompiler_type CompilerType // the type of the C compiler used
166+
cppcompiler string // the name of the CPP compiler used
166167
third_party_option string
167168
building_v bool
168169
no_bounds_checking bool // `-no-bounds-checking` turns off *all* bounds checks for all functions at runtime, as if they all had been tagged with `[direct_array_access]`
@@ -738,6 +739,10 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
738739
res.build_options << '${arg} "${res.ccompiler}"'
739740
i++
740741
}
742+
'-c++' {
743+
res.cppcompiler = cmdline.option(current_args, '-c++', 'c++')
744+
i++
745+
}
741746
'-checker-match-exhaustive-cutoff-limit' {
742747
res.checker_match_exhaustive_cutoff_limit = cmdline.option(current_args,
743748
arg, '10').int()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module main
2+
3+
#flag @VMODROOT/implementation.o
4+
#include "@VMODROOT/implementation.h"
5+
6+
fn C.sizeof_char() int
7+
8+
fn test_the_implementation_object_file_was_compiled_with_a_c_plus_plus_compiler() {
9+
res := C.sizeof_char()
10+
dump(res)
11+
if res == sizeof(int) {
12+
eprintln('implementation.o was compiled with a C compiler. Fail.')
13+
} else if res == sizeof(char) {
14+
println('implementation.o was compiled with a C++ compiler. Good.')
15+
} else {
16+
eprintln(\\_(ツ)_/¯ ... unknown C/C++ compiler')
17+
}
18+
assert res == sizeof(char)
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// This file should be compiled with a C++ compiler:
2+
extern "C" {
3+
int sizeof_char(void);
4+
}
5+
6+
int sizeof_char(void) {
7+
// see https://stackoverflow.com/a/12887719/1023403
8+
return sizeof('a'); // 4 for C compilers, 1 for C++ compilers
9+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int sizeof_char(void);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Module {
2+
name: 'project_with_cpp_code',
3+
description: 'A simple project, containing a .cpp file with C++ code, that has to be compiled with a C++ compiler.',
4+
dependencies: []
5+
}

0 commit comments

Comments
 (0)