From 0b7b8ba4a22786c327a739be67e285ded9348b34 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 16 Aug 2026 16:16:35 +0200 Subject: [PATCH] Set console codepage to utf-8 (on Windows), and restore old one on exit Avoid mojibake. --- base/runtime/entry_windows.odin | 59 ++++++++++++++++++++++++++++----- src/common.cpp | 14 ++++++++ src/main.cpp | 7 ++++ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/base/runtime/entry_windows.odin b/base/runtime/entry_windows.odin index d3b38bc9c..56cb9063d 100644 --- a/base/runtime/entry_windows.odin +++ b/base/runtime/entry_windows.odin @@ -5,6 +5,14 @@ package runtime import "base:intrinsics" +when !ODIN_BEDROCK { + @(private="file") + old_console_codepage: u32 + + @(private="file") + UTF_8 :: 65001 +} + when ODIN_BUILD_MODE == .Dynamic { @(link_name="DllMain", linkage="strong", require) DllMain :: proc "system" (hinstDLL: rawptr, fdwReason: u32, lpReserved: rawptr) -> b32 { @@ -16,10 +24,17 @@ when ODIN_BUILD_MODE == .Dynamic { switch dll_forward_reason { case .Process_Attach: - when !ODIN_BEDROCK { #force_no_inline _startup_runtime() } + when !ODIN_BEDROCK { + #force_no_inline _startup_runtime() + old_console_codepage = GetConsoleOutputCP() + SetConsoleOutputCP(UTF_8) + } intrinsics.__entry_point() case .Process_Detach: - when !ODIN_BEDROCK { #force_no_inline _cleanup_runtime() } + when !ODIN_BEDROCK { + #force_no_inline _cleanup_runtime() + SetConsoleOutputCP(old_console_codepage) + } case .Thread_Attach: break case .Thread_Detach: @@ -35,18 +50,32 @@ when ODIN_BUILD_MODE == .Dynamic { main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 { args__ = argv[:argc] context = default_context() - when !ODIN_BEDROCK { #force_no_inline _startup_runtime() } + when !ODIN_BEDROCK { + #force_no_inline _startup_runtime() + old_console_codepage = GetConsoleOutputCP() + SetConsoleOutputCP(UTF_8) + } intrinsics.__entry_point() - when !ODIN_BEDROCK { #force_no_inline _cleanup_runtime() } + when !ODIN_BEDROCK { + #force_no_inline _cleanup_runtime() + SetConsoleOutputCP(old_console_codepage) + } return 0 } } else when ODIN_NO_CRT { @(link_name="mainCRTStartup", linkage="strong", require) mainCRTStartup :: proc "system" () -> i32 { context = default_context() - when !ODIN_BEDROCK { #force_no_inline _startup_runtime() } + when !ODIN_BEDROCK { + #force_no_inline _startup_runtime() + old_console_codepage = GetConsoleOutputCP() + SetConsoleOutputCP(UTF_8) + } intrinsics.__entry_point() - when !ODIN_BEDROCK { #force_no_inline _cleanup_runtime() } + when !ODIN_BEDROCK { + #force_no_inline _cleanup_runtime() + SetConsoleOutputCP(old_console_codepage) + } return 0 } } else { @@ -54,10 +83,24 @@ when ODIN_BUILD_MODE == .Dynamic { main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 { args__ = argv[:argc] context = default_context() - when !ODIN_BEDROCK { #force_no_inline _startup_runtime() } + when !ODIN_BEDROCK { + #force_no_inline _startup_runtime() + old_console_codepage = GetConsoleOutputCP() + SetConsoleOutputCP(UTF_8) + } intrinsics.__entry_point() - when !ODIN_BEDROCK { #force_no_inline _cleanup_runtime() } + when !ODIN_BEDROCK { + #force_no_inline _cleanup_runtime() + SetConsoleOutputCP(old_console_codepage) + } return 0 } } +} + +foreign import kernel32 "system:Kernel32.lib" +@(default_calling_convention="system") +foreign kernel32 { + GetConsoleOutputCP :: proc() -> u32 --- + SetConsoleOutputCP :: proc(codepage: u32) -> b32 --- } \ No newline at end of file diff --git a/src/common.cpp b/src/common.cpp index 8338ec707..3b4557cde 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -65,6 +65,20 @@ template struct TypeIs64BitInteger { enum {value = false}; }; template <> struct TypeIs64BitInteger { enum {value = true}; }; template <> struct TypeIs64BitInteger { enum {value = true}; }; +#if defined(GB_SYSTEM_WINDOWS) +uint32_t old_console_codepage = 0; +void set_utf8_codepage() { + old_console_codepage = GetConsoleOutputCP(); +} + +void restore_old_codepage() { + // Nothing we can do if this fails, so we're not asserting or anything. + SetConsoleOutputCP(old_console_codepage); +} +#else +void set_utf8_codepage() {} +void restore_old_codepage() {} +#endif #include "unicode.cpp" diff --git a/src/main.cpp b/src/main.cpp index 74900587f..7d2f4d713 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3794,6 +3794,13 @@ int main(int arg_count, char const **arg_ptr) { defer (timings_destroy(&global_timings)); MAIN_TIME_SECTION("initialization"); + // NOTE(Jeroen): Set codepage to UTF-8 (Windows only) and restore on exit. + // Keep in mind this is for the compiler's own output only. + // Like error messages on lines containing unicode. + // Child processes will inherit the default codepage, + // and so must do their own codepage management if they want. + set_utf8_codepage(); + defer (restore_old_codepage()); init_string_interner(); init_global_error_collector();