Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions vlib/builtin/backtraces_windows.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,10 @@ fn print_backtrace_skipping_top_frames_msvc(skipframes int) bool {
}
for i in 0 .. frames {
frame_addr := backtraces[i]
if C.SymFromAddr(handle, frame_addr, &offset, si) == 1 {
if C.SymFromAddr(handle, u64(frame_addr), &offset, si) == 1 {
nframe := frames - i - 1
mut lineinfo := ''
if C.SymGetLineFromAddr64(handle, frame_addr, &offset, &sline64) == 1 {
if C.SymGetLineFromAddr64(handle, u64(frame_addr), &offset, &sline64) == 1 {
file_name := unsafe { tos3(sline64.f_file_name) }
lnumber := sline64.f_line_number
lineinfo = file_name + ':' + i64(lnumber).str()
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/compiler_tests/cross_output_codegen_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,14 @@ fn test_cross_windows_output_orders_windows_header_before_bcrypt() {

fn test_cross_output_leaves_the_atomic_helpers_to_the_windows_tcc_header() {
// The snapshot does not know its C compiler yet. V's WinAPI atomic header is
// emitted behind `_WIN32 && __TINYC__` and defines `atomic_fetch_add_byte` and
// emitted behind `_WIN32 && (__TINYC__ || MSVC)` and defines `atomic_fetch_add_byte` and
// friends as function-like macros, so the backend's own `static inline`
// definitions have to sit behind the negation of that same guard. Without it
// the macro expanded over the definition and tcc rejected `vc/v_win.c` with
// `redefinition of 'ManualInterlockedExchangeAdd8'`.
for flags in ['-cross -os windows -cc msvc', '-os cross'] {
c_code := cross_generate_with(flags, 'atomics', "module main\n\nfn main() {\n\tprintln('ok')\n}\n")
guard := '#if !(defined(_WIN32) && defined(__TINYC__))'
guard := '#if !(defined(_WIN32) && (defined(__TINYC__) || (defined(_MSC_VER) && !defined(__clang__))))'
definition := 'static inline byte atomic_fetch_add_byte('
at := c_code.index(definition) or {
assert false, '${flags}: the atomic helpers are missing from the snapshot'
Expand Down
46 changes: 44 additions & 2 deletions vlib/v/driver/driver.v
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,19 @@ fn compile_cached_c_source_object(obj_path string, source_file string, source_la
if language.len > 0 {
args << ['-x', language]
}
if c_compiler_is_msvc(compiler) {
// `cl` cannot list a source's dependencies like `-M` does, so the object cannot
// be validated against its headers later. Build it for this compilation only.
msvc_obj := os.join_path(uncached_dir, '${os.file_name(obj_path).all_before_last('.')}_${tempname.unique_token()}.obj')
args << ['-o', msvc_obj, '-c', source_file]
res := cmdexec.run(compiler, msvc_cl_object_args(args, target.os))
if res.exit_code != 0 {
os.rm(msvc_obj) or {}
return error('failed to build C object ${obj_path} from ${source_file}:\n${res.output}')
}
stats.temporary_objects << msvc_obj
return msvc_obj
}
manifest_path := c_object_manifest_path(cache_dir, obj_path, compiler, args, target, mut stats)
if cached_obj := valid_c_object_manifest(manifest_path, mut stats) {
return cached_obj
Expand Down Expand Up @@ -2835,6 +2848,10 @@ fn v3_c_compiler_flag_plan(options V3CCompilerFlagOptions) V3CCompilerFlagPlan {
before_inputs << options.pic_flag
}
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)
if options.c_compiler == 'msvc' {
before_inputs << v3_msvc_link_flags(options.target_os, options.is_shared, options.is_o,
options.subsystem, options.windows_gui_app)
}
mut tcc_includes := ''
if options.is_tcc {
tcc_resources := v3_tcc_resource_flags(options.vroot)
Expand Down Expand Up @@ -3770,6 +3787,10 @@ fn c_typedef_is_function_pointer(source string, name string) bool {
}

fn cache_c_compiler_predefined_macros(flags []string, ccompiler string, target pref.Target, native_inputs_language string) (map[string]string, bool) {
if c_compiler_is_msvc(ccompiler) {
// `cl` has no `-dM` equivalent.
return map[string]string{}, false
}
path := os.join_path(os.vtmp_dir(), 'v3_compiler_macros_${tempname.unique_token()}.c')
defer {
os.rm(path) or {}
Expand Down Expand Up @@ -10509,7 +10530,7 @@ pub fn run(args []string) {
minimal_literal_output := !is_prof && !is_trace_calls
&& input_uses_minimal_literal_output_builtin(input_file, prefs, is_test_command, is_checker_fixture)
mut use_parallel_c_compilation := parallel_cc && backend == 'c' && !c_only && !effective_tcc
&& !is_o && coverage_dir.len == 0 && profile_file.len == 0
&& effective_c_compiler != 'msvc' && !is_o && coverage_dir.len == 0 && profile_file.len == 0
&& !is_trace_calls
&& v3_parallel_cc_monolithic_define !in user_defines
// `-keepc` and explicit `-b c` promise a complete generated C translation unit.
Expand Down Expand Up @@ -11304,7 +11325,10 @@ pub fn run(args []string) {
set_diagnostic_files(mut pre_tc, user_files)
// The C generator has a dedicated literal-output path. The SSA/native backend
// still builds ordinary builtin bodies, so it needs their full dependency set.
// So does MSVC: its backtraces demangle symbols with string slices, which only
// become `string.substr` calls after markused.
trivial_literal_output = !is_trace_calls && backend != 'arm64' && test_files.len == 0 && !is_checker_fixture
&& effective_c_compiler != 'msvc'
&& markused.is_trivial_literal_output_program(a, pre_tc.diagnostic_files)
if verbose {
eprintln(' [ttime] ck trivial gate ${f64(ckpre_sw.elapsed().microseconds()) / 1000.0:7.2f} ms')
Expand Down Expand Up @@ -11624,6 +11648,10 @@ pub fn run(args []string) {
used_fns = markused.mark_used_without_generic_detection(a, markused_tc)
}
uses_generics = false
} else if effective_c_compiler == 'msvc' {
// Keep the runtime seeds that a literal-output program would drop; see
// `trivial_literal_output` above.
used_fns, uses_generics = markused.mark_used_with_generic_usage_full_runtime(a, markused_tc)
} else {
used_fns, uses_generics = markused.mark_used_with_generic_usage(a, markused_tc)
}
Expand Down Expand Up @@ -12617,6 +12645,17 @@ pub fn run(args []string) {
} else {
b.step_parallel('cgen', cgen_was_parallel)
}
if effective_c_compiler == 'msvc' && !cache_state.manager.enabled {
msvc_lower_c_file(cc_src) or {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Lower typeof before invoking MSVC

When a program calls .pointers() on a fixed array, gen_fixed_array_pointers_expr emits a GNU-style typeof(...) declaration (vlib/v/gen/c/array.v:975), but this compatibility pass leaves that token unchanged. The resulting source is then compiled with /std:c11; Microsoft documents C typeof as requiring /std:clatest, so these otherwise valid V programs fail under -cc msvc. Add an MSVC-specific declaration in cgen or teach this pass to replace the emitted typeof.

Useful? React with 👍 / 👎.

eprintln('error preparing the generated C source for MSVC: ${err.msg()}')
cleanup_c_build_dir(cc_dir)
exit(1)
}
b.step('MSVC C compatibility')
}
if effective_c_compiler == 'msvc' && !c_only {
msvc_require_cl(c_compiler, host_os, prefs.target)
}
pic_flag := shared_pic_flag(is_shared || use_cached_dev_dylib, prefs.normalized_target_os())
mut linux_cross_sysroot := ''
if macos_linux_cross_compile && !c_only {
Expand Down Expand Up @@ -13375,7 +13414,10 @@ pub fn run(args []string) {
&& fallback_source == 'src.c' {
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)
} else {
cc_args := c_flag_plan.compiler_args(cc_output_name, compiler_inputs, [])
mut cc_args := c_flag_plan.compiler_args(cc_output_name, compiler_inputs, [])
if effective_c_compiler == 'msvc' {
cc_args = msvc_cl_args(cc_args, prefs.normalized_target_os())
}
if verbose || show_cc {
println(' > ${cmdexec.display(c_compiler, cc_args)}')
}
Expand Down
Loading
Loading