CBuild
C++ build system with scripts written in c++
Loading...
Searching...
No Matches
generator.cpp
Go to the documentation of this file.
1
22// C++ libraries
23#include "array"
24#include "fstream"
25#include "iostream"
26#include "string"
27#include "string_view"
28#include "vector"
29// Project includes
35#include "../../headers/map.hpp"
39/* makefile.hpp */
41 std::vector<std::string>* pargs) {
42 CBuild::print("Generating Makefile ...", CBuild::color::MAGENTA);
43 // Get command log
44 auto log = CBuild::get_log();
45 // Create Makefile if needed
46 if (!CBuild::fs::exists(this->OUT)) {
48 }
49 // Open file
50 std::ofstream makefile;
51 makefile.open(this->OUT, std::ios::app);
52 std::string name = "";
53 // Create name of make task, first part - CBuild run type or
54 // cbuild_ placeholder
55 switch (mode) {
56 case CBuild::BUILD:
57 name += "build_";
58 break;
60 name += "build_run_";
61 break;
62 case CBuild::RUN:
63 name += "run_";
64 break;
65 case CBuild::CLEAR:
66 name += "clear_";
67 break;
68 case CBuild::DEBUG:
69 name += "debug_";
70 break;
71 case CBuild::TASK:
72 name += "task_";
73 break;
74 default:
75 name += "cbuild_";
76 break;
77 }
78 // Second part of make task - target or task id or cbuild
79 // placeholder
80 if (mode == CBuild::BUILD || mode == CBuild::BUILD_RUN || mode == CBuild::RUN ||
81 mode == CBuild::DEBUG || mode == CBuild::CLEAR) {
82 name += *(args->get("toolchain_id"));
83 } else if (mode == CBuild::TASK) {
84 name += *(args->get("task_id"));
85 } else {
87 }
88 // Write all executed command to Makefile
89 makefile << "\n";
90 makefile << name << ":\n";
91 for (auto elem : *log) {
92 makefile << "\t" << elem << "\n";
93 }
94 // End Makefile
95 makefile << "\n";
96 makefile.close();
97}
99 return true;
100}
101/* ccj.hpp - helper */
102namespace CBuild {
113std::string eval_cmd(std::array<std::string, 4> data) {
114 std::string cmd = data[2] + " -c ";
115 cmd += data[0];
116 cmd += " ";
117 cmd += data[3];
118 cmd += " -o ";
119 cmd += data[1];
120 return cmd;
121}
125typedef struct {
129 std::string base_path;
133 std::string cmd;
137 std::string file;
142} cmd;
149std::string preprocess_json_str(std::string_view str) {
150 std::string ret;
151 for (char c : str) {
152 switch (c) {
153 case '\"':
154 ret += "\\\"";
155 break;
156 case '\\':
157 ret += "\\\\";
158 break;
159 case '/':
160 ret += "\\/";
161 break;
162 case '\b':
163 ret += "\\b";
164 break;
165 case '\f':
166 ret += "\\f";
167 break;
168 case '\n':
169 ret += "\\n";
170 break;
171 case '\r':
172 ret += "\\r";
173 break;
174 case '\t':
175 ret += "\\t";
176 break;
177 default:
178 ret += c;
179 break;
180 }
181 }
182 return ret;
183}
184} // namespace CBuild
185//{
186// "directory": "/home/wolodiam/dev/c++/CBuild",
187// "command": "g++ -c file.cpp -std=c++20 -o file.o",
188// "file": "/home/wolodiam/dev/c++/CBuild/CBuild/CBuild/src/system.cpp"
189// }
190/* ccj.hpp */
192 std::vector<std::string>* pargs) {
193 // Fail fast if we not building
194 if (mode != CBuild::BUILD) {
195 CBuild::print("Not in build mode, ERROR!", CBuild::RED);
196 return;
197 }
198 // Cannot generate compile_commands.json for meta-toolchain 'all'
199 if (*(args->get("toolchain_id")) == std::string("all")) {
200 CBuild::print("Cannot generate compile commands for meta-toolchain \"all\"", CBuild::RED);
201 return;
202 }
203 // Get commands
204 // Vars
206 // Get data from target
207 auto toolchain = CBuild::Registry::GetToolchain(*(args->get("toolchain_id")));
208 auto cmds = toolchain->get_cmds();
209 if (cmds[0] != std::string("META") && cmds[1] != std::string("META") &&
210 cmds[2] != std::string("META")) {
211 toolchain->call(pargs, true, false, true);
212 auto files = toolchain->gen_file_list_force();
213 auto targs = toolchain->get_compile_args();
214 auto dir = args->get_ptr("curr_path")->data;
215 for (auto file : files) {
216 data.push_back({file.key,
217 {.base_path = dir,
218 .cmd = CBuild::eval_cmd(
219 std::array<std::string, 4>{file.key, file.data, cmds[0], targs}),
220 .file = file.key,
221 .in_file = false}});
222 }
223 // Store in file
224 CBuild::print("Generating compile_commands.json ...", CBuild::color::MAGENTA);
225 CBuild::print("This can breaks if compile_commands.json already exists and "
226 "this file was not created by CBuild!",
228 if (CBuild::fs::exists(this->OUT) == false) {
229 CBuild::print_full("File not found, creating file...");
231 std::fstream ccj(this->OUT);
232 ccj << "[\n";
233 for (unsigned int j = 0; j < data.size(); j++) {
234 auto elem = data.at(j);
235 if (j == 0) {
236 ccj << "{";
237 } else {
238 ccj << ",\n{\n";
239 }
240 ccj << (std::string("\t\"directory\": \"") + dir + std::string("\",\n"));
241 ccj << (std::string("\t\"command\": \"") +
242 CBuild::preprocess_json_str(elem.data.cmd) + std::string("\",\n"));
243 ccj << (std::string("\t\"file\": \"") + elem.data.file + std::string("\"\n"));
244 ccj << "}";
245 }
246 ccj << "\n]";
247 } else {
248 CBuild::print_full("File found, appending...");
249 CBuild::line_filebuff ccj(this->OUT);
250 ccj.update();
251 int i = 0;
252 try {
253 while (true) {
254 std::string str = ccj.get_line(i);
255 size_t pos = str.find("\"file\":");
256 if (pos != std::string::npos) {
257 // We find file
258 size_t st = str.find_first_of('"', pos + 7);
259 size_t ed = str.find_last_of('"');
260 std::string fname = str.substr(st + 1, ed - st - 1);
261 auto elem = data.get_ptr(fname);
262 if (elem != NULL) {
263 // File is recompiled, so replace "command"
264 CBuild::print_full(std::string("Found file \"") + fname +
265 std::string("\" that is recompiled, replacing "
266 "\"command\" entry"));
267 ccj.del_line(i - 1);
268 ccj.set_line(std::string("\t\"command\": \"") +
269 CBuild::preprocess_json_str(elem->data.cmd) +
270 std::string("\","),
271 i - 1);
272 // Mark file as processed
273 elem->data.in_file = true;
274 }
275 }
276 i++;
277 }
278 } catch (std::exception& e) {
279 // Add coma at the end, no worry about this later
280 ccj.del_line(i - 2);
281 ccj.set_line("},", i - 2);
282 // Check if all files are processed
283 for (unsigned int j = 0; j < data.size(); j++) {
284 auto elem = data.at(j);
285 if (elem.data.in_file == false) {
286 CBuild::print_full(std::string("Found new file: \"") + elem.data.file +
287 std::string("\", inserting new entry"));
288 // If file is not in database - insert entry, we dont need
289 // to sert in_file tag, because this is last part, where
290 // data map is valid
291 ccj.set_line("{", i - 1);
292 i++;
293 ccj.set_line(std::string("\t\"directory\": \"") + dir + std::string("\","),
294 i - 1);
295 i++;
296 ccj.set_line(std::string("\t\"command\": \"") +
297 CBuild::preprocess_json_str(elem.data.cmd) +
298 std::string("\","),
299 i - 1);
300 i++;
301 ccj.set_line(std::string("\t\"file\": \"") + elem.data.file +
302 std::string("\""),
303 i - 1);
304 i++;
305 ccj.set_line("},", i - 1);
306 i++;
307 }
308 }
309 // Remove comma after last element as per json specs
310 ccj.del_line(i - 2);
311 ccj.set_line("}", i - 2);
312 ccj.update();
313 }
314 }
315 }
316}
319 return false;
320}
Main headers of CBuild core.
Generator for compile_command.json.
virtual bool init() override
Some init.
virtual void generate(CBuild::RType mode, lib::map< std::string, std::string > *args, std::vector< std::string > *pargs) override
Generate some output.
std::string get_line(unsigned int pos)
Get line from buffer.
Definition filebuff.hpp:390
void set_line(std::string str, unsigned int pos)
Set line in file.
Definition filebuff.hpp:407
void del_line(unsigned int pos)
Delete line from file.
Definition filebuff.hpp:428
void update()
Update file/buffer based on internal state variable.
Definition filebuff.hpp:442
virtual bool init() override
Some init.
Definition generator.cpp:98
virtual void generate(CBuild::RType mode, lib::map< std::string, std::string > *args, std::vector< std::string > *pargs) override
Generate some output.
Definition generator.cpp:40
Simple map implementation with some stack operation added.
Definition map.hpp:79
__SIZE_TYPE__ size()
Size of map.
Definition map.hpp:275
void push_back(lib::mapData< _K, _D > element)
Push new element to map, stack operation ! Dangerous not perform chak if this elemnt exists in map.
Definition map.hpp:111
const _D * get(_K key)
Get element by it's key.
Definition map.hpp:159
lib::mapData< _K, _D > at(__SIZE_TYPE__ i)
Array operation, get element at index.
Definition map.hpp:223
lib::mapData< _K, _D > * get_ptr(_K key)
Get reference to key and value of map.
Definition map.hpp:175
filesystem++ api
Makefile generator.
Custom implementation of map datatype.
CBuild::Toolchain * GetToolchain(std::string name, bool force=false)
Get the registered toolchain.
Definition register.cpp:239
bool exists(std::string path)
Check if file exists.
bool create(std::vector< std::string > paths, CBuild::fs::type what)
Create element.
@ FILE
Standard file.
Filebuffer for CBuild ecosystem.
Definition Build.hpp:34
void print(std::string msg, color fg=CBuild::WHITE)
Print colored text to STDOUT.
Definition print.cpp:70
@ RED
Definition print.hpp:34
@ MAGENTA
Definition print.hpp:38
std::vector< std::string > * get_log()
Get the internall command log.
Definition system.cpp:74
std::string eval_cmd(std::array< std::string, 4 > data)
Evaluate compilation cmd.
std::string preprocess_json_str(std::string_view str)
Preprocess string for json.
RType
Run mode.
Definition CBuild.hpp:34
@ DEBUG
Build and run target in debug mode.
Definition CBuild.hpp:54
@ RUN
Run target.
Definition CBuild.hpp:46
@ CLEAR
Clear build output and cache.
Definition CBuild.hpp:58
@ TASK
Run task.
Definition CBuild.hpp:38
@ BUILD_RUN
Build and run target.
Definition CBuild.hpp:50
@ BUILD
Build target.
Definition CBuild.hpp:42
void disable_system()
Disable system commands execution.
Definition system.cpp:77
std::string get_random_string(unsigned int length)
Generate random string with specified range, on Linux can use /dev/urandom.
Definition CBuild.cpp:570
void print_full(std::string msg, color fg=CBuild::WHITE)
Print colored text to STDOUT if verbose flag is set.
Definition print.cpp:75
std::vector< std::string > log
Definition system.cpp:32
Custom print that support color codes.
Register any things.
Command for compile_commands.json.
std::string base_path
"directory":
bool in_file
Does this entry is already in file.
std::string cmd
"command":
std::string file
"file":
Custom system() wraper.