@@ -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
37723789fn 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