diff --git a/CMakeLists.txt b/CMakeLists.txt index e69e0b5..0b8c1a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,208 +1,208 @@ -cmake_minimum_required(VERSION 3.20) -project(CLeonOS NONE) - -# User-configurable toolchain and tool variables (Makefile-compatible defaults). -set(NO_COLOR 0 CACHE STRING "Disable colored log output when set to 1") -include("${CMAKE_SOURCE_DIR}/cmake/log.cmake") -set(CL_LOG_EMIT_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/log_emit.cmake") - -set(CC "x86_64-elf-gcc" CACHE STRING "Kernel C compiler") -set(KERNEL_CXX "g++" CACHE STRING "Kernel C++ compiler") -set(LD "x86_64-elf-ld" CACHE STRING "Kernel linker") -set(USER_CC "cc" CACHE STRING "User-space C compiler") -set(USER_LD "ld" CACHE STRING "User-space linker") -set(RUSTC "rustc" CACHE STRING "Rust compiler") -set(NM "nm" CACHE STRING "nm executable") -set(ADDR2LINE "addr2line" CACHE STRING "addr2line executable") - -set(XORRISO "xorriso" CACHE STRING "xorriso executable") -set(TAR "tar" CACHE STRING "tar executable") -set(GIT_TOOL "git" CACHE STRING "git executable") -set(MAKE_TOOL "make" CACHE STRING "make executable") -set(SH_TOOL "sh" CACHE STRING "POSIX shell executable") - -set(OBJCOPY_FOR_TARGET "llvm-objcopy" CACHE STRING "objcopy tool for limine configure") -set(OBJDUMP_FOR_TARGET "llvm-objdump" CACHE STRING "objdump tool for limine configure") -set(READELF_FOR_TARGET "llvm-readelf" CACHE STRING "readelf tool for limine configure") - -set(QEMU_X86_64 "qemu-system-x86_64" CACHE STRING "QEMU executable") - -set(CLEONOS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/cleonos") -if(EXISTS "${CLEONOS_SOURCE_DIR}/CMakeLists.txt") - set(_cleonos_enable_default ON) -else() - set(_cleonos_enable_default OFF) -endif() -set(CLEONOS_ENABLE ${_cleonos_enable_default} CACHE BOOL "Enable CLeonOS userland/ramdisk/iso integration") -if(CLEONOS_ENABLE AND NOT EXISTS "${CLEONOS_SOURCE_DIR}/CMakeLists.txt") - cl_log_error("CLEONOS_ENABLE=ON but missing ${CLEONOS_SOURCE_DIR}/CMakeLists.txt") -endif() -if(NOT CLEONOS_ENABLE) - cl_log_warn("CLEONOS_ENABLE=OFF, running in CLKS-only build mode") -endif() - -set(LIMINE_DIR "limine" CACHE STRING "Limine source directory") -set(LIMINE_REPO "https://gh-proxy.com/https://github.com/limine-bootloader/limine.git" CACHE STRING "Limine git repository") -set(LIMINE_REF "" CACHE STRING "Optional Limine branch or tag") -set(LIMINE_BIN_DIR "${LIMINE_DIR}/bin" CACHE STRING "Limine bin directory") -set(LIMINE_CONFIGURE_FLAGS "--enable-bios-cd --enable-uefi-cd --enable-uefi-x86-64" CACHE STRING "Limine configure flags") -set(LIMINE_SKIP_CONFIGURE 0 CACHE BOOL "Skip Limine configure step") - -function(resolve_path INPUT_PATH OUTPUT_VAR) - if(IS_ABSOLUTE "${INPUT_PATH}") - set(${OUTPUT_VAR} "${INPUT_PATH}" PARENT_SCOPE) - else() - set(${OUTPUT_VAR} "${CMAKE_SOURCE_DIR}/${INPUT_PATH}" PARENT_SCOPE) - endif() -endfunction() - -function(resolve_tool_with_fallback VAR_NAME) - set(_fallbacks ${ARGN}) - set(_requested "${${VAR_NAME}}") - - if("${_requested}" STREQUAL "") - cl_log_error("empty tool variable: ${VAR_NAME}") - endif() - - if(IS_ABSOLUTE "${_requested}") - if(NOT EXISTS "${_requested}") - cl_log_error("${VAR_NAME} not found: ${_requested}") - endif() - set(_resolved "${_requested}") - else() - unset(_requested_path CACHE) - unset(_requested_path) - find_program(_requested_path NAMES "${_requested}") - if(_requested_path) - set(_resolved "${_requested_path}") - else() - set(_resolved "") - foreach(_cand IN LISTS _fallbacks) - unset(_cand_path CACHE) - unset(_cand_path) - find_program(_cand_path NAMES "${_cand}") - if(_cand_path) - cl_log_warn("${VAR_NAME} '${_requested}' not found; fallback to '${_cand}'") - set(_resolved "${_cand_path}") - break() - endif() - endforeach() - if("${_resolved}" STREQUAL "") - cl_log_error("${VAR_NAME} tool not found: '${_requested}', fallbacks='${_fallbacks}'") - endif() - endif() - endif() - - get_property(_help CACHE "${VAR_NAME}" PROPERTY HELPSTRING) - if("${_help}" STREQUAL "") - set(_help "tool path/name") - endif() - set(${VAR_NAME} "${_resolved}" CACHE STRING "${_help}" FORCE) - set(${VAR_NAME} "${_resolved}" PARENT_SCOPE) -endfunction() - -set(BUILD_ROOT "${CMAKE_SOURCE_DIR}/build/x86_64") -set(OBJ_ROOT "${BUILD_ROOT}/obj") -set(ISO_ROOT "${BUILD_ROOT}/iso_root") -set(RAMDISK_ROOT "${BUILD_ROOT}/ramdisk_root") -set(KERNEL_ELF "${BUILD_ROOT}/clks_kernel.elf") -set(RAMDISK_IMAGE "${BUILD_ROOT}/cleonos_ramdisk.tar") -set(DISK_IMAGE "${BUILD_ROOT}/cleonos_disk.img") -set(CLEONOS_DISK_IMAGE_MB "64" CACHE STRING "Default runtime disk image size in MB") -set(ISO_IMAGE "${CMAKE_SOURCE_DIR}/build/CLeonOS-x86_64.iso") -set(KERNEL_SYMBOLS_FILE "${BUILD_ROOT}/kernel.sym") - -set(USER_BUILD_ROOT "${BUILD_ROOT}/user") -set(USER_OBJ_ROOT "${USER_BUILD_ROOT}/obj") -set(USER_APP_DIR "${USER_BUILD_ROOT}/apps") -set(USER_LIB_DIR "${USER_BUILD_ROOT}/lib") -set(USER_RUST_LIB "${USER_LIB_DIR}/libcleonos_user_rust.a") -set(KERNEL_RUST_LIB "${BUILD_ROOT}/libclks_kernel_rust.a") - -resolve_tool_with_fallback(CC gcc cc clang) -resolve_tool_with_fallback(KERNEL_CXX g++ clang++ x86_64-elf-g++) -resolve_tool_with_fallback(LD ld.lld ld) -if(CLEONOS_ENABLE) - resolve_tool_with_fallback(USER_CC cc gcc clang) - resolve_tool_with_fallback(USER_LD ld.lld ld) -endif() -resolve_tool_with_fallback(NM llvm-nm x86_64-elf-nm nm) -resolve_tool_with_fallback(ADDR2LINE llvm-addr2line x86_64-elf-addr2line addr2line) -resolve_tool_with_fallback(OBJCOPY_FOR_TARGET llvm-objcopy x86_64-linux-gnu-objcopy objcopy) -resolve_tool_with_fallback(OBJDUMP_FOR_TARGET llvm-objdump x86_64-linux-gnu-objdump objdump) -resolve_tool_with_fallback(READELF_FOR_TARGET llvm-readelf x86_64-linux-gnu-readelf readelf) - -resolve_path("${LIMINE_DIR}" LIMINE_DIR_ABS) -resolve_path("${LIMINE_BIN_DIR}" LIMINE_BIN_DIR_ABS) -set(LIMINE_SETUP_STAMP "${LIMINE_DIR_ABS}/.cleonos-limine-setup.stamp") -set(LIMINE_BUILD_STAMP "${LIMINE_DIR_ABS}/.cleonos-limine-build.stamp") - -set(CLKS_ARCH "x86_64" CACHE STRING "Target CLKS arch") -set(USER_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/cleonos/c/user.ld") -set(KELF_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/cleonos/c/kelf.ld") -set(CLEONOS_MENUCONFIG_CMAKE "${CMAKE_SOURCE_DIR}/configs/menuconfig/config.cmake" CACHE FILEPATH "menuconfig generated CMake config") - -if(EXISTS "${CLEONOS_MENUCONFIG_CMAKE}") - include("${CLEONOS_MENUCONFIG_CMAKE}") - cl_log_info("menuconfig loaded from ${CLEONOS_MENUCONFIG_CMAKE}") -endif() - -# CLKS compile flags and feature-to-macro expansion now live in the CLKS submodule build system. -set(USER_CFLAGS - -std=c11 - -ffreestanding - -fno-stack-protector - -fno-builtin - -Wall - -Wextra - -Werror - "-I${CMAKE_SOURCE_DIR}/cleonos/c/include" -) - -set(USER_CFLAGS_DOOM - -std=c11 - -ffreestanding - -fno-stack-protector - -fno-builtin - -Wall - -Wextra - -Wno-error - -Wno-unused-parameter - -Wno-missing-field-initializers - -Wno-sign-compare - -D_DEFAULT_SOURCE - -D_POSIX_C_SOURCE=200809L - "-I${CMAKE_SOURCE_DIR}/cleonos/third-party/doomgeneric/doomgeneric" - "-include" - "${CMAKE_SOURCE_DIR}/cleonos/c/apps/doom/doom_shim.h" -) - -set(USER_LDFLAGS - -nostdlib - -z - max-page-size=0x1000 - -T - "${USER_LINKER_SCRIPT}" -) - -set(KELF_LDFLAGS - -nostdlib - -z - max-page-size=0x1000 - -T - "${KELF_LINKER_SCRIPT}" -) - -if(NOT CLKS_ARCH STREQUAL "x86_64") - cl_log_error("CLKS_ARCH=${CLKS_ARCH} is not supported by this CMake build yet; use x86_64") -endif() - -set(CLKS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/clks") -set(CLKS_CMAKE_BUILD_DIR "${CMAKE_BINARY_DIR}/clks-cmake") -if(NOT EXISTS "${CLKS_SOURCE_DIR}/CMakeLists.txt") - cl_log_error("missing CLKS submodule CMakeLists: ${CLKS_SOURCE_DIR}/CMakeLists.txt") -endif() - +cmake_minimum_required(VERSION 3.20) +project(CLeonOS NONE) + +# User-configurable toolchain and tool variables (Makefile-compatible defaults). +set(NO_COLOR 0 CACHE STRING "Disable colored log output when set to 1") +include("${CMAKE_SOURCE_DIR}/cmake/log.cmake") +set(CL_LOG_EMIT_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/log_emit.cmake") + +set(CC "x86_64-elf-gcc" CACHE STRING "Kernel C compiler") +set(KERNEL_CXX "g++" CACHE STRING "Kernel C++ compiler") +set(LD "x86_64-elf-ld" CACHE STRING "Kernel linker") +set(USER_CC "cc" CACHE STRING "User-space C compiler") +set(USER_LD "ld" CACHE STRING "User-space linker") +set(RUSTC "rustc" CACHE STRING "Rust compiler") +set(NM "nm" CACHE STRING "nm executable") +set(ADDR2LINE "addr2line" CACHE STRING "addr2line executable") + +set(XORRISO "xorriso" CACHE STRING "xorriso executable") +set(TAR "tar" CACHE STRING "tar executable") +set(GIT_TOOL "git" CACHE STRING "git executable") +set(MAKE_TOOL "make" CACHE STRING "make executable") +set(SH_TOOL "sh" CACHE STRING "POSIX shell executable") + +set(OBJCOPY_FOR_TARGET "llvm-objcopy" CACHE STRING "objcopy tool for limine configure") +set(OBJDUMP_FOR_TARGET "llvm-objdump" CACHE STRING "objdump tool for limine configure") +set(READELF_FOR_TARGET "llvm-readelf" CACHE STRING "readelf tool for limine configure") + +set(QEMU_X86_64 "qemu-system-x86_64" CACHE STRING "QEMU executable") + +set(CLEONOS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/cleonos") +if(EXISTS "${CLEONOS_SOURCE_DIR}/CMakeLists.txt") + set(_cleonos_enable_default ON) +else() + set(_cleonos_enable_default OFF) +endif() +set(CLEONOS_ENABLE ${_cleonos_enable_default} CACHE BOOL "Enable CLeonOS userland/ramdisk/iso integration") +if(CLEONOS_ENABLE AND NOT EXISTS "${CLEONOS_SOURCE_DIR}/CMakeLists.txt") + cl_log_error("CLEONOS_ENABLE=ON but missing ${CLEONOS_SOURCE_DIR}/CMakeLists.txt") +endif() +if(NOT CLEONOS_ENABLE) + cl_log_warn("CLEONOS_ENABLE=OFF, running in CLKS-only build mode") +endif() + +set(LIMINE_DIR "limine" CACHE STRING "Limine source directory") +set(LIMINE_REPO "https://gh-proxy.com/https://github.com/limine-bootloader/limine.git" CACHE STRING "Limine git repository") +set(LIMINE_REF "" CACHE STRING "Optional Limine branch or tag") +set(LIMINE_BIN_DIR "${LIMINE_DIR}/bin" CACHE STRING "Limine bin directory") +set(LIMINE_CONFIGURE_FLAGS "--enable-bios-cd --enable-uefi-cd --enable-uefi-x86-64" CACHE STRING "Limine configure flags") +set(LIMINE_SKIP_CONFIGURE 0 CACHE BOOL "Skip Limine configure step") + +function(resolve_path INPUT_PATH OUTPUT_VAR) + if(IS_ABSOLUTE "${INPUT_PATH}") + set(${OUTPUT_VAR} "${INPUT_PATH}" PARENT_SCOPE) + else() + set(${OUTPUT_VAR} "${CMAKE_SOURCE_DIR}/${INPUT_PATH}" PARENT_SCOPE) + endif() +endfunction() + +function(resolve_tool_with_fallback VAR_NAME) + set(_fallbacks ${ARGN}) + set(_requested "${${VAR_NAME}}") + + if("${_requested}" STREQUAL "") + cl_log_error("empty tool variable: ${VAR_NAME}") + endif() + + if(IS_ABSOLUTE "${_requested}") + if(NOT EXISTS "${_requested}") + cl_log_error("${VAR_NAME} not found: ${_requested}") + endif() + set(_resolved "${_requested}") + else() + unset(_requested_path CACHE) + unset(_requested_path) + find_program(_requested_path NAMES "${_requested}") + if(_requested_path) + set(_resolved "${_requested_path}") + else() + set(_resolved "") + foreach(_cand IN LISTS _fallbacks) + unset(_cand_path CACHE) + unset(_cand_path) + find_program(_cand_path NAMES "${_cand}") + if(_cand_path) + cl_log_warn("${VAR_NAME} '${_requested}' not found; fallback to '${_cand}'") + set(_resolved "${_cand_path}") + break() + endif() + endforeach() + if("${_resolved}" STREQUAL "") + cl_log_error("${VAR_NAME} tool not found: '${_requested}', fallbacks='${_fallbacks}'") + endif() + endif() + endif() + + get_property(_help CACHE "${VAR_NAME}" PROPERTY HELPSTRING) + if("${_help}" STREQUAL "") + set(_help "tool path/name") + endif() + set(${VAR_NAME} "${_resolved}" CACHE STRING "${_help}" FORCE) + set(${VAR_NAME} "${_resolved}" PARENT_SCOPE) +endfunction() + +set(BUILD_ROOT "${CMAKE_SOURCE_DIR}/build/x86_64") +set(OBJ_ROOT "${BUILD_ROOT}/obj") +set(ISO_ROOT "${BUILD_ROOT}/iso_root") +set(RAMDISK_ROOT "${BUILD_ROOT}/ramdisk_root") +set(KERNEL_ELF "${BUILD_ROOT}/clks_kernel.elf") +set(RAMDISK_IMAGE "${BUILD_ROOT}/cleonos_ramdisk.tar") +set(DISK_IMAGE "${BUILD_ROOT}/cleonos_disk.img") +set(CLEONOS_DISK_IMAGE_MB "64" CACHE STRING "Default runtime disk image size in MB") +set(ISO_IMAGE "${CMAKE_SOURCE_DIR}/build/CLeonOS-x86_64.iso") +set(KERNEL_SYMBOLS_FILE "${BUILD_ROOT}/kernel.sym") + +set(USER_BUILD_ROOT "${BUILD_ROOT}/user") +set(USER_OBJ_ROOT "${USER_BUILD_ROOT}/obj") +set(USER_APP_DIR "${USER_BUILD_ROOT}/apps") +set(USER_LIB_DIR "${USER_BUILD_ROOT}/lib") +set(USER_RUST_LIB "${USER_LIB_DIR}/libcleonos_user_rust.a") +set(KERNEL_RUST_LIB "${BUILD_ROOT}/libclks_kernel_rust.a") + +resolve_tool_with_fallback(CC gcc cc clang) +resolve_tool_with_fallback(KERNEL_CXX g++ clang++ x86_64-elf-g++) +resolve_tool_with_fallback(LD ld.lld ld) +if(CLEONOS_ENABLE) + resolve_tool_with_fallback(USER_CC cc gcc clang) + resolve_tool_with_fallback(USER_LD ld.lld ld) +endif() +resolve_tool_with_fallback(NM llvm-nm x86_64-elf-nm nm) +resolve_tool_with_fallback(ADDR2LINE llvm-addr2line x86_64-elf-addr2line addr2line) +resolve_tool_with_fallback(OBJCOPY_FOR_TARGET llvm-objcopy x86_64-linux-gnu-objcopy objcopy) +resolve_tool_with_fallback(OBJDUMP_FOR_TARGET llvm-objdump x86_64-linux-gnu-objdump objdump) +resolve_tool_with_fallback(READELF_FOR_TARGET llvm-readelf x86_64-linux-gnu-readelf readelf) + +resolve_path("${LIMINE_DIR}" LIMINE_DIR_ABS) +resolve_path("${LIMINE_BIN_DIR}" LIMINE_BIN_DIR_ABS) +set(LIMINE_SETUP_STAMP "${LIMINE_DIR_ABS}/.cleonos-limine-setup.stamp") +set(LIMINE_BUILD_STAMP "${LIMINE_DIR_ABS}/.cleonos-limine-build.stamp") + +set(CLKS_ARCH "x86_64" CACHE STRING "Target CLKS arch") +set(USER_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/cleonos/c/user.ld") +set(KELF_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/cleonos/c/kelf.ld") +set(CLEONOS_MENUCONFIG_CMAKE "${CMAKE_SOURCE_DIR}/configs/menuconfig/config.cmake" CACHE FILEPATH "menuconfig generated CMake config") + +if(EXISTS "${CLEONOS_MENUCONFIG_CMAKE}") + include("${CLEONOS_MENUCONFIG_CMAKE}") + cl_log_info("menuconfig loaded from ${CLEONOS_MENUCONFIG_CMAKE}") +endif() + +# CLKS compile flags and feature-to-macro expansion now live in the CLKS submodule build system. +set(USER_CFLAGS + -std=c11 + -ffreestanding + -fno-stack-protector + -fno-builtin + -Wall + -Wextra + -Werror + "-I${CMAKE_SOURCE_DIR}/cleonos/c/include" +) + +set(USER_CFLAGS_DOOM + -std=c11 + -ffreestanding + -fno-stack-protector + -fno-builtin + -Wall + -Wextra + -Wno-error + -Wno-unused-parameter + -Wno-missing-field-initializers + -Wno-sign-compare + -D_DEFAULT_SOURCE + -D_POSIX_C_SOURCE=200809L + "-I${CMAKE_SOURCE_DIR}/cleonos/third-party/doomgeneric/doomgeneric" + "-include" + "${CMAKE_SOURCE_DIR}/cleonos/c/apps/doom/doom_shim.h" +) + +set(USER_LDFLAGS + -nostdlib + -z + max-page-size=0x1000 + -T + "${USER_LINKER_SCRIPT}" +) + +set(KELF_LDFLAGS + -nostdlib + -z + max-page-size=0x1000 + -T + "${KELF_LINKER_SCRIPT}" +) + +if(NOT CLKS_ARCH STREQUAL "x86_64") + cl_log_error("CLKS_ARCH=${CLKS_ARCH} is not supported by this CMake build yet; use x86_64") +endif() + +set(CLKS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/clks") +set(CLKS_CMAKE_BUILD_DIR "${CMAKE_BINARY_DIR}/clks-cmake") +if(NOT EXISTS "${CLKS_SOURCE_DIR}/CMakeLists.txt") + cl_log_error("missing CLKS submodule CMakeLists: ${CLKS_SOURCE_DIR}/CMakeLists.txt") +endif() + set(CLKS_SUBMODULE_CMAKE_ARGS "-DNO_COLOR=${NO_COLOR}" "-DCLKS_ARCH=${CLKS_ARCH}" @@ -211,273 +211,273 @@ set(CLKS_SUBMODULE_CMAKE_ARGS "-DCC=${CC}" "-DKERNEL_CXX=${KERNEL_CXX}" "-DLD=${LD}" - "-DRUSTC=${RUSTC}" - "-DNM=${NM}" - "-DADDR2LINE=${ADDR2LINE}" - "-DOBJCOPY_FOR_TARGET=${OBJCOPY_FOR_TARGET}" - "-DOBJDUMP_FOR_TARGET=${OBJDUMP_FOR_TARGET}" - "-DREADELF_FOR_TARGET=${READELF_FOR_TARGET}" -) - -add_custom_target(kernel - COMMAND ${CMAKE_COMMAND} -S "${CLKS_SOURCE_DIR}" -B "${CLKS_CMAKE_BUILD_DIR}" ${CLKS_SUBMODULE_CMAKE_ARGS} - COMMAND ${CMAKE_COMMAND} --build "${CLKS_CMAKE_BUILD_DIR}" --target kernel - USES_TERMINAL -) - -add_custom_target(kernel-symbols - COMMAND ${CMAKE_COMMAND} -S "${CLKS_SOURCE_DIR}" -B "${CLKS_CMAKE_BUILD_DIR}" ${CLKS_SUBMODULE_CMAKE_ARGS} - COMMAND ${CMAKE_COMMAND} --build "${CLKS_CMAKE_BUILD_DIR}" --target kernel-symbols - USES_TERMINAL -) -add_dependencies(kernel-symbols kernel) - -if(CLEONOS_ENABLE) - include("${CMAKE_SOURCE_DIR}/cleonos/CMakeLists.txt") -endif() - -add_custom_target(setup-tools - COMMAND ${CMAKE_COMMAND} - "-DCLEONOS_ENABLE=${CLEONOS_ENABLE}" - "-DGIT_TOOL=${GIT_TOOL}" - "-DTAR_TOOL=${TAR}" - "-DXORRISO_TOOL=${XORRISO}" - "-DNO_COLOR=${NO_COLOR}" - "-DCC_TOOL=${CC}" - "-DLD_TOOL=${LD}" - "-DOBJCOPY_TOOL=${OBJCOPY_FOR_TARGET}" - "-DOBJDUMP_TOOL=${OBJDUMP_FOR_TARGET}" - "-DREADELF_TOOL=${READELF_FOR_TARGET}" - "-DNM_TOOL=${NM}" - "-DADDR2LINE_TOOL=${ADDR2LINE}" - "-DUSER_CC_TOOL=${USER_CC}" - "-DUSER_LD_TOOL=${USER_LD}" - "-DRUSTC_TOOL=${RUSTC}" - "-DMAKE_TOOL=${MAKE_TOOL}" - "-DSH_TOOL=${SH_TOOL}" - -P "${CMAKE_SOURCE_DIR}/cmake/check_tools.cmake" -) - -add_custom_target(setup-limine - COMMAND ${CMAKE_COMMAND} - "-DGIT_TOOL=${GIT_TOOL}" - "-DMAKE_TOOL=${MAKE_TOOL}" - "-DSH_TOOL=${SH_TOOL}" - "-DNO_COLOR=${NO_COLOR}" - "-DLIMINE_DIR=${LIMINE_DIR_ABS}" - "-DLIMINE_REPO=${LIMINE_REPO}" - "-DLIMINE_REF=${LIMINE_REF}" - "-DLIMINE_BIN_DIR=${LIMINE_BIN_DIR_ABS}" - "-DLIMINE_SETUP_STAMP=${LIMINE_SETUP_STAMP}" - "-DLIMINE_BUILD_STAMP=${LIMINE_BUILD_STAMP}" - "-DLIMINE_CONFIGURE_FLAGS=${LIMINE_CONFIGURE_FLAGS}" - "-DLIMINE_SKIP_CONFIGURE=${LIMINE_SKIP_CONFIGURE}" - "-DOBJCOPY_FOR_TARGET=${OBJCOPY_FOR_TARGET}" - "-DOBJDUMP_FOR_TARGET=${OBJDUMP_FOR_TARGET}" - "-DREADELF_FOR_TARGET=${READELF_FOR_TARGET}" - -P "${CMAKE_SOURCE_DIR}/cmake/setup_limine.cmake" -) -add_dependencies(setup-limine setup-tools) - -add_custom_target(setup DEPENDS setup-tools setup-limine) -add_custom_command( - TARGET setup - POST_BUILD - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=INFO" - "-DLOG_TEXT=environment ready" - -P "${CL_LOG_EMIT_SCRIPT}" -) - -if(CLEONOS_ENABLE) - add_custom_target(disk-image - COMMAND ${CMAKE_COMMAND} - "-DDISK_IMAGE=${DISK_IMAGE}" - "-DDISK_MB=${CLEONOS_DISK_IMAGE_MB}" - -P "${CMAKE_SOURCE_DIR}/cmake/ensure_disk_image.cmake" - BYPRODUCTS "${DISK_IMAGE}" - VERBATIM - ) - - add_custom_command( - OUTPUT "${ISO_IMAGE}" - COMMAND ${CMAKE_COMMAND} -E rm -rf "${ISO_ROOT}" - COMMAND ${CMAKE_COMMAND} -E make_directory "${ISO_ROOT}/boot/limine" "${ISO_ROOT}/EFI/BOOT" - COMMAND ${CMAKE_COMMAND} -E copy "${KERNEL_ELF}" "${ISO_ROOT}/boot/clks_kernel.elf" - COMMAND ${CMAKE_COMMAND} -E copy "${RAMDISK_IMAGE}" "${ISO_ROOT}/boot/cleonos_ramdisk.tar" - COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/configs/limine.conf" "${ISO_ROOT}/boot/limine/limine.conf" - COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/configs/limine.conf" "${ISO_ROOT}/EFI/BOOT/limine.conf" - COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/configs/limine.conf" "${ISO_ROOT}/limine.conf" - COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/limine-bios.sys" "${ISO_ROOT}/boot/limine/limine-bios.sys" - COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/limine-bios-cd.bin" "${ISO_ROOT}/boot/limine/limine-bios-cd.bin" - COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/limine-uefi-cd.bin" "${ISO_ROOT}/boot/limine/limine-uefi-cd.bin" - COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/BOOTX64.EFI" "${ISO_ROOT}/EFI/BOOT/BOOTX64.EFI" - COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_SOURCE_DIR}/build" - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=STEP" - "-DLOG_TEXT=building iso -> ${ISO_IMAGE}" - -P "${CL_LOG_EMIT_SCRIPT}" - COMMAND ${XORRISO} -as mkisofs - -b boot/limine/limine-bios-cd.bin - -no-emul-boot - -boot-load-size 4 - -boot-info-table - --efi-boot boot/limine/limine-uefi-cd.bin - -efi-boot-part - --efi-boot-image - --protective-msdos-label - "${ISO_ROOT}" - -o "${ISO_IMAGE}" - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=STEP" - "-DLOG_TEXT=installing limine boot sectors" - -P "${CL_LOG_EMIT_SCRIPT}" - COMMAND "${LIMINE_BIN_DIR_ABS}/limine" bios-install "${ISO_IMAGE}" - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=INFO" - "-DLOG_TEXT=iso ready: ${ISO_IMAGE}" - -P "${CL_LOG_EMIT_SCRIPT}" - DEPENDS "${KERNEL_ELF}" "${RAMDISK_IMAGE}" "${CMAKE_SOURCE_DIR}/configs/limine.conf" - VERBATIM - ) - - add_custom_target(iso ALL DEPENDS "${ISO_IMAGE}") - add_dependencies(iso setup-tools setup-limine kernel ramdisk) - - add_custom_target(run - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=STEP" - "-DLOG_TEXT=launching qemu run" - -P "${CL_LOG_EMIT_SCRIPT}" - COMMAND ${QEMU_X86_64} -M pc -m 1024M -boot order=d -cdrom "${ISO_IMAGE}" -drive "file=${DISK_IMAGE},format=raw,if=ide,index=0,media=disk" -serial stdio - DEPENDS iso disk-image - USES_TERMINAL - ) - - add_custom_target(debug - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=STEP" - "-DLOG_TEXT=launching qemu debug (-s -S)" - -P "${CL_LOG_EMIT_SCRIPT}" - COMMAND ${QEMU_X86_64} -M pc -m 1024M -boot order=d -cdrom "${ISO_IMAGE}" -drive "file=${DISK_IMAGE},format=raw,if=ide,index=0,media=disk" -serial stdio -s -S - DEPENDS iso disk-image - USES_TERMINAL - ) -else() - add_custom_target(clks-default ALL DEPENDS kernel) -endif() - -add_custom_target(clean-x86 - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=STEP" - "-DLOG_TEXT=cleaning ${BUILD_ROOT}" - -P "${CL_LOG_EMIT_SCRIPT}" - COMMAND ${CMAKE_COMMAND} -E rm -rf "${BUILD_ROOT}" - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=INFO" - "-DLOG_TEXT=clean done" - -P "${CL_LOG_EMIT_SCRIPT}" -) - -add_custom_target(clean-all - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=STEP" - "-DLOG_TEXT=cleaning build" - -P "${CL_LOG_EMIT_SCRIPT}" - COMMAND ${CMAKE_COMMAND} -E rm -rf "${CMAKE_SOURCE_DIR}/build" - COMMAND ${CMAKE_COMMAND} - "-DNO_COLOR=${NO_COLOR}" - "-DLOG_LEVEL=INFO" - "-DLOG_TEXT=clean-all done" - -P "${CL_LOG_EMIT_SCRIPT}" -) - -find_package(Python3 COMPONENTS Interpreter QUIET) -if(Python3_Interpreter_FOUND) - if(CLEONOS_ENABLE) - add_custom_target(menuconfig - COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" - USES_TERMINAL - ) - add_custom_target(menuconfig-gui - COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --gui - USES_TERMINAL - ) - else() - add_custom_target(menuconfig - COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --clks-only - USES_TERMINAL - ) - add_custom_target(menuconfig-gui - COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --gui --clks-only - USES_TERMINAL - ) - endif() - add_custom_target(menuconfig-clks - COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --clks-only - USES_TERMINAL - ) - add_custom_target(menuconfig-gui-clks - COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --gui --clks-only - USES_TERMINAL - ) -else() - add_custom_target(menuconfig - COMMAND ${CMAKE_COMMAND} -E echo "python3 not found; run scripts/menuconfig.py manually" - USES_TERMINAL - ) - add_custom_target(menuconfig-gui - COMMAND ${CMAKE_COMMAND} -E echo "python3 not found; run scripts/menuconfig.py --gui manually" - USES_TERMINAL - ) - add_custom_target(menuconfig-clks - COMMAND ${CMAKE_COMMAND} -E echo "python3 not found; run scripts/menuconfig.py --clks-only manually" - USES_TERMINAL - ) - add_custom_target(menuconfig-gui-clks - COMMAND ${CMAKE_COMMAND} -E echo "python3 not found; run scripts/menuconfig.py --gui --clks-only manually" - USES_TERMINAL - ) -endif() - -if(CLEONOS_ENABLE) - add_custom_target(cleonos-help - COMMAND ${CMAKE_COMMAND} -E echo "CLeonOS CMake build system (x86_64 only)" - COMMAND ${CMAKE_COMMAND} -E echo " CLEONOS_ENABLE=${CLEONOS_ENABLE}" - COMMAND ${CMAKE_COMMAND} -E echo " cmake -S . -B build-cmake" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-gui" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-clks" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-gui-clks" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target setup" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target kernel" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target userapps" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target iso" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target run" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target debug" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target disk-image" - ) -else() - add_custom_target(cleonos-help - COMMAND ${CMAKE_COMMAND} -E echo "CLeonOS CMake build system (x86_64 only)" - COMMAND ${CMAKE_COMMAND} -E echo " CLEONOS_ENABLE=${CLEONOS_ENABLE}" - COMMAND ${CMAKE_COMMAND} -E echo " cmake -S . -B build-cmake" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-gui" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-clks" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-gui-clks" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target setup" - COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target kernel" - COMMAND ${CMAKE_COMMAND} -E echo " (CLKS-only mode: userapps/iso/run/debug/disk-image are disabled)" - ) -endif() - + "-DRUSTC=${RUSTC}" + "-DNM=${NM}" + "-DADDR2LINE=${ADDR2LINE}" + "-DOBJCOPY_FOR_TARGET=${OBJCOPY_FOR_TARGET}" + "-DOBJDUMP_FOR_TARGET=${OBJDUMP_FOR_TARGET}" + "-DREADELF_FOR_TARGET=${READELF_FOR_TARGET}" +) + +add_custom_target(kernel + COMMAND ${CMAKE_COMMAND} -S "${CLKS_SOURCE_DIR}" -B "${CLKS_CMAKE_BUILD_DIR}" ${CLKS_SUBMODULE_CMAKE_ARGS} + COMMAND ${CMAKE_COMMAND} --build "${CLKS_CMAKE_BUILD_DIR}" --target kernel + USES_TERMINAL +) + +add_custom_target(kernel-symbols + COMMAND ${CMAKE_COMMAND} -S "${CLKS_SOURCE_DIR}" -B "${CLKS_CMAKE_BUILD_DIR}" ${CLKS_SUBMODULE_CMAKE_ARGS} + COMMAND ${CMAKE_COMMAND} --build "${CLKS_CMAKE_BUILD_DIR}" --target kernel-symbols + USES_TERMINAL +) +add_dependencies(kernel-symbols kernel) + +if(CLEONOS_ENABLE) + include("${CMAKE_SOURCE_DIR}/cleonos/CMakeLists.txt") +endif() + +add_custom_target(setup-tools + COMMAND ${CMAKE_COMMAND} + "-DCLEONOS_ENABLE=${CLEONOS_ENABLE}" + "-DGIT_TOOL=${GIT_TOOL}" + "-DTAR_TOOL=${TAR}" + "-DXORRISO_TOOL=${XORRISO}" + "-DNO_COLOR=${NO_COLOR}" + "-DCC_TOOL=${CC}" + "-DLD_TOOL=${LD}" + "-DOBJCOPY_TOOL=${OBJCOPY_FOR_TARGET}" + "-DOBJDUMP_TOOL=${OBJDUMP_FOR_TARGET}" + "-DREADELF_TOOL=${READELF_FOR_TARGET}" + "-DNM_TOOL=${NM}" + "-DADDR2LINE_TOOL=${ADDR2LINE}" + "-DUSER_CC_TOOL=${USER_CC}" + "-DUSER_LD_TOOL=${USER_LD}" + "-DRUSTC_TOOL=${RUSTC}" + "-DMAKE_TOOL=${MAKE_TOOL}" + "-DSH_TOOL=${SH_TOOL}" + -P "${CMAKE_SOURCE_DIR}/cmake/check_tools.cmake" +) + +add_custom_target(setup-limine + COMMAND ${CMAKE_COMMAND} + "-DGIT_TOOL=${GIT_TOOL}" + "-DMAKE_TOOL=${MAKE_TOOL}" + "-DSH_TOOL=${SH_TOOL}" + "-DNO_COLOR=${NO_COLOR}" + "-DLIMINE_DIR=${LIMINE_DIR_ABS}" + "-DLIMINE_REPO=${LIMINE_REPO}" + "-DLIMINE_REF=${LIMINE_REF}" + "-DLIMINE_BIN_DIR=${LIMINE_BIN_DIR_ABS}" + "-DLIMINE_SETUP_STAMP=${LIMINE_SETUP_STAMP}" + "-DLIMINE_BUILD_STAMP=${LIMINE_BUILD_STAMP}" + "-DLIMINE_CONFIGURE_FLAGS=${LIMINE_CONFIGURE_FLAGS}" + "-DLIMINE_SKIP_CONFIGURE=${LIMINE_SKIP_CONFIGURE}" + "-DOBJCOPY_FOR_TARGET=${OBJCOPY_FOR_TARGET}" + "-DOBJDUMP_FOR_TARGET=${OBJDUMP_FOR_TARGET}" + "-DREADELF_FOR_TARGET=${READELF_FOR_TARGET}" + -P "${CMAKE_SOURCE_DIR}/cmake/setup_limine.cmake" +) +add_dependencies(setup-limine setup-tools) + +add_custom_target(setup DEPENDS setup-tools setup-limine) +add_custom_command( + TARGET setup + POST_BUILD + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=INFO" + "-DLOG_TEXT=environment ready" + -P "${CL_LOG_EMIT_SCRIPT}" +) + +if(CLEONOS_ENABLE) + add_custom_target(disk-image + COMMAND ${CMAKE_COMMAND} + "-DDISK_IMAGE=${DISK_IMAGE}" + "-DDISK_MB=${CLEONOS_DISK_IMAGE_MB}" + -P "${CMAKE_SOURCE_DIR}/cmake/ensure_disk_image.cmake" + BYPRODUCTS "${DISK_IMAGE}" + VERBATIM + ) + + add_custom_command( + OUTPUT "${ISO_IMAGE}" + COMMAND ${CMAKE_COMMAND} -E rm -rf "${ISO_ROOT}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${ISO_ROOT}/boot/limine" "${ISO_ROOT}/EFI/BOOT" + COMMAND ${CMAKE_COMMAND} -E copy "${KERNEL_ELF}" "${ISO_ROOT}/boot/clks_kernel.elf" + COMMAND ${CMAKE_COMMAND} -E copy "${RAMDISK_IMAGE}" "${ISO_ROOT}/boot/cleonos_ramdisk.tar" + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/configs/limine.conf" "${ISO_ROOT}/boot/limine/limine.conf" + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/configs/limine.conf" "${ISO_ROOT}/EFI/BOOT/limine.conf" + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/configs/limine.conf" "${ISO_ROOT}/limine.conf" + COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/limine-bios.sys" "${ISO_ROOT}/boot/limine/limine-bios.sys" + COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/limine-bios-cd.bin" "${ISO_ROOT}/boot/limine/limine-bios-cd.bin" + COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/limine-uefi-cd.bin" "${ISO_ROOT}/boot/limine/limine-uefi-cd.bin" + COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/BOOTX64.EFI" "${ISO_ROOT}/EFI/BOOT/BOOTX64.EFI" + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_SOURCE_DIR}/build" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=building iso -> ${ISO_IMAGE}" + -P "${CL_LOG_EMIT_SCRIPT}" + COMMAND ${XORRISO} -as mkisofs + -b boot/limine/limine-bios-cd.bin + -no-emul-boot + -boot-load-size 4 + -boot-info-table + --efi-boot boot/limine/limine-uefi-cd.bin + -efi-boot-part + --efi-boot-image + --protective-msdos-label + "${ISO_ROOT}" + -o "${ISO_IMAGE}" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=installing limine boot sectors" + -P "${CL_LOG_EMIT_SCRIPT}" + COMMAND "${LIMINE_BIN_DIR_ABS}/limine" bios-install "${ISO_IMAGE}" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=INFO" + "-DLOG_TEXT=iso ready: ${ISO_IMAGE}" + -P "${CL_LOG_EMIT_SCRIPT}" + DEPENDS "${KERNEL_ELF}" "${RAMDISK_IMAGE}" "${CMAKE_SOURCE_DIR}/configs/limine.conf" + VERBATIM + ) + + add_custom_target(iso ALL DEPENDS "${ISO_IMAGE}") + add_dependencies(iso setup-tools setup-limine kernel ramdisk) + + add_custom_target(run + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=launching qemu run" + -P "${CL_LOG_EMIT_SCRIPT}" + COMMAND ${QEMU_X86_64} -M pc -m 1024M -boot order=d -cdrom "${ISO_IMAGE}" -drive "file=${DISK_IMAGE},format=raw,if=none,id=clksdisk,media=disk" -device "ide-hd,drive=clksdisk,bus=ide.0" -serial stdio + DEPENDS iso disk-image + USES_TERMINAL + ) + + add_custom_target(debug + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=launching qemu debug (-s -S)" + -P "${CL_LOG_EMIT_SCRIPT}" + COMMAND ${QEMU_X86_64} -M pc -m 1024M -boot order=d -cdrom "${ISO_IMAGE}" -drive "file=${DISK_IMAGE},format=raw,if=none,id=clksdisk,media=disk" -device "ide-hd,drive=clksdisk,bus=ide.0" -serial stdio -s -S + DEPENDS iso disk-image + USES_TERMINAL + ) +else() + add_custom_target(clks-default ALL DEPENDS kernel) +endif() + +add_custom_target(clean-x86 + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=cleaning ${BUILD_ROOT}" + -P "${CL_LOG_EMIT_SCRIPT}" + COMMAND ${CMAKE_COMMAND} -E rm -rf "${BUILD_ROOT}" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=INFO" + "-DLOG_TEXT=clean done" + -P "${CL_LOG_EMIT_SCRIPT}" +) + +add_custom_target(clean-all + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=cleaning build" + -P "${CL_LOG_EMIT_SCRIPT}" + COMMAND ${CMAKE_COMMAND} -E rm -rf "${CMAKE_SOURCE_DIR}/build" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=INFO" + "-DLOG_TEXT=clean-all done" + -P "${CL_LOG_EMIT_SCRIPT}" +) + +find_package(Python3 COMPONENTS Interpreter QUIET) +if(Python3_Interpreter_FOUND) + if(CLEONOS_ENABLE) + add_custom_target(menuconfig + COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" + USES_TERMINAL + ) + add_custom_target(menuconfig-gui + COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --gui + USES_TERMINAL + ) + else() + add_custom_target(menuconfig + COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --clks-only + USES_TERMINAL + ) + add_custom_target(menuconfig-gui + COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --gui --clks-only + USES_TERMINAL + ) + endif() + add_custom_target(menuconfig-clks + COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --clks-only + USES_TERMINAL + ) + add_custom_target(menuconfig-gui-clks + COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/menuconfig.py" --gui --clks-only + USES_TERMINAL + ) +else() + add_custom_target(menuconfig + COMMAND ${CMAKE_COMMAND} -E echo "python3 not found; run scripts/menuconfig.py manually" + USES_TERMINAL + ) + add_custom_target(menuconfig-gui + COMMAND ${CMAKE_COMMAND} -E echo "python3 not found; run scripts/menuconfig.py --gui manually" + USES_TERMINAL + ) + add_custom_target(menuconfig-clks + COMMAND ${CMAKE_COMMAND} -E echo "python3 not found; run scripts/menuconfig.py --clks-only manually" + USES_TERMINAL + ) + add_custom_target(menuconfig-gui-clks + COMMAND ${CMAKE_COMMAND} -E echo "python3 not found; run scripts/menuconfig.py --gui --clks-only manually" + USES_TERMINAL + ) +endif() + +if(CLEONOS_ENABLE) + add_custom_target(cleonos-help + COMMAND ${CMAKE_COMMAND} -E echo "CLeonOS CMake build system (x86_64 only)" + COMMAND ${CMAKE_COMMAND} -E echo " CLEONOS_ENABLE=${CLEONOS_ENABLE}" + COMMAND ${CMAKE_COMMAND} -E echo " cmake -S . -B build-cmake" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-gui" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-clks" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-gui-clks" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target setup" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target kernel" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target userapps" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target iso" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target run" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target debug" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target disk-image" + ) +else() + add_custom_target(cleonos-help + COMMAND ${CMAKE_COMMAND} -E echo "CLeonOS CMake build system (x86_64 only)" + COMMAND ${CMAKE_COMMAND} -E echo " CLEONOS_ENABLE=${CLEONOS_ENABLE}" + COMMAND ${CMAKE_COMMAND} -E echo " cmake -S . -B build-cmake" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-gui" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-clks" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target menuconfig-gui-clks" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target setup" + COMMAND ${CMAKE_COMMAND} -E echo " cmake --build build-cmake --target kernel" + COMMAND ${CMAKE_COMMAND} -E echo " (CLKS-only mode: userapps/iso/run/debug/disk-image are disabled)" + ) +endif() + diff --git a/Makefile b/Makefile index 21c7a55..fe617e5 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,19 @@ MENUCONFIG_ARGS ?= MENUCONFIG_PRESET ?= DISK_IMAGE_MB ?= CLEONOS_ENABLE ?= auto +QEMU_DRIVE_IMAGE ?= build/x86_64/cleonos_disk.img +SHOW_COMMANDS ?= 0 +V ?= 0 + +ifneq ($(filter 1 ON on TRUE true YES yes Y y,$(SHOW_COMMANDS) $(V)),) +Q := +CMAKE_BUILD_VERBOSE_ARG := --verbose +CMAKE_CONFIG_VERBOSE_ARG := -DCMAKE_VERBOSE_MAKEFILE=ON +else +Q := @ +CMAKE_BUILD_VERBOSE_ARG := +CMAKE_CONFIG_VERBOSE_ARG := +endif ifeq ($(strip $(CMAKE_GENERATOR)),) GEN_ARG := @@ -84,7 +97,7 @@ ifneq ($(strip $(DISK_IMAGE_MB)),) CMAKE_PASSTHROUGH_ARGS += -DCLEONOS_DISK_IMAGE_MB=$(DISK_IMAGE_MB) endif -.PHONY: all configure reconfigure menuconfig menuconfig-gui menuconfig-clks menuconfig-gui-clks setup setup-tools setup-limine kernel userapps ramdisk-root ramdisk disk-image iso run debug clean clean-all help +.PHONY: all configure reconfigure menuconfig menuconfig-gui menuconfig-clks menuconfig-gui-clks setup setup-tools setup-limine kernel userapps ramdisk-root ramdisk disk-image iso run debug clean-drive-image clean clean-all help ifeq ($(CLEONOS_ENABLED_BOOL),1) all: iso @@ -93,14 +106,14 @@ all: kernel endif configure: -> @$(CMAKE) -S . -B $(CMAKE_BUILD_DIR) $(GEN_ARG) -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DNO_COLOR=$(NO_COLOR) $(CMAKE_EXTRA_ARGS) $(CMAKE_PASSTHROUGH_ARGS) +> $(Q)$(CMAKE) -S . -B $(CMAKE_BUILD_DIR) $(GEN_ARG) -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DNO_COLOR=$(NO_COLOR) $(CMAKE_CONFIG_VERBOSE_ARG) $(CMAKE_EXTRA_ARGS) $(CMAKE_PASSTHROUGH_ARGS) reconfigure: -> @rm -rf $(CMAKE_BUILD_DIR) -> @$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" +> $(Q)rm -rf $(CMAKE_BUILD_DIR) +> $(Q)$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" menuconfig: -> @if command -v $(PYTHON) >/dev/null 2>&1; then \ +> $(Q)if command -v $(PYTHON) >/dev/null 2>&1; then \ > $(PYTHON) scripts/menuconfig.py $(MENUCONFIG_SCOPE_ARG) $(MENUCONFIG_PRESET_ARG) $(MENUCONFIG_ARGS); \ > elif command -v python >/dev/null 2>&1; then \ > python scripts/menuconfig.py $(MENUCONFIG_SCOPE_ARG) $(MENUCONFIG_PRESET_ARG) $(MENUCONFIG_ARGS); \ @@ -108,10 +121,10 @@ menuconfig: > echo "python3/python not found"; \ > exit 1; \ > fi -> @$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" +> $(Q)$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" menuconfig-gui: -> @if command -v $(PYTHON) >/dev/null 2>&1; then \ +> $(Q)if command -v $(PYTHON) >/dev/null 2>&1; then \ > $(PYTHON) scripts/menuconfig.py --gui $(MENUCONFIG_SCOPE_ARG) $(MENUCONFIG_PRESET_ARG) $(MENUCONFIG_ARGS); \ > elif command -v python >/dev/null 2>&1; then \ > python scripts/menuconfig.py --gui $(MENUCONFIG_SCOPE_ARG) $(MENUCONFIG_PRESET_ARG) $(MENUCONFIG_ARGS); \ @@ -119,10 +132,10 @@ menuconfig-gui: > echo "python3/python not found"; \ > exit 1; \ > fi -> @$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" +> $(Q)$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" menuconfig-clks: -> @if command -v $(PYTHON) >/dev/null 2>&1; then \ +> $(Q)if command -v $(PYTHON) >/dev/null 2>&1; then \ > $(PYTHON) scripts/menuconfig.py --clks-only $(MENUCONFIG_PRESET_ARG) $(MENUCONFIG_ARGS); \ > elif command -v python >/dev/null 2>&1; then \ > python scripts/menuconfig.py --clks-only $(MENUCONFIG_PRESET_ARG) $(MENUCONFIG_ARGS); \ @@ -130,10 +143,10 @@ menuconfig-clks: > echo "python3/python not found"; \ > exit 1; \ > fi -> @$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" +> $(Q)$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" menuconfig-gui-clks: -> @if command -v $(PYTHON) >/dev/null 2>&1; then \ +> $(Q)if command -v $(PYTHON) >/dev/null 2>&1; then \ > $(PYTHON) scripts/menuconfig.py --gui --clks-only $(MENUCONFIG_PRESET_ARG) $(MENUCONFIG_ARGS); \ > elif command -v python >/dev/null 2>&1; then \ > python scripts/menuconfig.py --gui --clks-only $(MENUCONFIG_PRESET_ARG) $(MENUCONFIG_ARGS); \ @@ -141,88 +154,99 @@ menuconfig-gui-clks: > echo "python3/python not found"; \ > exit 1; \ > fi -> @$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" +> $(Q)$(MAKE) configure CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_GENERATOR="$(CMAKE_GENERATOR)" CMAKE_EXTRA_ARGS="$(CMAKE_EXTRA_ARGS)" NO_COLOR="$(NO_COLOR)" LIMINE_SKIP_CONFIGURE="$(LIMINE_SKIP_CONFIGURE)" LIMINE_REF="$(LIMINE_REF)" LIMINE_REPO="$(LIMINE_REPO)" LIMINE_DIR="$(LIMINE_DIR)" LIMINE_BIN_DIR="$(LIMINE_BIN_DIR)" OBJCOPY_FOR_TARGET="$(OBJCOPY_FOR_TARGET)" OBJDUMP_FOR_TARGET="$(OBJDUMP_FOR_TARGET)" READELF_FOR_TARGET="$(READELF_FOR_TARGET)" CLEONOS_ENABLE="$(CLEONOS_ENABLE)" setup: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target setup +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target setup $(CMAKE_BUILD_VERBOSE_ARG) setup-tools: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target setup-tools +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target setup-tools $(CMAKE_BUILD_VERBOSE_ARG) setup-limine: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target setup-limine +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target setup-limine $(CMAKE_BUILD_VERBOSE_ARG) kernel: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target kernel +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target kernel $(CMAKE_BUILD_VERBOSE_ARG) ifeq ($(CLEONOS_ENABLED_BOOL),1) userapps: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target userapps +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target userapps $(CMAKE_BUILD_VERBOSE_ARG) ramdisk-root: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target ramdisk-root +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target ramdisk-root $(CMAKE_BUILD_VERBOSE_ARG) ramdisk: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target ramdisk +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target ramdisk $(CMAKE_BUILD_VERBOSE_ARG) disk-image: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target disk-image +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target disk-image $(CMAKE_BUILD_VERBOSE_ARG) iso: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target iso +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target iso $(CMAKE_BUILD_VERBOSE_ARG) run: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target run +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target run $(CMAKE_BUILD_VERBOSE_ARG) debug: configure -> @$(CMAKE) --build $(CMAKE_BUILD_DIR) --target debug +> $(Q)$(CMAKE) --build $(CMAKE_BUILD_DIR) --target debug $(CMAKE_BUILD_VERBOSE_ARG) else userapps ramdisk-root ramdisk disk-image iso run debug: -> @echo "target '$@' requires CLEONOS_ENABLE=ON and cleonos sources present" -> @exit 1 +> $(Q)echo "target '$@' requires CLEONOS_ENABLE=ON and cleonos sources present" +> $(Q)exit 1 endif clean: -> @if [ -d "$(CMAKE_BUILD_DIR)" ]; then \ -> $(CMAKE) --build $(CMAKE_BUILD_DIR) --target clean-x86; \ +> $(Q)if [ -d "$(CMAKE_BUILD_DIR)" ]; then \ +> $(CMAKE) --build $(CMAKE_BUILD_DIR) --target clean-x86 $(CMAKE_BUILD_VERBOSE_ARG); \ > else \ > rm -rf build/x86_64; \ > fi +> $(Q)$(MAKE) clean-drive-image QEMU_DRIVE_IMAGE="$(QEMU_DRIVE_IMAGE)" clean-all: -> @if [ -d "$(CMAKE_BUILD_DIR)" ]; then \ -> $(CMAKE) --build $(CMAKE_BUILD_DIR) --target clean-all; \ +> $(Q)if [ -d "$(CMAKE_BUILD_DIR)" ]; then \ +> $(CMAKE) --build $(CMAKE_BUILD_DIR) --target clean-all $(CMAKE_BUILD_VERBOSE_ARG); \ > else \ > rm -rf build build-cmake; \ > fi +> $(Q)$(MAKE) clean-drive-image QEMU_DRIVE_IMAGE="$(QEMU_DRIVE_IMAGE)" + +clean-drive-image: +> $(Q)rm -f "$(QEMU_DRIVE_IMAGE)" help: -> @echo "CLeonOS (CMake-backed wrapper)" -> @echo "Mode: CLEONOS_ENABLE=$(CLEONOS_ENABLE_EFFECTIVE) ($(CLEONOS_MODE_LABEL))" -> @echo " make configure" -> @echo " make menuconfig" -> @echo " make menuconfig-gui" -> @echo " make menuconfig-clks" -> @echo " make menuconfig-gui-clks" -> @echo " make setup" -> @echo " make userapps" -> @echo " make disk-image" -> @echo " make iso" -> @echo " make run" -> @echo " make debug" -> @echo " make clean" -> @echo " make clean-all" -> @echo "" -> @echo "Pass custom CMake cache args via:" -> @echo " make configure CMAKE_EXTRA_ARGS='-DLIMINE_SKIP_CONFIGURE=1 -DOBJCOPY_FOR_TARGET=objcopy'" -> @echo "Direct passthrough is also supported:" -> @echo " make run LIMINE_SKIP_CONFIGURE=1" -> @echo "Kernel-only mode:" -> @echo " make kernel CLEONOS_ENABLE=OFF" -> @echo " make -C clks kernel" -> @echo "Disk image size example:" -> @echo " make run DISK_IMAGE_MB=128" -> @echo "Preset examples:" -> @echo " make menuconfig MENUCONFIG_PRESET=full" -> @echo " make menuconfig MENUCONFIG_PRESET=minimal" -> @echo " make menuconfig-gui MENUCONFIG_PRESET=dev" +> $(Q)echo "CLeonOS (CMake-backed wrapper)" +> $(Q)echo "Mode: CLEONOS_ENABLE=$(CLEONOS_ENABLE_EFFECTIVE) ($(CLEONOS_MODE_LABEL))" +> $(Q)echo " make configure" +> $(Q)echo " make menuconfig" +> $(Q)echo " make menuconfig-gui" +> $(Q)echo " make menuconfig-clks" +> $(Q)echo " make menuconfig-gui-clks" +> $(Q)echo " make setup" +> $(Q)echo " make userapps" +> $(Q)echo " make disk-image" +> $(Q)echo " make iso" +> $(Q)echo " make run" +> $(Q)echo " make debug" +> $(Q)echo " make clean-drive-image" +> $(Q)echo " make clean" +> $(Q)echo " make clean-all" +> $(Q)echo "" +> $(Q)echo "Show commands:" +> $(Q)echo " make run V=1" +> $(Q)echo " make run SHOW_COMMANDS=1" +> $(Q)echo " (includes CMake build internals: compiler/linker command lines)" +> $(Q)echo "" +> $(Q)echo "Pass custom CMake cache args via:" +> $(Q)echo " make configure CMAKE_EXTRA_ARGS='-DLIMINE_SKIP_CONFIGURE=1 -DOBJCOPY_FOR_TARGET=objcopy'" +> $(Q)echo "Direct passthrough is also supported:" +> $(Q)echo " make run LIMINE_SKIP_CONFIGURE=1" +> $(Q)echo "Kernel-only mode:" +> $(Q)echo " make kernel CLEONOS_ENABLE=OFF" +> $(Q)echo " make -C clks kernel" +> $(Q)echo "Disk image size example:" +> $(Q)echo " make run DISK_IMAGE_MB=128" +> $(Q)echo "Preset examples:" +> $(Q)echo " make menuconfig MENUCONFIG_PRESET=full" +> $(Q)echo " make menuconfig MENUCONFIG_PRESET=minimal" +> $(Q)echo " make menuconfig-gui MENUCONFIG_PRESET=dev" diff --git a/cleonos/c/apps/fdtest_main.c b/cleonos/c/apps/fdtest_main.c new file mode 100644 index 0000000..9b9302a --- /dev/null +++ b/cleonos/c/apps/fdtest_main.c @@ -0,0 +1,40 @@ +#include +#include + +static void fdtest_tty_line(const char *text) { + u64 len = 0ULL; + + if (text == (const char *)0) { + return; + } + + while (text[len] != '\0') { + len++; + } + + (void)cleonos_sys_tty_write(text, len); + (void)cleonos_sys_tty_write("\n", 1ULL); +} + +int cleonos_app_main(void) { + (void)fputs("[fdtest] begin", 1); + (void)fputc('\n', 1); + + (void)fputs("[fdtest] stdout fputs line", 1); + (void)fputc('\n', 1); + + (void)printf("[fdtest] stdout printf value=%d hex=%X\n", 42, 0x2A); + (void)dprintf(1, "[fdtest] stdout dprintf line\n"); + (void)fprintf(1, "[fdtest] stdout fprintf line\n"); + + (void)fputs("[fdtest] stdout split part A", 1); + (void)fputs(" + part B", 1); + (void)fputc('\n', 1); + + (void)dprintf(2, "[fdtest] stderr dprintf line\n"); + (void)fprintf(2, "[fdtest] stderr fprintf line\n"); + + fdtest_tty_line("[fdtest] tty syscall line"); + fdtest_tty_line("[fdtest] end"); + return 0; +} diff --git a/cleonos/c/apps/mkfsfat32_main.c b/cleonos/c/apps/mkfsfat32_main.c index e270627..c8816f0 100644 --- a/cleonos/c/apps/mkfsfat32_main.c +++ b/cleonos/c/apps/mkfsfat32_main.c @@ -1,6 +1,14 @@ #include "cmd_runtime.h" #include +static void ush_mkfs_println(const char *text) { + if (text == (const char *)0) { + return; + } + + ush_writeln(text); +} + static int ush_arg_parse_label(const char *arg, char *out_label, u64 out_label_size) { char first[USH_ARG_MAX]; const char *rest = (const char *)0; @@ -34,30 +42,50 @@ static int ush_arg_parse_label(const char *arg, char *out_label, u64 out_label_s static int ush_cmd_mkfsfat32(const char *arg) { char label[16]; u64 ok; + u64 present; + u64 size_bytes; + u64 sectors; + u64 formatted; + u64 mounted; - if (cleonos_sys_disk_present() == 0ULL) { - (void)fputs("mkfsfat32: disk not present\n", 1); + present = cleonos_sys_disk_present(); + if (present == 0ULL) { + ush_mkfs_println("mkfsfat32: disk not present"); return 0; } if (ush_arg_parse_label(arg, label, (u64)sizeof(label)) == 0) { - (void)fputs("mkfsfat32: usage mkfsfat32 [label]\n", 1); + ush_mkfs_println("mkfsfat32: usage mkfsfat32 [label]"); return 0; } ok = cleonos_sys_disk_format_fat32((label[0] != '\0') ? label : (const char *)0); if (ok == 0ULL) { - (void)fputs("mkfsfat32: format failed\n", 1); + char line[USH_LINE_MAX]; + + size_bytes = cleonos_sys_disk_size_bytes(); + sectors = cleonos_sys_disk_sector_count(); + formatted = cleonos_sys_disk_formatted(); + mounted = cleonos_sys_disk_mounted(); + ush_mkfs_println("mkfsfat32: format failed"); + (void)snprintf(line, (unsigned long)sizeof(line), + "mkfsfat32: disk.present=%llu size=%llu sectors=%llu formatted=%llu mounted=%llu", + (unsigned long long)present, (unsigned long long)size_bytes, (unsigned long long)sectors, + (unsigned long long)formatted, (unsigned long long)mounted); + ush_mkfs_println(line); return 0; } if (label[0] != '\0') { - (void)printf("mkfsfat32: formatted (label=%s)\n", label); + char line[USH_LINE_MAX]; + + (void)snprintf(line, (unsigned long)sizeof(line), "mkfsfat32: formatted (label=%s)", label); + ush_mkfs_println(line); } else { - (void)fputs("mkfsfat32: formatted\n", 1); + ush_mkfs_println("mkfsfat32: formatted"); } - (void)fputs("mkfsfat32: now run 'mount /temp/disk' (or another mount path)\n", 1); + ush_mkfs_println("mkfsfat32: now run 'mount /temp/disk' (or another mount path)"); return 1; } diff --git a/clks b/clks index 6bc15d6..015c8d9 160000 --- a/clks +++ b/clks @@ -1 +1 @@ -Subproject commit 6bc15d6aba7a3a6cbf0d6d6c0df684146a37320b +Subproject commit 015c8d9d70dec9b6f1fb9617058df1ef9cc35a25 diff --git a/configs/menuconfig/.config.cleonos.json b/configs/menuconfig/.config.cleonos.json index 27ac1a9..90f5586 100644 --- a/configs/menuconfig/.config.cleonos.json +++ b/configs/menuconfig/.config.cleonos.json @@ -18,6 +18,7 @@ "CLEONOS_USER_APP_EXEC": true, "CLEONOS_USER_APP_EXIT": true, "CLEONOS_USER_APP_FASTFETCH": true, + "CLEONOS_USER_APP_FDTEST": true, "CLEONOS_USER_APP_FG": true, "CLEONOS_USER_APP_FSSTAT": true, "CLEONOS_USER_APP_GREP": true, diff --git a/configs/menuconfig/.config.clks.json b/configs/menuconfig/.config.clks.json index e015c14..e96a70a 100644 --- a/configs/menuconfig/.config.clks.json +++ b/configs/menuconfig/.config.clks.json @@ -19,12 +19,21 @@ "CLEONOS_CLKS_ENABLE_KEYBOARD": true, "CLEONOS_CLKS_ENABLE_KLOGD_TASK": true, "CLEONOS_CLKS_ENABLE_KWORKER_TASK": true, + "CLEONOS_CLKS_ENABLE_LOG_LEVEL_DEBUG": true, + "CLEONOS_CLKS_ENABLE_LOG_LEVEL_ERROR": true, + "CLEONOS_CLKS_ENABLE_LOG_LEVEL_INFO": true, + "CLEONOS_CLKS_ENABLE_LOG_LEVEL_WARN": true, + "CLEONOS_CLKS_ENABLE_LOG_OUTPUT_JOURNAL": true, + "CLEONOS_CLKS_ENABLE_LOG_OUTPUT_SERIAL": true, + "CLEONOS_CLKS_ENABLE_LOG_OUTPUT_TTY": true, "CLEONOS_CLKS_ENABLE_MOUSE": true, "CLEONOS_CLKS_ENABLE_PMM_STATS_LOG": "m", "CLEONOS_CLKS_ENABLE_PROCFS": true, "CLEONOS_CLKS_ENABLE_SCHED_TASK_COUNT_LOG": "y", "CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG": "m", + "CLEONOS_CLKS_ENABLE_SYSCALL_SERIAL_LOG": false, "CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY": true, + "CLEONOS_CLKS_ENABLE_SYSCALL_USERID_SERIAL_LOG": false, "CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK": true, "CLEONOS_CLKS_ENABLE_TTY_READY_LOG": "m", "CLEONOS_CLKS_ENABLE_USC": true, diff --git a/configs/menuconfig/clks_features.json b/configs/menuconfig/clks_features.json index 560a793..7ddb5fe 100644 --- a/configs/menuconfig/clks_features.json +++ b/configs/menuconfig/clks_features.json @@ -1,376 +1,578 @@ -{ - "features": [ - { - "key": "CLEONOS_CLKS_ENABLE_AUDIO", - "title": "Audio Driver Init", - "description": "Initialize kernel audio subsystem during boot.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_MOUSE", - "title": "PS/2 Mouse Input", - "description": "Initialize kernel PS/2 mouse input subsystem.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_DESKTOP", - "title": "TTY2 Desktop", - "description": "Enable desktop compositor tick/update path on TTY2.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_MOUSE" - }, - { - "key": "CLEONOS_CLKS_ENABLE_DRIVER_MANAGER", - "title": "Driver Manager", - "description": "Initialize kernel ELF driver manager.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_KELF", - "title": "KELF Executor", - "description": "Enable kernel ELF app dispatcher and kelfd task.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_DRIVER_MANAGER && CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT", - "imply": [ - "CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE", - "CLEONOS_CLKS_ENABLE_USER_SYSTEM_APP_PROBE" - ] - }, - { - "key": "CLEONOS_CLKS_ENABLE_USERLAND_AUTO_EXEC", - "title": "Auto Enter User Shell", - "description": "Auto-exec /shell/shell.elf after kernel boot.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USRD_TASK && CLEONOS_CLKS_ENABLE_KEYBOARD", - "select": [ - "CLEONOS_CLKS_ENABLE_USRD_TASK", - "CLEONOS_CLKS_ENABLE_KEYBOARD" - ], - "imply": [ - "CLEONOS_CLKS_ENABLE_USER_INIT_SCRIPT_PROBE", - "CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG" - ] - }, - { - "key": "CLEONOS_CLKS_ENABLE_HEAP_SELFTEST", - "title": "Heap Selftest", - "description": "Run kmalloc/kfree selftest during kernel boot.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_EXTERNAL_PSF", - "title": "Load External PSF Font", - "description": "Load /system/tty.psf and apply it to framebuffer TTY.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_KEYBOARD", - "title": "PS/2 Keyboard Input", - "description": "Initialize PS/2 keyboard input subsystem.", - "type": "bool", - "default": true, - "imply": [ - "CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY", - "CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS" - ] - }, - { - "key": "CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE", - "title": "ELFRUNNER Probe", - "description": "Probe kernel ELF runtime metadata after ELFRUNNER init.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT && CLEONOS_CLKS_ENABLE_KELF" - }, - { - "key": "CLEONOS_CLKS_ENABLE_KLOGD_TASK", - "title": "Scheduler Task: klogd", - "description": "Enable periodic klogd maintenance task.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_KWORKER_TASK", - "title": "Scheduler Task: kworker", - "description": "Enable periodic kernel worker service-heartbeat task.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_USRD_TASK", - "title": "Scheduler Task: usrd", - "description": "Enable user/runtime dispatch task (shell tick, tty tick, exec tick).", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG", - "title": "Boot Video Geometry Logs", - "description": "Print framebuffer width/height/pitch/bpp logs at boot.", - "type": "tristate", - "default": "y" - }, - { - "key": "CLEONOS_CLKS_ENABLE_PMM_STATS_LOG", - "title": "PMM Stats Logs", - "description": "Print PMM managed/free/used/dropped pages at boot.", - "type": "tristate", - "default": "y" - }, - { - "key": "CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG", - "title": "Heap Stats Logs", - "description": "Print heap total/free bytes at boot.", - "type": "tristate", - "default": "y" - }, - { - "key": "CLEONOS_CLKS_ENABLE_FS_ROOT_LOG", - "title": "FS Root Children Log", - "description": "Print root directory children count during FS init.", - "type": "tristate", - "default": "y", - "depends_on": "CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK" - }, - { - "key": "CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK", - "title": "FS /SYSTEM Sanity Check", - "description": "Require /system directory check during boot.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT", - "title": "ELFRUNNER Init", - "description": "Initialize ELFRUNNER framework in kernel boot path.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY", - "title": "SYSCALL Tick Query", - "description": "Query timer ticks via syscall and log result during boot.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_PROCFS" - }, - { - "key": "CLEONOS_CLKS_ENABLE_TTY_READY_LOG", - "title": "TTY Ready Logs", - "description": "Print TTY count/active/cursor ready logs.", - "type": "tristate", - "default": "y" - }, - { - "key": "CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG", - "title": "Idle Loop Debug Log", - "description": "Print debug log before entering kernel idle loop.", - "type": "tristate", - "default": "y" - }, - { - "key": "CLEONOS_CLKS_ENABLE_PROCFS", - "title": "Virtual /proc", - "description": "Enable virtual procfs paths (/proc, /proc/list, /proc/self, /proc/) in syscall FS layer.", - "type": "bool", - "default": true - }, - { - "key": "CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG", - "title": "EXEC Serial Logs", - "description": "Print EXEC run/return/path logs to serial output.", - "type": "tristate", - "default": "y" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC", - "title": "UserSafeController (USC)", - "description": "Prompt before dangerous user syscalls and remember per-app approval for current boot.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_MKDIR", - "title": "Intercept FS_MKDIR", - "description": "USC prompt for syscall FS_MKDIR.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_WRITE", - "title": "Intercept FS_WRITE", - "description": "USC prompt for syscall FS_WRITE.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_APPEND", - "title": "Intercept FS_APPEND", - "description": "USC prompt for syscall FS_APPEND.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_REMOVE", - "title": "Intercept FS_REMOVE", - "description": "USC prompt for syscall FS_REMOVE.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATH", - "title": "Intercept EXEC_PATH", - "description": "USC prompt for syscall EXEC_PATH.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV", - "title": "Intercept EXEC_PATHV", - "description": "USC prompt for syscall EXEC_PATHV.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV_IO", - "title": "Intercept EXEC_PATHV_IO", - "description": "USC prompt for syscall EXEC_PATHV_IO.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATH", - "title": "Intercept SPAWN_PATH", - "description": "USC prompt for syscall SPAWN_PATH.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATHV", - "title": "Intercept SPAWN_PATHV", - "description": "USC prompt for syscall SPAWN_PATHV.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_PROC_KILL", - "title": "Intercept PROC_KILL", - "description": "USC prompt for syscall PROC_KILL.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_SHUTDOWN", - "title": "Intercept SHUTDOWN", - "description": "USC prompt for syscall SHUTDOWN.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USC_SC_RESTART", - "title": "Intercept RESTART", - "description": "USC prompt for syscall RESTART.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USC", - "group": "USC Syscall Policy" - }, - { - "key": "CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY", - "title": "Keyboard TTY Switch Hotkey", - "description": "Enable ALT+F1..F4 keyboard hotkey for active TTY switching.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD" - }, - { - "key": "CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS", - "title": "Keyboard Ctrl Shortcuts", - "description": "Enable Ctrl+A/C/V shortcuts for input selection/copy/paste.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD", - "imply": [ - "CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY" - ] - }, - { - "key": "CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY", - "title": "Keyboard Force-Stop Hotkey", - "description": "Enable Ctrl+Alt+C force-stop for current running user process.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD && CLEONOS_CLKS_ENABLE_PROCFS" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USER_INIT_SCRIPT_PROBE", - "title": "User Init Script Probe", - "description": "Probe and log /shell/init.cmd presence during userland init.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_USERLAND_AUTO_EXEC" - }, - { - "key": "CLEONOS_CLKS_ENABLE_USER_SYSTEM_APP_PROBE", - "title": "User System App Probe", - "description": "Probe /system/elfrunner.elf and /system/memc.elf during userland init.", - "type": "bool", - "default": true, - "depends_on": "CLEONOS_CLKS_ENABLE_KELF" - }, - { - "key": "CLEONOS_CLKS_ENABLE_SCHED_TASK_COUNT_LOG", - "title": "Scheduler Task Count Log", - "description": "Print scheduler task count after scheduler initialization.", - "type": "tristate", - "default": "y", - "depends_on": "CLEONOS_CLKS_ENABLE_KLOGD_TASK || CLEONOS_CLKS_ENABLE_KWORKER_TASK || CLEONOS_CLKS_ENABLE_USRD_TASK" - }, - { - "key": "CLEONOS_CLKS_ENABLE_INTERRUPT_READY_LOG", - "title": "Interrupt Ready Log", - "description": "Print IDT/PIC initialized log after interrupt setup.", - "type": "tristate", - "default": "y" - }, - { - "key": "CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG", - "title": "Shell Mode Log", - "description": "Print whether boot default mode is user shell or kernel shell.", - "type": "tristate", - "default": "y" - } - ] -} +{ + "features": [ + { + "key": "CLEONOS_CLKS_ENABLE_AUDIO", + "title": "Audio Driver Init", + "title_zh": "音频驱动初始化", + "description": "Initialize kernel audio subsystem during boot.", + "description_zh": "在启动阶段初始化内核音频子系统。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_MOUSE", + "title": "PS/2 Mouse Input", + "title_zh": "PS/2 鼠标输入", + "description": "Initialize kernel PS/2 mouse input subsystem.", + "description_zh": "初始化内核 PS/2 鼠标输入子系统。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_DESKTOP", + "title": "TTY2 Desktop", + "title_zh": "TTY2 桌面", + "description": "Enable desktop compositor tick/update path on TTY2.", + "description_zh": "在 TTY2 启用桌面合成器 tick/更新路径。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_MOUSE" + }, + { + "key": "CLEONOS_CLKS_ENABLE_DRIVER_MANAGER", + "title": "Driver Manager", + "title_zh": "驱动管理器", + "description": "Initialize kernel ELF driver manager.", + "description_zh": "初始化内核 ELF 驱动管理器。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_KELF", + "title": "KELF Executor", + "title_zh": "KELF 执行器", + "description": "Enable kernel ELF app dispatcher and kelfd task.", + "description_zh": "启用内核 ELF 应用分发器和 kelfd 任务。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_DRIVER_MANAGER && CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT", + "imply": [ + "CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE", + "CLEONOS_CLKS_ENABLE_USER_SYSTEM_APP_PROBE" + ] + }, + { + "key": "CLEONOS_CLKS_ENABLE_USERLAND_AUTO_EXEC", + "title": "Auto Enter User Shell", + "title_zh": "自动进入用户 Shell", + "description": "Auto-exec /shell/shell.elf after kernel boot.", + "description_zh": "内核启动后自动执行 /shell/shell.elf。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USRD_TASK && CLEONOS_CLKS_ENABLE_KEYBOARD", + "select": [ + "CLEONOS_CLKS_ENABLE_USRD_TASK", + "CLEONOS_CLKS_ENABLE_KEYBOARD" + ], + "imply": [ + "CLEONOS_CLKS_ENABLE_USER_INIT_SCRIPT_PROBE", + "CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG" + ] + }, + { + "key": "CLEONOS_CLKS_ENABLE_HEAP_SELFTEST", + "title": "Heap Selftest", + "title_zh": "堆自检", + "description": "Run kmalloc/kfree selftest during kernel boot.", + "description_zh": "在内核启动期间运行 kmalloc/kfree 自检。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_EXTERNAL_PSF", + "title": "Load External PSF Font", + "title_zh": "加载外部 PSF 字体", + "description": "Load /system/tty.psf and apply it to framebuffer TTY.", + "description_zh": "加载 /system/tty.psf 并应用到 framebuffer TTY。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_KEYBOARD", + "title": "PS/2 Keyboard Input", + "title_zh": "PS/2 键盘输入", + "description": "Initialize PS/2 keyboard input subsystem.", + "description_zh": "初始化 PS/2 键盘输入子系统。", + "type": "bool", + "default": true, + "imply": [ + "CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY", + "CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS" + ] + }, + { + "key": "CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE", + "title": "ELFRUNNER Probe", + "title_zh": "ELFRUNNER 探测", + "description": "Probe kernel ELF runtime metadata after ELFRUNNER init.", + "description_zh": "在 ELFRUNNER 初始化后探测内核 ELF 运行时元数据。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT && CLEONOS_CLKS_ENABLE_KELF" + }, + { + "key": "CLEONOS_CLKS_ENABLE_KLOGD_TASK", + "title": "Scheduler Task: klogd", + "title_zh": "调度任务:klogd", + "description": "Enable periodic klogd maintenance task.", + "description_zh": "启用周期性 klogd 维护任务。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_KWORKER_TASK", + "title": "Scheduler Task: kworker", + "title_zh": "调度任务:kworker", + "description": "Enable periodic kernel worker service-heartbeat task.", + "description_zh": "启用周期性内核 worker 服务心跳任务。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_USRD_TASK", + "title": "Scheduler Task: usrd", + "title_zh": "调度任务:usrd", + "description": "Enable user/runtime dispatch task (shell tick, tty tick, exec tick).", + "description_zh": "启用用户/运行时分发任务(shell tick、tty tick、exec tick)。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG", + "title": "Boot Video Geometry Logs", + "title_zh": "启动视频几何日志", + "description": "Print framebuffer width/height/pitch/bpp logs at boot.", + "description_zh": "在启动时打印 framebuffer 宽/高/pitch/bpp 日志。", + "type": "tristate", + "default": "y" + }, + { + "key": "CLEONOS_CLKS_ENABLE_PMM_STATS_LOG", + "title": "PMM Stats Logs", + "title_zh": "PMM 统计日志", + "description": "Print PMM managed/free/used/dropped pages at boot.", + "description_zh": "在启动时打印 PMM 托管/空闲/已用/丢弃页数。", + "type": "tristate", + "default": "y" + }, + { + "key": "CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG", + "title": "Heap Stats Logs", + "title_zh": "堆统计日志", + "description": "Print heap total/free bytes at boot.", + "description_zh": "在启动时打印堆总字节/空闲字节。", + "type": "tristate", + "default": "y" + }, + { + "key": "CLEONOS_CLKS_ENABLE_FS_ROOT_LOG", + "title": "FS Root Children Log", + "title_zh": "FS 根目录子项日志", + "description": "Print root directory children count during FS init.", + "description_zh": "在文件系统初始化时打印根目录子项数量。", + "type": "tristate", + "default": "y", + "depends_on": "CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK" + }, + { + "key": "CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK", + "title": "FS /SYSTEM Sanity Check", + "title_zh": "FS /SYSTEM 健全性检查", + "description": "Require /system directory check during boot.", + "description_zh": "在启动时要求通过 /system 目录检查。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT", + "title": "ELFRUNNER Init", + "title_zh": "ELFRUNNER 初始化", + "description": "Initialize ELFRUNNER framework in kernel boot path.", + "description_zh": "在内核启动路径中初始化 ELFRUNNER 框架。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY", + "title": "SYSCALL Tick Query", + "title_zh": "SYSCALL Tick 查询", + "description": "Query timer ticks via syscall and log result during boot.", + "description_zh": "在启动时通过 syscall 查询定时器 tick 并记录日志。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_PROCFS" + }, + { + "key": "CLEONOS_CLKS_ENABLE_TTY_READY_LOG", + "title": "TTY Ready Logs", + "title_zh": "TTY 就绪日志", + "description": "Print TTY count/active/cursor ready logs.", + "description_zh": "打印 TTY 数量/活动终端/光标就绪日志。", + "type": "tristate", + "default": "y" + }, + { + "key": "CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG", + "title": "Idle Loop Debug Log", + "title_zh": "空闲循环调试日志", + "description": "Print debug log before entering kernel idle loop.", + "description_zh": "进入内核空闲循环前打印调试日志。", + "type": "tristate", + "default": "y" + }, + { + "key": "CLEONOS_CLKS_ENABLE_PROCFS", + "title": "Virtual /proc", + "title_zh": "虚拟 /proc", + "description": "Enable virtual procfs paths (/proc, /proc/list, /proc/self, /proc/) in syscall FS layer.", + "description_zh": "在 syscall 文件系统层启用虚拟 procfs 路径(/proc、/proc/list、/proc/self、/proc/)。", + "type": "bool", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG", + "title": "EXEC Serial Logs", + "title_zh": "EXEC 串口日志", + "description": "Print EXEC run/return/path logs to serial output.", + "description_zh": "将 EXEC run/return/path 日志输出到串口。", + "type": "tristate", + "default": "y" + }, + { + "key": "CLEONOS_CLKS_ENABLE_SYSCALL_SERIAL_LOG", + "title": "SYSCALL Serial Logs", + "title_zh": "SYSCALL 串口日志", + "description": "Print user syscall CALL/RET trace logs to serial output.", + "description_zh": "将用户态 syscall 的 CALL/RET 跟踪日志输出到串口。", + "type": "bool", + "default": true, + "group": "Logging Controls", + "group_zh": "日志控制" + }, + { + "key": "CLEONOS_CLKS_ENABLE_SYSCALL_USERID_SERIAL_LOG", + "title": "SYSCALL USER_ID Serial Logs", + "title_zh": "SYSCALL USER_ID 串口日志", + "description": "Print USER_TRACE_BEGIN/END, PID, and USER_ID trace logs to serial output.", + "description_zh": "将 USER_TRACE_BEGIN/END、PID 与 USER_ID 跟踪日志输出到串口。", + "type": "bool", + "default": true, + "group": "Logging Controls", + "group_zh": "日志控制" + }, + { + "key": "CLEONOS_CLKS_ENABLE_LOG_LEVEL_DEBUG", + "title": "Kernel Log Level: DEBUG", + "title_zh": "内核日志级别:DEBUG", + "description": "Allow CLKS_LOG_DEBUG messages to be emitted by clks_log/clks_log_hex.", + "description_zh": "允许 clks_log/clks_log_hex 输出 CLKS_LOG_DEBUG 消息。", + "type": "bool", + "default": true, + "group": "Logging Controls", + "group_zh": "日志控制" + }, + { + "key": "CLEONOS_CLKS_ENABLE_LOG_LEVEL_INFO", + "title": "Kernel Log Level: INFO", + "title_zh": "内核日志级别:INFO", + "description": "Allow CLKS_LOG_INFO messages to be emitted by clks_log/clks_log_hex.", + "description_zh": "允许 clks_log/clks_log_hex 输出 CLKS_LOG_INFO 消息。", + "type": "bool", + "default": true, + "group": "Logging Controls", + "group_zh": "日志控制" + }, + { + "key": "CLEONOS_CLKS_ENABLE_LOG_LEVEL_WARN", + "title": "Kernel Log Level: WARN", + "title_zh": "内核日志级别:WARN", + "description": "Allow CLKS_LOG_WARN messages to be emitted by clks_log/clks_log_hex.", + "description_zh": "允许 clks_log/clks_log_hex 输出 CLKS_LOG_WARN 消息。", + "type": "bool", + "default": true, + "group": "Logging Controls", + "group_zh": "日志控制" + }, + { + "key": "CLEONOS_CLKS_ENABLE_LOG_LEVEL_ERROR", + "title": "Kernel Log Level: ERROR", + "title_zh": "内核日志级别:ERROR", + "description": "Allow CLKS_LOG_ERROR messages to be emitted by clks_log/clks_log_hex.", + "description_zh": "允许 clks_log/clks_log_hex 输出 CLKS_LOG_ERROR 消息。", + "type": "bool", + "default": true, + "group": "Logging Controls", + "group_zh": "日志控制" + }, + { + "key": "CLEONOS_CLKS_ENABLE_LOG_OUTPUT_SERIAL", + "title": "Kernel Log Output: Serial", + "title_zh": "内核日志输出:串口", + "description": "Send clks_log/clks_log_hex output to serial port.", + "description_zh": "将 clks_log/clks_log_hex 输出发送到串口。", + "type": "bool", + "default": true, + "group": "Logging Controls", + "group_zh": "日志控制" + }, + { + "key": "CLEONOS_CLKS_ENABLE_LOG_OUTPUT_TTY", + "title": "Kernel Log Output: TTY", + "title_zh": "内核日志输出:TTY", + "description": "Render clks_log/clks_log_hex output to TTY with ANSI colors.", + "description_zh": "将 clks_log/clks_log_hex 输出渲染到 TTY(含 ANSI 颜色)。", + "type": "bool", + "default": true, + "group": "Logging Controls", + "group_zh": "日志控制" + }, + { + "key": "CLEONOS_CLKS_ENABLE_LOG_OUTPUT_JOURNAL", + "title": "Kernel Log Output: Journal", + "title_zh": "内核日志输出:日志缓冲", + "description": "Store clks_log/clks_log_hex lines into in-memory log journal for dmesg/procfs reads.", + "description_zh": "将 clks_log/clks_log_hex 行写入内存日志缓冲,供 dmesg/procfs 读取。", + "type": "bool", + "default": true, + "group": "Logging Controls", + "group_zh": "日志控制" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC", + "title": "UserSafeController (USC)", + "title_zh": "用户安全控制器(USC)", + "description": "Prompt before dangerous user syscalls and remember per-app approval for current boot.", + "description_zh": "在危险用户态 syscall 执行前弹出确认,并在本次启动期间按应用记住授权。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_MKDIR", + "title": "Intercept FS_MKDIR", + "title_zh": "拦截 FS_MKDIR", + "description": "USC prompt for syscall FS_MKDIR.", + "description_zh": "USC 对 FS_MKDIR syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_WRITE", + "title": "Intercept FS_WRITE", + "title_zh": "拦截 FS_WRITE", + "description": "USC prompt for syscall FS_WRITE.", + "description_zh": "USC 对 FS_WRITE syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_APPEND", + "title": "Intercept FS_APPEND", + "title_zh": "拦截 FS_APPEND", + "description": "USC prompt for syscall FS_APPEND.", + "description_zh": "USC 对 FS_APPEND syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_FS_REMOVE", + "title": "Intercept FS_REMOVE", + "title_zh": "拦截 FS_REMOVE", + "description": "USC prompt for syscall FS_REMOVE.", + "description_zh": "USC 对 FS_REMOVE syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATH", + "title": "Intercept EXEC_PATH", + "title_zh": "拦截 EXEC_PATH", + "description": "USC prompt for syscall EXEC_PATH.", + "description_zh": "USC 对 EXEC_PATH syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV", + "title": "Intercept EXEC_PATHV", + "title_zh": "拦截 EXEC_PATHV", + "description": "USC prompt for syscall EXEC_PATHV.", + "description_zh": "USC 对 EXEC_PATHV syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV_IO", + "title": "Intercept EXEC_PATHV_IO", + "title_zh": "拦截 EXEC_PATHV_IO", + "description": "USC prompt for syscall EXEC_PATHV_IO.", + "description_zh": "USC 对 EXEC_PATHV_IO syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATH", + "title": "Intercept SPAWN_PATH", + "title_zh": "拦截 SPAWN_PATH", + "description": "USC prompt for syscall SPAWN_PATH.", + "description_zh": "USC 对 SPAWN_PATH syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATHV", + "title": "Intercept SPAWN_PATHV", + "title_zh": "拦截 SPAWN_PATHV", + "description": "USC prompt for syscall SPAWN_PATHV.", + "description_zh": "USC 对 SPAWN_PATHV syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_PROC_KILL", + "title": "Intercept PROC_KILL", + "title_zh": "拦截 PROC_KILL", + "description": "USC prompt for syscall PROC_KILL.", + "description_zh": "USC 对 PROC_KILL syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_SHUTDOWN", + "title": "Intercept SHUTDOWN", + "title_zh": "拦截 SHUTDOWN", + "description": "USC prompt for syscall SHUTDOWN.", + "description_zh": "USC 对 SHUTDOWN syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USC_SC_RESTART", + "title": "Intercept RESTART", + "title_zh": "拦截 RESTART", + "description": "USC prompt for syscall RESTART.", + "description_zh": "USC 对 RESTART syscall 弹出确认。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USC", + "group": "USC Syscall Policy", + "group_zh": "USC 系统调用策略" + }, + { + "key": "CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY", + "title": "Keyboard TTY Switch Hotkey", + "title_zh": "键盘 TTY 切换热键", + "description": "Enable ALT+F1..F4 keyboard hotkey for active TTY switching.", + "description_zh": "启用 ALT+F1..F4 热键切换当前活动 TTY。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD" + }, + { + "key": "CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS", + "title": "Keyboard Ctrl Shortcuts", + "title_zh": "键盘 Ctrl 快捷键", + "description": "Enable Ctrl+A/C/V shortcuts for input selection/copy/paste.", + "description_zh": "启用 Ctrl+A/C/V 输入区全选/复制/粘贴快捷键。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD", + "imply": [ + "CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY" + ] + }, + { + "key": "CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY", + "title": "Keyboard Force-Stop Hotkey", + "title_zh": "键盘强制停止热键", + "description": "Enable Ctrl+Alt+C force-stop for current running user process.", + "description_zh": "启用 Ctrl+Alt+C 强制停止当前运行的用户进程。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_KEYBOARD && CLEONOS_CLKS_ENABLE_PROCFS" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USER_INIT_SCRIPT_PROBE", + "title": "User Init Script Probe", + "title_zh": "用户初始化脚本探测", + "description": "Probe and log /shell/init.cmd presence during userland init.", + "description_zh": "在用户态初始化期间探测并记录 /shell/init.cmd 是否存在。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_USERLAND_AUTO_EXEC" + }, + { + "key": "CLEONOS_CLKS_ENABLE_USER_SYSTEM_APP_PROBE", + "title": "User System App Probe", + "title_zh": "用户系统应用探测", + "description": "Probe /system/elfrunner.elf and /system/memc.elf during userland init.", + "description_zh": "在用户态初始化期间探测 /system/elfrunner.elf 与 /system/memc.elf。", + "type": "bool", + "default": true, + "depends_on": "CLEONOS_CLKS_ENABLE_KELF" + }, + { + "key": "CLEONOS_CLKS_ENABLE_SCHED_TASK_COUNT_LOG", + "title": "Scheduler Task Count Log", + "title_zh": "调度任务数量日志", + "description": "Print scheduler task count after scheduler initialization.", + "description_zh": "在调度器初始化后打印任务数量。", + "type": "tristate", + "default": "y", + "depends_on": "CLEONOS_CLKS_ENABLE_KLOGD_TASK || CLEONOS_CLKS_ENABLE_KWORKER_TASK || CLEONOS_CLKS_ENABLE_USRD_TASK" + }, + { + "key": "CLEONOS_CLKS_ENABLE_INTERRUPT_READY_LOG", + "title": "Interrupt Ready Log", + "title_zh": "中断就绪日志", + "description": "Print IDT/PIC initialized log after interrupt setup.", + "description_zh": "在完成中断初始化后打印 IDT/PIC 就绪日志。", + "type": "tristate", + "default": "y" + }, + { + "key": "CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG", + "title": "Shell Mode Log", + "title_zh": "Shell 模式日志", + "description": "Print whether boot default mode is user shell or kernel shell.", + "description_zh": "打印默认启动模式是用户 Shell 还是内核 Shell。", + "type": "tristate", + "default": "y" + } + ] +} diff --git a/configs/menuconfig/config.cleonos.cmake b/configs/menuconfig/config.cleonos.cmake index c6d5d7f..12f6408 100644 --- a/configs/menuconfig/config.cleonos.cmake +++ b/configs/menuconfig/config.cleonos.cmake @@ -21,6 +21,7 @@ set(CLEONOS_USER_APP_DOOM ON CACHE BOOL "doom.elf [shell]" FORCE) set(CLEONOS_USER_APP_EXEC ON CACHE BOOL "exec.elf [shell]" FORCE) set(CLEONOS_USER_APP_EXIT ON CACHE BOOL "exit.elf [shell]" FORCE) set(CLEONOS_USER_APP_FASTFETCH ON CACHE BOOL "fastfetch.elf [shell]" FORCE) +set(CLEONOS_USER_APP_FDTEST ON CACHE BOOL "fdtest.elf [shell]" FORCE) set(CLEONOS_USER_APP_FG ON CACHE BOOL "fg.elf [shell]" FORCE) set(CLEONOS_USER_APP_FSSTAT ON CACHE BOOL "fsstat.elf [shell]" FORCE) set(CLEONOS_USER_APP_GREP ON CACHE BOOL "grep.elf [shell]" FORCE) diff --git a/configs/menuconfig/config.clks.cmake b/configs/menuconfig/config.clks.cmake index ddb7452..86cd3e7 100644 --- a/configs/menuconfig/config.clks.cmake +++ b/configs/menuconfig/config.clks.cmake @@ -1,58 +1,67 @@ # Auto-generated by scripts/menuconfig.py # Do not edit manually unless you know what you are doing. set(CLEONOS_MENUCONFIG_CLKS_LOADED ON CACHE BOOL "CLeonOS menuconfig loaded" FORCE) -set(CLEONOS_CLKS_ENABLE_AUDIO ON CACHE BOOL "Audio Driver Init" FORCE) -set(CLEONOS_CLKS_ENABLE_MOUSE ON CACHE BOOL "PS/2 Mouse Input" FORCE) -set(CLEONOS_CLKS_ENABLE_DESKTOP ON CACHE BOOL "TTY2 Desktop" FORCE) -set(CLEONOS_CLKS_ENABLE_DRIVER_MANAGER ON CACHE BOOL "Driver Manager" FORCE) -set(CLEONOS_CLKS_ENABLE_KELF ON CACHE BOOL "KELF Executor" FORCE) -set(CLEONOS_CLKS_ENABLE_USERLAND_AUTO_EXEC ON CACHE BOOL "Auto Enter User Shell" FORCE) -set(CLEONOS_CLKS_ENABLE_HEAP_SELFTEST ON CACHE BOOL "Heap Selftest" FORCE) -set(CLEONOS_CLKS_ENABLE_EXTERNAL_PSF ON CACHE BOOL "Load External PSF Font" FORCE) -set(CLEONOS_CLKS_ENABLE_KEYBOARD ON CACHE BOOL "PS/2 Keyboard Input" FORCE) -set(CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE ON CACHE BOOL "ELFRUNNER Probe" FORCE) -set(CLEONOS_CLKS_ENABLE_KLOGD_TASK ON CACHE BOOL "Scheduler Task: klogd" FORCE) -set(CLEONOS_CLKS_ENABLE_KWORKER_TASK ON CACHE BOOL "Scheduler Task: kworker" FORCE) -set(CLEONOS_CLKS_ENABLE_USRD_TASK ON CACHE BOOL "Scheduler Task: usrd" FORCE) -set(CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG "M" CACHE STRING "Boot Video Geometry Logs" FORCE) -set(CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG_IS_ENABLED ON CACHE BOOL "Boot Video Geometry Logs enabled(y|m)" FORCE) -set(CLEONOS_CLKS_ENABLE_PMM_STATS_LOG "M" CACHE STRING "PMM Stats Logs" FORCE) -set(CLEONOS_CLKS_ENABLE_PMM_STATS_LOG_IS_ENABLED ON CACHE BOOL "PMM Stats Logs enabled(y|m)" FORCE) -set(CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG "M" CACHE STRING "Heap Stats Logs" FORCE) -set(CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG_IS_ENABLED ON CACHE BOOL "Heap Stats Logs enabled(y|m)" FORCE) -set(CLEONOS_CLKS_ENABLE_FS_ROOT_LOG "M" CACHE STRING "FS Root Children Log" FORCE) -set(CLEONOS_CLKS_ENABLE_FS_ROOT_LOG_IS_ENABLED ON CACHE BOOL "FS Root Children Log enabled(y|m)" FORCE) -set(CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK ON CACHE BOOL "FS /SYSTEM Sanity Check" FORCE) -set(CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT ON CACHE BOOL "ELFRUNNER Init" FORCE) -set(CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY ON CACHE BOOL "SYSCALL Tick Query" FORCE) -set(CLEONOS_CLKS_ENABLE_TTY_READY_LOG "M" CACHE STRING "TTY Ready Logs" FORCE) -set(CLEONOS_CLKS_ENABLE_TTY_READY_LOG_IS_ENABLED ON CACHE BOOL "TTY Ready Logs enabled(y|m)" FORCE) -set(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG "M" CACHE STRING "Idle Loop Debug Log" FORCE) -set(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG_IS_ENABLED ON CACHE BOOL "Idle Loop Debug Log enabled(y|m)" FORCE) -set(CLEONOS_CLKS_ENABLE_PROCFS ON CACHE BOOL "Virtual /proc" FORCE) -set(CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG "M" CACHE STRING "EXEC Serial Logs" FORCE) -set(CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG_IS_ENABLED ON CACHE BOOL "EXEC Serial Logs enabled(y|m)" FORCE) -set(CLEONOS_CLKS_ENABLE_USC ON CACHE BOOL "UserSafeController (USC)" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_FS_MKDIR OFF CACHE BOOL "Intercept FS_MKDIR" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_FS_WRITE OFF CACHE BOOL "Intercept FS_WRITE" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_FS_APPEND OFF CACHE BOOL "Intercept FS_APPEND" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_FS_REMOVE OFF CACHE BOOL "Intercept FS_REMOVE" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATH ON CACHE BOOL "Intercept EXEC_PATH" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV ON CACHE BOOL "Intercept EXEC_PATHV" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV_IO OFF CACHE BOOL "Intercept EXEC_PATHV_IO" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATH ON CACHE BOOL "Intercept SPAWN_PATH" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATHV ON CACHE BOOL "Intercept SPAWN_PATHV" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_PROC_KILL ON CACHE BOOL "Intercept PROC_KILL" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_SHUTDOWN ON CACHE BOOL "Intercept SHUTDOWN" FORCE) -set(CLEONOS_CLKS_ENABLE_USC_SC_RESTART ON CACHE BOOL "Intercept RESTART" FORCE) -set(CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY ON CACHE BOOL "Keyboard TTY Switch Hotkey" FORCE) -set(CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS ON CACHE BOOL "Keyboard Ctrl Shortcuts" FORCE) -set(CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY ON CACHE BOOL "Keyboard Force-Stop Hotkey" FORCE) -set(CLEONOS_CLKS_ENABLE_USER_INIT_SCRIPT_PROBE ON CACHE BOOL "User Init Script Probe" FORCE) -set(CLEONOS_CLKS_ENABLE_USER_SYSTEM_APP_PROBE ON CACHE BOOL "User System App Probe" FORCE) -set(CLEONOS_CLKS_ENABLE_SCHED_TASK_COUNT_LOG "Y" CACHE STRING "Scheduler Task Count Log" FORCE) -set(CLEONOS_CLKS_ENABLE_SCHED_TASK_COUNT_LOG_IS_ENABLED ON CACHE BOOL "Scheduler Task Count Log enabled(y|m)" FORCE) -set(CLEONOS_CLKS_ENABLE_INTERRUPT_READY_LOG "M" CACHE STRING "Interrupt Ready Log" FORCE) -set(CLEONOS_CLKS_ENABLE_INTERRUPT_READY_LOG_IS_ENABLED ON CACHE BOOL "Interrupt Ready Log enabled(y|m)" FORCE) -set(CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG "M" CACHE STRING "Shell Mode Log" FORCE) -set(CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG_IS_ENABLED ON CACHE BOOL "Shell Mode Log enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_AUDIO ON CACHE BOOL "音频驱动初始化" FORCE) +set(CLEONOS_CLKS_ENABLE_MOUSE ON CACHE BOOL "PS/2 鼠标输入" FORCE) +set(CLEONOS_CLKS_ENABLE_DESKTOP ON CACHE BOOL "TTY2 桌面" FORCE) +set(CLEONOS_CLKS_ENABLE_DRIVER_MANAGER ON CACHE BOOL "驱动管理器" FORCE) +set(CLEONOS_CLKS_ENABLE_KELF ON CACHE BOOL "KELF 执行器" FORCE) +set(CLEONOS_CLKS_ENABLE_USERLAND_AUTO_EXEC ON CACHE BOOL "自动进入用户 Shell" FORCE) +set(CLEONOS_CLKS_ENABLE_HEAP_SELFTEST ON CACHE BOOL "堆自检" FORCE) +set(CLEONOS_CLKS_ENABLE_EXTERNAL_PSF ON CACHE BOOL "加载外部 PSF 字体" FORCE) +set(CLEONOS_CLKS_ENABLE_KEYBOARD ON CACHE BOOL "PS/2 键盘输入" FORCE) +set(CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE ON CACHE BOOL "ELFRUNNER 探测" FORCE) +set(CLEONOS_CLKS_ENABLE_KLOGD_TASK ON CACHE BOOL "调度任务:klogd" FORCE) +set(CLEONOS_CLKS_ENABLE_KWORKER_TASK ON CACHE BOOL "调度任务:kworker" FORCE) +set(CLEONOS_CLKS_ENABLE_USRD_TASK ON CACHE BOOL "调度任务:usrd" FORCE) +set(CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG "M" CACHE STRING "启动视频几何日志" FORCE) +set(CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG_IS_ENABLED ON CACHE BOOL "启动视频几何日志 enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_PMM_STATS_LOG "M" CACHE STRING "PMM 统计日志" FORCE) +set(CLEONOS_CLKS_ENABLE_PMM_STATS_LOG_IS_ENABLED ON CACHE BOOL "PMM 统计日志 enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG "M" CACHE STRING "堆统计日志" FORCE) +set(CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG_IS_ENABLED ON CACHE BOOL "堆统计日志 enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_FS_ROOT_LOG "M" CACHE STRING "FS 根目录子项日志" FORCE) +set(CLEONOS_CLKS_ENABLE_FS_ROOT_LOG_IS_ENABLED ON CACHE BOOL "FS 根目录子项日志 enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK ON CACHE BOOL "FS /SYSTEM 健全性检查" FORCE) +set(CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT ON CACHE BOOL "ELFRUNNER 初始化" FORCE) +set(CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY ON CACHE BOOL "SYSCALL Tick 查询" FORCE) +set(CLEONOS_CLKS_ENABLE_TTY_READY_LOG "M" CACHE STRING "TTY 就绪日志" FORCE) +set(CLEONOS_CLKS_ENABLE_TTY_READY_LOG_IS_ENABLED ON CACHE BOOL "TTY 就绪日志 enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG "M" CACHE STRING "空闲循环调试日志" FORCE) +set(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG_IS_ENABLED ON CACHE BOOL "空闲循环调试日志 enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_PROCFS ON CACHE BOOL "虚拟 /proc" FORCE) +set(CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG "M" CACHE STRING "EXEC 串口日志" FORCE) +set(CLEONOS_CLKS_ENABLE_EXEC_SERIAL_LOG_IS_ENABLED ON CACHE BOOL "EXEC 串口日志 enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_SYSCALL_SERIAL_LOG OFF CACHE BOOL "SYSCALL 串口日志" FORCE) +set(CLEONOS_CLKS_ENABLE_SYSCALL_USERID_SERIAL_LOG OFF CACHE BOOL "SYSCALL USER_ID 串口日志" FORCE) +set(CLEONOS_CLKS_ENABLE_LOG_LEVEL_DEBUG ON CACHE BOOL "内核日志级别:DEBUG" FORCE) +set(CLEONOS_CLKS_ENABLE_LOG_LEVEL_INFO ON CACHE BOOL "内核日志级别:INFO" FORCE) +set(CLEONOS_CLKS_ENABLE_LOG_LEVEL_WARN ON CACHE BOOL "内核日志级别:WARN" FORCE) +set(CLEONOS_CLKS_ENABLE_LOG_LEVEL_ERROR ON CACHE BOOL "内核日志级别:ERROR" FORCE) +set(CLEONOS_CLKS_ENABLE_LOG_OUTPUT_SERIAL ON CACHE BOOL "内核日志输出:串口" FORCE) +set(CLEONOS_CLKS_ENABLE_LOG_OUTPUT_TTY ON CACHE BOOL "内核日志输出:TTY" FORCE) +set(CLEONOS_CLKS_ENABLE_LOG_OUTPUT_JOURNAL ON CACHE BOOL "内核日志输出:日志缓冲" FORCE) +set(CLEONOS_CLKS_ENABLE_USC ON CACHE BOOL "用户安全控制器(USC)" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_FS_MKDIR OFF CACHE BOOL "拦截 FS_MKDIR" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_FS_WRITE OFF CACHE BOOL "拦截 FS_WRITE" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_FS_APPEND OFF CACHE BOOL "拦截 FS_APPEND" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_FS_REMOVE OFF CACHE BOOL "拦截 FS_REMOVE" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATH ON CACHE BOOL "拦截 EXEC_PATH" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV ON CACHE BOOL "拦截 EXEC_PATHV" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_EXEC_PATHV_IO OFF CACHE BOOL "拦截 EXEC_PATHV_IO" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATH ON CACHE BOOL "拦截 SPAWN_PATH" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_SPAWN_PATHV ON CACHE BOOL "拦截 SPAWN_PATHV" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_PROC_KILL ON CACHE BOOL "拦截 PROC_KILL" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_SHUTDOWN ON CACHE BOOL "拦截 SHUTDOWN" FORCE) +set(CLEONOS_CLKS_ENABLE_USC_SC_RESTART ON CACHE BOOL "拦截 RESTART" FORCE) +set(CLEONOS_CLKS_ENABLE_KBD_TTY_SWITCH_HOTKEY ON CACHE BOOL "键盘 TTY 切换热键" FORCE) +set(CLEONOS_CLKS_ENABLE_KBD_CTRL_SHORTCUTS ON CACHE BOOL "键盘 Ctrl 快捷键" FORCE) +set(CLEONOS_CLKS_ENABLE_KBD_FORCE_STOP_HOTKEY ON CACHE BOOL "键盘强制停止热键" FORCE) +set(CLEONOS_CLKS_ENABLE_USER_INIT_SCRIPT_PROBE ON CACHE BOOL "用户初始化脚本探测" FORCE) +set(CLEONOS_CLKS_ENABLE_USER_SYSTEM_APP_PROBE ON CACHE BOOL "用户系统应用探测" FORCE) +set(CLEONOS_CLKS_ENABLE_SCHED_TASK_COUNT_LOG "Y" CACHE STRING "调度任务数量日志" FORCE) +set(CLEONOS_CLKS_ENABLE_SCHED_TASK_COUNT_LOG_IS_ENABLED ON CACHE BOOL "调度任务数量日志 enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_INTERRUPT_READY_LOG "M" CACHE STRING "中断就绪日志" FORCE) +set(CLEONOS_CLKS_ENABLE_INTERRUPT_READY_LOG_IS_ENABLED ON CACHE BOOL "中断就绪日志 enabled(y|m)" FORCE) +set(CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG "M" CACHE STRING "Shell 模式日志" FORCE) +set(CLEONOS_CLKS_ENABLE_SHELL_MODE_LOG_IS_ENABLED ON CACHE BOOL "Shell 模式日志 enabled(y|m)" FORCE) diff --git a/scripts/menuconfig.py b/scripts/menuconfig.py index 4aef2b7..1b4a925 100644 --- a/scripts/menuconfig.py +++ b/scripts/menuconfig.py @@ -53,6 +53,38 @@ CONFIG_CLEONOS_JSON_PATH = MENUCONFIG_DIR / ".config.cleonos.json" CONFIG_CLKS_CMAKE_PATH = MENUCONFIG_DIR / "config.clks.cmake" CONFIG_CLEONOS_CMAKE_PATH = MENUCONFIG_DIR / "config.cleonos.cmake" +MENUCONFIG_LANG = "en" + + +def _is_zh() -> bool: + return MENUCONFIG_LANG == "zh-CN" + + +def _t(en: str, zh: str) -> str: + return zh if _is_zh() else en + + +def _resolve_language(requested: str) -> str: + token = str(requested or "auto").strip().lower() + + if token in {"zh", "zh-cn", "zh_cn"}: + return "zh-CN" + if token == "en": + return "en" + if token != "auto": + return "en" + + env_candidates = ( + os.environ.get("LC_ALL", ""), + os.environ.get("LC_MESSAGES", ""), + os.environ.get("LANG", ""), + ) + for value in env_candidates: + text = str(value).strip().lower() + if text.startswith("zh"): + return "zh-CN" + return "en" + @dataclass(frozen=True) class OptionItem: @@ -314,14 +346,20 @@ def load_clks_options() -> List[OptionItem]: if not isinstance(entry, dict): continue key = str(entry.get("key", "")).strip() - title = str(entry.get("title", key)).strip() - description = str(entry.get("description", "")).strip() + title_key = "title_zh" if _is_zh() else "title" + desc_key = "description_zh" if _is_zh() else "description" + group_key = "group_zh" if _is_zh() else "group" + + title = str(entry.get(title_key, entry.get("title", key))).strip() + description = str(entry.get(desc_key, entry.get("description", ""))).strip() kind = normalize_kind(entry.get("type", "bool")) default = normalize_tri(entry.get("default", TRI_Y), TRI_Y, kind) depends_on = str(entry.get("depends_on", entry.get("depends", ""))).strip() selects = _normalize_key_list(entry.get("select", entry.get("selects", ()))) implies = _normalize_key_list(entry.get("imply", entry.get("implies", ()))) - group = str(entry.get("group", entry.get("menu", "General"))).strip() or "General" + group = str(entry.get(group_key, entry.get("group", entry.get("menu", _t("General", "通用"))))).strip() or _t( + "General", "通用" + ) if not key: continue options.append( @@ -378,7 +416,10 @@ def discover_user_apps() -> List[OptionItem]: for app, section in final_apps: key = f"CLEONOS_USER_APP_{sanitize_token(app)}" title = f"{app}.elf [{section}]" - description = f"Build and package user app '{app}' into ramdisk/{section}." + if _is_zh(): + description = f"构建并打包用户应用 '{app}' 到 ramdisk/{section}。" + else: + description = f"Build and package user app '{app}' into ramdisk/{section}." options.append( OptionItem( key=key, @@ -729,34 +770,34 @@ def _detail_lines(item: OptionItem, values: Dict[str, int], ev: EvalResult) -> L allowed = ",".join(tri_char(v) for v in _allowed_values(item, floor_val, ceil_val)) lines = [ - f"kind: {item.kind}", - f"requested: {tri_char(req)}", - f"effective: {tri_char(eff)}", - f"visible: {'yes' if visible else 'no'}", - f"allowed: {allowed}", - f"depends: {item.depends_on or ''}", + f"{_t('kind', '类型')}: {item.kind}", + f"{_t('requested', '请求值')}: {tri_char(req)}", + f"{_t('effective', '生效值')}: {tri_char(eff)}", + f"{_t('visible', '可见')}: {_t('yes', '是') if visible else _t('no', '否')}", + f"{_t('allowed', '可选')}: {allowed}", + f"{_t('depends', '依赖')}: {item.depends_on or _t('', '<无>')}", ] symbols = ev.depends_symbols.get(item.key, []) if symbols: parts = [f"{sym}={tri_char(ev.effective.get(sym, TRI_N))}" for sym in symbols] - lines.append("depends values: " + ", ".join(parts)) + lines.append(_t("depends values: ", "依赖值: ") + ", ".join(parts)) else: - lines.append("depends values: ") + lines.append(_t("depends values: ", "依赖值: <无>")) sel = ev.selected_by.get(item.key, []) imp = ev.implied_by.get(item.key, []) - lines.append("selected by: " + (", ".join(sel) if sel else "")) - lines.append("implied by: " + (", ".join(imp) if imp else "")) + lines.append(_t("selected by: ", "被选择自: ") + (", ".join(sel) if sel else _t("", "<无>"))) + lines.append(_t("implied by: ", "被蕴含自: ") + (", ".join(imp) if imp else _t("", "<无>"))) return lines def _tri_word(value: int) -> str: if value >= TRI_Y: - return "Enabled" + return _t("Enabled", "启用") if value >= TRI_M: - return "Module" - return "Disabled" + return _t("Module", "模块") + return _t("Disabled", "禁用") def _detail_lines_human(item: OptionItem, values: Dict[str, int], ev: EvalResult) -> List[str]: @@ -771,26 +812,26 @@ def _detail_lines_human(item: OptionItem, values: Dict[str, int], ev: EvalResult if symbols: dep_values = ", ".join(f"{sym}={tri_char(ev.effective.get(sym, TRI_N))}" for sym in symbols) else: - dep_values = "" + dep_values = _t("", "<无>") - selected_chain = ", ".join(ev.selected_by.get(item.key, [])) or "" - implied_chain = ", ".join(ev.implied_by.get(item.key, [])) or "" + selected_chain = ", ".join(ev.selected_by.get(item.key, [])) or _t("", "<无>") + implied_chain = ", ".join(ev.implied_by.get(item.key, [])) or _t("", "<无>") allowed_text = "/".join(f"{tri_char(v)}({_tri_word(v)})" for v in allowed_vals) return [ - "State:", - f" Running now : {tri_char(eff)} ({_tri_word(eff)})", - f" Your choice : {tri_char(req)} ({_tri_word(req)})", - f" Type : {item.kind}", - f" Visible : {'yes' if visible else 'no'}", - f" Allowed now : {allowed_text}", - "Why:", - f" depends on : {item.depends_on or ''}", - f" depends value : {dep_values}", - f" selected by : {selected_chain}", - f" implied by : {implied_chain}", - "Notes:", - " [a/b] in list means [effective/requested].", + _t("State:", "状态:"), + f" {_t('Running now', '当前生效'):12s} : {tri_char(eff)} ({_tri_word(eff)})", + f" {_t('Your choice', '你的选择'):12s} : {tri_char(req)} ({_tri_word(req)})", + f" {_t('Type', '类型'):12s} : {item.kind}", + f" {_t('Visible', '可见'):12s} : {_t('yes', '是') if visible else _t('no', '否')}", + f" {_t('Allowed now', '当前可选'):12s} : {allowed_text}", + _t("Why:", "原因:"), + f" {_t('depends on', '依赖于'):12s} : {item.depends_on or _t('', '<无>')}", + f" {_t('depends value', '依赖值'):12s} : {dep_values}", + f" {_t('selected by', '被选择自'):12s} : {selected_chain}", + f" {_t('implied by', '被蕴含自'):12s} : {implied_chain}", + _t("Notes:", "说明:"), + _t(" [a/b] in list means [effective/requested].", " 列表中的 [a/b] 表示 [生效值/请求值]。"), f" {item.description}", ] @@ -817,15 +858,20 @@ def print_section(title: str, section_options: List[OptionItem], all_options: Li flags.append("implied") flag_text = f" ({', '.join(flags)})" if flags else "" print(f"{idx:3d}. [{tri_char(eff)}|{tri_char(req)}] {item.title}{flag_text}") - print("Commands: cycle, a all->y, n all->n, m all->m, i info, b back") - print("Legend: [effective|requested], states: y/m/n") + print( + _t( + "Commands: cycle, a all->y, n all->n, m all->m, i info, b back", + "命令: <编号> 切换, a 全部->y, n 全部->n, m 全部->m, i 详情, b 返回", + ) + ) + print(_t("Legend: [effective|requested], states: y/m/n", "图例: [生效值|请求值], 状态: y/m/n")) def section_loop(title: str, section_options: List[OptionItem], all_options: List[OptionItem], values: Dict[str, int]) -> None: while True: ev = evaluate_config(all_options, values) print_section(title, section_options, all_options, values) - raw = input(f"{title}> ").strip() + raw = input(f"{title}{_t('> ', '> ')}").strip() if not raw: continue lower = raw.lower() @@ -852,12 +898,12 @@ def section_loop(title: str, section_options: List[OptionItem], all_options: Lis item = section_options[idx - 1] print() print(f"[{idx}] {item.title}") - print(f"key: {item.key}") + print(f"{_t('key', '键名')}: {item.key}") for line in _detail_lines(item, values, ev): print(line) - print(f"desc: {item.description}") + print(f"{_t('desc', '描述')}: {item.description}") continue - print("invalid info index") + print(_t("invalid info index", "无效的详情编号")) continue if raw.isdigit(): @@ -866,10 +912,10 @@ def section_loop(title: str, section_options: List[OptionItem], all_options: Lis item = section_options[idx - 1] _cycle_option_value(values, item, ev) else: - print("invalid index") + print(_t("invalid index", "无效编号")) continue - print("unknown command") + print(_t("unknown command", "未知命令")) def grouped_section_loop( @@ -887,19 +933,22 @@ def grouped_section_loop( while True: ev = evaluate_config(all_options, values) print() - print(f"== {title} / Groups ==") - print(f" 0. All ({_group_enabled_count(section_options, ev)}/{len(section_options)} enabled)") + print(f"== {title} / {_t('Groups', '分组')} ==") + print( + f" 0. {_t('All', '全部')} ({_group_enabled_count(section_options, ev)}/{len(section_options)} " + f"{_t('enabled', '已启用')})" + ) for idx, (name, opts) in enumerate(groups, start=1): - print(f"{idx:3d}. {name} ({_group_enabled_count(opts, ev)}/{len(opts)} enabled)") - print("Commands: open, b back") + print(f"{idx:3d}. {name} ({_group_enabled_count(opts, ev)}/{len(opts)} {_t('enabled', '已启用')})") + print(_t("Commands: open, b back", "命令: <编号> 打开, b 返回")) - raw = input(f"{title}/groups> ").strip().lower() + raw = input(f"{title}/{_t('groups', 'groups')}> ").strip().lower() if not raw: continue if raw in {"b", "back", "q", "quit"}: return if not raw.isdigit(): - print("invalid selection") + print(_t("invalid selection", "无效选择")) continue idx = int(raw) @@ -910,7 +959,7 @@ def grouped_section_loop( group_name, group_items = groups[idx - 1] section_loop(f"{title}/{group_name}", group_items, all_options, values) continue - print("invalid selection") + print(_t("invalid selection", "无效选择")) def _safe_addnstr(stdscr, y: int, x: int, text: str, attr: int = 0) -> None: @@ -1122,8 +1171,14 @@ def _run_ncurses_section( h, w = stdscr.getmaxyx() if h < 14 or w < 70: - _safe_addnstr(stdscr, 0, 0, "Terminal too small for rich UI (need >= 70x14).", theme["status_warn"]) - _safe_addnstr(stdscr, 2, 0, "Resize terminal then press any key, or ESC to go back.") + _safe_addnstr( + stdscr, + 0, + 0, + _t("Terminal too small for rich UI (need >= 70x14).", "终端太小,无法显示完整界面(至少需要 70x14)。"), + theme["status_warn"], + ) + _safe_addnstr(stdscr, 2, 0, _t("Resize terminal then press any key, or ESC to go back.", "请调整终端大小后按任意键,或按 ESC 返回。")) key = stdscr.getch() if key in (27,): return @@ -1152,12 +1207,33 @@ def _run_ncurses_section( stdscr, 1, 0, - f" on:{enabled_count} mod:{module_count} total:{len(section_options)} | Space cycle a/n/m all Enter/ESC back ", + ( + f" {_t('on', '开')}:{enabled_count} {_t('mod', '模')}:{module_count} {_t('total', '总数')}:{len(section_options)}" + f" | {_t('Space cycle', '空格切换')} a/n/m {_t('all', '全部')} Enter/ESC {_t('back', '返回')} " + ), theme["subtitle"], ) - _draw_box(stdscr, list_box_y, list_box_x, list_box_h, list_box_w, "Options", theme["panel_border"], theme["panel_title"]) - _draw_box(stdscr, detail_box_y, detail_box_x, detail_box_h, detail_box_w, "Details", theme["panel_border"], theme["panel_title"]) + _draw_box( + stdscr, + list_box_y, + list_box_x, + list_box_h, + list_box_w, + _t("Options", "选项"), + theme["panel_border"], + theme["panel_title"], + ) + _draw_box( + stdscr, + detail_box_y, + detail_box_x, + detail_box_h, + detail_box_w, + _t("Details", "详情"), + theme["panel_border"], + theme["panel_title"], + ) list_inner_y = list_box_y + 1 list_inner_x = list_box_x + 1 @@ -1219,12 +1295,12 @@ def _run_ncurses_section( _safe_addnstr(stdscr, detail_inner_y + 0, detail_inner_x, cur.title, theme["value_label"]) _safe_addnstr(stdscr, detail_inner_y + 1, detail_inner_x, cur.key, theme["value_key"]) - _safe_addnstr(stdscr, detail_inner_y + 2, detail_inner_x, f"State: {state_text}", state_attr) + _safe_addnstr(stdscr, detail_inner_y + 2, detail_inner_x, f"{_t('State', '状态')}: {state_text}", state_attr) _safe_addnstr( stdscr, detail_inner_y + 3, detail_inner_x, - f"Item: {selected + 1}/{len(section_options)} flags: {_option_flags(cur, ev)}", + f"{_t('Item', '条目')}: {selected + 1}/{len(section_options)} {_t('flags', '标记')}: {_option_flags(cur, ev)}", theme["value_label"], ) _draw_progress_bar( @@ -1239,7 +1315,7 @@ def _run_ncurses_section( ) desc_title_y = detail_inner_y + 6 - _safe_addnstr(stdscr, desc_title_y, detail_inner_x, "Details:", theme["value_label"]) + _safe_addnstr(stdscr, desc_title_y, detail_inner_x, f"{_t('Details', '详情')}:", theme["value_label"]) raw_lines = _detail_lines_human(cur, values, ev) wrapped_lines: List[str] = [] wrap_width = max(12, detail_inner_w) @@ -1256,7 +1332,16 @@ def _run_ncurses_section( for i, part in enumerate(wrapped_lines[:max_desc_lines]): _safe_addnstr(stdscr, desc_title_y + 1 + i, detail_inner_x, part, 0) - _safe_addnstr(stdscr, h - 1, 0, " Space:cycle a:all-y n:all-n m:all-m Enter/ESC:back ", theme["help"]) + _safe_addnstr( + stdscr, + h - 1, + 0, + _t( + " Space:cycle a:all-y n:all-n m:all-m Enter/ESC:back ", + " 空格:切换 a:全y n:全n m:全m Enter/ESC:返回 ", + ), + theme["help"], + ) stdscr.refresh() key = stdscr.getch() @@ -1319,17 +1404,23 @@ def _run_ncurses_grouped_section( items: List[Tuple[str, List[OptionItem]]] = [("All", section_options)] + groups if h < 12 or w < 56: - _safe_addnstr(stdscr, 0, 0, "Terminal too small for grouped view (need >= 56x12).", theme["status_warn"]) - _safe_addnstr(stdscr, 2, 0, "Resize terminal then press any key, or ESC to go back.") + _safe_addnstr( + stdscr, + 0, + 0, + _t("Terminal too small for grouped view (need >= 56x12).", "终端太小,无法显示分组视图(至少需要 56x12)。"), + theme["status_warn"], + ) + _safe_addnstr(stdscr, 2, 0, _t("Resize terminal then press any key, or ESC to go back.", "请调整终端大小后按任意键,或按 ESC 返回。")) key = stdscr.getch() if key in (27,): return continue - _safe_addnstr(stdscr, 0, 0, f" CLeonOS menuconfig / {title} / Groups ", theme["header"]) - _safe_addnstr(stdscr, 1, 0, " Enter: open group ESC: back ", theme["subtitle"]) + _safe_addnstr(stdscr, 0, 0, f" CLeonOS menuconfig / {title} / {_t('Groups', '分组')} ", theme["header"]) + _safe_addnstr(stdscr, 1, 0, _t(" Enter: open group ESC: back ", " Enter:打开分组 ESC:返回 "), theme["subtitle"]) - _draw_box(stdscr, 2, 0, h - 4, w, "CLKS Groups", theme["panel_border"], theme["panel_title"]) + _draw_box(stdscr, 2, 0, h - 4, w, _t("CLKS Groups", "CLKS 分组"), theme["panel_border"], theme["panel_title"]) if selected < 0: selected = 0 @@ -1341,11 +1432,12 @@ def _run_ncurses_grouped_section( if row >= h - 2: break on_count = _group_enabled_count(opts, ev) - line = f"{'>' if i == selected else ' '} {i:02d} {name} ({on_count}/{len(opts)} enabled)" + localized_name = _t("All", "全部") if name == "All" else name + line = f"{'>' if i == selected else ' '} {i:02d} {localized_name} ({on_count}/{len(opts)} {_t('enabled', '已启用')})" attr = theme["selected"] if i == selected else theme["value_label"] _safe_addnstr(stdscr, row, 2, line, attr) - _safe_addnstr(stdscr, h - 1, 0, " Arrows/jk move Enter open ESC back ", theme["help"]) + _safe_addnstr(stdscr, h - 1, 0, _t(" Arrows/jk move Enter open ESC back ", " 方向键/jk移动 Enter打开 ESC返回 "), theme["help"]) stdscr.refresh() key = stdscr.getch() @@ -1387,25 +1479,37 @@ def _run_ncurses_main(stdscr, clks_options: List[OptionItem], user_options: List total_on = clks_on + user_on menu_entries: List[Tuple[str, str]] = [ - ("clks", f"CLKS features ({clks_on}/{len(clks_options)} enabled)"), + ("clks", f"{_t('CLKS features', 'CLKS 功能')} ({clks_on}/{len(clks_options)} {_t('enabled', '已启用')})"), ] if user_options: - menu_entries.append(("user", f"User apps ({user_on}/{len(user_options)} enabled)")) + menu_entries.append(("user", f"{_t('User apps', '用户应用')} ({user_on}/{len(user_options)} {_t('enabled', '已启用')})")) else: - menu_entries.append(("user-disabled", "User apps (CLKS-only mode)")) - menu_entries.append(("save", "Save and Exit")) - menu_entries.append(("quit", "Quit without Saving")) + menu_entries.append(("user-disabled", _t("User apps (CLKS-only mode)", "用户应用(仅 CLKS 模式)"))) + menu_entries.append(("save", _t("Save and Exit", "保存并退出"))) + menu_entries.append(("quit", _t("Quit without Saving", "不保存退出"))) if h < 12 or w < 58: - _safe_addnstr(stdscr, 0, 0, "Terminal too small for menuconfig (need >= 58x12).", theme["status_warn"]) - _safe_addnstr(stdscr, 2, 0, "Resize terminal then press any key.") + _safe_addnstr( + stdscr, + 0, + 0, + _t("Terminal too small for menuconfig (need >= 58x12).", "终端太小,无法显示 menuconfig(至少需要 58x12)。"), + theme["status_warn"], + ) + _safe_addnstr(stdscr, 2, 0, _t("Resize terminal then press any key.", "请调整终端大小后按任意键。")) stdscr.getch() continue _safe_addnstr(stdscr, 0, 0, " CLeonOS menuconfig ", theme["header"]) - _safe_addnstr(stdscr, 1, 0, " Stylish ncurses UI | Enter: open/select s: save q: quit ", theme["subtitle"]) + _safe_addnstr( + stdscr, + 1, + 0, + _t(" Stylish ncurses UI | Enter: open/select s: save q: quit ", " 现代 ncurses 界面 | Enter:打开/选择 s:保存 q:退出 "), + theme["subtitle"], + ) - _draw_box(stdscr, 2, 0, h - 5, w, "Main", theme["panel_border"], theme["panel_title"]) + _draw_box(stdscr, 2, 0, h - 5, w, _t("Main", "主菜单"), theme["panel_border"], theme["panel_title"]) base = 4 for i, (_action, text) in enumerate(menu_entries): @@ -1414,7 +1518,7 @@ def _run_ncurses_main(stdscr, clks_options: List[OptionItem], user_options: List attr = theme["selected"] if i == selected else theme["value_label"] _safe_addnstr(stdscr, base + i, 2, row_text, attr) - _safe_addnstr(stdscr, base + 6, 2, "Global Progress:", theme["value_label"]) + _safe_addnstr(stdscr, base + 6, 2, _t("Global Progress:", "全局进度:"), theme["value_label"]) _draw_progress_bar( stdscr, base + 7, @@ -1426,11 +1530,29 @@ def _run_ncurses_main(stdscr, clks_options: List[OptionItem], user_options: List theme["progress_off"], ) - _safe_addnstr(stdscr, h - 2, 0, " Arrows/jk move Enter select s save q quit ", theme["help"]) + _safe_addnstr(stdscr, h - 2, 0, _t(" Arrows/jk move Enter select s save q quit ", " 方向键/jk移动 Enter选择 s保存 q退出 "), theme["help"]) if user_options: - _safe_addnstr(stdscr, h - 1, 0, " Tip: open CLKS/USER section then use Space to toggle options. ", theme["help"]) + _safe_addnstr( + stdscr, + h - 1, + 0, + _t( + " Tip: open CLKS/USER section then use Space to toggle options. ", + " 提示: 进入 CLKS/USER 分区后,用空格切换选项。", + ), + theme["help"], + ) else: - _safe_addnstr(stdscr, h - 1, 0, " Tip: CLKS-only mode, open CLKS section then use Space to toggle options. ", theme["help"]) + _safe_addnstr( + stdscr, + h - 1, + 0, + _t( + " Tip: CLKS-only mode, open CLKS section then use Space to toggle options. ", + " 提示: 当前是仅 CLKS 模式,进入 CLKS 分区后用空格切换选项。", + ), + theme["help"], + ) stdscr.refresh() key = stdscr.getch() @@ -1462,18 +1584,18 @@ def _run_ncurses_main(stdscr, clks_options: List[OptionItem], user_options: List def interactive_menu_ncurses(clks_options: List[OptionItem], user_options: List[OptionItem], values: Dict[str, int]) -> bool: if curses is None: - raise RuntimeError("python curses module unavailable (install python3-curses / ncurses)") + raise RuntimeError(_t("python curses module unavailable (install python3-curses / ncurses)", "缺少 python curses 模块(请安装 python3-curses / ncurses)")) if "TERM" not in os.environ or not os.environ["TERM"]: - raise RuntimeError("TERM is not set; cannot start ncurses UI") + raise RuntimeError(_t("TERM is not set; cannot start ncurses UI", "TERM 未设置,无法启动 ncurses 界面")) return bool(curses.wrapper(lambda stdscr: _run_ncurses_main(stdscr, clks_options, user_options, values))) def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[OptionItem], values: Dict[str, int]) -> bool: if QtWidgets is None or QtCore is None: - raise RuntimeError("python PySide unavailable (install PySide6, or use --plain)") + raise RuntimeError(_t("python PySide unavailable (install PySide6, or use --plain)", "缺少 PySide(请安装 PySide6,或使用 --plain)")) if os.name != "nt" and not os.environ.get("DISPLAY") and not os.environ.get("WAYLAND_DISPLAY"): - raise RuntimeError("GUI mode requires a desktop display (DISPLAY/WAYLAND_DISPLAY)") + raise RuntimeError(_t("GUI mode requires a desktop display (DISPLAY/WAYLAND_DISPLAY)", "GUI 模式需要桌面显示环境(DISPLAY/WAYLAND_DISPLAY)")) app = QtWidgets.QApplication.instance() owns_app = False @@ -1510,7 +1632,7 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti result = {"save": False} dialog = QtWidgets.QDialog() - dialog.setWindowTitle("CLeonOS menuconfig (PySide)") + dialog.setWindowTitle(_t("CLeonOS menuconfig (PySide)", "CLeonOS menuconfig(PySide)")) dialog.resize(1180, 760) dialog.setMinimumSize(920, 560) @@ -1521,7 +1643,7 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti root_layout.setContentsMargins(12, 10, 12, 12) root_layout.setSpacing(8) - header_title = QtWidgets.QLabel("CLeonOS menuconfig") + header_title = QtWidgets.QLabel(_t("CLeonOS menuconfig", "CLeonOS 配置菜单")) header_font = header_title.font() header_font.setPointSize(header_font.pointSize() + 4) header_font.setBold(True) @@ -1529,9 +1651,13 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti root_layout.addWidget(header_title) if user_options: - root_layout.addWidget(QtWidgets.QLabel("Window mode (PySide): configure CLKS features and user apps, then save.")) + root_layout.addWidget( + QtWidgets.QLabel(_t("Window mode (PySide): configure CLKS features and user apps, then save.", "窗口模式(PySide):配置 CLKS 功能和用户应用后保存。")) + ) else: - root_layout.addWidget(QtWidgets.QLabel("Window mode (PySide): CLKS-only mode (user app options unavailable).")) + root_layout.addWidget( + QtWidgets.QLabel(_t("Window mode (PySide): CLKS-only mode (user app options unavailable).", "窗口模式(PySide):仅 CLKS 模式(用户应用选项不可用)。")) + ) summary_label = QtWidgets.QLabel("") root_layout.addWidget(summary_label) @@ -1546,9 +1672,11 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti user_on = sum(1 for item in user_options if ev.effective.get(item.key, item.default) > TRI_N) total = len(clks_options) + len(user_options) summary_label.setText( - f"CLKS: {clks_on}/{len(clks_options)} on " - f"User: {user_on}/{len(user_options)} on " - f"Total: {clks_on + user_on}/{total}" + ( + f"CLKS: {clks_on}/{len(clks_options)} {_t('on', '开')} " + f"{_t('User', '用户')}: {user_on}/{len(user_options)} {_t('on', '开')} " + f"{_t('Total', '总计')}: {clks_on + user_on}/{total}" + ) ) class _SectionPanel(QtWidgets.QWidget): @@ -1569,12 +1697,12 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti toolbar.addWidget(title_label) toolbar.addStretch(1) - toggle_btn = QtWidgets.QPushButton("Cycle Selected") - set_y_btn = QtWidgets.QPushButton("Set Y") - set_m_btn = QtWidgets.QPushButton("Set M") - set_n_btn = QtWidgets.QPushButton("Set N") - enable_all_btn = QtWidgets.QPushButton("All Y") - disable_all_btn = QtWidgets.QPushButton("All N") + toggle_btn = QtWidgets.QPushButton(_t("Cycle Selected", "切换选中项")) + set_y_btn = QtWidgets.QPushButton(_t("Set Y", "设为 Y")) + set_m_btn = QtWidgets.QPushButton(_t("Set M", "设为 M")) + set_n_btn = QtWidgets.QPushButton(_t("Set N", "设为 N")) + enable_all_btn = QtWidgets.QPushButton(_t("All Y", "全部 Y")) + disable_all_btn = QtWidgets.QPushButton(_t("All N", "全部 N")) toolbar.addWidget(enable_all_btn) toolbar.addWidget(disable_all_btn) toolbar.addWidget(set_m_btn) @@ -1590,7 +1718,7 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti left_layout = QtWidgets.QVBoxLayout(left) left_layout.setContentsMargins(0, 0, 0, 0) self.table = QtWidgets.QTableWidget(len(options), 3) - self.table.setHorizontalHeaderLabels(["Value", "Option", "Status"]) + self.table.setHorizontalHeaderLabels([_t("Value", "值"), _t("Option", "选项"), _t("Status", "状态")]) self.table.verticalHeader().setVisible(False) self.table.horizontalHeader().setSectionResizeMode(0, resize_to_contents) self.table.horizontalHeader().setSectionResizeMode(1, stretch_mode) @@ -1604,8 +1732,8 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti right = QtWidgets.QWidget() right_layout = QtWidgets.QVBoxLayout(right) right_layout.setContentsMargins(0, 0, 0, 0) - self.state_label = QtWidgets.QLabel("State: -") - self.key_label = QtWidgets.QLabel("Key: -") + self.state_label = QtWidgets.QLabel(f"{_t('State', '状态')}: -") + self.key_label = QtWidgets.QLabel(f"{_t('Key', '键名')}: -") self.detail_text = QtWidgets.QPlainTextEdit() self.detail_text.setReadOnly(True) right_layout.addWidget(self.state_label) @@ -1646,8 +1774,8 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti def _show_detail(self, row: int) -> None: if row < 0 or row >= len(self.options): - self.state_label.setText("State: -") - self.key_label.setText("Key: -") + self.state_label.setText(f"{_t('State', '状态')}: -") + self.key_label.setText(f"{_t('Key', '键名')}: -") self.detail_text.setPlainText("") return @@ -1656,9 +1784,9 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti eff = ev.effective.get(item.key, item.default) req = normalize_tri(values.get(item.key, item.default), item.default, item.kind) self.state_label.setText( - f"State: eff={tri_char(eff)} req={tri_char(req)} kind={item.kind} flags={_option_flags(item, ev)}" + f"{_t('State', '状态')}: eff={tri_char(eff)} req={tri_char(req)} kind={item.kind} flags={_option_flags(item, ev)}" ) - self.key_label.setText(f"Key: {item.key}") + self.key_label.setText(f"{_t('Key', '键名')}: {item.key}") self.detail_text.setPlainText("\n".join([item.title, ""] + _detail_lines(item, values, ev) + ["", item.description])) def _on_selection_changed(self) -> None: @@ -1669,9 +1797,14 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti return if len(rows) > 1: - self.state_label.setText(f"State: {len(rows)} items selected") - self.key_label.setText("Key: ") - self.detail_text.setPlainText("Multiple options selected.\nUse Cycle/Set buttons to update selected entries.") + self.state_label.setText(f"{_t('State', '状态')}: {len(rows)} {_t('items selected', '项已选中')}") + self.key_label.setText(f"{_t('Key', '键名')}: {_t('', '<多项>')}") + self.detail_text.setPlainText( + _t( + "Multiple options selected.\nUse Cycle/Set buttons to update selected entries.", + "已选中多个选项。\n使用 Cycle/Set 按钮批量修改。", + ) + ) return self._show_detail(-1) @@ -1761,7 +1894,7 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti clks_groups = _grouped_options(clks_options) if len(clks_groups) <= 1: - clks_panel = _SectionPanel("CLKS Features", clks_options) + clks_panel = _SectionPanel(_t("CLKS Features", "CLKS 功能"), clks_options) else: clks_panel = QtWidgets.QWidget() clks_layout = QtWidgets.QVBoxLayout(clks_panel) @@ -1769,22 +1902,22 @@ def interactive_menu_gui(clks_options: List[OptionItem], user_options: List[Opti clks_layout.setSpacing(6) clks_tabs = QtWidgets.QTabWidget() clks_layout.addWidget(clks_tabs, 1) - clks_tabs.addTab(_SectionPanel("CLKS Features / All", clks_options), "All") + clks_tabs.addTab(_SectionPanel(_t("CLKS Features / All", "CLKS 功能 / 全部"), clks_options), _t("All", "全部")) for group_name, group_items in clks_groups: - clks_tabs.addTab(_SectionPanel(f"CLKS Features / {group_name}", group_items), group_name) + clks_tabs.addTab(_SectionPanel(f"{_t('CLKS Features', 'CLKS 功能')} / {group_name}", group_items), group_name) tabs.addTab(clks_panel, "CLKS") if user_options: - user_panel = _SectionPanel("User Apps", user_options) - tabs.addTab(user_panel, "USER") + user_panel = _SectionPanel(_t("User Apps", "用户应用"), user_options) + tabs.addTab(user_panel, _t("USER", "用户")) update_summary() footer = QtWidgets.QHBoxLayout() - footer.addWidget(QtWidgets.QLabel("Tip: double-click a row to cycle, or use Set/Cycle buttons.")) + footer.addWidget(QtWidgets.QLabel(_t("Tip: double-click a row to cycle, or use Set/Cycle buttons.", "提示:双击一行可切换,或使用 Set/Cycle 按钮。"))) footer.addStretch(1) - save_btn = QtWidgets.QPushButton("Save and Exit") - quit_btn = QtWidgets.QPushButton("Quit without Saving") + save_btn = QtWidgets.QPushButton(_t("Save and Exit", "保存并退出")) + quit_btn = QtWidgets.QPushButton(_t("Quit without Saving", "不保存退出")) footer.addWidget(save_btn) footer.addWidget(quit_btn) root_layout.addLayout(footer) @@ -1888,14 +2021,20 @@ def show_summary(clks_options: List[OptionItem], user_options: List[OptionItem], clks_m = sum(1 for item in clks_options if ev.effective.get(item.key, item.default) == TRI_M) user_m = sum(1 for item in user_options if ev.effective.get(item.key, item.default) == TRI_M) print() - print("========== CLeonOS menuconfig ==========") - print(f"1) CLKS features : on={clks_on} m={clks_m} total={len(clks_options)}") + print(_t("========== CLeonOS menuconfig ==========", "========== CLeonOS 配置菜单 ==========")) + print( + f"1) {_t('CLKS features', 'CLKS 功能')} : " + f"{_t('on', '开')}={clks_on} m={clks_m} {_t('total', '总数')}={len(clks_options)}" + ) if user_options: - print(f"2) User features : on={user_on} m={user_m} total={len(user_options)}") + print( + f"2) {_t('User features', '用户功能')} : " + f"{_t('on', '开')}={user_on} m={user_m} {_t('total', '总数')}={len(user_options)}" + ) else: - print("2) User features : unavailable (CLKS-only mode)") - print("s) Save and exit") - print("q) Quit without saving") + print(_t("2) User features : unavailable (CLKS-only mode)", "2) 用户功能 : 不可用(仅 CLKS 模式)")) + print(_t("s) Save and exit", "s) 保存并退出")) + print(_t("q) Quit without saving", "q) 不保存退出")) def interactive_menu(clks_options: List[OptionItem], user_options: List[OptionItem], values: Dict[str, int]) -> bool: @@ -1903,7 +2042,7 @@ def interactive_menu(clks_options: List[OptionItem], user_options: List[OptionIt has_user = len(user_options) > 0 while True: show_summary(clks_options, user_options, values) - choice = input("Select> ").strip().lower() + choice = input(_t("Select> ", "选择> ")).strip().lower() if choice == "1": grouped_section_loop("CLKS", clks_options, all_options, values) continue @@ -1911,13 +2050,13 @@ def interactive_menu(clks_options: List[OptionItem], user_options: List[OptionIt section_loop("USER", user_options, all_options, values) continue if choice == "2" and not has_user: - print("user features unavailable in CLKS-only mode") + print(_t("user features unavailable in CLKS-only mode", "仅 CLKS 模式下,用户功能不可用")) continue if choice in {"s", "save"}: return True if choice in {"q", "quit"}: return False - print("unknown selection") + print(_t("unknown selection", "未知选择")) def parse_set_overrides(values: Dict[str, int], option_index: Dict[str, OptionItem], kv_pairs: List[str]) -> None: @@ -1942,6 +2081,12 @@ def parse_args() -> argparse.Namespace: parser.add_argument("--plain", action="store_true", help="use legacy plain-text menu instead of ncurses") parser.add_argument("--gui", action="store_true", help="use GUI window mode (PySide)") parser.add_argument("--clks-only", action="store_true", help="only expose CLKS options and emit CLKS-only config") + parser.add_argument( + "--lang", + choices=["auto", "en", "zh", "zh-CN", "zh-cn", "zh_CN", "zh_cn"], + default="auto", + help="menu language: auto|en|zh-CN", + ) parser.add_argument( "--preset", choices=["full", "minimal", "dev"], @@ -1958,15 +2103,23 @@ def parse_args() -> argparse.Namespace: def main() -> int: + global MENUCONFIG_LANG + args = parse_args() + MENUCONFIG_LANG = _resolve_language(args.lang) if args.gui and args.plain: - raise RuntimeError("--gui and --plain cannot be used together") + raise RuntimeError(_t("--gui and --plain cannot be used together", "--gui 和 --plain 不能同时使用")) clks_options = load_clks_options() clks_only_mode = args.clks_only or not APPS_DIR.exists() if clks_only_mode and not args.clks_only: - print(f"menuconfig: cleonos app directory not found, switching to CLKS-only mode ({APPS_DIR})") + print( + _t( + f"menuconfig: cleonos app directory not found, switching to CLKS-only mode ({APPS_DIR})", + f"menuconfig: 未找到 cleonos 应用目录,切换到仅 CLKS 模式({APPS_DIR})", + ) + ) user_options = [] if clks_only_mode else discover_user_apps() all_options = clks_options + user_options @@ -1985,27 +2138,27 @@ def main() -> int: should_save = interactive_menu_gui(clks_options, user_options, values) else: if not sys.stdin.isatty(): - raise RuntimeError("menuconfig requires interactive tty (or use --non-interactive or --gui)") + raise RuntimeError(_t("menuconfig requires interactive tty (or use --non-interactive or --gui)", "menuconfig 需要交互式终端(或使用 --non-interactive / --gui)")) if args.plain: should_save = interactive_menu(clks_options, user_options, values) else: should_save = interactive_menu_ncurses(clks_options, user_options, values) if not should_save: - print("menuconfig: no changes saved") + print(_t("menuconfig: no changes saved", "menuconfig: 未保存任何更改")) return 0 final_eval = evaluate_config(all_options, values) write_outputs(final_eval.effective, clks_options, user_options) - print(f"menuconfig: wrote {CONFIG_JSON_PATH}") - print(f"menuconfig: wrote {CONFIG_CMAKE_PATH}") - print(f"menuconfig: wrote {CONFIG_CLKS_JSON_PATH}") - print(f"menuconfig: wrote {CONFIG_CLKS_CMAKE_PATH}") + print(_t(f"menuconfig: wrote {CONFIG_JSON_PATH}", f"menuconfig: 已写入 {CONFIG_JSON_PATH}")) + print(_t(f"menuconfig: wrote {CONFIG_CMAKE_PATH}", f"menuconfig: 已写入 {CONFIG_CMAKE_PATH}")) + print(_t(f"menuconfig: wrote {CONFIG_CLKS_JSON_PATH}", f"menuconfig: 已写入 {CONFIG_CLKS_JSON_PATH}")) + print(_t(f"menuconfig: wrote {CONFIG_CLKS_CMAKE_PATH}", f"menuconfig: 已写入 {CONFIG_CLKS_CMAKE_PATH}")) if user_options: - print(f"menuconfig: wrote {CONFIG_CLEONOS_JSON_PATH}") - print(f"menuconfig: wrote {CONFIG_CLEONOS_CMAKE_PATH}") + print(_t(f"menuconfig: wrote {CONFIG_CLEONOS_JSON_PATH}", f"menuconfig: 已写入 {CONFIG_CLEONOS_JSON_PATH}")) + print(_t(f"menuconfig: wrote {CONFIG_CLEONOS_CMAKE_PATH}", f"menuconfig: 已写入 {CONFIG_CLEONOS_CMAKE_PATH}")) else: - print("menuconfig: CLeonOS app config skipped (CLKS-only mode)") + print(_t("menuconfig: CLeonOS app config skipped (CLKS-only mode)", "menuconfig: 已跳过 CLeonOS 应用配置(仅 CLKS 模式)")) return 0 @@ -2013,5 +2166,5 @@ if __name__ == "__main__": try: raise SystemExit(main()) except RuntimeError as exc: - print(f"menuconfig error: {exc}", file=sys.stderr) + print(_t(f"menuconfig error: {exc}", f"menuconfig 错误: {exc}"), file=sys.stderr) raise SystemExit(1)