diff --git a/src/IRPrinter.cpp b/src/IRPrinter.cpp index 65cfb54f7eff..85228772393e 100644 --- a/src/IRPrinter.cpp +++ b/src/IRPrinter.cpp @@ -554,11 +554,18 @@ bool supports_ansi(const std::ostream *os) { IRPrinter::IRPrinter(ostream &s) : stream(s) { s.setf(std::ios::fixed, std::ios::floatfield); - auto detect_color = [&](const std::ostream *terminal) { - std::string opt = get_env_variable("HL_COLORS"); - bool use_colors = !opt.empty() ? opt == "1" : supports_ansi(terminal); - + // Keep this color gate identical to the profiler report's in + // src/runtime/profiler_common.cpp: HL_COLORS, if set, is an explicit + // override (atoi() != 0); otherwise honor NO_COLOR in addition to + // detecting a color-capable terminal. + bool use_colors; + if (const char *opt = getenv("HL_COLORS")) { + use_colors = std::atoi(opt) != 0; + } else { + const char *no_color = getenv("NO_COLOR"); + use_colors = !(no_color && no_color[0]) && supports_ansi(terminal); + } if (use_colors) { ansi = true; // Simple palette using standard VGA colors. diff --git a/src/LLVM_Runtime_Linker.cpp b/src/LLVM_Runtime_Linker.cpp index dc612a15ddd7..2f90ec424f8c 100644 --- a/src/LLVM_Runtime_Linker.cpp +++ b/src/LLVM_Runtime_Linker.cpp @@ -826,7 +826,7 @@ void add_underscore_to_posix_call(llvm::CallInst *call, llvm::Function *fn, llvm * of mcjit, so we just rewrite uses of these functions to include an * underscore. */ void add_underscores_to_posix_calls_on_windows(llvm::Module *m) { - string posix_fns[] = {"vsnprintf", "open", "close", "write", "fileno"}; + string posix_fns[] = {"vsnprintf", "open", "close", "write", "fileno", "isatty"}; string *posix_fns_begin = posix_fns; string *posix_fns_end = posix_fns + sizeof(posix_fns) / sizeof(posix_fns[0]); diff --git a/src/runtime/profiler_common.cpp b/src/runtime/profiler_common.cpp index 2384c38f4aca..40e105f812e3 100644 --- a/src/runtime/profiler_common.cpp +++ b/src/runtime/profiler_common.cpp @@ -513,10 +513,24 @@ ALWAYS_INLINE bool counter_is_approximate(const halide_profiler_func_stats *fs, WEAK void halide_profiler_report_unlocked(void *user_context, halide_profiler_state *s) { StringStreamPrinter<1024> sstr(user_context); - bool support_colors = false; - const char *term = getenv("TERM"); - if (term && (strstr(term, "color") || strstr(term, "xterm"))) { - support_colors = true; + // Decide whether to emit ANSI color escapes. HL_COLORS, if set, is an + // explicit override matching IRPrinter: "0" forces colors off, anything + // else on. Otherwise honor NO_COLOR and auto-detect a color-capable + // terminal. Checking TERM alone isn't enough: CI and other redirected + // environments often set TERM=xterm-256color while stdout is a pipe or + // file, which would splatter escape codes into the captured log. The + // report is printed via halide_print, whose default writes to stdout. + bool support_colors; + const char *hl_colors = getenv("HL_COLORS"); + if (hl_colors) { + support_colors = atoi(hl_colors) != 0; + } else { + const char *no_color = getenv("NO_COLOR"); + const char *term = getenv("TERM"); + support_colors = + !(no_color && no_color[0]) && + term && (strstr(term, "color") || strstr(term, "xterm")) && + isatty(STDOUT_FILENO); } // Column-aligned rows are produced from `const char *` templates. A diff --git a/src/runtime/runtime_internal.h b/src/runtime/runtime_internal.h index fdf951c7dc87..11c63c94b274 100644 --- a/src/runtime/runtime_internal.h +++ b/src/runtime/runtime_internal.h @@ -121,6 +121,7 @@ int fclose(void *); int close(int); size_t fwrite(const void *, size_t, size_t, void *); ssize_t write(int fd, const void *buf, size_t bytes); +int isatty(int fd); int remove(const char *pathname); int ioctl(int fd, unsigned long request, ...); char *strncpy(char *dst, const char *src, size_t n);