Skip to content

Commit b9df847

Browse files
authored
Args::Instance constructed from Args for better segregation (#203)
1 parent 94d62c9 commit b9df847

File tree

22 files changed

+374
-301
lines changed

22 files changed

+374
-301
lines changed

bootstrap/main.buildcc.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,12 @@ static void hybrid_simple_example_cb(BaseTarget &target,
3333
const BaseTarget &libbuildcc);
3434

3535
int main(int argc, char **argv) {
36-
Args::Init();
3736
ArgToolchain custom_toolchain_arg;
38-
Args::AddToolchain("host", "Host Toolchain", custom_toolchain_arg);
39-
Args::Parse(argc, argv);
37+
Args::Init()
38+
.AddToolchain("host", "Host Toolchain", custom_toolchain_arg)
39+
.Parse(argc, argv);
4040

4141
Register reg;
42-
;
4342
reg.Clean(clean_cb);
4443

4544
BaseToolchain toolchain = custom_toolchain_arg.ConstructToolchain();

buildcc/lib/args/include/args/args.h

Lines changed: 61 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -85,57 +85,71 @@ struct ArgTarget {
8585
std::string link_command{""};
8686
};
8787

88+
struct ArgCustom {
89+
virtual void Add(CLI::App &app) = 0;
90+
};
91+
8892
class Args {
89-
public:
93+
private:
94+
class Instance {
95+
public:
96+
/**
97+
* @brief Parse command line information to CLI11
98+
*
99+
* @param argc from int main(int argc, char ** argv)
100+
* @param argv from int main(int argc, char ** argv)
101+
*/
102+
static void Parse(int argc, const char *const *argv);
103+
104+
/**
105+
* @brief Add toolchain with a unique name and description
106+
*
107+
* @param out Receive the toolchain information through the CLI
108+
* @param initial Set the default toolchain information as a fallback
109+
*/
110+
Instance &AddToolchain(const std::string &name,
111+
const std::string &description, ArgToolchain &out,
112+
const ArgToolchain &initial = ArgToolchain());
113+
114+
/**
115+
* @brief Add toolchain with a unique name and description
116+
*
117+
* @param out Receive the toolchain information through the CLI
118+
* @param initial Set the default toolchain information as a fallback
119+
*/
120+
Instance &AddTarget(const std::string &name, const std::string &description,
121+
ArgTarget &out, const ArgTarget &initial = ArgTarget());
122+
123+
/**
124+
* @brief Custom callback for data
125+
*
126+
* @param add_cb Add callback that exposes underlying CLI::App
127+
*/
128+
Instance &AddCustomCallback(const std::function<void(CLI::App &)> &add_cb);
129+
130+
/**
131+
* @brief Add custom data
132+
*
133+
* @param data Derive from `buildcc::ArgCustom` and override the `Add` API
134+
*/
135+
Instance &AddCustomData(ArgCustom &data);
136+
};
137+
138+
struct Internal {
139+
Instance instance;
140+
CLI::App app{"BuildCC Buildsystem"};
141+
CLI::App *toolchain{nullptr};
142+
CLI::App *target{nullptr};
143+
};
144+
90145
public:
91146
Args() = delete;
92147
Args(const Args &) = delete;
93148
Args(Args &&) = delete;
94149

95-
static void Init();
150+
static Instance &Init();
96151
static void Deinit();
97152

98-
/**
99-
* @brief Parse command line information to CLI11
100-
*
101-
* @param argc from int main(int argc, char ** argv)
102-
* @param argv from int main(int argc, char ** argv)
103-
*/
104-
static void Parse(int argc, const char *const *argv);
105-
106-
/**
107-
* @brief Modifiable reference to CLI::App (CLI11)
108-
*/
109-
static CLI::App &Ref();
110-
111-
/**
112-
* @brief Constant reference to CLI::App (CLI11)
113-
*/
114-
static const CLI::App &ConstRef();
115-
116-
// Setters
117-
118-
/**
119-
* @brief Add toolchain with a unique name and description
120-
*
121-
* @param out Receive the toolchain information through the CLI
122-
* @param initial Set the default toolchain information as a fallback
123-
*/
124-
static void AddToolchain(const std::string &name,
125-
const std::string &description, ArgToolchain &out,
126-
const ArgToolchain &initial = ArgToolchain());
127-
128-
/**
129-
* @brief Add Target config commands with a unique name and description
130-
*
131-
* @param out Receive the target command information through the CLI
132-
* @param initial Set the default target command information as a fallback
133-
*
134-
* TODO, Update with other options for TargetConfig
135-
*/
136-
static void AddTarget(const std::string &name, const std::string &description,
137-
ArgTarget &out, const ArgTarget &initial = ArgTarget());
138-
139153
// Getters
140154
static bool Clean();
141155
static env::LogLevel GetLogLevel();
@@ -145,6 +159,10 @@ class Args {
145159

146160
private:
147161
static void RootArgs();
162+
static CLI::App &Ref();
163+
164+
private:
165+
static std::unique_ptr<Internal> internal_;
148166
};
149167

150168
} // namespace buildcc

buildcc/lib/args/include/args/register.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ namespace buildcc {
3333

3434
class Register {
3535
public:
36-
// Register(const Args &args) : args_(args) { Initialize(); }
3736
Register() { Initialize(); }
3837
Register(const Register &) = delete;
3938

@@ -155,8 +154,6 @@ class Register {
155154
void BuildStoreTask(const std::string &unique_id, const tf::Task &task);
156155

157156
private:
158-
// const Args &args_;
159-
160157
// Build
161158
tf::Taskflow build_tf_{"Targets"};
162159

buildcc/lib/args/mock/parse.cpp

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

55
namespace buildcc {
66

7-
void Args::Parse(int argc, const char *const *argv) {
7+
void Args::Instance::Parse(int argc, const char *const *argv) {
88
try {
99
Ref().parse(argc, argv);
1010
} catch (const CLI::ParseError &e) {

buildcc/lib/args/src/args.cpp

Lines changed: 76 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -90,52 +90,72 @@ buildcc::env::LogLevel loglevel_{buildcc::env::LogLevel::Info};
9090
fs::path project_root_dir_{""};
9191
fs::path project_build_dir_{"_internal"};
9292

93-
// Internal
94-
// std::unique_ptr<CLI::App> app_;
95-
// CLI::App *toolchain_{nullptr};
96-
// CLI::App *target_{nullptr};
97-
98-
struct ArgsInstance {
99-
CLI::App app_{"BuildCC Buildsystem"};
100-
CLI::App *toolchain_{nullptr};
101-
CLI::App *target_{nullptr};
102-
};
103-
104-
std::unique_ptr<ArgsInstance> args_instance_;
105-
10693
} // namespace
10794

10895
namespace buildcc {
10996

110-
void Args::Init() {
111-
if (!args_instance_) {
112-
args_instance_ = std::make_unique<ArgsInstance>();
113-
args_instance_->toolchain_ =
97+
std::unique_ptr<Args::Internal> Args::internal_;
98+
99+
Args::Instance &Args::Init() {
100+
if (!internal_) {
101+
internal_ = std::make_unique<Internal>();
102+
internal_->toolchain =
114103
Ref().add_subcommand(kToolchainSubcommand, kToolchainDesc);
115-
args_instance_->target_ =
116-
Ref().add_subcommand(kTargetSubcommand, kTargetDesc);
104+
internal_->target = Ref().add_subcommand(kTargetSubcommand, kTargetDesc);
117105
RootArgs();
118106
}
107+
return internal_->instance;
119108
}
120109

121-
void Args::Deinit() { args_instance_.reset(nullptr); }
122-
123-
CLI::App &Args::Ref() { return args_instance_->app_; }
124-
const CLI::App &Args::ConstRef() { return args_instance_->app_; }
110+
void Args::Deinit() { internal_.reset(nullptr); }
125111

126112
bool Args::Clean() { return clean_; }
127113
env::LogLevel Args::GetLogLevel() { return loglevel_; }
128114

129115
const fs::path &Args::GetProjectRootDir() { return project_root_dir_; }
130116
const fs::path &Args::GetProjectBuildDir() { return project_build_dir_; }
131117

132-
void Args::AddToolchain(const std::string &name, const std::string &description,
133-
ArgToolchain &out, const ArgToolchain &initial) {
134-
CLI::App *toolchain_ = args_instance_->toolchain_;
135-
env::assert_fatal(toolchain_ != nullptr,
118+
// Private
119+
120+
void Args::RootArgs() {
121+
auto &app = Ref();
122+
app.set_help_all_flag(kHelpAllParam, kHelpAllDesc);
123+
124+
app.set_config(kConfigParam, "", kConfigDesc)->expected(kMinFiles, kMaxFiles);
125+
126+
// Root flags
127+
auto *root_group = app.add_option_group(kRootGroup);
128+
129+
root_group->add_flag(kCleanParam, clean_, kCleanDesc);
130+
root_group->add_option(kLoglevelParam, loglevel_, kLoglevelDesc)
131+
->transform(CLI::CheckedTransformer(kLogLevelMap, CLI::ignore_case));
132+
133+
// Dir flags
134+
root_group->add_option(kRootDirParam, project_root_dir_, kRootDirDesc)
135+
->required();
136+
root_group->add_option(kBuildDirParam, project_build_dir_, kBuildDirDesc)
137+
->required();
138+
}
139+
140+
CLI::App &Args::Ref() { return internal_->app; }
141+
142+
// Args::Instance
143+
144+
/**
145+
* @brief Add toolchain with a unique name and description
146+
*
147+
* @param out Receive the toolchain information through the CLI
148+
* @param initial Set the default toolchain information as a fallback
149+
*/
150+
Args::Instance &Args::Instance::AddToolchain(const std::string &name,
151+
const std::string &description,
152+
ArgToolchain &out,
153+
const ArgToolchain &initial) {
154+
CLI::App *toolchain = internal_->toolchain;
155+
env::assert_fatal(toolchain != nullptr,
136156
"Initialize Args using the Args::Init API");
137157
CLI::App *t_user =
138-
toolchain_->add_subcommand(name, description)->group(kToolchainGroup);
158+
toolchain->add_subcommand(name, description)->group(kToolchainGroup);
139159
t_user->add_flag(kToolchainBuildParam, out.state.build);
140160
t_user->add_flag(kToolchainTestParam, out.state.test);
141161

@@ -153,42 +173,42 @@ void Args::AddToolchain(const std::string &name, const std::string &description,
153173
->default_val(initial.executables.archiver);
154174
t_user->add_option(kToolchainLinkerParam, out.executables.linker)
155175
->default_val(initial.executables.linker);
176+
return *this;
156177
}
157178

158-
void Args::AddTarget(const std::string &name, const std::string &description,
159-
ArgTarget &out, const ArgTarget &initial) {
160-
CLI::App *target_ = args_instance_->target_;
161-
env::assert_fatal(target_ != nullptr,
179+
/**
180+
* @brief Add toolchain with a unique name and description
181+
*
182+
* @param out Receive the toolchain information through the CLI
183+
* @param initial Set the default toolchain information as a fallback
184+
*/
185+
Args::Instance &Args::Instance::AddTarget(const std::string &name,
186+
const std::string &description,
187+
ArgTarget &out,
188+
const ArgTarget &initial) {
189+
CLI::App *target = internal_->target;
190+
env::assert_fatal(target != nullptr,
162191
"Initialize Args using the Args::Init API");
163-
CLI::App *target_user =
164-
target_->add_subcommand(name, description)->group(kTargetGroup);
165-
target_user->add_option(kTargetCompileCommandParam, out.compile_command)
192+
CLI::App *targetuser =
193+
target->add_subcommand(name, description)->group(kTargetGroup);
194+
targetuser->add_option(kTargetCompileCommandParam, out.compile_command)
166195
->default_val(initial.compile_command);
167-
target_user->add_option(kTargetLinkCommandParam, out.link_command)
196+
targetuser->add_option(kTargetLinkCommandParam, out.link_command)
168197
->default_val(initial.link_command);
198+
return *this;
169199
}
170200

171-
// Private
172-
173-
void Args::RootArgs() {
174-
Ref().set_help_all_flag(kHelpAllParam, kHelpAllDesc);
175-
176-
Ref()
177-
.set_config(kConfigParam, "", kConfigDesc)
178-
->expected(kMinFiles, kMaxFiles);
179-
180-
// Root flags
181-
auto *root_group = Ref().add_option_group(kRootGroup);
182-
183-
root_group->add_flag(kCleanParam, clean_, kCleanDesc);
184-
root_group->add_option(kLoglevelParam, loglevel_, kLoglevelDesc)
185-
->transform(CLI::CheckedTransformer(kLogLevelMap, CLI::ignore_case));
201+
Args::Instance &Args::Instance::AddCustomCallback(
202+
const std::function<void(CLI::App &)> &add_cb) {
203+
auto &app = Ref();
204+
add_cb(app);
205+
return *this;
206+
}
186207

187-
// Dir flags
188-
root_group->add_option(kRootDirParam, project_root_dir_, kRootDirDesc)
189-
->required();
190-
root_group->add_option(kBuildDirParam, project_build_dir_, kBuildDirDesc)
191-
->required();
208+
Args::Instance &Args::Instance::AddCustomData(ArgCustom &data) {
209+
auto &app = Ref();
210+
data.Add(app);
211+
return *this;
192212
}
193213

194214
} // namespace buildcc

buildcc/lib/args/src/parse.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@
1818

1919
namespace buildcc {
2020

21-
void Args::Parse(int argc, const char *const *argv) {
21+
void Args::Instance::Parse(int argc, const char *const *argv) {
22+
auto &app = Ref();
2223
try {
23-
Ref().parse(argc, argv);
24+
app.parse(argc, argv);
2425
} catch (const CLI::ParseError &e) {
25-
exit(ConstRef().exit(e));
26+
exit(app.exit(e));
2627
}
2728
}
2829

0 commit comments

Comments
 (0)