|
40 | 40 | #include <vix/cli/util/Strings.hpp> |
41 | 41 | #include <vix/cli/util/Ui.hpp> |
42 | 42 |
|
| 43 | +#include <vix/cli/commands/run/detail/ScriptProbe.hpp> |
| 44 | +#include <vix/cli/commands/run/detail/DirectScriptRunner.hpp> |
| 45 | +#include <vix/cli/commands/run/detail/ScriptCMake.hpp> |
| 46 | +#include <vix/cli/commands/run/RunDetail.hpp> |
| 47 | + |
43 | 48 | namespace fs = std::filesystem; |
44 | 49 | using namespace vix::cli::style; |
45 | 50 | namespace process = vix::cli::process; |
46 | 51 | namespace util = vix::cli::util; |
47 | 52 | namespace build = vix::cli::build; |
48 | 53 | namespace artifact_cache = vix::cli::cache; |
| 54 | +namespace run_detail = vix::commands::RunCommand::detail; |
49 | 55 |
|
50 | 56 | namespace vix::commands::BuildCommand |
51 | 57 | { |
@@ -329,6 +335,31 @@ namespace vix::commands::BuildCommand |
329 | 335 | { |
330 | 336 | o.withMySql = true; |
331 | 337 | } |
| 338 | + else if (!a.empty() && a[0] != '-') |
| 339 | + { |
| 340 | + if (o.singleCpp) |
| 341 | + { |
| 342 | + error("Only one single C++ source file can be passed to vix build."); |
| 343 | + exitCode = 2; |
| 344 | + return o; |
| 345 | + } |
| 346 | + |
| 347 | + fs::path candidate = fs::path(a); |
| 348 | + if (candidate.extension() == ".cpp" || |
| 349 | + candidate.extension() == ".cc" || |
| 350 | + candidate.extension() == ".cxx") |
| 351 | + { |
| 352 | + o.singleCpp = true; |
| 353 | + o.cppFile = fs::absolute(candidate); |
| 354 | + } |
| 355 | + else |
| 356 | + { |
| 357 | + error("Unknown positional argument: " + a); |
| 358 | + hint("For single-file mode, pass a .cpp file."); |
| 359 | + exitCode = 2; |
| 360 | + return o; |
| 361 | + } |
| 362 | + } |
332 | 363 | else if (a.rfind("--preset=", 0) == 0) |
333 | 364 | { |
334 | 365 | o.preset = a.substr(std::string("--preset=").size()); |
@@ -1072,6 +1103,9 @@ namespace vix::commands::BuildCommand |
1072 | 1103 | { |
1073 | 1104 | const fs::path cwd = fs::current_path(); |
1074 | 1105 |
|
| 1106 | + if (opt_.singleCpp) |
| 1107 | + return run_single_cpp_build(); |
| 1108 | + |
1075 | 1109 | const auto planOpt = make_plan(opt_, cwd); |
1076 | 1110 | if (!planOpt) |
1077 | 1111 | { |
@@ -1432,6 +1466,9 @@ namespace vix::commands::BuildCommand |
1432 | 1466 | return 0; |
1433 | 1467 | } |
1434 | 1468 |
|
| 1469 | + private: |
| 1470 | + int run_single_cpp_build(); |
| 1471 | + |
1435 | 1472 | private: |
1436 | 1473 | process::Options opt_; |
1437 | 1474 | process::Plan plan_{}; |
@@ -1467,6 +1504,76 @@ namespace vix::commands::BuildCommand |
1467 | 1504 | return cmd.run(); |
1468 | 1505 | } |
1469 | 1506 |
|
| 1507 | + int BuildCommand::run_single_cpp_build() |
| 1508 | + { |
| 1509 | + if (opt_.cppFile.empty()) |
| 1510 | + { |
| 1511 | + error("No C++ source file provided."); |
| 1512 | + return 1; |
| 1513 | + } |
| 1514 | + |
| 1515 | + if (!fs::exists(opt_.cppFile)) |
| 1516 | + { |
| 1517 | + error("Source file not found: " + opt_.cppFile.string()); |
| 1518 | + return 1; |
| 1519 | + } |
| 1520 | + |
| 1521 | + if (!opt_.exportBin && opt_.outPath.empty()) |
| 1522 | + { |
| 1523 | + error("Single-file build requires --bin or --out <path>."); |
| 1524 | + hint("Example: vix build main.cpp --out app.exe"); |
| 1525 | + return 2; |
| 1526 | + } |
| 1527 | + |
| 1528 | + run_detail::Options runOpt{}; |
| 1529 | + runOpt.singleCpp = true; |
| 1530 | + runOpt.cppFile = fs::absolute(opt_.cppFile); |
| 1531 | + |
| 1532 | + runOpt.preset = opt_.preset; |
| 1533 | + runOpt.dir = opt_.dir; |
| 1534 | + runOpt.jobs = opt_.jobs; |
| 1535 | + runOpt.clean = opt_.clean; |
| 1536 | + |
| 1537 | + runOpt.quiet = opt_.quiet; |
| 1538 | + runOpt.verbose = opt_.verbose; |
| 1539 | + |
| 1540 | + runOpt.withSqlite = opt_.withSqlite; |
| 1541 | + runOpt.withMySql = opt_.withMySql; |
| 1542 | + |
| 1543 | + runOpt.enableSanitizers = false; |
| 1544 | + runOpt.enableUbsanOnly = false; |
| 1545 | + |
| 1546 | + runOpt.forceServerLike = false; |
| 1547 | + runOpt.forceScriptLike = true; |
| 1548 | + |
| 1549 | + runOpt.watch = false; |
| 1550 | + runOpt.timeoutSec = 0; |
| 1551 | + runOpt.cwd.clear(); |
| 1552 | + |
| 1553 | + runOpt.runArgs.clear(); |
| 1554 | + runOpt.runEnv.clear(); |
| 1555 | + runOpt.scriptFlags = opt_.cmakeArgs; |
| 1556 | + |
| 1557 | + fs::path exePath; |
| 1558 | + const int code = run_detail::build_script_executable(runOpt, exePath); |
| 1559 | + if (code != 0) |
| 1560 | + return code; |
| 1561 | + |
| 1562 | + if (exePath.empty() || !fs::exists(exePath)) |
| 1563 | + { |
| 1564 | + error("Built executable was not produced."); |
| 1565 | + return 1; |
| 1566 | + } |
| 1567 | + |
| 1568 | + fs::path dest; |
| 1569 | + if (opt_.exportBin) |
| 1570 | + dest = fs::current_path() / exePath.filename(); |
| 1571 | + else |
| 1572 | + dest = fs::absolute(fs::path(opt_.outPath)); |
| 1573 | + |
| 1574 | + return export_built_binary(exePath, dest, opt_.quiet) ? 0 : 1; |
| 1575 | + } |
| 1576 | + |
1470 | 1577 | int help() |
1471 | 1578 | { |
1472 | 1579 | std::ostream &out = std::cout; |
|
0 commit comments