Skip to content

Commit f94c7ed

Browse files
authored
v3: make -cc msvc work again (#28922)
1 parent b9a2d87 commit f94c7ed

11 files changed

Lines changed: 2382 additions & 16 deletions

File tree

‎vlib/builtin/backtraces_windows.c.v‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ fn print_backtrace_skipping_top_frames_msvc(skipframes int) bool {
114114
}
115115
for i in 0 .. frames {
116116
frame_addr := backtraces[i]
117-
if C.SymFromAddr(handle, frame_addr, &offset, si) == 1 {
117+
if C.SymFromAddr(handle, u64(frame_addr), &offset, si) == 1 {
118118
nframe := frames - i - 1
119119
mut lineinfo := ''
120-
if C.SymGetLineFromAddr64(handle, frame_addr, &offset, &sline64) == 1 {
120+
if C.SymGetLineFromAddr64(handle, u64(frame_addr), &offset, &sline64) == 1 {
121121
file_name := unsafe { tos3(sline64.f_file_name) }
122122
lnumber := sline64.f_line_number
123123
lineinfo = file_name + ':' + i64(lnumber).str()

‎vlib/v/compiler_tests/cross_output_codegen_test.v‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,14 @@ fn test_cross_windows_output_orders_windows_header_before_bcrypt() {
9393

9494
fn test_cross_output_leaves_the_atomic_helpers_to_the_windows_tcc_header() {
9595
// The snapshot does not know its C compiler yet. V's WinAPI atomic header is
96-
// emitted behind `_WIN32 && __TINYC__` and defines `atomic_fetch_add_byte` and
96+
// emitted behind `_WIN32 && (__TINYC__ || MSVC)` and defines `atomic_fetch_add_byte` and
9797
// friends as function-like macros, so the backend's own `static inline`
9898
// definitions have to sit behind the negation of that same guard. Without it
9999
// the macro expanded over the definition and tcc rejected `vc/v_win.c` with
100100
// `redefinition of 'ManualInterlockedExchangeAdd8'`.
101101
for flags in ['-cross -os windows -cc msvc', '-os cross'] {
102102
c_code := cross_generate_with(flags, 'atomics', "module main\n\nfn main() {\n\tprintln('ok')\n}\n")
103-
guard := '#if !(defined(_WIN32) && defined(__TINYC__))'
103+
guard := '#if !(defined(_WIN32) && (defined(__TINYC__) || (defined(_MSC_VER) && !defined(__clang__))))'
104104
definition := 'static inline byte atomic_fetch_add_byte('
105105
at := c_code.index(definition) or {
106106
assert false, '${flags}: the atomic helpers are missing from the snapshot'

‎vlib/v/driver/driver.v‎

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,19 @@ fn compile_cached_c_source_object(obj_path string, source_file string, source_la
13301330
if language.len > 0 {
13311331
args << ['-x', language]
13321332
}
1333+
if c_compiler_is_msvc(compiler) {
1334+
// `cl` cannot list a source's dependencies like `-M` does, so the object cannot
1335+
// be validated against its headers later. Build it for this compilation only.
1336+
msvc_obj := os.join_path(uncached_dir, '${os.file_name(obj_path).all_before_last('.')}_${tempname.unique_token()}.obj')
1337+
args << ['-o', msvc_obj, '-c', source_file]
1338+
res := cmdexec.run(compiler, msvc_cl_object_args(args, target.os))
1339+
if res.exit_code != 0 {
1340+
os.rm(msvc_obj) or {}
1341+
return error('failed to build C object ${obj_path} from ${source_file}:\n${res.output}')
1342+
}
1343+
stats.temporary_objects << msvc_obj
1344+
return msvc_obj
1345+
}
13331346
manifest_path := c_object_manifest_path(cache_dir, obj_path, compiler, args, target, mut stats)
13341347
if cached_obj := valid_c_object_manifest(manifest_path, mut stats) {
13351348
return cached_obj
@@ -2835,6 +2848,10 @@ fn v3_c_compiler_flag_plan(options V3CCompilerFlagOptions) V3CCompilerFlagPlan {
28352848
before_inputs << options.pic_flag
28362849
}
28372850
before_inputs << v3_windows_executable_linker_flags(options.target_os, options.c_compiler, options.is_shared, options.is_o, options.subsystem, options.windows_gui_app)
2851+
if options.c_compiler == 'msvc' {
2852+
before_inputs << v3_msvc_link_flags(options.target_os, options.is_shared, options.is_o,
2853+
options.subsystem, options.windows_gui_app)
2854+
}
28382855
mut tcc_includes := ''
28392856
if options.is_tcc {
28402857
tcc_resources := v3_tcc_resource_flags(options.vroot)
@@ -3770,6 +3787,10 @@ fn c_typedef_is_function_pointer(source string, name string) bool {
37703787
}
37713788

37723789
fn cache_c_compiler_predefined_macros(flags []string, ccompiler string, target pref.Target, native_inputs_language string) (map[string]string, bool) {
3790+
if c_compiler_is_msvc(ccompiler) {
3791+
// `cl` has no `-dM` equivalent.
3792+
return map[string]string{}, false
3793+
}
37733794
path := os.join_path(os.vtmp_dir(), 'v3_compiler_macros_${tempname.unique_token()}.c')
37743795
defer {
37753796
os.rm(path) or {}
@@ -10509,7 +10530,7 @@ pub fn run(args []string) {
1050910530
minimal_literal_output := !is_prof && !is_trace_calls
1051010531
&& input_uses_minimal_literal_output_builtin(input_file, prefs, is_test_command, is_checker_fixture)
1051110532
mut use_parallel_c_compilation := parallel_cc && backend == 'c' && !c_only && !effective_tcc
10512-
&& !is_o && coverage_dir.len == 0 && profile_file.len == 0
10533+
&& effective_c_compiler != 'msvc' && !is_o && coverage_dir.len == 0 && profile_file.len == 0
1051310534
&& !is_trace_calls
1051410535
&& v3_parallel_cc_monolithic_define !in user_defines
1051510536
// `-keepc` and explicit `-b c` promise a complete generated C translation unit.
@@ -11304,7 +11325,10 @@ pub fn run(args []string) {
1130411325
set_diagnostic_files(mut pre_tc, user_files)
1130511326
// The C generator has a dedicated literal-output path. The SSA/native backend
1130611327
// still builds ordinary builtin bodies, so it needs their full dependency set.
11328+
// So does MSVC: its backtraces demangle symbols with string slices, which only
11329+
// become `string.substr` calls after markused.
1130711330
trivial_literal_output = !is_trace_calls && backend != 'arm64' && test_files.len == 0 && !is_checker_fixture
11331+
&& effective_c_compiler != 'msvc'
1130811332
&& markused.is_trivial_literal_output_program(a, pre_tc.diagnostic_files)
1130911333
if verbose {
1131011334
eprintln(' [ttime] ck trivial gate ${f64(ckpre_sw.elapsed().microseconds()) / 1000.0:7.2f} ms')
@@ -11624,6 +11648,10 @@ pub fn run(args []string) {
1162411648
used_fns = markused.mark_used_without_generic_detection(a, markused_tc)
1162511649
}
1162611650
uses_generics = false
11651+
} else if effective_c_compiler == 'msvc' {
11652+
// Keep the runtime seeds that a literal-output program would drop; see
11653+
// `trivial_literal_output` above.
11654+
used_fns, uses_generics = markused.mark_used_with_generic_usage_full_runtime(a, markused_tc)
1162711655
} else {
1162811656
used_fns, uses_generics = markused.mark_used_with_generic_usage(a, markused_tc)
1162911657
}
@@ -12617,6 +12645,17 @@ pub fn run(args []string) {
1261712645
} else {
1261812646
b.step_parallel('cgen', cgen_was_parallel)
1261912647
}
12648+
if effective_c_compiler == 'msvc' && !cache_state.manager.enabled {
12649+
msvc_lower_c_file(cc_src) or {
12650+
eprintln('error preparing the generated C source for MSVC: ${err.msg()}')
12651+
cleanup_c_build_dir(cc_dir)
12652+
exit(1)
12653+
}
12654+
b.step('MSVC C compatibility')
12655+
}
12656+
if effective_c_compiler == 'msvc' && !c_only {
12657+
msvc_require_cl(c_compiler, host_os, prefs.target)
12658+
}
1262012659
pic_flag := shared_pic_flag(is_shared || use_cached_dev_dylib, prefs.normalized_target_os())
1262112660
mut linux_cross_sysroot := ''
1262212661
if macos_linux_cross_compile && !c_only {
@@ -13375,7 +13414,10 @@ pub fn run(args []string) {
1337513414
&& fallback_source == 'src.c' {
1337613415
result = compile_v3_parallel_c(cc_src, c_compiler, &c_flag_plan, &large_c_flag_plan, native_support_inputs, cached_objects, cached_dev_dylib, needs_objective_c, cc_dir, cc_output_name, verbose || show_cc, parallel_c_job_count, parallel_c_unit_count, is_shared)
1337713416
} else {
13378-
cc_args := c_flag_plan.compiler_args(cc_output_name, compiler_inputs, [])
13417+
mut cc_args := c_flag_plan.compiler_args(cc_output_name, compiler_inputs, [])
13418+
if effective_c_compiler == 'msvc' {
13419+
cc_args = msvc_cl_args(cc_args, prefs.normalized_target_os())
13420+
}
1337913421
if verbose || show_cc {
1338013422
println(' > ${cmdexec.display(c_compiler, cc_args)}')
1338113423
}

0 commit comments

Comments
 (0)