From 9020fc2ffea145ed1469d73fb8d363e74b595d4a Mon Sep 17 00:00:00 2001 From: Catherine Date: Wed, 5 Aug 2026 15:15:16 +0000 Subject: [PATCH] Accept UTF-8 filenames and terminal I/O on Windows. --- CMakeLists.txt | 2 +- kernel/driver.cc | 24 ++++++++++++++++++++++++ kernel/io.cc | 17 ++++++++++------- kernel/yosys.cc | 22 ++++++++++------------ 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bccf29049..3771394b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -426,7 +426,7 @@ if (NOT YOSYS_BUILD_PYTHON_ONLY) yosys_link_components(yosys PRIVATE ${driver_components}) set_property(TARGET yosys PROPERTY ENABLE_EXPORTS ON) if (MINGW) - target_link_options(yosys PRIVATE LINKER:--export-all-symbols) + target_link_options(yosys PRIVATE -municode LINKER:--export-all-symbols) set_target_properties(yosys PROPERTIES # Final name: `yosys.exe.a` (linked to explicitly) IMPORT_PREFIX "" diff --git a/kernel/driver.cc b/kernel/driver.cc index 2a4ad1295..c67630f10 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -48,6 +48,7 @@ namespace py = pybind11; #include #include #include +#include #ifndef __STDC_FORMAT_MACROS # define __STDC_FORMAT_MACROS #endif @@ -112,8 +113,31 @@ namespace Yosys { }; #endif +#ifdef _WIN32 +int wmain(int argc, wchar_t **wargv) +{ + // Configure ASCII functions like fopen() to use UTF-8 filenames. + // See https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?view=msvc-170#utf-8-support +#ifdef _UCRT + setlocale(LC_ALL, ".UTF-8"); +#endif + // Configure the Win32 console to use UTF-8. + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + + std::vector uargs; + for (int i = 0; i < argc; i++) { + int usize = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, NULL); + char *uarg = (char *)malloc(usize); + WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, uarg, usize, NULL, NULL); + uargs.push_back(uarg); + } + uargs.push_back(NULL); + char **argv = uargs.data(); +#else int main(int argc, char **argv) { +#endif auto wall_clock_start = std::chrono::steady_clock::now(); std::string frontend_command = "auto"; std::string backend_command = "auto"; diff --git a/kernel/io.cc b/kernel/io.cc index a82f88a62..1d0566930 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -155,13 +155,16 @@ std::string get_base_tmpdir() } #if defined(_WIN32) - char longpath[MAX_PATH + 1]; - char shortpath[MAX_PATH + 1]; - if (!GetTempPathA(MAX_PATH+1, longpath)) - log_error("GetTempPath() failed.\n"); - if (!GetShortPathNameA(longpath, shortpath, MAX_PATH + 1)) - log_error("GetShortPathName() failed.\n"); - tmpdir += shortpath; + std::wstring wtmppath(4096, L'\0'); + // typically returns a 8.3 path, but this can be disabled via registry + if (!GetTempPathW(wtmppath.size(), wtmppath.data())) + log_error("GetTempPathW() failed.\n"); + wtmppath.resize(wtmppath.find(L'\0')); + std::string utmppath; + utmppath.resize(WideCharToMultiByte(CP_UTF8, 0, wtmppath.data(), wtmppath.size(), NULL, 0, NULL, NULL)); + if (WideCharToMultiByte(CP_UTF8, 0, wtmppath.data(), wtmppath.size(), utmppath.data(), utmppath.size(), NULL, NULL) == 0) + log_error("WideCharToMultiByte() failed.\n"); + tmpdir += utmppath; #else char * var = std::getenv("TMPDIR"); if (var && strlen(var)!=0) { diff --git a/kernel/yosys.cc b/kernel/yosys.cc index d47610800..c2574497d 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -537,18 +537,16 @@ std::string proc_self_dirname() #elif defined(_WIN32) std::string proc_self_dirname() { - int i = 0; - char longpath[MAX_PATH + 1]; - char shortpath[MAX_PATH + 1]; - if (!GetModuleFileNameA(0, longpath, MAX_PATH+1)) - log_error("GetModuleFileName() failed.\n"); - if (!GetShortPathNameA(longpath, shortpath, MAX_PATH+1)) - log_error("GetShortPathName() failed.\n"); - while (shortpath[i] != 0) - i++; - while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\') - shortpath[--i] = 0; - return shortpath; + std::wstring wbinpath(4096, L'\0'); + if (!GetModuleFileNameW(0, &wbinpath[0], wbinpath.size())) + fprintf(stderr, "GetModuleFileNameW() failed.\n"); + wbinpath.resize(wbinpath.rfind(L'\\') + 1); // remove filename + std::string ubinpath; + ubinpath.resize(WideCharToMultiByte(CP_UTF8, 0, wbinpath.data(), wbinpath.size(), NULL, 0, NULL, NULL)); + if (WideCharToMultiByte(CP_UTF8, 0, wbinpath.data(), wbinpath.size(), &ubinpath[0], ubinpath.size(), NULL, NULL) == 0) + fprintf(stderr, "WideCharToMultiByte() failed.\n"); + return ubinpath; + } #elif defined(__wasm) std::string proc_self_dirname()