Skip to content

Commit 07fc6ca

Browse files
committed
feat(cli): add explicit sanitizer build variants
2 parents ba91277 + c2428b7 commit 07fc6ca

22 files changed

Lines changed: 4362 additions & 1064 deletions

include/vix/cli/commands/run/RunDetail.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ namespace vix::commands::RunCommand::detail
134134
bool enableSanitizers = false; // ASan + UBSan
135135
bool enableUbsanOnly = false; // UBSan only
136136
bool enableThreadSanitizer = false; // TSan only
137+
bool sanitizerSelectionExplicit = false;
137138

138139
bool withSqlite = false;
139140
bool withMySql = false;

include/vix/cli/process/Process.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@
2222
#include <vix/engine/BuildTools.hpp>
2323
#include <vix/engine/ExecutionPlan.hpp>
2424
#include <vix/engine/Preset.hpp>
25+
#include <vix/engine/SanitizerMode.hpp>
2526

2627
namespace vix::cli::process
2728
{
2829
namespace fs = std::filesystem;
2930

3031
using LinkerMode = vix::engine::LinkerMode;
3132
using LauncherMode = vix::engine::LauncherMode;
33+
using SanitizerMode = vix::engine::SanitizerMode;
3234

3335
/**
3436
* @brief Parsed options for the `vix build` command.
@@ -147,6 +149,18 @@ namespace vix::cli::process
147149
*/
148150
std::vector<std::string> cmakeArgs;
149151

152+
/**
153+
* @brief Sanitizer instrumentation selected for this build.
154+
*
155+
* The default build remains uninstrumented.
156+
*/
157+
SanitizerMode sanitizerMode = SanitizerMode::None;
158+
159+
/**
160+
* @brief True when the sanitizer mode was explicitly selected.
161+
*/
162+
bool sanitizerSelectionExplicit = false;
163+
150164
bool withSqlite = false;
151165
bool withMySql = false;
152166

src/ErrorHandler.cpp

Lines changed: 63 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@
2626
#include <sstream>
2727
#include <string>
2828
#include <string_view>
29-
#include <unordered_map>
3029
#include <unordered_set>
3130
#include <vector>
32-
#include <fstream>
3331
#include <cstdlib>
3432
#include <cctype>
3533

@@ -54,51 +52,6 @@ namespace
5452
<< "\n";
5553
}
5654

57-
std::vector<std::string> read_code_frame_lines(
58-
const fs::path &file,
59-
std::size_t line,
60-
std::size_t contextLines,
61-
std::size_t maxLineWidth)
62-
{
63-
std::vector<std::string> out;
64-
65-
if (file.empty() || line == 0)
66-
return out;
67-
68-
std::ifstream in(file);
69-
if (!in)
70-
return out;
71-
72-
const std::size_t startLine =
73-
line > contextLines ? line - contextLines : 1;
74-
75-
const std::size_t endLine = line + contextLines;
76-
77-
std::string current;
78-
std::size_t currentLine = 0;
79-
80-
while (std::getline(in, current))
81-
{
82-
++currentLine;
83-
84-
if (currentLine < startLine)
85-
continue;
86-
87-
if (currentLine > endLine)
88-
break;
89-
90-
if (maxLineWidth > 0 && current.size() > maxLineWidth)
91-
{
92-
current = current.substr(0, maxLineWidth);
93-
current += "...";
94-
}
95-
96-
out.push_back(current);
97-
}
98-
99-
return out;
100-
}
101-
10255
std::string hint_for_compiler_error(
10356
const vix::cli::errors::CompilerError &err)
10457
{
@@ -126,9 +79,10 @@ namespace
12679
return "Declare the symbol before use, include the right header, or check the namespace.";
12780
}
12881

129-
if (message.find("was not declared in this scope") != std::string::npos)
82+
if (message.find("has not been declared") != std::string::npos ||
83+
message.find("was not declared in this scope") != std::string::npos)
13084
{
131-
return "Declare the symbol before use, include the right header, or move the function definition above the call.";
85+
return "Include the header that declares this name or check its namespace.";
13286
}
13387

13488
if (message.find("does not name a type") != std::string::npos)
@@ -171,37 +125,6 @@ namespace
171125
return {};
172126
}
173127

174-
vix::cli::build::BuildDiagnostic diagnostic_from_compiler_error(
175-
const vix::cli::errors::CompilerError &err,
176-
const std::string &contextMessage)
177-
{
178-
vix::cli::build::BuildDiagnostic diagnostic;
179-
180-
diagnostic.title =
181-
contextMessage.empty()
182-
? "Build failed"
183-
: contextMessage;
184-
185-
diagnostic.error = err.message;
186-
diagnostic.hint = hint_for_compiler_error(err);
187-
188-
diagnostic.location.file = err.file;
189-
diagnostic.location.line =
190-
err.line > 0 ? static_cast<std::size_t>(err.line) : 0;
191-
diagnostic.location.column =
192-
err.column > 0 ? static_cast<std::size_t>(err.column) : 0;
193-
194-
diagnostic.codeFrame.location = diagnostic.location;
195-
diagnostic.codeFrame.lines =
196-
read_code_frame_lines(
197-
fs::path(err.file),
198-
diagnostic.location.line,
199-
2,
200-
120);
201-
202-
return diagnostic;
203-
}
204-
205128
bool handle_unrecognized_cli_option_as_script_runtime_args(
206129
std::string_view log)
207130
{
@@ -386,15 +309,6 @@ namespace vix::cli
386309
if (pipeline.tryHandle(errors, ctx))
387310
return true;
388311

389-
std::unordered_map<std::string, int> counts;
390-
counts.reserve(errors.size());
391-
392-
for (const auto &err : errors)
393-
{
394-
const std::string key = err.file + "|" + err.message;
395-
++counts[key];
396-
}
397-
398312
std::vector<CompilerError> unique;
399313
unique.reserve(errors.size());
400314

@@ -403,7 +317,14 @@ namespace vix::cli
403317

404318
for (const auto &err : errors)
405319
{
406-
const std::string key = err.file + "|" + err.message;
320+
const std::string key =
321+
err.file +
322+
"|" +
323+
std::to_string(err.line) +
324+
"|" +
325+
std::to_string(err.column) +
326+
"|" +
327+
err.message;
407328

408329
if (seen.insert(key).second)
409330
unique.push_back(err);
@@ -414,72 +335,81 @@ namespace vix::cli
414335
std::cerr << RED
415336
<< "error: "
416337
<< RESET
417-
<< contextMessage
338+
<< (contextMessage.empty()
339+
? "Build failed"
340+
: contextMessage)
418341
<< "\n";
419342

420-
print_hint("no unique compiler error was detected; inspect the raw compiler output");
421-
422-
if (!cleanedLog.empty())
423-
std::cerr << cleanedLog << "\n";
343+
print_hint(
344+
"no compiler error could be extracted; "
345+
"run with VIX_LOG_LEVEL=debug to inspect the full output");
424346

425347
return false;
426348
}
427349

428-
std::cerr << RED
429-
<< "error: "
430-
<< RESET
431-
<< contextMessage
432-
<< "\n";
350+
/*
351+
* Show the first compiler error by default.
352+
*
353+
* Compiler errors frequently cascade: once the parser cannot
354+
* understand one declaration, it may report several secondary
355+
* errors. Showing the first error keeps the output focused for
356+
* beginners.
357+
*/
358+
const std::size_t maxToShow = 1;
433359

434360
CodeFrameOptions codeFrameOptions;
435-
codeFrameOptions.contextLines = 2;
361+
codeFrameOptions.contextLines = 1;
436362
codeFrameOptions.maxLineWidth = 120;
437363
codeFrameOptions.tabWidth = 4;
364+
codeFrameOptions.leadingBlankLine = true;
438365

439-
const std::size_t maxToShow =
440-
std::min<std::size_t>(unique.size(), 3);
441-
442-
for (std::size_t i = 0; i < maxToShow; ++i)
366+
for (std::size_t i = 0;
367+
i < unique.size() && i < maxToShow;
368+
++i)
443369
{
444-
const auto &err = unique[i];
445-
446-
const vix::cli::build::BuildDiagnostic diagnostic =
447-
::diagnostic_from_compiler_error(
448-
err,
449-
contextMessage);
450-
451-
vix::cli::build::print_build_diagnostic(
452-
std::cerr,
453-
diagnostic);
370+
const CompilerError &err = unique[i];
454371

455-
const std::string key = err.file + "|" + err.message;
456-
const auto it = counts.find(key);
372+
std::cerr << RED
373+
<< "error: "
374+
<< RESET
375+
<< err.message
376+
<< "\n";
457377

458-
if (it != counts.end() && it->second > 1)
459-
{
460-
vix::cli::build::print_build_warning(
461-
std::cerr,
462-
std::to_string(it->second - 1) + " similar error(s) hidden");
463-
}
378+
/*
379+
* Use the shared codeframe contract directly.
380+
*
381+
* This avoids creating a second list of source lines with
382+
* incorrect line-number assumptions.
383+
*/
384+
printCodeFrame(
385+
err,
386+
ctx,
387+
codeFrameOptions);
388+
389+
const std::string hint =
390+
hint_for_compiler_error(err);
391+
392+
if (!hint.empty())
393+
print_hint(hint);
464394
}
465395

466-
if (unique.size() > maxToShow)
396+
const std::size_t hiddenCount =
397+
unique.size() > maxToShow
398+
? unique.size() - maxToShow
399+
: 0;
400+
401+
if (hiddenCount > 0)
467402
{
468403
std::cerr << "\n"
469404
<< GRAY
470-
<< (unique.size() - maxToShow)
471-
<< " more distinct error(s) hidden. Run with --verbose for full output."
405+
<< hiddenCount
406+
<< " more compiler error"
407+
<< (hiddenCount == 1 ? "" : "s")
408+
<< " hidden. Run with --verbose to see them."
472409
<< RESET
473410
<< "\n";
474411
}
475412

476-
if (!sourceFile.empty())
477-
{
478-
vix::cli::build::print_build_info(
479-
std::cerr,
480-
"at: " + sourceFile.string());
481-
}
482-
483413
return true;
484414
}
485415
} // namespace vix::cli

0 commit comments

Comments
 (0)