diff --git a/src/Builder/BuildProfile.hpp b/src/Builder/BuildProfile.hpp index 59d89a255..d720bbd1d 100644 --- a/src/Builder/BuildProfile.hpp +++ b/src/Builder/BuildProfile.hpp @@ -15,6 +15,7 @@ class BuildProfile { enum Type : uint8_t { Dev, Release, + Test, }; private: @@ -56,6 +57,8 @@ struct fmt::formatter { return fmt::format_to(ctx.out(), "dev"); case cabin::BuildProfile::Release: return fmt::format_to(ctx.out(), "release"); + case cabin::BuildProfile::Test: + return fmt::format_to(ctx.out(), "test"); } __builtin_unreachable(); } else { diff --git a/src/Cmd/Test.cc b/src/Cmd/Test.cc index f356b2f94..110397098 100644 --- a/src/Cmd/Test.cc +++ b/src/Cmd/Test.cc @@ -25,19 +25,13 @@ namespace cabin { class Test { - struct TestArgs { - BuildProfile buildProfile = BuildProfile::Dev; - }; - - TestArgs args; Manifest manifest; std::string unittestTargetPrefix; std::vector unittestTargets; - Test(TestArgs args, Manifest manifest) - : args(std::move(args)), manifest(std::move(manifest)) {} + explicit Test(Manifest manifest) : manifest(std::move(manifest)) {} - static Result parseArgs(CliArgsView cliArgs); + static Result parseArgs(CliArgsView cliArgs); Result compileTestTargets(); Result runTestTargets(); @@ -49,25 +43,19 @@ const Subcmd TEST_CMD = // Subcmd{ "test" } .setShort("t") .setDesc("Run the tests of a local package") - .addOpt(OPT_RELEASE) .addOpt(OPT_JOBS) .setMainFn(Test::exec); -Result +Result Test::parseArgs(const CliArgsView cliArgs) { - TestArgs args; - for (auto itr = cliArgs.begin(); itr != cliArgs.end(); ++itr) { const std::string_view arg = *itr; const auto control = Try(Cli::handleGlobalOpts(itr, cliArgs.end(), "test")); if (control == Cli::Return) { - return Ok(args); + return Ok(); } else if (control == Cli::Continue) { continue; - } else if (arg == "-r" || arg == "--release") { - Diag::warn("Tests in release mode possibly disables assert macros."); - args.buildProfile = BuildProfile::Release; } else if (arg == "-j" || arg == "--jobs") { if (itr + 1 == cliArgs.end()) { return Subcmd::missingOptArgumentFor(arg); @@ -85,15 +73,16 @@ Test::parseArgs(const CliArgsView cliArgs) { } } - return Ok(args); + return Ok(); } Result Test::compileTestTargets() { const auto start = std::chrono::steady_clock::now(); + const BuildProfile buildProfile = BuildProfile::Test; const BuildConfig config = - Try(emitMakefile(manifest, args.buildProfile, /*includeDevDeps=*/true)); + Try(emitMakefile(manifest, buildProfile, /*includeDevDeps=*/true)); // Collect test targets from the generated Makefile. unittestTargetPrefix = (config.outBasePath / "unittests").string() + '/'; @@ -150,9 +139,9 @@ Test::compileTestTargets() { const auto end = std::chrono::steady_clock::now(); const std::chrono::duration elapsed = end - start; - const Profile& profile = manifest.profiles.at(args.buildProfile); + const Profile& profile = manifest.profiles.at(buildProfile); Diag::info( - "Finished", "`{}` profile [{}] target(s) in {:.2f}s", args.buildProfile, + "Finished", "`{}` profile [{}] target(s) in {:.2f}s", buildProfile, profile, elapsed.count() ); @@ -206,9 +195,9 @@ Test::runTestTargets() { Result Test::exec(const CliArgsView cliArgs) { - const TestArgs args = Try(parseArgs(cliArgs)); + Try(parseArgs(cliArgs)); Manifest manifest = Try(Manifest::tryParse()); - Test cmd(args, std::move(manifest)); + Test cmd(std::move(manifest)); Try(cmd.compileTestTargets()); if (cmd.unittestTargets.empty()) { diff --git a/src/Manifest.cc b/src/Manifest.cc index 00738c47d..6c93eff61 100644 --- a/src/Manifest.cc +++ b/src/Manifest.cc @@ -154,32 +154,33 @@ static Result parseDevProfile( const toml::value& val, const BaseProfile& baseProfile ) noexcept { - auto devCxxflags = Try(validateFlags( + static constexpr const char* key = "dev"; + + auto cxxflags = Try(validateFlags( "cxxflags", toml::find_or>( - val, "profile", "dev", "cxxflags", baseProfile.cxxflags + val, "profile", key, "cxxflags", baseProfile.cxxflags ) )); - auto devLdflags = Try(validateFlags( + auto ldflags = Try(validateFlags( "ldflags", toml::find_or>( - val, "profile", "dev", "ldflags", baseProfile.ldflags + val, "profile", key, "ldflags", baseProfile.ldflags ) )); - const auto devLto = - toml::find_or(val, "profile", "dev", "lto", baseProfile.lto); - const auto devDebug = toml::find_or( - val, "profile", "dev", "debug", baseProfile.debug.unwrap_or(true) - ); - const auto devCompDb = - toml::find_or(val, "profile", "dev", "compdb", baseProfile.compDb); - const auto devOptLevel = Try(validateOptLevel( + const auto lto = + toml::find_or(val, "profile", key, "lto", baseProfile.lto); + const auto debug = toml::find_or( + val, "profile", key, "debug", baseProfile.debug.unwrap_or(true) + ); + const auto compDb = + toml::find_or(val, "profile", key, "compdb", baseProfile.compDb); + const auto optLevel = Try(validateOptLevel( toml::find_or( - val, "profile", "dev", "opt-level", baseProfile.optLevel.unwrap_or(0) + val, "profile", key, "opt-level", baseProfile.optLevel.unwrap_or(0) ) )); return Ok(Profile( - std::move(devCxxflags), std::move(devLdflags), devLto, devDebug, - devCompDb, devOptLevel + std::move(cxxflags), std::move(ldflags), lto, debug, compDb, optLevel )); } @@ -187,35 +188,65 @@ static Result parseReleaseProfile( const toml::value& val, const BaseProfile& baseProfile ) noexcept { - auto relCxxflags = Try(validateFlags( - "cxxflags", - toml::find_or>( - val, "profile", "release", "cxxflags", baseProfile.cxxflags + static constexpr const char* key = "release"; + + auto cxxflags = Try(validateFlags( + "cxxflags", toml::find_or>( + val, "profile", key, "cxxflags", baseProfile.cxxflags + ) + )); + auto ldflags = Try(validateFlags( + "ldflags", toml::find_or>( + val, "profile", key, "ldflags", baseProfile.ldflags + ) + )); + const auto lto = + toml::find_or(val, "profile", key, "lto", baseProfile.lto); + const auto debug = toml::find_or( + val, "profile", key, "debug", baseProfile.debug.unwrap_or(false) + ); + const auto compDb = + toml::find_or(val, "profile", key, "compdb", baseProfile.compDb); + const auto optLevel = Try(validateOptLevel( + toml::find_or( + val, "profile", key, "opt-level", baseProfile.optLevel.unwrap_or(3) ) )); - auto relLdflags = Try(validateFlags( + + return Ok(Profile( + std::move(cxxflags), std::move(ldflags), lto, debug, compDb, optLevel + )); +} + +// Inherits from `dev`. +static Result +parseTestProfile(const toml::value& val, const Profile& devProfile) noexcept { + static constexpr const char* key = "test"; + + auto cxxflags = Try(validateFlags( + "cxxflags", toml::find_or>( + val, "profile", key, "cxxflags", devProfile.cxxflags + ) + )); + auto ldflags = Try(validateFlags( "ldflags", toml::find_or>( - val, "profile", "release", "ldflags", baseProfile.ldflags + val, "profile", key, "ldflags", devProfile.ldflags ) )); - const auto relLto = - toml::find_or(val, "profile", "release", "lto", baseProfile.lto); - const auto relDebug = toml::find_or( - val, "profile", "release", "debug", baseProfile.debug.unwrap_or(false) - ); - const auto relCompDb = toml::find_or( - val, "profile", "release", "compdb", baseProfile.compDb - ); - const auto relOptLevel = Try(validateOptLevel( + const auto lto = + toml::find_or(val, "profile", key, "lto", devProfile.lto); + const auto debug = + toml::find_or(val, "profile", key, "debug", devProfile.debug); + const auto compDb = + toml::find_or(val, "profile", key, "compdb", devProfile.compDb); + const auto optLevel = Try(validateOptLevel( toml::find_or( - val, "profile", "release", "opt-level", - baseProfile.optLevel.unwrap_or(3) + val, "profile", key, "opt-level", devProfile.optLevel ) )); return Ok(Profile( - std::move(relCxxflags), std::move(relLdflags), relLto, relDebug, - relCompDb, relOptLevel + std::move(cxxflags), std::move(ldflags), lto, debug, compDb, optLevel )); } @@ -223,7 +254,9 @@ static Result> parseProfiles(const toml::value& val) noexcept { std::unordered_map profiles; const BaseProfile baseProfile = Try(parseBaseProfile(val)); - profiles.emplace(BuildProfile::Dev, Try(parseDevProfile(val, baseProfile))); + Profile devProfile = Try(parseDevProfile(val, baseProfile)); + profiles.emplace(BuildProfile::Test, Try(parseTestProfile(val, devProfile))); + profiles.emplace(BuildProfile::Dev, std::move(devProfile)); profiles.emplace( BuildProfile::Release, Try(parseReleaseProfile(val, baseProfile)) ); @@ -821,17 +854,19 @@ testParseProfiles() { const toml::value empty = ""_toml; const auto profiles = parseProfiles(empty).unwrap(); - assertEq(profiles.size(), 2UL); + assertEq(profiles.size(), 3UL); assertEq(profiles.at(BuildProfile::Dev), devProfileDefault); assertEq(profiles.at(BuildProfile::Release), relProfileDefault); + assertEq(profiles.at(BuildProfile::Test), devProfileDefault); } { const toml::value profOnly = "[profile]"_toml; const auto profiles = parseProfiles(profOnly).unwrap(); - assertEq(profiles.size(), 2UL); + assertEq(profiles.size(), 3UL); assertEq(profiles.at(BuildProfile::Dev), devProfileDefault); assertEq(profiles.at(BuildProfile::Release), relProfileDefault); + assertEq(profiles.at(BuildProfile::Test), devProfileDefault); } { const toml::value baseOnly = R"( @@ -851,9 +886,10 @@ testParseProfiles() { ); const auto profiles = parseProfiles(baseOnly).unwrap(); - assertEq(profiles.size(), 2UL); + assertEq(profiles.size(), 3UL); assertEq(profiles.at(BuildProfile::Dev), expected); assertEq(profiles.at(BuildProfile::Release), expected); + assertEq(profiles.at(BuildProfile::Test), expected); } { const toml::value overwrite = R"( @@ -868,9 +904,10 @@ testParseProfiles() { )"_toml; const auto profiles = parseProfiles(overwrite).unwrap(); - assertEq(profiles.size(), 2UL); + assertEq(profiles.size(), 3UL); assertEq(profiles.at(BuildProfile::Dev), devProfileDefault); assertEq(profiles.at(BuildProfile::Release), relProfileDefault); + assertEq(profiles.at(BuildProfile::Test), devProfileDefault); } { const toml::value overwrite = R"( @@ -879,6 +916,9 @@ testParseProfiles() { [profile.dev] opt-level = 1 + + [profile.test] + cxxflags = ["-fno-rtti"] )"_toml; const Profile devExpected( @@ -891,11 +931,17 @@ testParseProfiles() { /*debug=*/false, /*compDb=*/false, /*optLevel=*/2 // here, the default is 3 ); + const Profile testExpected( + /*cxxflags=*/{ "-fno-rtti" }, /*ldflags=*/{}, /*lto=*/false, + /*debug=*/true, + /*compDb=*/false, /*optLevel=*/1 + ); const auto profiles = parseProfiles(overwrite).unwrap(); - assertEq(profiles.size(), 2UL); + assertEq(profiles.size(), 3UL); assertEq(profiles.at(BuildProfile::Dev), devExpected); assertEq(profiles.at(BuildProfile::Release), relExpected); + assertEq(profiles.at(BuildProfile::Test), testExpected); } }