Skip to content

Commit

Permalink
builder,pref: allow thirdparty objects compilation with CPP compiler (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
lenaing authored Aug 13, 2023
1 parent 9543123 commit 492e918
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 12 deletions.
1 change: 1 addition & 0 deletions cmd/tools/modules/testing/common.v
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ pub fn new_test_session(_vargs string, will_compile bool) TestSession {
skip_files << 'examples/coroutines/simple_coroutines.v'
$if msvc {
skip_files << 'vlib/v/tests/const_comptime_eval_before_vinit_test.v' // _constructor used
skip_files << 'vlib/v/tests/project_with_cpp_code/compiling_cpp_files_with_a_cplusplus_compiler_test.v'
}
$if solaris {
skip_files << 'examples/gg/gg2.v'
Expand Down
3 changes: 3 additions & 0 deletions cmd/tools/vtest-self.v
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ const (
'vlib/orm/orm_insert_reserved_name_test.v',
'vlib/v/tests/orm_sub_array_struct_test.v',
'vlib/v/tests/orm_handle_error_for_select_from_not_created_table_test.v',
'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'
]
skip_with_werror = [
'do_not_remove',
Expand Down Expand Up @@ -243,6 +244,7 @@ const (
'vlib/v/tests/const_fixed_array_containing_references_to_itself_test.v', // error C2099: initializer is not a constant
'vlib/v/tests/const_and_global_with_same_name_test.v', // error C2099: initializer is not a constant
'vlib/v/tests/sumtype_as_cast_test.v', // error: cannot support compound statement expression ({expr; expr; expr;})
'vlib/v/tests/project_with_cpp_code/compiling_cpp_files_with_a_cplusplus_compiler_test.v', // TODO
]
skip_on_windows = [
'do_not_remove',
Expand Down Expand Up @@ -333,6 +335,7 @@ fn main() {
}

if github_job == 'windows-tcc' {
tsession.skip_files << 'vlib/v/tests/project_with_cpp_code/compiling_cpp_files_with_a_cplusplus_compiler_test.v'
// TODO: fix these ASAP
tsession.skip_files << 'vlib/net/tcp_test.v'
tsession.skip_files << 'vlib/net/udp_test.v'
Expand Down
65 changes: 53 additions & 12 deletions vlib/v/builder/cc.v
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import v.util
import v.vcache
import term

const (
c_std = 'c99'
c_std_gnu = 'gnu99'
cpp_std = 'c++17'
cpp_std_gnu = 'gnu++17'
)

const c_verror_message_marker = 'VERROR_MESSAGE '

const c_error_info = '
Expand Down Expand Up @@ -131,13 +138,6 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
// arguments for the C compiler
ccoptions.args = [v.pref.cflags]
ccoptions.ldflags = [v.pref.ldflags]
if !v.pref.no_std {
if v.pref.os == .linux {
ccoptions.args << '-std=gnu99 -D_DEFAULT_SOURCE'
} else {
ccoptions.args << '-std=c99 -D_DEFAULT_SOURCE'
}
}
ccoptions.wargs = [
'-Wall',
'-Wextra',
Expand Down Expand Up @@ -343,6 +343,14 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
if v.pref.os == .macos {
ccoptions.source_args << '-x none'
}
if !v.pref.no_std {
if v.pref.os == .linux {
ccoptions.source_args << '-std=${builder.c_std_gnu}'
} else {
ccoptions.source_args << '-std=${builder.c_std}'
}
ccoptions.source_args << '-D_DEFAULT_SOURCE'
}
// Min macos version is mandatory I think?
if v.pref.os == .macos {
ccoptions.post_args << '-mmacosx-version-min=10.7'
Expand Down Expand Up @@ -396,7 +404,7 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
// setup the cache too, so that different compilers/options do not interfere:
v.pref.cache_manager.set_temporary_options(v.thirdparty_object_args(v.ccoptions, [
ccoptions.guessed_compiler,
]))
], false))
}

fn (v &Builder) all_args(ccoptions CcompilerOptions) []string {
Expand Down Expand Up @@ -437,8 +445,26 @@ fn (v &Builder) all_args(ccoptions CcompilerOptions) []string {
return all
}

fn (v &Builder) thirdparty_object_args(ccoptions CcompilerOptions, middle []string) []string {
fn (v &Builder) thirdparty_object_args(ccoptions CcompilerOptions, middle []string, cpp_file bool) []string {
mut all := []string{}

if !v.pref.no_std {
if v.pref.os == .linux {
if cpp_file {
all << '-std=${builder.cpp_std_gnu}'
} else {
all << '-std=${builder.c_std_gnu}'
}
} else {
if cpp_file {
all << '-std=${builder.cpp_std}'
} else {
all << '-std=${builder.c_std}'
}
}
all << '-D_DEFAULT_SOURCE'
}

all << ccoptions.env_cflags
all << ccoptions.args
all << middle
Expand Down Expand Up @@ -888,7 +914,13 @@ fn (mut b Builder) build_thirdparty_obj_files() {

fn (mut v Builder) build_thirdparty_obj_file(mod string, path string, moduleflags []cflag.CFlag) {
obj_path := os.real_path(path)
cfile := '${obj_path[..obj_path.len - 2]}.c'
mut cfile := '${obj_path[..obj_path.len - 2]}.c'
mut cpp_file := false
if !os.exists(cfile) {
// Guessed C file does not exist, so it may be a CPP file
cfile += 'pp'
cpp_file = true
}
opath := v.pref.cache_manager.mod_postfix_with_key2cpath(mod, '.o', obj_path)
mut rebuild_reason_message := '${obj_path} not found, building it in ${opath} ...'
if os.exists(opath) {
Expand Down Expand Up @@ -918,8 +950,17 @@ fn (mut v Builder) build_thirdparty_obj_file(mod string, path string, moduleflag
all_options << moduleflags.c_options_before_target()
all_options << '-o ${os.quoted_path(opath)}'
all_options << '-c ${os.quoted_path(cfile)}'
cc_options := v.thirdparty_object_args(v.ccoptions, all_options).join(' ')
cmd := '${v.quote_compiler_name(v.pref.ccompiler)} ${cc_options}'
cc_options := v.thirdparty_object_args(v.ccoptions, all_options, cpp_file).join(' ')

// If the third party object file requires a CPP file compilation, switch to a CPP compiler
mut ccompiler := v.pref.ccompiler
if cpp_file {
$if trace_thirdparty_obj_files ? {
println('>>> build_thirdparty_obj_files switched from compiler "${ccompiler}" to "${v.pref.cppcompiler}"')
}
ccompiler = v.pref.cppcompiler
}
cmd := '${v.quote_compiler_name(ccompiler)} ${cc_options}'
$if trace_thirdparty_obj_files ? {
println('>>> build_thirdparty_obj_files cmd: ${cmd}')
}
Expand Down
11 changes: 11 additions & 0 deletions vlib/v/pref/default.v
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ pub fn (mut p Preferences) fill_with_defaults() {
if p.ccompiler == '' {
p.default_c_compiler()
}
if p.cppcompiler == '' {
p.default_cpp_compiler()
}
p.find_cc_if_cross_compiling()
p.ccompiler_type = cc_from_string(p.ccompiler)
p.is_test = p.path.ends_with('_test.v') || p.path.ends_with('_test.vv')
Expand Down Expand Up @@ -244,6 +247,14 @@ pub fn (mut p Preferences) default_c_compiler() {
return
}

pub fn (mut p Preferences) default_cpp_compiler() {
if p.ccompiler.contains('clang') {
p.cppcompiler = 'clang++'
return
}
p.cppcompiler = 'c++'
}

pub fn vexe_path() string {
vexe := os.getenv('VEXE')
if vexe != '' {
Expand Down
5 changes: 5 additions & 0 deletions vlib/v/pref/pref.v
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ pub mut:
m64 bool // true = generate 64-bit code, defaults to x64
ccompiler string // the name of the C compiler used
ccompiler_type CompilerType // the type of the C compiler used
cppcompiler string // the name of the CPP compiler used
third_party_option string
building_v bool
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]`
Expand Down Expand Up @@ -738,6 +739,10 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
res.build_options << '${arg} "${res.ccompiler}"'
i++
}
'-c++' {
res.cppcompiler = cmdline.option(current_args, '-c++', 'c++')
i++
}
'-checker-match-exhaustive-cutoff-limit' {
res.checker_match_exhaustive_cutoff_limit = cmdline.option(current_args,
arg, '10').int()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module main

#flag @VMODROOT/implementation.o
#include "@VMODROOT/implementation.h"

fn C.sizeof_char() int

fn test_the_implementation_object_file_was_compiled_with_a_c_plus_plus_compiler() {
res := C.sizeof_char()
dump(res)
if res == sizeof(int) {
eprintln('implementation.o was compiled with a C compiler. Fail.')
} else if res == sizeof(char) {
println('implementation.o was compiled with a C++ compiler. Good.')
} else {
eprintln(\\_(ツ)_/¯ ... unknown C/C++ compiler')
}
assert res == sizeof(char)
}
9 changes: 9 additions & 0 deletions vlib/v/tests/project_with_cpp_code/implementation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This file should be compiled with a C++ compiler:
extern "C" {
int sizeof_char(void);
}

int sizeof_char(void) {
// see https://stackoverflow.com/a/12887719/1023403
return sizeof('a'); // 4 for C compilers, 1 for C++ compilers
}
1 change: 1 addition & 0 deletions vlib/v/tests/project_with_cpp_code/implementation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
int sizeof_char(void);
5 changes: 5 additions & 0 deletions vlib/v/tests/project_with_cpp_code/v.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Module {
name: 'project_with_cpp_code',
description: 'A simple project, containing a .cpp file with C++ code, that has to be compiled with a C++ compiler.',
dependencies: []
}

0 comments on commit 492e918

Please sign in to comment.