@@ -186,34 +186,89 @@ namespace vix::cli::errors::build
186186 return message;
187187 }
188188
189- // Returns the single most informative line from the first CMake Error block.
190- // Prefers the content after the first colon on the opening "CMake Error" line;
191- // falls back to the entire block if the opening line is content-free.
192189 std::string first_cmake_error_message (std::string_view log)
193190 {
194191 const std::size_t pos = log.find (" CMake Error" );
195192 if (pos == std::string_view::npos)
196193 return {};
197194
198195 const std::size_t lineEnd = log.find (' \n ' , pos);
196+
199197 const std::string firstLine =
200198 (lineEnd == std::string_view::npos)
201199 ? std::string (log.substr (pos))
202200 : std::string (log.substr (pos, lineEnd - pos));
203201
204- // Try to get the message that follows the first colon on the error line.
205- const std::size_t colon = firstLine.find (' :' );
206- if (colon != std::string::npos && colon + 1 < firstLine.size ())
202+ // CMake form:
203+ // CMake Error at CMakeLists.txt:135 (message):
204+ //
205+ // Do not split at the first ':' because that belongs to file:line.
206+ // Only use same-line text after the final "):" when it exists.
207+ const std::size_t commandEnd = firstLine.find (" ):" );
208+ if (commandEnd != std::string::npos)
207209 {
208- std::string sameLine = trim_copy (firstLine.substr (colon + 1 ));
210+ const std::string sameLine =
211+ trim_copy (firstLine.substr (commandEnd + 2 ));
212+
209213 if (!sameLine.empty () && !is_cmake_noise_line (sameLine))
210214 return sameLine;
211215 }
212216
213- // Fall back: collect a multi-line block, skipping noise.
217+ // CMake form:
218+ // CMake Error: some message
219+ //
220+ // This one has no file:line prefix, so splitting after "CMake Error:"
221+ // is safe.
222+ constexpr std::string_view directPrefix = " CMake Error:" ;
223+ if (starts_with (firstLine, directPrefix))
224+ {
225+ const std::string sameLine =
226+ trim_copy (firstLine.substr (directPrefix.size ()));
227+
228+ if (!sameLine.empty () && !is_cmake_noise_line (sameLine))
229+ return sameLine;
230+ }
231+
232+ if (lineEnd == std::string_view::npos)
233+ return first_cmake_error_block (log);
234+
235+ std::istringstream stream{
236+ std::string (log.substr (lineEnd + 1 ))};
237+
238+ std::string message;
239+ std::string line;
240+
241+ while (std::getline (stream, line))
242+ {
243+ const std::string trimmed = trim_copy (line);
244+
245+ if (trimmed.empty ())
246+ continue ;
247+
248+ if (starts_with (trimmed, " CMake Error" ))
249+ break ;
250+
251+ if (is_cmake_noise_line (trimmed))
252+ break ;
253+
254+ if (starts_with (trimmed, " -- Configuring incomplete" ) ||
255+ starts_with (trimmed, " -- Configuring done" ) ||
256+ starts_with (trimmed, " -- Generating done" ))
257+ {
258+ break ;
259+ }
260+
261+ if (!message.empty ())
262+ message += ' \n ' ;
263+
264+ message += trimmed;
265+ }
266+
267+ if (!message.empty ())
268+ return message;
269+
214270 return first_cmake_error_block (log);
215271 }
216-
217272 // -------------------------------------------------------------------------
218273 // Output helpers (preserve existing Vix CLI style)
219274 // -------------------------------------------------------------------------
@@ -244,7 +299,30 @@ namespace vix::cli::errors::build
244299 if (value.empty ())
245300 return ;
246301
247- std::cerr << PAD << label << value << " \n " ;
302+ const std::string text (value);
303+
304+ const std::size_t firstNewline = text.find (' \n ' );
305+
306+ if (firstNewline == std::string::npos)
307+ {
308+ std::cerr << PAD << label << text << " \n " ;
309+ return ;
310+ }
311+
312+ std::cerr << PAD << label << " \n " ;
313+
314+ std::istringstream in (text);
315+ std::string line;
316+
317+ while (std::getline (in, line))
318+ {
319+ const std::string trimmed = trim_copy (line);
320+
321+ if (trimmed.empty ())
322+ continue ;
323+
324+ std::cerr << PAD << " " << trimmed << " \n " ;
325+ }
248326 }
249327
250328 void print_colored_field (std::string_view label,
@@ -254,12 +332,38 @@ namespace vix::cli::errors::build
254332 if (value.empty ())
255333 return ;
256334
257- std::cerr << PAD
258- << label
259- << color
260- << value
261- << RESET
262- << " \n " ;
335+ const std::string text (value);
336+
337+ if (text.find (' \n ' ) == std::string::npos)
338+ {
339+ std::cerr << PAD
340+ << label
341+ << color
342+ << text
343+ << RESET
344+ << " \n " ;
345+ return ;
346+ }
347+
348+ std::cerr << PAD << label << " \n " ;
349+
350+ std::istringstream in (text);
351+ std::string line;
352+
353+ while (std::getline (in, line))
354+ {
355+ const std::string trimmed = trim_copy (line);
356+
357+ if (trimmed.empty ())
358+ continue ;
359+
360+ std::cerr << PAD
361+ << " "
362+ << color
363+ << trimmed
364+ << RESET
365+ << " \n " ;
366+ }
263367 }
264368
265369 // -------------------------------------------------------------------------
@@ -1569,7 +1673,7 @@ namespace vix::cli::errors::build
15691673 " reason: " ,
15701674 message.empty () ? " unclassified CMake error" : message);
15711675
1572- print_hint (" run vix build --verbose to inspect the full CMake output " );
1676+ print_hint (" check the CMake message above or inspect build-ninja/configure.log " );
15731677 return true ;
15741678 }
15751679
0 commit comments