import common { Task, exec_args } import crypto.sha256 import os // Shared tasks/helpers fn all_code_is_formatted() { if common.is_github_job { exec_args(['v', '-silent', 'test-cleancode']) } else { exec_args(['v', '-progress', 'test-cleancode']) } } fn verify_v_test_works() { println(os.getenv('VFLAGS')) exec_args(['v', 'cmd/tools/test_if_v_test_system_works.v']) exec_args(['./cmd/tools/test_if_v_test_system_works']) } fn test_pure_v_math_module() { exec_args(['v', '-d', 'pure_v_math', '-exclude', '@vlib/math/*.c.v', 'test', 'vlib/math/']) } fn self_tests() { // Never select the V1 compatibility compiler here. It is a separate V 0.5.2 // installation, so `test-self vlib` would resolve `vlib` under *its* VROOT and // test the release's own standard library instead of this repository's. if common.is_github_job { exec_args(['v', '-W', '-silent', 'test-self', 'vlib']) } else { exec_args(['v', '-progress', 'test-self', 'vlib']) } } fn build_examples() { if common.is_github_job { // The exhaustive CI matrix includes a few deliberately large examples. // Keep the user-facing V3 memory guard while allowing CI to validate them. exec_args(['v', '-no-memory-limit', '-W', 'build-examples']) } else { exec_args(['v', '-progress', 'build-examples']) } } fn v_doctor() { exec_args(['v', 'doctor']) } fn build_v_with_prealloc() { exec_args(['v', '-cg', '-cstrict', '-o', 'vstrict1', 'cmd/v']) // -prealloc uses _Thread_local for g_memory_block; bundled tcc does not support it. prealloc_cc_flag := if os.getenv('VFLAGS').contains('-cc tcc') { ' -cc cc' } else { '' } exec_args(['./vstrict1', ...(os.split_args(prealloc_cc_flag) or { panic(err) }), '-o', 'vprealloc', '-prealloc', 'cmd/v']) exec_args(['./vprealloc', 'run', 'examples/hello_world.v']) exec_args(['./vprealloc', '-o', 'v3', 'cmd/v']) exec_args(['./v3', '-o', 'v4', 'cmd/v']) exec_args(['./v4', '-d', 'debug_malloc', '-d', 'debug_realloc', '-o', 'vdebug1', 'cmd/v']) } // TCC job tasks fn install_dependencies_for_examples_and_tools_tcc() { if common.is_github_job && os.exists('/etc/apt/apt-mirrors.txt') { exec_args(['.github/workflows/disable_azure_mirror.sh']) } exec_args(['v', 'retry', '--', 'sudo', 'apt', 'update']) exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libssl-dev', 'sqlite3', 'libsqlite3-dev', 'valgrind', 'nodejs']) exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libfreetype6-dev', 'libxi-dev', 'libxcursor-dev', 'libgl-dev', 'libxrandr-dev', 'libasound2-dev', 'libegl-dev', 'libx11-xcb-dev']) // Wayland development libraries for sokol Wayland support exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libwayland-dev', 'libxkbcommon-dev', 'libwayland-egl1', 'libxkbcommon-x11-dev']) // The following is needed for examples/c_interop_wkhtmltopdf.v. exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'xfonts-75dpi', 'xfonts-base', 'expect']) exec_args(['v', 'retry', '--', 'sh', 'ci/install_wkhtmltox.sh']) } fn test_v_to_c_tcc() { exec_args(['thirdparty/tcc/tcc.exe', '-version']) exec_args(['v', '-cg', '-o', 'vtcc', 'cmd/v']) // ensure vtcc can build itself twice } fn v_self_compilation_tcc() { exec_args(['v', '-o', 'v2', 'cmd/v']) exec_args(['./v2', '-o', 'v3', 'cmd/v']) exec_args(['./v3', '-o', 'v4', 'cmd/v']) } fn v_doctor_tcc() { v_doctor() } fn verify_v_test_works_tcc() { verify_v_test_works() } fn test_pure_v_math_module_tcc() { test_pure_v_math_module() } fn self_tests_tcc() { exec_args(['v', '-keepc', '-cc', 'tcc', '-g', 'self']) self_tests() } fn self_tests_vprod_tcc() { // Keep the optimized test compiler while still checking a TCC debug self-build. exec_args(['v', '-keepc', '-cc', 'tcc', '-g', '-o', 'v_tcc_debug', 'self']) exec_args(['./v_tcc_debug', 'run', 'examples/hello_world.v']) // Emit a separate result line for every file instead of hiding successes. exec_args(['v', '-W', 'test-self', 'vlib']) } fn build_examples_tcc() { build_examples() } fn run_submodule_example_tcc() { exec_args(['v', '-W', 'run', 'examples/submodule']) } fn build_tools_tcc() { if common.is_github_job { exec_args(['v', '-N', '-W', 'build-tools']) } else { exec_args(['v', '-progress', '-N', '-W', 'build-tools']) } } fn build_vbinaries_tcc() { exec_args(['v', '-N', '-W', 'build-vbinaries']) } fn build_benches_tcc() { exec_args(['v', 'should-compile-all', 'vlib/v/tests/bench/']) } fn run_vsh_script_tcc() { exec_args(['v', 'run', 'examples/v_script.vsh']) } fn test_v_tutorials_tcc() { exec_args(['v', 'tutorials/building_a_simple_web_blog_with_veb/code/blog']) } fn build_fast_tcc() { os.chdir('cmd/tools/fast') or { panic(err) } exec_args(['v', '-o', 'fast', '.']) os.chdir('../../..') or { panic(err) } os.chdir('cmd/tools/fast') or { panic(err) } exec_args(['./fast', 'help']) os.chdir('../../..') or { panic(err) } } fn v_self_compilation_usecache_tcc() { $if !enable_usecache_test ? { eprintln('> ${@LOCATION} use `-d enable_usecache_test` in VFLAGS to enable this task') return } exec_args(['v', 'wipe-cache']) exec_args(['v', 'examples/hello_world.v']) exec_args(['./examples/hello_world']) exec_args(['v', 'wipe-cache']) exec_args(['v', '-o', 'v2', 'cmd/v']) exec_args(['./v2', '-o', 'v3', 'cmd/v']) exec_args(['./v3', 'version']) exec_args(['v', 'wipe-cache']) exec_args(['./v3', '-o', 'tetris', 'examples/tetris/tetris.v']) exec_args(['rm', '-f', './examples/hello_world', 'v2', 'v3', 'tetris']) } fn test_password_input_tcc() { exec_args(['v', 'test', 'examples/password/']) } fn test_readline_tcc() { exec_args(['v', 'test', 'examples/readline/']) } fn test_leak_detector_tcc() { exec_args(['v', '-gc', 'boehm_leak', '-o', 'testcase_leak', 'vlib/v/tests/testcase_leak.vv']) exec_args(['sh', '-c', './testcase_leak 2>leaks.txt']) exec_args(['grep', 'Found 1 leaked object', 'leaks.txt']) exec_args(['grep', '-P', ', sz=\\s?1000,', 'leaks.txt']) } fn test_leak_detector_not_active_tcc() { exec_args(['v', '-o', 'testcase_leak', 'vlib/v/tests/testcase_leak.vv']) exec_args(['sh', '-c', './testcase_leak 2>leaks.txt']) assert os.file_size('leaks.txt') == 0, os.read_file('leaks.txt') or { err.msg() } } // GCC job tasks fn all_code_is_formatted_gcc() { all_code_is_formatted() } fn install_dependencies_for_examples_and_tools_gcc() { if common.is_github_job && os.exists('/etc/apt/apt-mirrors.txt') { exec_args(['.github/workflows/disable_azure_mirror.sh']) } exec_args(['v', 'retry', '--', 'sudo', 'apt', 'update']) exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'postgresql', 'libpq-dev', 'libssl-dev', 'sqlite3', 'libsqlite3-dev', 'valgrind', 'nodejs']) exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libfreetype6-dev', 'libxi-dev', 'libxcursor-dev', 'libgl-dev', 'libxrandr-dev', 'libasound2-dev']) // Wayland development libraries for sokol Wayland support exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libwayland-dev', 'libxkbcommon-dev', 'libwayland-egl1', 'libxkbcommon-x11-dev', 'wayland-protocols', 'libegl-dev']) exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libx11-dev', 'libx11-xcb-dev', 'libgl1-mesa-dri', 'xauth', 'xvfb']) } fn recompile_v_with_cstrict_gcc() { exec_args(['v', '-cc', 'gcc', '-cg', '-cstrict', '-o', 'vstrict', 'cmd/v']) } fn valgrind_v_c_gcc() { exec_args(['valgrind', '--error-exitcode=1', 'v', '-o', 'v.c', 'cmd/v']) } fn run_sanitizers_gcc() { exec_args(['v', '-o', 'v2', 'cmd/v', '-cflags', '-fsanitize=thread']) exec_args(['v', '-o', 'v3', 'cmd/v', '-cflags', '-fsanitize=undefined -fno-sanitize=alignment']) exec_args(['env', 'UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1', './v2', '-o', 'v.c', 'cmd/v']) exec_args(['env', 'UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1', './v3', '-o', 'v.c', 'cmd/v']) } fn v_self_compilation_gcc() { exec_args(['v', '-o', 'v2', 'cmd/v']) exec_args(['./v2', '-o', 'v3', 'cmd/v']) exec_args(['./v3', '-o', 'v4', 'cmd/v']) } fn v_self_compilation_usecache_gcc() { $if !enable_usecache_test ? { eprintln('> ${@LOCATION} use `-d enable_usecache_test` in VFLAGS to enable this task') return } exec_args(['v', 'wipe-cache']) exec_args(['v', 'examples/hello_world.v']) exec_args(['examples/hello_world']) exec_args(['v', 'wipe-cache']) exec_args(['v', '-o', 'v2', 'cmd/v']) exec_args(['./v2', '-o', 'v3', 'cmd/v']) exec_args(['./v3', 'version']) exec_args(['v', 'wipe-cache']) exec_args(['./v3', '-o', 'tetris', 'examples/tetris/tetris.v']) exec_args(['rm', '-f', './examples/hello_world', 'v2', 'v3', 'tetris']) } fn verify_v_test_works_gcc() { verify_v_test_works() } fn test_pure_v_math_module_gcc() { test_pure_v_math_module() } fn self_tests_gcc() { self_tests() } fn self_tests_prod_gcc() { exec_args(['v', '-o', 'vprod', '-prod', 'cmd/v']) exec_args(['./vprod', '-silent', 'test-self', 'vlib']) } fn self_tests_cstrict_gcc() { exec_args(['env', 'VTEST_JUST_ESSENTIAL=1', 'V_CI_CSTRICT=1', 'v', '-cc', 'gcc', '-cstrict', '-silent', 'test-self', 'vlib']) } fn skip_ownership_autofree_test() bool { return common.is_github_job || os.getenv('VTEST_SKIP_OWNERSHIP') == '1' } fn report_skipped_ownership_autofree_test() { eprintln('> skipping ownership/autofree test') } fn build_examples_gcc() { build_examples() } fn build_tetris_autofree_gcc() { if skip_ownership_autofree_test() { report_skipped_ownership_autofree_test() return } exec_args(['v', '-autofree', '-o', 'tetris', 'examples/tetris/tetris.v']) exec_args(['rm', '-f', 'tetris']) } fn build_blog_autofree_gcc() { if skip_ownership_autofree_test() { report_skipped_ownership_autofree_test() return } exec_args(['v', '-autofree', '-o', 'blog', 'tutorials/building_a_simple_web_blog_with_veb/code/blog']) exec_args(['rm', '-f', 'blog']) } fn build_option_test_autofree_gcc() { if skip_ownership_autofree_test() { report_skipped_ownership_autofree_test() return } exec_args(['v', '-autofree', 'vlib/v/tests/options/option_test.c.v']) } fn v_self_compilation_parallel_cc_gcc() { exec_args(['v', '-o', 'v2', '-parallel-cc', 'cmd/v']) exec_args(['rm', '-f', 'v2']) } fn build_modules_gcc() { exec_args(['v', 'build-module', 'vlib/os']) exec_args(['v', 'build-module', 'vlib/builtin']) exec_args(['v', 'build-module', 'vlib/strconv']) exec_args(['v', 'build-module', 'vlib/time']) exec_args(['v', 'build-module', 'vlib/term']) exec_args(['v', 'build-module', 'vlib/math']) exec_args(['v', 'build-module', 'vlib/strings']) exec_args(['v', 'build-module', 'vlib/v/token']) exec_args(['v', 'build-module', 'vlib/v/parser']) exec_args(['v', 'build-module', 'vlib/v/gen/c']) exec_args(['v', 'build-module', 'vlib/os/cmdline']) } fn compile_vdoctor_prod_gcc() { exec_args(['v', '-showcc', '-cc', 'gcc', '-prod', 'cmd/tools/vdoctor.v']) } fn compile_vup_prod_gcc() { exec_args(['v', '-showcc', '-cc', 'gcc', '-prod', 'cmd/tools/vup.v']) } // Clang job tasks fn all_code_is_formatted_clang() { all_code_is_formatted() } fn install_dependencies_for_examples_and_tools_clang() { if common.is_github_job && os.exists('/etc/apt/apt-mirrors.txt') { exec_args(['.github/workflows/disable_azure_mirror.sh']) } exec_args(['v', 'retry', '--', 'sudo', 'apt', 'update']) exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'postgresql', 'libpq-dev', 'libssl-dev', 'sqlite3', 'libsqlite3-dev', 'valgrind', 'nodejs']) exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libfreetype6-dev', 'libxi-dev', 'libxcursor-dev', 'libgl-dev', 'libxrandr-dev', 'libasound2-dev']) // Wayland development libraries for sokol Wayland support exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'libwayland-dev', 'libxkbcommon-dev', 'libwayland-egl1', 'libxkbcommon-x11-dev', 'wayland-protocols', 'libegl-dev']) exec_args(['v', 'retry', '--', 'sudo', 'apt', 'install', '--quiet', '-y', 'clang', 'libx11-xcb-dev']) } fn recompile_v_with_cstrict_clang() { exec_args(['v', '-cc', 'clang', '-cg', '-cstrict', '-o', 'vstrict', 'cmd/v']) exec_args(['rm', '-f', 'vstrict']) } fn valgrind_clang() { exec_args(['valgrind', '--error-exitcode=1', 'v', '-o', 'v.c', 'cmd/v']) exec_args(['rm', '-f', 'v.c']) } fn run_sanitizers_clang() { exec_args(['.github/workflows/run_sanitizers.sh']) } fn v_self_compilation_clang() { exec_args(['v', '-o', 'v2', 'cmd/v']) exec_args(['./v2', '-o', 'v3', 'cmd/v']) exec_args(['./v3', '-o', 'v4', 'cmd/v']) } fn v_self_compilation_usecache_clang() { $if !enable_usecache_test ? { eprintln('> ${@LOCATION} use `-d enable_usecache_test` in VFLAGS to enable this task') return } exec_args(['v', 'wipe-cache']) exec_args(['v', 'examples/hello_world.v']) exec_args(['./examples/hello_world']) exec_args(['v', 'wipe-cache']) exec_args(['v', '-o', 'v2', 'cmd/v']) exec_args(['./v2', '-o', 'v3', 'cmd/v']) exec_args(['./v3', 'version']) exec_args(['v', 'wipe-cache']) exec_args(['./v3', '-o', 'tetris', 'examples/tetris/tetris.v']) exec_args(['rm', '-f', './examples/hello_world', 'v2', 'v3', 'tetris']) } fn verify_v_test_works_clang() { verify_v_test_works() } fn test_pure_v_math_module_clang() { test_pure_v_math_module() } fn self_tests_clang() { self_tests() } fn self_tests_vprod_clang() { exec_args(['v', '-o', 'vprod', '-prod', 'cmd/v']) exec_args(['./vprod', '-silent', 'test-self', 'vlib']) } fn self_tests_cstrict_clang() { exec_args(['env', 'VTEST_JUST_ESSENTIAL=1', 'V_CI_CSTRICT=1', './vprod', '-cstrict', '-silent', 'test-self', 'vlib']) } fn build_examples_clang() { build_examples() } fn build_examples_autofree_clang() { if skip_ownership_autofree_test() { report_skipped_ownership_autofree_test() return } exec_args(['v', '-N', '-W', '-autofree', '-experimental', '-o', 'tetris', 'examples/tetris/tetris.v']) exec_args(['rm', '-f', 'tetris']) } fn build_modules_clang() { exec_args(['v', 'build-module', 'vlib/os']) exec_args(['v', 'build-module', 'vlib/builtin']) exec_args(['v', 'build-module', 'vlib/strconv']) exec_args(['v', 'build-module', 'vlib/time']) exec_args(['v', 'build-module', 'vlib/term']) exec_args(['v', 'build-module', 'vlib/math']) exec_args(['v', 'build-module', 'vlib/strings']) exec_args(['v', 'build-module', 'vlib/v/token']) exec_args(['v', 'build-module', 'vlib/v/parser']) exec_args(['v', 'build-module', 'vlib/v/gen/c']) exec_args(['v', 'build-module', 'vlib/os/cmdline']) } fn test_inline_assembly() { exec_args(['v', 'test', 'vlib/v/slow_tests/assembly']) } // Keep this list in the same order as the active tasks in // .github/workflows/linux_ci.yml. The aggregate runner changes compiler flags at // the same boundaries as the three workflow jobs. // Order is deliberate on both sides: the cheapest check that can prove a checkout // broken runs first, and `build_v_with_prealloc`, which is five compiler builds, // runs last so a red run reports the cheap signal before paying for it. const ci_tasks = [ 'all_code_is_formatted_tcc', 'install_dependencies_for_examples_and_tools_tcc', 'test_v_to_c_tcc', 'v_self_compilation_tcc', 'v_doctor_tcc', 'verify_v_test_works_tcc', 'test_pure_v_math_module_tcc', 'test_inline_assembly', 'self_tests_vprod_tcc', 'build_examples_tcc', 'run_submodule_example_tcc', 'build_tools_tcc', 'build_vbinaries_tcc', 'build_benches_tcc', 'run_vsh_script_tcc', 'test_v_tutorials_tcc', 'build_fast_tcc', 'v_self_compilation_usecache_tcc', 'test_password_input_tcc', 'test_readline_tcc', 'test_leak_detector_tcc', 'test_leak_detector_not_active_tcc', 'build_v_with_prealloc', 'all_code_is_formatted_gcc', 'install_dependencies_for_examples_and_tools_gcc', 'recompile_v_with_cstrict_gcc', 'valgrind_v_c_gcc', 'run_sanitizers_gcc', 'v_self_compilation_gcc', 'v_self_compilation_usecache_gcc', 'verify_v_test_works_gcc', 'test_pure_v_math_module_gcc', 'self_tests_gcc', 'self_tests_prod_gcc', 'self_tests_cstrict_gcc', 'build_examples_gcc', 'build_tetris_autofree_gcc', 'build_blog_autofree_gcc', 'build_option_test_autofree_gcc', 'v_self_compilation_parallel_cc_gcc', 'build_modules_gcc', 'compile_vdoctor_prod_gcc', 'compile_vup_prod_gcc', 'all_code_is_formatted_clang', 'install_dependencies_for_examples_and_tools_clang', 'recompile_v_with_cstrict_clang', 'valgrind_clang', 'run_sanitizers_clang', 'v_self_compilation_clang', 'v_self_compilation_usecache_clang', 'verify_v_test_works_clang', 'test_pure_v_math_module_clang', 'self_tests_clang', 'self_tests_vprod_clang', 'self_tests_cstrict_clang', 'build_examples_clang', 'build_examples_autofree_clang', 'build_modules_clang', ] // Keep progress across edits/rebuilds, but isolate users and checkout directories. fn ci_progress_path() string { checkout := sha256.hexhash(os.real_path(os.getwd())) return os.join_path(os.cache_dir(), 'v-linux-ci-${os.getuid()}-${checkout}.progress') } fn ci_progress_contents(task_name string) string { // Record the whole ordered task list so changed plans restart safely. return 'linux-ci-v1\n${task_name}\n${ci_tasks.join('\n')}\n' } fn ci_resume_index(path string) !int { if !os.exists(path) { return -1 } if !os.is_file(path) { return error('CI progress path is not a file: ${path}') } saved := os.read_file(path)! for i, task_name in ci_tasks { if saved == ci_progress_contents(task_name) { return i } } eprintln('Ignoring invalid or outdated CI progress; restarting from the first task.') return -1 } fn save_ci_progress(path string, task_name string) ! { // Write privately, then rename on the same filesystem. An interrupted write // leaves the previous checkpoint intact, never a partially written cursor. if os.exists(path) && !os.is_file(path) { return error('CI progress path is not a file: ${path}') } tmp_dir := '${path}.${os.getpid()}.tmp' os.mkdir(tmp_dir, mode: 0o700)! defer { os.rmdir_all(tmp_dir) or {} } tmp_path := os.join_path(tmp_dir, 'progress') os.write_file(tmp_path, ci_progress_contents(task_name))! os.rename(tmp_path, path)! } fn ci_vflags(task_index int) string { if task_index < ci_tasks.index('all_code_is_formatted_gcc') { return '-cc tcc -no-retry-compilation' } if task_index < ci_tasks.index('all_code_is_formatted_clang') { return '-cc gcc' } return '-cc clang' } // run_ci_tasks mirrors the active ci/linux_ci.vsh steps in // .github/workflows/linux_ci.yml. The generic `all` mode intentionally remains // exhaustive, including tasks that are currently disabled in the workflow. fn run_ci_tasks(reset bool) ! { // Match the GitHub Actions environment that changes test behavior. os.setenv('CI', 'true', true) os.setenv('GITHUB_ACTIONS', 'true', true) os.setenv('RUNNER_OS', 'Linux', true) os.setenv('V_MACOS_V3_NO_FALLBACK', '1', true) // Stop test/build sessions promptly while retaining Linux CI's normal worker count. os.setenv('VTEST_FAIL_FAST', '1', true) os.setenv('VTEST_SHOW_LONGEST_BY_RUNTIME', '3', true) os.setenv('VTEST_SHOW_LONGEST_BY_COMPTIME', '3', true) os.setenv('VTEST_SHOW_LONGEST_BY_TOTALTIME', '3', true) os.setenv('VTEST_SKIP_OWNERSHIP', '1', true) progress_path := ci_progress_path() progress_dir := '${progress_path}.d' saved_index := if reset { -1 } else { ci_resume_index(progress_path)! } // No valid cursor means none of its finer-grained records may be reused. if saved_index < 0 && os.exists(progress_dir) { os.rmdir_all(progress_dir)! } if !os.exists(progress_dir) { os.mkdir(progress_dir, mode: 0o700)! } start := if saved_index < 0 { 0 } else { saved_index } os.unsetenv('VTEST_RESUME_OWNER') eprintln('CI progress: ${progress_path}') eprintln('Use `v run ci/linux_ci.vsh ci --reset` to restart from the first task.') if start > 0 { eprintln('Resuming at ${ci_tasks[start]}; skipping ${start} completed CI tasks.') } for i in start .. ci_tasks.len { task_name := ci_tasks[i] // Save BEFORE execution: a failure or interruption must retry this task. save_ci_progress(progress_path, task_name)! os.setenv('V_CI_TASK_PROGRESS', os.join_path(progress_dir, task_name), true) os.setenv('VFLAGS', ci_vflags(i), true) if task_name.ends_with('_tcc') || task_name in ['build_v_with_prealloc', 'test_inline_assembly'] { os.setenv('GITHUB_JOB', 'tcc-linux', true) } else if task_name.ends_with('_gcc') { os.setenv('GITHUB_JOB', 'gcc-linux', true) } else { os.setenv('GITHUB_JOB', 'clang-linux', true) } eprintln('CI task ${i + 1}/${ci_tasks.len}: ${task_name}') exec_args(['v', 'run', 'ci/linux_ci.vsh', '${task_name}']) } os.rmdir_all(progress_dir)! os.rm(progress_path)! eprintln('CI tasks complete; progress cleared.') } // Collect all tasks const all_tasks = { 'build_v_with_prealloc': Task{build_v_with_prealloc, 'Build V with prealloc'} // tcc tasks 'all_code_is_formatted_tcc': Task{all_code_is_formatted, 'All code is formatted (tcc)'} 'install_dependencies_for_examples_and_tools_tcc': Task{install_dependencies_for_examples_and_tools_tcc, 'Install deps for examples/tools (tcc)'} 'test_v_to_c_tcc': Task{test_v_to_c_tcc, 'Test v->c with tcc'} 'v_self_compilation_tcc': Task{v_self_compilation_tcc, 'V self compilation (tcc)'} 'v_doctor_tcc': Task{v_doctor_tcc, 'v doctor (tcc)'} 'verify_v_test_works_tcc': Task{verify_v_test_works_tcc, 'Verify `v test` works (tcc)'} 'test_pure_v_math_module_tcc': Task{test_pure_v_math_module_tcc, 'Test pure V math module (tcc)'} 'self_tests_tcc': Task{self_tests_tcc, 'Self tests (tcc)'} 'self_tests_vprod_tcc': Task{self_tests_vprod_tcc, 'Self tests using the optimized compiler (tcc)'} 'build_examples_tcc': Task{build_examples_tcc, 'Build examples (tcc)'} 'run_submodule_example_tcc': Task{run_submodule_example_tcc, 'Run submodule example (tcc)'} 'build_tools_tcc': Task{build_tools_tcc, 'Build V tools (tcc)'} 'build_vbinaries_tcc': Task{build_vbinaries_tcc, 'Build V binaries (tcc)'} 'build_benches_tcc': Task{build_benches_tcc, 'Build benches (tcc)'} 'run_vsh_script_tcc': Task{run_vsh_script_tcc, 'Run a VSH script (tcc)'} 'test_v_tutorials_tcc': Task{test_v_tutorials_tcc, 'Test V tutorials (tcc)'} 'build_fast_tcc': Task{build_fast_tcc, 'Build cmd/tools/fast (tcc)'} 'v_self_compilation_usecache_tcc': Task{v_self_compilation_usecache_tcc, 'V self compilation with default caching (tcc)'} 'test_password_input_tcc': Task{test_password_input_tcc, 'Test password input (tcc)'} 'test_readline_tcc': Task{test_readline_tcc, 'Test readline (tcc)'} 'test_leak_detector_tcc': Task{test_leak_detector_tcc, 'Test leak detector (tcc)'} 'test_leak_detector_not_active_tcc': Task{test_leak_detector_not_active_tcc, 'Test leak detector not active (tcc)'} // gcc tasks 'all_code_is_formatted_gcc': Task{all_code_is_formatted_gcc, 'All code is formatted (gcc)'} 'install_dependencies_for_examples_and_tools_gcc': Task{install_dependencies_for_examples_and_tools_gcc, 'Install deps for examples/tools (gcc)'} 'recompile_v_with_cstrict_gcc': Task{recompile_v_with_cstrict_gcc, 'Recompile V with -cstrict and gcc'} 'valgrind_v_c_gcc': Task{valgrind_v_c_gcc, 'Valgrind v.c (gcc)'} 'run_sanitizers_gcc': Task{run_sanitizers_gcc, 'Run sanitizers (gcc)'} 'v_self_compilation_gcc': Task{v_self_compilation_gcc, 'V self compilation (gcc)'} 'v_self_compilation_usecache_gcc': Task{v_self_compilation_usecache_gcc, 'V self compilation with default caching (gcc)'} 'verify_v_test_works_gcc': Task{verify_v_test_works_gcc, 'Verify `v test` works (gcc)'} 'test_pure_v_math_module_gcc': Task{test_pure_v_math_module_gcc, 'Test pure V math module (gcc)'} 'self_tests_gcc': Task{self_tests_gcc, 'Self tests (gcc)'} 'self_tests_prod_gcc': Task{self_tests_prod_gcc, 'Self tests (-prod) (gcc)'} 'self_tests_cstrict_gcc': Task{self_tests_cstrict_gcc, 'Self tests (-cstrict) (gcc)'} 'build_examples_gcc': Task{build_examples_gcc, 'Build examples (gcc)'} 'build_tetris_autofree_gcc': Task{build_tetris_autofree_gcc, 'Build tetris with -autofree (gcc)'} 'build_blog_autofree_gcc': Task{build_blog_autofree_gcc, 'Build blog tutorial with -autofree (gcc)'} 'build_option_test_autofree_gcc': Task{build_option_test_autofree_gcc, 'Build option_test.c.v with -autofree (gcc)'} 'v_self_compilation_parallel_cc_gcc': Task{v_self_compilation_parallel_cc_gcc, 'V self compilation with -parallel-cc (gcc)'} 'build_modules_gcc': Task{build_modules_gcc, 'Build modules (gcc)'} 'compile_vdoctor_prod_gcc': Task{compile_vdoctor_prod_gcc, 'compile vdoctor with -prod (gcc)'} 'compile_vup_prod_gcc': Task{compile_vup_prod_gcc, 'compile vup with -prod (gcc)'} // clang tasks 'all_code_is_formatted_clang': Task{all_code_is_formatted_clang, 'All code is formatted (clang)'} 'install_dependencies_for_examples_and_tools_clang': Task{install_dependencies_for_examples_and_tools_clang, 'Install deps for examples/tools (clang)'} 'recompile_v_with_cstrict_clang': Task{recompile_v_with_cstrict_clang, 'Recompile V with -cstrict and clang'} 'valgrind_clang': Task{valgrind_clang, 'Valgrind (clang)'} 'run_sanitizers_clang': Task{run_sanitizers_clang, 'Run sanitizers (clang)'} 'v_self_compilation_clang': Task{v_self_compilation_clang, 'V self compilation (clang)'} 'v_self_compilation_usecache_clang': Task{v_self_compilation_usecache_clang, 'V self compilation with default caching (clang)'} 'verify_v_test_works_clang': Task{verify_v_test_works_clang, 'Verify `v test` works (clang)'} 'test_pure_v_math_module_clang': Task{test_pure_v_math_module_clang, 'Test pure V math module (clang)'} 'self_tests_clang': Task{self_tests_clang, 'Self tests (clang)'} 'self_tests_vprod_clang': Task{self_tests_vprod_clang, 'Self tests (vprod) (clang)'} 'self_tests_cstrict_clang': Task{self_tests_cstrict_clang, 'Self tests (-cstrict) (clang)'} 'build_examples_clang': Task{build_examples_clang, 'Build examples (clang)'} 'build_examples_autofree_clang': Task{build_examples_autofree_clang, 'Build examples with -autofree (clang)'} 'build_modules_clang': Task{build_modules_clang, 'Build modules (clang)'} 'test_inline_assembly': Task{test_inline_assembly, 'Test inline assembly'} } if os.args.len > 1 && os.args[1] == 'ci' { if os.args.len > 3 || (os.args.len == 3 && os.args[2] != '--reset') { eprintln('Usage: v run ci/linux_ci.vsh ci [--reset]') exit(1) } run_ci_tasks(os.args.len == 3) or { eprintln('Could not update CI progress: ${err.msg()}') exit(1) } exit(0) } common.run(all_tasks)