Skip to content

Commit 2f1bc1c

Browse files
committed
fix(main): move the stdout buffering call into mcpp.ui
`module;` opens a global module fragment, which is only legal in a module unit. main.cpp is not one, so the fragment introduced for <cstdio> made it ill-formed: GCC accepted it silently, Clang rejected it outright ("missing 'module' declaration at end of global module fragment") and every macOS job — where the toolchain is Clang — failed to build. The policy belongs in mcpp.ui anyway: that module already owns "when does output become visible", already has a legitimate global module fragment for <cstdio>, and already exports flush() for the Windows half of the same guarantee. Verified by building mcpp with llvm@22.1.8 locally, not just gcc — the class of bug this was is invisible to a single-compiler check.
1 parent e7771b9 commit 2f1bc1c

2 files changed

Lines changed: 13 additions & 4 deletions

File tree

src/main.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
// mcpp — Modular C++ Package Manager & Build Tool
22
// Entry point — delegates to mcpp.cli command dispatch.
33

4-
module;
5-
#include <cstdio> // setvbuf, stdout, _IOLBF
6-
74
import std;
85
import mcpp.cli;
6+
import mcpp.ui;
97

108
int main(int argc, char* argv[]) {
119
// Line-buffer stdout even when it is not a TTY.
@@ -21,9 +19,11 @@ int main(int argc, char* argv[]) {
2119
// mcpp's. When that run was then killed by the job timeout, the whole buffer
2220
// went with it — a 45-minute step with no attributable output at all.
2321
//
22+
// Lives in mcpp.ui because a non-module TU may not open a global module
23+
// fragment for <cstdio> (Clang rejects `module;` here; GCC accepted it).
2424
// ui::flush() covers the same ground for the ui layer on Windows, where
2525
// MSVCRT silently treats _IOLBF as _IOFBF.
26-
std::setvbuf(stdout, nullptr, _IOLBF, 0);
26+
mcpp::ui::set_line_buffered();
2727

2828
int rc;
2929
try {

src/ui.cppm

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ void plain(std::string_view message);
8181
// when its last lines matter most.
8282
void flush();
8383

84+
// Make stdout line-buffered. Call once, before any output. See main() for why
85+
// this is not left to the libc default: the default block size is a different
86+
// number on every platform (musl 1024, Apple libc st_blksize = 65536 on a pipe,
87+
// MSVCRT 4096), so identical output becomes visible at wildly different times —
88+
// and not at all if the process is killed before its buffer fills.
89+
void set_line_buffered();
90+
8491
// --- progress bar (single-line, \r-rewritten) ---
8592
class ProgressBar {
8693
public:
@@ -237,6 +244,8 @@ bool is_quiet() { return g_quiet; }
237244

238245
void flush() { std::fflush(stdout); }
239246

247+
void set_line_buffered() { std::setvbuf(stdout, nullptr, _IOLBF, 0); }
248+
240249
void status(std::string_view verb, std::string_view message) {
241250
if (g_quiet) return;
242251
init();

0 commit comments

Comments
 (0)