Skip to content

Commit 9f9df34

Browse files
authored
Target Command module (#67)
Internal Command module to efficiently construct process commands
1 parent 54c3574 commit 9f9df34

26 files changed

+337
-183
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ Basic Installation steps
181181
# FAQ
182182

183183
- [Why has _this_ third-party library been chosen?](doc/faq/why_this_lib.md)
184+
- [How do I create my own custom target commands?](doc/custom_target/commands.md)
184185

185186
## Design
186187

buildcc/lib/target/cmake/mock_target.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ target_sources(mock_target PRIVATE
1919
${CMAKE_CURRENT_SOURCE_DIR}/src/fbs/fbs_storer.cpp
2020

2121
${CMAKE_CURRENT_SOURCE_DIR}/src/util/util.cpp
22-
${CMAKE_CURRENT_SOURCE_DIR}/mock/util/command.cpp
22+
${CMAKE_CURRENT_SOURCE_DIR}/src/util/command.cpp
23+
${CMAKE_CURRENT_SOURCE_DIR}/mock/util/execute.cpp
2324
)
2425

2526
target_compile_options(mock_target PUBLIC ${TEST_COMPILE_FLAGS} ${BUILD_COMPILE_FLAGS})

buildcc/lib/target/cmake/target.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ target_sources(target PRIVATE
3131

3232
src/util/util.cpp
3333
src/util/command.cpp
34+
src/util/execute.cpp
3435

3536
include/target.h
3637
include/internal/fbs_loader.h

buildcc/lib/target/cmake/target_install.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ install(FILES
77
${CMAKE_CURRENT_SOURCE_DIR}/include/internal/fbs_loader.h
88
${CMAKE_CURRENT_SOURCE_DIR}/include/internal/path.h
99
${CMAKE_CURRENT_SOURCE_DIR}/include/internal/util.h
10+
${CMAKE_CURRENT_SOURCE_DIR}/include/internal/command.h
1011
DESTINATION "${BUILDCC_INSTALL_HEADER_PREFIX}/internal"
1112
)
1213
install(EXPORT targetConfig DESTINATION "${BUILDCC_INSTALL_LIB_PREFIX}/target")
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2021 Niket Naidu. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef TARGET_INCLUDE_INTERNAL_COMMAND_H_
18+
#define TARGET_INCLUDE_INTERNAL_COMMAND_H_
19+
20+
#include <unordered_map>
21+
22+
#include "internal/path.h"
23+
24+
#include "toolchain.h"
25+
26+
namespace buildcc::internal {
27+
28+
class Command {
29+
public:
30+
explicit Command() = default;
31+
32+
void AddDefaultArguments(
33+
const std::unordered_map<const char *, std::string> &arguments);
34+
35+
std::string Construct(std::string_view format,
36+
const std::unordered_map<const char *, std::string>
37+
&arguments = {}) const;
38+
bool ConstructAndExecute(std::string_view format,
39+
const std::unordered_map<const char *, std::string>
40+
&arguments = {}) const;
41+
42+
static bool Execute(const std::string &command);
43+
44+
private:
45+
std::unordered_map<const char *, std::string> default_values_;
46+
};
47+
48+
} // namespace buildcc::internal
49+
50+
#endif

buildcc/lib/target/include/internal/util.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,6 @@
2424

2525
namespace buildcc::internal {
2626

27-
// System
28-
/**
29-
* @brief Executes an external command
30-
* Internally command uses `std::system`
31-
* TODO, Replace with `subprocess`
32-
*
33-
* @param command
34-
* @return true
35-
* @return false
36-
*/
37-
bool command(const std::string &command);
38-
3927
// Additions
4028
/**
4129
* @brief Existing path is stored inside stored_paths

buildcc/lib/target/include/target.h

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <vector>
2626

2727
// Internal
28+
#include "internal/command.h"
2829
#include "internal/fbs_loader.h"
2930
#include "internal/path.h"
3031

@@ -260,29 +261,21 @@ class Target {
260261
std::unordered_set<std::string> current_cpp_compile_flags_;
261262
std::unordered_set<std::string> current_link_flags_;
262263

263-
// TODO, Make appending to this more efficient
264264
// TODO, Might not need to be persistent
265-
// TODO, aggregates might not need to exist, check `std::insert` APIs over
266-
// vector and unordered_set
267-
std::string aggregated_include_dirs_;
268-
std::string aggregated_lib_dirs_;
269-
// NOTE, This contains current_external_lib_deps_ + current_lib_deps_
270-
std::string aggregated_lib_deps_;
271-
272-
std::string aggregated_preprocessor_flags_;
273265
std::string aggregated_c_compile_flags_;
274266
std::string aggregated_cpp_compile_flags_;
275-
std::string aggregated_link_flags_;
276267

277268
// TODO, Add more internal variables
278269

279270
internal::FbsLoader loader_;
280-
bool dirty_ = false;
271+
internal::Command command_;
281272

282273
// Build states
274+
bool dirty_ = false;
283275
bool first_build_ = false;
284276
bool rebuild_ = false;
285277

278+
// Dependency
286279
static constexpr const char *const kCompileTaskName = "Compile";
287280
static constexpr const char *const kLinkTaskName = "Link";
288281

buildcc/lib/target/mock/expect_target.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace buildcc {
77

88
namespace internal::m {
99

10-
void Expect_command(unsigned int calls, bool expectation);
10+
void CommandExpect_Execute(unsigned int calls, bool expectation);
1111

1212
} // namespace internal::m
1313

buildcc/lib/target/mock/util/command.cpp

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "internal/command.h"
2+
3+
#include "CppUTestExt/MockSupport.h"
4+
5+
namespace buildcc::internal {
6+
7+
static constexpr const char *const EXECUTE_FUNCTION = "execute";
8+
9+
// command
10+
bool Command::Execute(const std::string &command) {
11+
(void)command;
12+
return mock().actualCall(EXECUTE_FUNCTION).returnBoolValue();
13+
}
14+
15+
namespace m {
16+
17+
void CommandExpect_Execute(unsigned int calls, bool expectation) {
18+
mock().expectNCalls(calls, EXECUTE_FUNCTION).andReturnValue(expectation);
19+
}
20+
21+
} // namespace m
22+
23+
} // namespace buildcc::internal

buildcc/lib/target/src/target/build.cpp

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,31 @@ void Target::Build() {
3434
env::log_trace(name_, __FUNCTION__);
3535

3636
// TODO, Optimize these
37-
aggregated_preprocessor_flags_ =
38-
internal::aggregate(current_preprocessor_flags_);
3937
aggregated_c_compile_flags_ = internal::aggregate(current_c_compile_flags_);
4038
aggregated_cpp_compile_flags_ =
4139
internal::aggregate(current_cpp_compile_flags_);
42-
aggregated_link_flags_ = internal::aggregate(current_link_flags_);
4340

44-
aggregated_lib_deps_ =
45-
fmt::format("{} {}", internal::aggregate(current_external_lib_deps_),
46-
internal::aggregate(current_lib_deps_));
41+
command_.AddDefaultArguments({
42+
{"include_dirs", internal::aggregate_with_prefix(prefix_include_dir_,
43+
current_include_dirs_)},
44+
{"lib_dirs",
45+
internal::aggregate_with_prefix(prefix_lib_dir_, current_lib_dirs_)},
4746

48-
aggregated_include_dirs_ = internal::aggregate_with_prefix(
49-
prefix_include_dir_, current_include_dirs_);
50-
aggregated_lib_dirs_ =
51-
internal::aggregate_with_prefix(prefix_lib_dir_, current_lib_dirs_);
47+
// TODO, Segregate this if needed
48+
{"lib_deps",
49+
fmt::format("{} {}", internal::aggregate(current_external_lib_deps_),
50+
internal::aggregate(current_lib_deps_))},
51+
52+
{"preprocessor_flags", internal::aggregate(current_preprocessor_flags_)},
53+
{"link_flags", internal::aggregate(current_link_flags_)},
54+
55+
// Toolchain executables here
56+
{"asm_compiler", toolchain_.GetAsmCompiler()},
57+
{"c_compiler", toolchain_.GetCCompiler()},
58+
{"cpp_compiler", toolchain_.GetCppCompiler()},
59+
{"archiver", toolchain_.GetArchiver()},
60+
{"linker", toolchain_.GetLinker()},
61+
});
5262

5363
const bool is_loaded = loader_.Load();
5464
// TODO, Add more checks for build files physically present
@@ -120,19 +130,11 @@ void Target::LinkTarget() {
120130
const std::string output_target =
121131
internal::Path::CreateNewPath(GetTargetPath()).GetPathAsString();
122132

123-
std::string link_command =
124-
fmt::format(Link(), fmt::arg("output", output_target),
125-
fmt::arg("link_flags", aggregated_link_flags_),
126-
fmt::arg("compiled_sources", aggregated_compiled_sources),
127-
fmt::arg("lib_dirs", aggregated_lib_dirs_),
128-
fmt::arg("lib_deps", aggregated_lib_deps_),
129-
// Toolchain executables here
130-
fmt::arg("asm_compiler", toolchain_.GetAsmCompiler()),
131-
fmt::arg("c_compiler", toolchain_.GetCCompiler()),
132-
fmt::arg("cpp_compiler", toolchain_.GetCppCompiler()),
133-
fmt::arg("archiver", toolchain_.GetArchiver()),
134-
fmt::arg("linker", toolchain_.GetLinker()));
135-
bool success = internal::command(link_command);
133+
const bool success = command_.ConstructAndExecute(
134+
Link(), {
135+
{"output", output_target},
136+
{"compiled_sources", aggregated_compiled_sources},
137+
});
136138
env::assert_fatal(success, fmt::format("Compilation failed for: {}", name_));
137139
}
138140

buildcc/lib/target/src/target/source.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ void Target::RecompileSources() {
172172
}
173173

174174
void Target::CompileSource(const fs::path &current_source) const {
175-
const bool success = internal::command(CompileCommand(current_source));
175+
const bool success =
176+
internal::Command::Execute(CompileCommand(current_source));
176177
env::assert_fatal(success, fmt::format("Compilation failed for: {}",
177178
current_source.string()));
178179
}
@@ -193,13 +194,13 @@ std::string Target::CompileCommand(const fs::path &current_source) const {
193194
: type == FileExtType::Cpp ? aggregated_cpp_compile_flags_
194195
: "";
195196

196-
// Construct the Compile Command
197-
return fmt::format(
198-
CompileCommand(), fmt::arg("compiler", compiler),
199-
fmt::arg("preprocessor_flags", aggregated_preprocessor_flags_),
200-
fmt::arg("compile_flags", aggregated_compile_flags),
201-
fmt::arg("include_dirs", aggregated_include_dirs_),
202-
fmt::arg("output", output), fmt::arg("input", input));
197+
return command_.Construct(CompileCommand(),
198+
{
199+
{"compiler", compiler},
200+
{"compile_flags", aggregated_compile_flags},
201+
{"output", output},
202+
{"input", input},
203+
});
203204
}
204205

205206
std::string_view Target::CompileCommand() const {

buildcc/lib/target/src/util/command.cpp

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,51 @@
1414
* limitations under the License.
1515
*/
1616

17-
#include "internal/util.h"
17+
#include "internal/command.h"
1818

19+
#include <algorithm>
20+
21+
#include "fmt/format.h"
1922
#include "logging.h"
2023

21-
#include "process.hpp"
24+
namespace buildcc::internal {
2225

23-
namespace tpl = TinyProcessLib;
26+
void Command::AddDefaultArguments(
27+
const std::unordered_map<const char *, std::string> &arguments) {
28+
default_values_.insert(arguments.begin(), arguments.end());
29+
}
2430

25-
namespace buildcc::internal {
31+
std::string Command::Construct(
32+
std::string_view format,
33+
const std::unordered_map<const char *, std::string> &arguments) const {
34+
// Construct your arguments
35+
fmt::dynamic_format_arg_store<fmt::format_context> store;
36+
std::string constructed_string;
37+
try {
2638

27-
bool command(const std::string &command) {
28-
buildcc::env::log_debug("system", command);
39+
std::for_each(default_values_.cbegin(), default_values_.cend(),
40+
[&store](const std::pair<const char *, std::string> &p) {
41+
store.push_back(fmt::arg(p.first, p.second));
42+
});
43+
44+
std::for_each(arguments.cbegin(), arguments.cend(),
45+
[&store](const std::pair<const char *, std::string> &p) {
46+
store.push_back(fmt::arg(p.first, p.second));
47+
});
48+
49+
// Construct your command
50+
constructed_string = fmt::vformat(format, store);
51+
} catch (const std::exception &e) {
52+
env::assert_fatal(false, e.what());
53+
}
54+
return constructed_string;
55+
}
2956

30-
tpl::Process process(command);
31-
return process.get_exit_status() == 0;
57+
bool Command::ConstructAndExecute(
58+
std::string_view format,
59+
const std::unordered_map<const char *, std::string> &arguments) const {
60+
const std::string constructed_command = Construct(format, arguments);
61+
return Execute(constructed_command);
3262
}
3363

3464
} // namespace buildcc::internal
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2021 Niket Naidu. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "internal/command.h"
18+
19+
#include "logging.h"
20+
21+
#include "process.hpp"
22+
23+
namespace tpl = TinyProcessLib;
24+
25+
namespace buildcc::internal {
26+
27+
bool Command::Execute(const std::string &command) {
28+
// Run the process
29+
buildcc::env::log_debug("system", command);
30+
tpl::Process process(command);
31+
return process.get_exit_status() == 0;
32+
}
33+
34+
} // namespace buildcc::internal

0 commit comments

Comments
 (0)