From d754dfd6fcbe37b37aaaebf3f76b058598457dd9 Mon Sep 17 00:00:00 2001 From: Raffaele <74499579+Helldez@users.noreply.github.com> Date: Sat, 29 Aug 2026 09:01:00 +0200 Subject: [PATCH] fix(cli): make the Windows release exe survive a double click (#183) A console program started from Explorer gets a console of its own, prints its usage because no model was given, exits, and the console vanishes with it: a window that flashes and disappears, indistinguishable from a crash. - cli: when the console was created for this process alone, the no-model path says it is a command-line program and waits for Enter before closing. From a terminal nothing changes. - release-host: the archive README.txt opens with that fact and a complete command, and no longer points a Windows user at a bash script as the only instruction. The Windows build links the MSVC runtime statically so the exe does not depend on the VC++ Redistributable. - 0.23.0: version bump and changelog entry. --- .github/workflows/release-host.yml | 23 +++++++++++++++++++---- CHANGELOG.md | 13 ++++++++++++- CMakeLists.txt | 2 +- cli/main.cpp | 24 ++++++++++++++++++++++++ examples/android/app/build.gradle | 4 ++-- 5 files changed, 58 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release-host.yml b/.github/workflows/release-host.yml index a7b9086..2951eff 100644 --- a/.github/workflows/release-host.yml +++ b/.github/workflows/release-host.yml @@ -45,7 +45,8 @@ jobs: cmake_extra: "" - os: windows-latest target: windows-x86_64 - cmake_extra: -DGGML_AVX2=ON -DGGML_FMA=ON -DGGML_F16C=ON + # Static MSVC runtime: the exe must not depend on the VC++ Redistributable being installed. + cmake_extra: -DGGML_AVX2=ON -DGGML_FMA=ON -DGGML_F16C=ON -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded runs-on: ${{ matrix.os }} steps: - name: Resolve tag @@ -101,12 +102,26 @@ jobs: strip "$NAME/bmoe-cli" || true fi cp LICENSE "$NAME/" + if [ "${{ runner.os }}" = "Windows" ]; then + EXE='.\bmoe-cli.exe'; SHELL_NAME='PowerShell or cmd' + else + EXE='./bmoe-cli'; SHELL_NAME='a terminal' + fi cat > "$NAME/README.txt" < #include +#if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include +#endif + using namespace bmoe; static int env_int(const char * k, int dflt) { @@ -353,6 +358,18 @@ static int run_session_loop(const RunConfig & cfg, return rc; } +// True when Explorer (a double click) created this console for us alone, so it will vanish the +// instant we return and nothing we printed gets read. A terminal the user already had open also +// holds the console and stays; the process count tells the two apart. +static bool console_is_ours_alone() { +#if defined(_WIN32) + DWORD pid; + return GetConsoleProcessList(&pid, 1) == 1; +#else + return false; +#endif +} + static void print_usage(const char * argv0) { std::printf( "usage: %s -m [options]\n" @@ -709,6 +726,13 @@ int main(int argc, char ** argv) { if (cfg.model_path.empty()) { print_usage(argv[0]); + // Double-clicked: without this the window closes before the usage can be read, and the + // program looks like it failed to start. + if (console_is_ours_alone()) { + std::fprintf(stderr, "\nbmoe-cli is a command-line program: run it from a terminal with -m .\n" + "Press Enter to close this window.\n"); + std::getchar(); + } return 1; } diff --git a/examples/android/app/build.gradle b/examples/android/app/build.gradle index 924db86..e386ce5 100644 --- a/examples/android/app/build.gradle +++ b/examples/android/app/build.gradle @@ -51,8 +51,8 @@ android { applicationId 'io.bigmoeonedge.example' minSdk 29 targetSdk 34 - versionCode 37 - versionName '0.22.0' + versionCode 38 + versionName '0.23.0' buildConfigField 'String', 'GIT_SHA', "\"${gitSha}\"" ndk { // The engine ships as prebuilt arm64 binaries staged by build-android.ps1.