Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
48 changes: 41 additions & 7 deletions cmd/v/macos_v3_args.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ fn macos_v3_non_compilation_command(command string) bool {
// macos_v3_force_requested reports whether `-new-compiler` should hand this
// invocation to the embedded V3 compiler. It gates on `-old-compiler`
// precedence, options/modes V3 cannot honor yet, and whether the command is an
// actual compilation command (never `test`, external tools, or the `cmd/v` /
// `vlib/v3/v3.v` bootstrap). Both the Darwin dispatcher (where it overrides the
// default heuristic) and the non-macOS dispatcher (where it is the sole gate)
// rely on it, so it must stay platform neutral.
// actual compilation command (never `test` or external tools). Compiler bootstrap
// targets normally stay on V1, but explicit `-b fastc` owns those targets too: its
// complete lane uses V3's checked frontend and full fastc generator for the compiler source.
// Both the Darwin dispatcher (where it overrides the default heuristic) and the
// non-macOS dispatcher (where it is the sole gate) rely on it, so it must stay
// platform neutral.
@[markused]
fn macos_v3_force_requested(command string, prefs &pref.Preferences) bool {
if !prefs.new_compiler || prefs.old_compiler {
Expand All @@ -34,23 +36,55 @@ fn macos_v3_force_requested(command string, prefs &pref.Preferences) bool {
if v3_has_v1_only_preferences(prefs) || (prefs.gc_set_by_flag && prefs.gc_mode != .no_gc) {
return false
}
if prefs.autofree && prefs.is_run {
if prefs.autofree && prefs.is_run && !macos_v3_fastc_requested(prefs) {
// V1 still owns the established `v -autofree run ...` orchestration.
// FastC promotes autofree programs to its checked C lane.
return false
}
if prefs.path == '' || command == 'test' || macos_v3_non_compilation_command(command)
|| command in external_tools {
return false
}
normalized_path := prefs.path.replace('\\', '/').trim_right('/')
if normalized_path == 'cmd/v' || normalized_path.starts_with('cmd/v/')
compiler_bootstrap := normalized_path == 'cmd/v' || normalized_path.starts_with('cmd/v/')
|| normalized_path.contains('/cmd/v/') || normalized_path.ends_with('/cmd/v')
|| normalized_path == 'vlib/v3/v3.v' || normalized_path.ends_with('/vlib/v3/v3.v') {
|| normalized_path == 'vlib/v3/v3.v' || normalized_path.ends_with('/vlib/v3/v3.v')
if compiler_bootstrap && !macos_v3_fastc_requested(prefs) {
return false
}
return command in ['run', 'build'] || prefs.is_script || os.is_dir(prefs.path)
|| normalized_path.ends_with('.v') || normalized_path.ends_with('.vsh')
}

fn macos_v3_fastc_requested(prefs &pref.Preferences) bool {
return prefs.is_fastc
}

// macos_v3_fastc_incompatibility reports why an explicit FastC selection cannot
// be honored, so dispatchers fail instead of silently continuing through V1.
fn macos_v3_fastc_incompatibility(prefs &pref.Preferences) ?string {
if !prefs.is_fastc {
return none
}
if prefs.gc_set_by_flag && prefs.gc_mode != .no_gc {
return '`-b fastc` only supports `-gc none`; remove the explicit collector or select `-b c`.'
}
if v3_has_v1_only_preferences(prefs) {
return '`-b fastc` cannot be combined with an option that is only supported by the V1 compiler.'
}
return none
}

// macos_v3_test_ownership_uses_v1 keeps ownership/autofree test binaries on
// V1. vtest marks its per-file compilations with `-skip-running`; compiling an
// autofree test through the ownership-enabled V3 tool can consume far more
// memory than the test itself. Direct V3 ownership builds remain available;
// fastc uses the same checked ownership lane as the C backend.
fn macos_v3_test_ownership_uses_v1(prefs &pref.Preferences, args []string) bool {
return prefs.skip_running && !macos_v3_fastc_requested(prefs)
&& (prefs.autofree || '-ownership' in args)
}

// These helpers are shared by the native Darwin dispatcher and the default
// implementation selected while generating cross-platform VC sources, so this
// file has to stay platform neutral (no `_darwin.c.v` suffix). Keep them outside
Expand Down
17 changes: 15 additions & 2 deletions cmd/v/macos_v3_darwin.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,17 @@ fn maybe_delegate_to_macos_v3(command string, prefs &pref.Preferences) ?MacosV3C
}
return take_macos_v3_c_error_report()
}
if message := macos_v3_fastc_incompatibility(prefs) {
eprintln(message)
exit(1)
}
all_args := util.join_env_vflags_and_os_args()
forwarded_args := all_args[1..]
if !is_macos_v3_default_executable(os.executable()) {
if macos_v3_test_ownership_uses_v1(prefs, forwarded_args) {
trace_macos_v3_skip('vtest ownership/autofree compilation')
return take_macos_v3_c_error_report()
}
if !macos_v3_executable_can_dispatch(os.executable(), prefs) {
trace_macos_v3_skip('non-default compiler executable `${os.executable()}`')
return none
}
Expand All @@ -66,6 +74,10 @@ fn is_macos_v3_default_executable(vexe string) bool {
return os.base(vexe) in ['v', 'v.exe', 'vnew', 'vnew.exe']
}

fn macos_v3_executable_can_dispatch(vexe string, prefs &pref.Preferences) bool {
return is_macos_v3_default_executable(vexe) || macos_v3_fastc_requested(prefs)
}

fn is_macos_v3_relevant_command(command string, prefs &pref.Preferences) bool {
if prefs.old_compiler {
return false
Expand All @@ -76,9 +88,10 @@ fn is_macos_v3_relevant_command(command string, prefs &pref.Preferences) bool {
// dispatch, but it must not prevent V3 from being the default compiler.
return false
}
if prefs.autofree && prefs.is_run {
if prefs.autofree && prefs.is_run && !macos_v3_fastc_requested(prefs) {
// V1 still owns the established `v -autofree run ...` orchestration.
// Direct autofree builds are selected earlier by the ownership dispatcher.
// FastC promotes autofree programs to its checked C lane.
return false
}
if command == 'test' {
Expand Down
8 changes: 6 additions & 2 deletions cmd/v/macos_v3_default.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import v.util
// compiler normally. `-new-compiler` opts into the embedded V3 driver and runs
// it in THIS process, the same way V3 runs by default on macOS. It applies the
// same gating as the Darwin dispatcher: `-old-compiler` wins, V1-only options
// are rejected, and only actual compilation commands are taken over (never
// `fmt`, `version`, `test`, external tools, or the compiler bootstrap).
// are rejected, and only actual compilation commands are taken over. Compiler
// bootstrap targets are included only when the V3-only fastc backend is explicit.
fn maybe_delegate_to_macos_v3(command string, prefs &pref.Preferences) ?MacosV3CErrorReport {
if !prefs.new_compiler || prefs.old_compiler {
// V1 is the default here, and `-old-compiler` takes precedence.
Expand All @@ -19,6 +19,10 @@ fn maybe_delegate_to_macos_v3(command string, prefs &pref.Preferences) ?MacosV3C
eprintln('`-new-compiler` requires a build that embeds the V3 compiler, which this one does not.')
exit(1)
}
if message := macos_v3_fastc_incompatibility(prefs) {
eprintln(message)
exit(1)
}
raw_args := util.join_env_vflags_and_os_args()[1..]
if macos_v3_has_v1_only_leading_option(raw_args, command) {
eprintln('`-new-compiler` cannot be combined with a V1-only option; drop `-new-compiler` or the option.')
Expand Down
67 changes: 67 additions & 0 deletions cmd/v/macos_v3_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -1573,6 +1573,11 @@ fn test_macos_v3_default_executable_excludes_temporary_self_hosted_compilers() {
assert !is_macos_v3_default_executable('/tmp/v2')
assert !is_macos_v3_default_executable('/tmp/vstrict1')
assert !is_macos_v3_default_executable('/tmp/vp')
assert !macos_v3_executable_can_dispatch('/tmp/v2', &pref.Preferences{})
assert macos_v3_executable_can_dispatch('/tmp/v2', &pref.Preferences{
build_options: ['-b fastc']
is_fastc: true
})
}
}

Expand Down Expand Up @@ -1687,3 +1692,65 @@ fn test_macos_v3_new_compiler_routing_and_precedence() {
path: 'main.v'
})
}

fn test_macos_v3_fastc_routes_compiler_selfhost_targets() {
for target in ['cmd/v', 'cmd/v/v.v', 'vlib/v3/v3.v'] {
assert macos_v3_force_requested('build', &pref.Preferences{
new_compiler: true
path: target
build_options: ['-b fastc']
is_fastc: true
})
assert !macos_v3_force_requested('build', &pref.Preferences{
new_compiler: true
path: target
build_options: ['-b c']
})
}
assert macos_v3_fastc_requested(&pref.Preferences{
build_options: ['-backend fastc']
is_fastc: true
})
assert !macos_v3_fastc_requested(&pref.Preferences{
build_options: ['-b fastc', '-b c']
})
repeated_backends, _ := pref.parse_args_and_show_errors([], ['-b', 'fastc', '-b', 'c', '-b',
'fastc', 'cmd/v'], false)
assert macos_v3_fastc_requested(repeated_backends)
assert macos_v3_force_requested('run', &pref.Preferences{
new_compiler: true
autofree: true
is_run: true
path: 'main.v'
build_options: ['-b fastc']
is_fastc: true
})
}

fn test_macos_v3_fastc_rejects_incompatible_preferences() {
fastc_boehm, _ := pref.parse_args_and_show_errors([],
['-b', 'fastc', '-gc', 'boehm', 'main.v'], false)
message := macos_v3_fastc_incompatibility(fastc_boehm) or {
assert false, 'expected explicit FastC with Boehm GC to be rejected'
return
}
assert message.contains('`-b fastc` only supports `-gc none`')

overridden, _ := pref.parse_args_and_show_errors([], ['-b', 'fastc', '-gc', 'boehm', '-b',
'c', 'main.v'], false)
assert macos_v3_fastc_incompatibility(overridden) == none
}

fn test_macos_v3_vtest_ownership_modes_use_v1_except_fastc() {
mut prefs := &pref.Preferences{
skip_running: true
autofree: true
}
assert macos_v3_test_ownership_uses_v1(prefs, ['-skip-running', '-autofree', 'main.v'])
prefs.autofree = false
assert macos_v3_test_ownership_uses_v1(prefs, ['-skip-running', '-ownership', 'main.v'])
prefs.build_options = ['-b fastc']
prefs.is_fastc = true
assert !macos_v3_test_ownership_uses_v1(prefs, ['-skip-running', '-ownership', '-b', 'fastc',
'main.v'])
}
5 changes: 5 additions & 0 deletions cmd/v/v.v
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ fn invoke_help_and_exit(remaining []string) {
fn maybe_delegate_to_ownership(command string, prefs &pref.Preferences, merged_args []string) {
is_ownership := '-ownership' in merged_args
is_autofree := prefs.autofree
$if macos {
if macos_v3_test_ownership_uses_v1(prefs, merged_args) {
return
}
}
if !ownership_delegation_is_requested(is_ownership, is_autofree, prefs.old_compiler,
os.user_os()) {
return
Expand Down
13 changes: 11 additions & 2 deletions vlib/v/pref/pref.v
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub mut:
os OS // the OS to compile for
backend Backend
backend_set_by_flag bool // true when the compiler receives `-b`/`-backend`
is_fastc bool // true when the final `-b`/`-backend` option selects fastc
build_mode BuildMode
arch Arch
output_mode OutputMode = .stdout
Expand Down Expand Up @@ -457,6 +458,7 @@ fn parse_args_impl(known_external_commands []string, args []string, show_output
mut no_skip_unused := false
mut command, mut command_idx := '', 0
mut build_vsh_source := false
mut new_compiler_set_by_flag := false
for i := 0; i < args.len; i++ {
arg := args[i]
if pass_external_command_args && command_idx < i && command in known_external_commands {
Expand Down Expand Up @@ -563,6 +565,7 @@ fn parse_args_impl(known_external_commands []string, args []string, show_output
}
'-new-compiler' {
res.new_compiler = true
new_compiler_set_by_flag = true
}
'-checker-fixture', '-macos-v3-compat-c99' {
// Passed through to the embedded V3 diagnostic fixture runner.
Expand Down Expand Up @@ -1129,9 +1132,10 @@ fn parse_args_impl(known_external_commands []string, args []string, show_output
}
'-b', '-backend' {
sbackend := cmdline.option(args[i..], arg, 'c')
res.is_fastc = sbackend == 'fastc'
res.build_options << '${arg} ${sbackend}'
b := backend_from_string(sbackend) or {
eprintln_exit('Unknown V backend: ${sbackend}\nValid -backend choices are: c, js, js_node, js_browser, js_freestanding, wasm')
eprintln_exit('Unknown V backend: ${sbackend}\nValid -backend choices are: c, fastc, js, js_node, js_browser, js_freestanding, wasm')
}
if b == .wasm {
res.compile_defines << 'wasm'
Expand Down Expand Up @@ -1386,6 +1390,11 @@ fn parse_args_impl(known_external_commands []string, args []string, show_output
}
res.build_options = m.keys()
// eprintln('>> res.build_options: ${res.build_options}')
// FastC belongs to the embedded V3 driver, but both `fastc` and `c` use
// Backend.c while cmd/v parses the command line. Only the final backend
// option should select V3 implicitly; an explicit -new-compiler remains an
// independent request.
res.new_compiler = new_compiler_set_by_flag || res.is_fastc
Comment thread
medvednikov marked this conversation as resolved.
res.fill_with_defaults()
if res.generate_c_project != '' {
// The generated C project should not depend on cached V module objects.
Expand Down Expand Up @@ -1439,7 +1448,7 @@ pub fn backend_from_string(s string) !Backend {
// TODO: unify the "different js backend" options into a single `-b js`
// + a separate option, to choose the wanted JS output.
return match s {
'c' { .c }
'c', 'fastc' { .c }
'eval', 'interpret' { eprintln_exit('The eval backend has been removed.') }
'js', 'js_node' { .js_node }
'js_browser' { .js_browser }
Expand Down
48 changes: 48 additions & 0 deletions vlib/v/pref/pref_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,54 @@ fn test_new_compiler_flag_is_accepted() {
assert '-new-compiler' !in prefs.build_options
}

fn test_fastc_backend_selects_v3_driver() {
target := os.join_path(vroot, 'examples', 'hello_world.v')
prefs, command := pref.parse_args_and_show_errors([], ['-b', 'fastc', target], false)
assert command == target
assert prefs.backend == .c
assert prefs.backend_set_by_flag
assert prefs.is_fastc
assert prefs.new_compiler
assert prefs.build_options.contains('-b fastc')
}

fn test_later_backend_overrides_fastc_v3_selection() {
target := os.join_path(vroot, 'examples', 'hello_world.v')
prefs, command := pref.parse_args_and_show_errors([], ['-b', 'fastc', '-b', 'c', target], false)
assert command == target
assert prefs.backend == .c
assert !prefs.is_fastc
assert !prefs.new_compiler
}

fn test_final_fastc_backend_selects_v3_driver() {
target := os.join_path(vroot, 'examples', 'hello_world.v')
prefs, command := pref.parse_args_and_show_errors([], ['-b', 'c', '-b', 'fastc', target], false)
assert command == target
assert prefs.backend == .c
assert prefs.is_fastc
assert prefs.new_compiler
}

fn test_explicit_new_compiler_survives_backend_override() {
target := os.join_path(vroot, 'examples', 'hello_world.v')
prefs, command := pref.parse_args_and_show_errors([], ['-new-compiler', '-b', 'fastc', '-b',
'c', target], false)
assert command == target
assert !prefs.is_fastc
assert prefs.new_compiler
}

fn test_repeated_backend_flags_preserve_final_fastc_selection() {
target := os.join_path(vroot, 'examples', 'hello_world.v')
prefs, command := pref.parse_args_and_show_errors([], ['-b', 'fastc', '-b', 'c', '-b', 'fastc',
target], false)
assert command == target
assert prefs.backend == .c
assert prefs.is_fastc
assert prefs.new_compiler
}

fn test_v3_checker_fixture_flag_is_accepted() {
target := os.join_path(vroot, 'examples', 'hello_world.v')
for flag in ['-checker-fixture', '-macos-v3-compat-c99'] {
Expand Down
Loading
Loading