Skip to content

Commit e405261

Browse files
committed
added default profiles release and debug
* added profile settings * added specification of sanitizers
1 parent 6e95bd4 commit e405261

File tree

10 files changed

+319
-18
lines changed

10 files changed

+319
-18
lines changed

include/flags.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ namespace muuk {
5454

5555
{ "lto", FlagCategory::Advanced, { "-flto", "-flto", "/GL" } },
5656
{ "march_native", FlagCategory::Advanced, { "-march=native", "-march=native", "/arch:AVX2" } },
57-
{ "cpp_std_17", FlagCategory::Advanced, { "-std=c++17", "-std=c++17", "/std:c++17" } },
5857
{ "no_exceptions", FlagCategory::Advanced, { "-fno-exceptions", "-fno-exceptions", "/EHs-c-" } },
5958
{ "no_rtti", FlagCategory::Advanced, { "-fno-rtti", "-fno-rtti", "/GR-" } },
6059

include/lockgen/config/base.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "compiler.hpp"
1212
#include "muuk.hpp"
13+
#include "opt_level.hpp"
1314
#include "toml_ext.hpp"
1415
#include "util.hpp"
1516

@@ -269,10 +270,39 @@ namespace muuk {
269270
}
270271
};
271272

273+
struct Settings {
274+
// CXX_Standard cxx_standard;
275+
// C_Standard c_standard;
276+
OptimizationLevel optimization_level;
277+
bool lto = false;
278+
bool debug = false;
279+
bool rpath = false;
280+
bool debug_assertions = false; // -DNDEBUG
281+
};
282+
283+
void load(Settings& settings, const toml::value& v);
284+
285+
void serialize(const Settings& settings, toml::value& out);
286+
287+
struct Sanitizers {
288+
bool address = false; // ASan
289+
bool thread = false; // TSan
290+
bool undefined = false; // UBSan
291+
bool memory = false; // MSan
292+
bool leak = false; // LSan
293+
};
294+
295+
void load(Sanitizers& sanitizers, const toml::value& v);
296+
297+
void serialize(const Sanitizers& sanitizers, toml::value& out);
298+
272299
struct ProfileConfig : BaseConfig<ProfileConfig> {
273300
std::string name;
274301
std::vector<std::string> inherits;
275302

303+
Settings settings;
304+
Sanitizers sanitizers;
305+
276306
void load(
277307
const toml::value& v,
278308
const std::string& profile_name,

include/opt_level.hpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#pragma once
2+
#ifndef MUUK_OPT_LEVEL_HPP
3+
#define MUUK_OPT_LEVEL_HPP
4+
5+
#include <string>
6+
7+
#include <compiler.hpp>
8+
#include <logger.hpp>
9+
10+
#define OPTIMIZATION_LEVELS(X) \
11+
X(O0, '0', "-O0", "-O0", "/Od") \
12+
X(O1, '1', "-O1", "-O1", "/O1") \
13+
X(O2, '2', "-O2", "-O2", "/O2") \
14+
X(O3, '3', "-O3", "-O3", "/Ox /Ob2") \
15+
X(Os, 's', "-Os", "-Os", "/Os") \
16+
X(Oz, 'z', "-Os", "-Oz", "/Os")
17+
// CLANG, GCC, MSVC
18+
19+
#define X_ENUM(name, chr, gcc, clang, msvc) name,
20+
enum class OptimizationLevel {
21+
OPTIMIZATION_LEVELS(X_ENUM)
22+
};
23+
24+
namespace muuk {
25+
inline OptimizationLevel opt_lvl_from_string(const std::string& str) {
26+
if (str.empty())
27+
return OptimizationLevel::O1;
28+
29+
char c;
30+
if ((str.size() == 2 || str.size() == 1) && (str[0] == 'O' || str[0] == 'o')) {
31+
c = str.size() == 2 ? str[1] : '\0';
32+
} else if (str.size() == 1) {
33+
c = str[0];
34+
} else {
35+
muuk::logger::warn("Invalid optimization level string: '{}'. Defaulting to O1.", str);
36+
return OptimizationLevel::O1;
37+
}
38+
39+
#define X_FROM_CHAR(name, chr, gcc, clang, msvc) \
40+
if (c == chr) \
41+
return OptimizationLevel::name;
42+
OPTIMIZATION_LEVELS(X_FROM_CHAR)
43+
#undef X_FROM_CHAR
44+
45+
return OptimizationLevel::O1; // Default optimization level
46+
}
47+
48+
inline std::string to_flag(OptimizationLevel level, Compiler::Type compiler) {
49+
switch (level) {
50+
#define X_TO_FLAG(name, chr, gcc, clang, msvc) \
51+
case OptimizationLevel::name: \
52+
switch (compiler) { \
53+
case Compiler::Type::GCC: \
54+
return gcc; \
55+
case Compiler::Type::Clang: \
56+
return clang; \
57+
case Compiler::Type::MSVC: \
58+
return msvc; \
59+
default: \
60+
return ""; \
61+
}
62+
OPTIMIZATION_LEVELS(X_TO_FLAG)
63+
#undef X_TO_FLAG
64+
}
65+
66+
return "";
67+
}
68+
69+
inline std::string to_string(OptimizationLevel level) {
70+
switch (level) {
71+
#define X_TO_CHAR(name, chr, gcc, clang, msvc) \
72+
case OptimizationLevel::name: \
73+
return std::string(1, chr);
74+
OPTIMIZATION_LEVELS(X_TO_CHAR)
75+
#undef X_TO_CHAR
76+
}
77+
return "1"; // Default string
78+
}
79+
}
80+
81+
#undef OPTIMIZATION_LEVELS
82+
83+
#endif // MUUK_OPT_LEVEL_HPP

include/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#define VERSION_MAJOR 0
55
#define VERSION_MINOR 0
6-
#define VERSION_PATCH 5
6+
#define VERSION_PATCH 6
77

88
#define STRINGIFY(x) #x
99
#define TOSTRING(x) STRINGIFY(x)

muuk.toml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,14 @@ sources = ['test/internal/muuk_test.cpp']
6161
dependencies = { googletest = '3fbe4db9a39291ae8d7a9c5f1d75896bb4c5a18f' }
6262

6363
[profile.base]
64-
cflags = ['-std=c++20', '/utf-8', '/EHsc', '/FS', '/nologo']
64+
cflags = ['-std=c++20', '/utf-8', '/EHsc', '/nologo']
6565
aflags = ['/nologo']
6666
lflags = ['/nologo']
6767

6868
[profile.release]
69-
cflags = ['/O2', '/DNDEBUG', '/GL']
7069
inherits = ['base']
71-
lflags = ['/OPT:REF', '/OPT:ICF', '/LTCG']
7270

7371
[profile.debug]
74-
cflags = ['/Od', '/DDEBUG', '/Zi', '/RTC1', '/FC', '/GS']
7572
default = true
76-
include = ['include']
7773
inherits = ['base']
78-
lflags = ['/DEBUG']
79-
libs = []
74+
cflags = ['/DDEBUG', '/FC']

src/build/parser.cpp

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "logger.hpp"
1717
#include "muuk.hpp"
1818
#include "muuk_parser.hpp"
19+
#include "opt_level.hpp"
1920
#include "rustify.hpp"
2021
#include "util.hpp"
2122

@@ -41,7 +42,7 @@ namespace muuk {
4142
if (!profile_table.contains(profile))
4243
return Err("Profile '{}' does not exist in the configuration.", profile);
4344

44-
auto profile_entry = profile_table.at(profile).as_table();
45+
auto profile_entry = profile_table.at(profile);
4546

4647
BuildProfile build_profile;
4748
build_profile.cflags = muuk::parse_array_as_vec(profile_entry, "cflags");
@@ -54,6 +55,87 @@ namespace muuk {
5455
muuk::normalize_flags_inplace(build_profile.lflags, compiler);
5556
muuk::normalize_flags_inplace(build_profile.defines, compiler);
5657

58+
// --- Link Type Optimization ---
59+
if (profile_entry.at("lto").as_boolean()) {
60+
muuk::logger::info("LTO enabled for profile '{}'", profile);
61+
switch (compiler.getType()) {
62+
case Compiler::Type::GCC:
63+
case Compiler::Type::Clang:
64+
build_profile.cflags.push_back("-flto");
65+
build_profile.lflags.push_back("-flto");
66+
case Compiler::Type::MSVC:
67+
build_profile.cflags.push_back("/GL");
68+
build_profile.lflags.push_back("/LTCG");
69+
}
70+
}
71+
72+
// --- Debug ---
73+
if (profile_entry.at("debug").as_boolean()) {
74+
muuk::logger::info("LTO enabled for profile '{}'", profile);
75+
switch (compiler.getType()) {
76+
case Compiler::Type::GCC:
77+
case Compiler::Type::Clang:
78+
build_profile.cflags.push_back("-g");
79+
case Compiler::Type::MSVC:
80+
build_profile.cflags.push_back("/Zi");
81+
build_profile.lflags.push_back("/DEBUG");
82+
}
83+
}
84+
85+
// --- Debug Assertions ---
86+
if (!profile_entry.at("debug-assertions").as_boolean()) {
87+
muuk::logger::info("LTO enabled for profile '{}'", profile);
88+
switch (compiler.getType()) {
89+
case Compiler::Type::GCC:
90+
case Compiler::Type::Clang:
91+
build_profile.cflags.push_back("-DNDEBUG");
92+
case Compiler::Type::MSVC:
93+
build_profile.cflags.push_back("/DNDEBUG");
94+
}
95+
}
96+
97+
// --- Optimization Level ---
98+
build_profile.cflags.push_back(to_flag(
99+
opt_lvl_from_string(profile_entry.at("opt-level").as_string()),
100+
compiler.getType()));
101+
102+
// --- Sanitizers ---
103+
if (profile_entry.contains("sanitizers") && profile_entry.at("sanitizers").is_array()) {
104+
for (const auto& item : profile_entry.at("sanitizers").as_array()) {
105+
if (!item.is_string())
106+
continue;
107+
108+
const std::string name = item.as_string();
109+
110+
switch (compiler.getType()) {
111+
case Compiler::Type::GCC:
112+
case Compiler::Type::Clang:
113+
if (name == "address")
114+
build_profile.cflags.push_back("-fsanitize=address");
115+
else if (name == "thread")
116+
build_profile.cflags.push_back("-fsanitize=thread");
117+
else if (name == "undefined")
118+
build_profile.cflags.push_back("-fsanitize=undefined");
119+
else if (name == "memory")
120+
build_profile.cflags.push_back("-fsanitize=memory");
121+
else if (compiler.getType() == Compiler::Type::Clang && name == "leak")
122+
build_profile.cflags.push_back("-fsanitize=leak");
123+
break;
124+
125+
case Compiler::Type::MSVC:
126+
if (name == "address")
127+
build_profile.cflags.push_back("/fsanitize=address");
128+
else if (name == "undefined") {
129+
build_profile.cflags.push_back("/RTC1");
130+
build_profile.cflags.push_back("/RTCc");
131+
build_profile.cflags.push_back("/RTCs");
132+
}
133+
// No leak, memory, or thread sanitizers in MSVC
134+
break;
135+
}
136+
}
137+
}
138+
57139
muuk::logger::trace("Profile '{}' CFLAGS: {}", profile, fmt::join(build_profile.cflags, " "));
58140
muuk::logger::trace("Profile '{}' AFLAGS: {}", profile, fmt::join(build_profile.cflags, " "));
59141
muuk::logger::trace("Profile '{}' LFLAGS: {}", profile, fmt::join(build_profile.lflags, " "));

src/compiler.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,5 +220,4 @@ namespace muuk {
220220
return "";
221221
}
222222
}
223-
224223
} // namespace muuk

src/lockgen/base_config.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,12 @@ namespace muuk {
147147
void ProfileConfig::load(const toml::value& v, const std::string& profile_name, const std::string& base_path) {
148148
BaseConfig<ProfileConfig>::load(v, base_path);
149149
name = profile_name;
150-
inherits = toml::find_or<std::vector<std::string>>(v, "inherits", {});
150+
inherits = toml::try_find_or<std::vector<std::string>>(
151+
v,
152+
"inherits",
153+
{});
154+
lockgen::load(settings, v);
155+
lockgen::load(sanitizers, v);
151156
}
152157

153158
void ProfileConfig::serialize(toml::value& out) const {
@@ -156,6 +161,9 @@ namespace muuk {
156161
// Serialize inheritance
157162
if (!inherits.empty())
158163
out["inherits"] = inherits;
164+
165+
lockgen::serialize(settings, out);
166+
lockgen::serialize(sanitizers, out);
159167
}
160168

161169
void Library::External::load(const toml::value& v) {

src/lockgen/parsing.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,37 @@ namespace muuk {
4343
}
4444

4545
Result<void> MuukLockGenerator::parse_profile(const toml::value& data) {
46+
// Default Profiles (debug and release)
47+
{
48+
ProfileConfig debug_profile;
49+
debug_profile.name = "debug";
50+
debug_profile.settings.debug = true;
51+
debug_profile.settings.optimization_level = OptimizationLevel::O0;
52+
debug_profile.settings.debug_assertions = true;
53+
debug_profile.settings.lto = false;
54+
debug_profile.sanitizers.address = true;
55+
debug_profile.sanitizers.undefined = true;
56+
57+
ProfileConfig release_profile;
58+
release_profile.name = "release";
59+
release_profile.settings.debug = false;
60+
release_profile.settings.optimization_level = OptimizationLevel::O3;
61+
debug_profile.settings.debug_assertions = false;
62+
release_profile.settings.lto = true;
63+
debug_profile.sanitizers.undefined = true;
64+
65+
profiles_config_["debug"] = std::move(debug_profile);
66+
profiles_config_["release"] = std::move(release_profile);
67+
}
68+
4669
// Two pass parsing for profiles
4770
// First pass: Load all profiles
4871
if (data.contains("profile") && data.at("profile").is_table()) {
4972
for (const auto& [profile_name, profile_data] : data.at("profile").as_table()) {
50-
if (!profile_data.is_table())
51-
continue;
73+
// this will create or get an existing profile
74+
ProfileConfig& config = profiles_config_[profile_name];
5275

53-
ProfileConfig config;
54-
config.name = profile_name;
55-
config.load(profile_data, profile_name, base_path_); // assuming you have `base_path_`
56-
profiles_config_[profile_name] = std::move(config);
76+
config.load(profile_data, profile_name, base_path_);
5777
}
5878
}
5979

0 commit comments

Comments
 (0)