CBuild
C++ build system with scripts written in c++
Loading...
Searching...
No Matches
hash.cpp
Go to the documentation of this file.
1
20// C++ libraries
21#include "fstream"
22#include "iostream"
23#include "regex"
24#include "sstream"
25#include "string"
26#include "vector"
27// CBuild headers
32#include "../../headers/map.hpp"
35// Code
36/* namespace CBuild */
37namespace CBuild {
41namespace consts {
45std::regex cxx_line_comment("//.*");
49std::regex c_multiline_comment("/\\*([\\s\\S]*?)\\*/");
53std::regex doxygen_comment("/\\*\\*([\\s\\S]*?)\\*/");
57std::regex include_parser("#include\\s+[\"<]([^\">]+)[\">]");
61std::regex check_type("\\.(cpp|cxx|cc|c)");
62} // namespace consts
63namespace types {
68struct file {
72 std::string abs_path;
76 std::vector<CBuild::types::file> includes;
80 uint64_t hash_new;
88 bool cpp;
92 bool change;
96 std::string object;
102 file(std::string path) {
103 this->change = false;
104 this->hash_new = 0;
105 this->hash_old.clear();
106 this->abs_path = path;
107 this->includes.clear();
108 if (std::regex_search(this->abs_path, CBuild::consts::check_type)) {
109 this->cpp = true;
110 } else {
111 this->cpp = false;
112 }
113 this->object = "";
114 }
115};
124 std::string content;
128 std::string path;
132 std::vector<std::string> includes;
133};
134} // namespace types
135namespace vars {
136std::vector<CBuild::types::file> filelist;
139} // namespace vars
148CBuild::types::file_content get_file_data(std::string path, std::string included_from = "") {
149 // Return variable
150 std::string p = path;
151 // Set path to file
152 included_from = CBuild::fs::base(included_from);
153 try {
155 } catch (const std::exception& e) {
156 CBuild::print_full(std::string("Error in path creation, path - \"") + path +
157 std::string("\", included_from - \"") + included_from +
158 std::string("\""),
160 exit(0xFF);
161 }
163 f.path = p;
164 // Load file content to string
165 std::ifstream file(path);
166 std::stringstream buff;
167 buff << file.rdbuf();
168 file.close();
169 std::string str = buff.str();
170 // Strip comments from file
171 str = std::regex_replace(str, CBuild::consts::cxx_line_comment, "");
172 str = std::regex_replace(str, CBuild::consts::c_multiline_comment, "");
173 str = std::regex_replace(str, CBuild::consts::doxygen_comment, "");
174 f.content = str;
175 // Get includes
176 std::smatch match;
177 std::string::const_iterator start(str.cbegin());
178 // Base file path
179 std::string base = CBuild::fs::base(path);
180 while (std::regex_search(start, str.cend(), match, CBuild::consts::include_parser)) {
181 // Get file
182 std::string head = match[1];
183 bool err = false;
184 // Convert to CBuild.run-relative path
185 try {
186 head = CBuild::fs::normalize_relative_path(head, base);
187 } catch (const std::exception& e) {
188 }
189 // Check for system includes
190 err = !CBuild::fs::exists(head);
191 // Push path, if it is project include
192 if (!err) {
193 f.includes.push_back(head);
194 }
195 start = match.suffix().first;
196 }
197 return f;
198}
199// /**
200// * @brief djb2 hashing function for std::string
201// *
202// * @param str => std::string -> Input string
203// * @return uint64_t -> Hash of data
204// */
205// uint64_t hash(std::string str) {
206// uint64_t hash = 5381;
207// for (auto ch : str) {
208// hash = ((hash << 5) + hash) + ch;
209// }
210// return hash;
211// }
218uint64_t hash(std::string str) {
219 uint64_t hash = 14695981039346656037ULL;
220 for (char c : str) {
221 hash ^= static_cast<uint64_t>(c);
222 hash *= 1099511628211ULL;
223 }
224 return hash;
225}
233void procces_files(std::vector<std::string> files, std::vector<std::string> objects,
234 std::string toolchain_id) {
235 CBuild::print_full("\t\t\tCBuild hash v3.0", CBuild::color::MAGENTA);
236 // For every input file
237 for (size_t i = 0; i < files.size(); i++) {
238 std::string file, object;
239 file = files.at(i);
240 object = objects.at(i);
241 // Get file data
242 auto data = CBuild::get_file_data(file);
243 auto cpp = CBuild::types::file(data.path);
244 cpp.object = object;
245 // Get file hash
246 cpp.hash_new = CBuild::hash(data.content);
247 CBuild::print_full("Calculating hash for \"" + cpp.abs_path + "\"", CBuild::color::GREEN);
248 CBuild::print_full("Need to calculate hash...", CBuild::color::RED);
249 auto old = CBuild::vars::old_hashes.get(cpp.abs_path);
250 if (old != NULL) {
251 cpp.hash_old.set(*old);
252 }
253 // For every invclude
254 for (auto inc : data.includes) {
255 // Get file data
256 auto hdata = CBuild::get_file_data(inc, cpp.abs_path);
257
258 auto hpp = CBuild::types::file(hdata.path);
259 // Check if hash is already stored in hash
260 const uint64_t* hash = NULL;
261 CBuild::print_full("Calculating hash for \"" + hpp.abs_path + "\"",
263 if ((hash = CBuild::vars::headers.get(hpp.abs_path)) != NULL) {
264 // Use stored hash
265 hpp.hash_new = *hash;
266 CBuild::print_full("Using hash from cache.", CBuild::color::GREEN);
267 } else {
268 // Calculate file hash
269 hpp.hash_new = CBuild::hash(hdata.content);
270 CBuild::print_full("Need to calculate hash...", CBuild::color::RED);
271 }
272 auto old = CBuild::vars::old_hashes.get(hpp.abs_path);
273 if (old != NULL) {
274 hpp.hash_old.set(*old);
275 }
276 // Store hash
277 try {
278 CBuild::vars::headers.push_back_check(hpp.abs_path, hpp.hash_new);
279 } catch (std::exception& e) {
280 // So, we already have this hash, we dont need to do anything
281 }
282 // Store proccesed include
283 cpp.includes.push_back(hpp);
284 }
285 // Store proccesed file
286 CBuild::vars::filelist.push_back(cpp);
287 }
288}
294void store_hash(std::string toolchain_id) {
295 for (auto cpp : CBuild::vars::filelist) {
296 int err = CBuild::write_file_hash(toolchain_id, cpp.abs_path, &cpp.hash_new);
297 if (err == -1) {
298 CBuild::fs::create({CBuild::get_file_metadata_path(toolchain_id, cpp.abs_path)},
301 for (auto inc : cpp.includes) {
302 m.deps.push_back(inc.abs_path);
303 }
304 m.hash = cpp.hash_new;
305 m.source = cpp.abs_path;
306 m.object = cpp.object;
307 CBuild::write_file_metadata(toolchain_id, cpp.abs_path, &m);
308 }
309 }
310 for (auto hpp : CBuild::vars::headers) {
311 int err = CBuild::write_file_hash(toolchain_id, hpp.key, &hpp.data);
312 if (err == -1) {
313 CBuild::fs::create({CBuild::get_file_metadata_path(toolchain_id, hpp.key)},
316 m.hash = hpp.data;
317 m.deps = {};
318 m.source = hpp.key;
319 m.object = "header";
320 CBuild::write_file_metadata(toolchain_id, hpp.key, &m);
321 }
322 }
323}
329void load_hash(std::string toolchain_id) {
330 std::string path = CBUILD_BUILD_DIR + "/" + toolchain_id + "/" + CBUILD_METADATA_FOLDER + "/";
331 auto files = CBuild::fs::dir(path, ".*\\.meta");
332 for (auto f : files) {
334 CBuild::read_file_metadata_direct(toolchain_id, f, &m);
335 auto file = m.source;
336 auto hash = m.hash;
337 try {
338 CBuild::vars::old_hashes.push_back_check(file, hash);
339 } catch (std::exception& e) {
340 CBuild::print_full(std::string("Error, multiple metadata files found for file ") + file,
342 }
343 }
344 // std::string path =
345 // CBUILD_BUILD_DIR + "/" + toolchain_id + "/" + CBUILD_HASH_DIR + "/" + CBUILD_HASH_FILE;
346 // if (!CBuild::fs::exists(path)) {
347 // return;
348 // }
349 // std::ifstream file(path);
350 // std::string line;
351 // while (std::getline(file, line)) {
352 // std::istringstream iss(line);
353 // std::string key;
354 // uint64_t value;
355 // iss >> key >> std::hex >> value;
356
357 // try {
358 // CBuild::vars::old_hashes.push_back_check(key, value);
359 // } catch (const std::exception& e) {
360 // // Maybe we have some previvous errors, and somehowe we have two
361 // // simmilar hashes, so, save only first, in future we fix this by
362 // // fully recreating file
363 // }
364 // }
365 // file.close();
366}
367} // namespace CBuild
368/* hash.hpp */
370 CBuild::print_full("\t\t\tCBuild hash v3.0 - Filelist", CBuild::color::MAGENTA);
371 std::stringstream buff;
372 for (auto file : CBuild::vars::filelist) {
373 buff << "\t\t" << file.abs_path << "\n"
374 << std::hex << "New hash: " << file.hash_new << ", old hash: ";
375 if (file.hash_old.is()) {
376 buff << std::hex << file.hash_old.get() << "\n";
377 } else {
378 buff << " null\n";
379 }
380 CBuild::print_full(buff.str());
381 buff.str("");
382 for (auto hfile : file.includes) {
383 buff << "\t\t\t" << hfile.abs_path << "\n"
384 << std::hex << "\tNew hash: " << hfile.hash_new << ", old hash: ";
385 if (hfile.hash_old.is()) {
386 buff << std::hex << hfile.hash_old.get() << "\n";
387 } else {
388 buff << " null\n";
389 }
390 CBuild::print_full(buff.str());
391 buff.str("");
392 }
393 }
394}
395std::vector<std::string> CBuild::get_files(std::vector<std::string> files,
396 std::vector<std::string> objects,
397 std::string toolchain_id) {
398 // Variables
399 std::vector<std::string> ret;
400 // Gather all file info and relevant hashes
401 CBuild::load_hash(toolchain_id);
402 CBuild::procces_files(files, objects, toolchain_id);
403 CBuild::store_hash(toolchain_id);
405 // Check differences in hashes
406 for (auto file : CBuild::vars::filelist) {
407 if ((!file.hash_old.is()) || (file.hash_new != file.hash_old.get())) {
408 ret.push_back(file.abs_path);
409 } else {
410 for (auto inc : file.includes) {
411 if ((!inc.hash_old.is()) || (inc.hash_new != inc.hash_old.get())) {
412 ret.push_back(file.abs_path);
413 } else {
414 }
415 }
416 }
417 }
418 // Clear oll things
419 CBuild::vars::headers.clear();
422 // Return value
423 return ret;
424}
#define CBUILD_METADATA_FOLDER
Metadata folder for targets.
#define CBUILD_BUILD_DIR
Build directory of CBuild.
Build metadata config file.
Simple map implementation with some stack operation added.
Definition map.hpp:79
Optional data type.
Definition optional.hpp:32
void clear()
Clear value.
Definition optional.hpp:71
filesystem++ api
Custom implementation of map datatype.
std::regex check_type("\\.(cpp|cxx|cc|c)")
For checking for source file.
std::regex include_parser("#include\\s+[\"<]([^\">]+)[\">]")
Get include directives from file and parse file name in it.
std::regex cxx_line_comment("//.*")
Regex for stripping c++ line comments from file.
std::regex doxygen_comment("/\\*\\*([\\s\\S]*?)\\*/")
Regex for stripping doxygen comments from file comtent.
std::regex c_multiline_comment("/\\*([\\s\\S]*?)\\*/")
Regex for stripping c multiline comments from file comtent.
bool exists(std::string path)
Check if file exists.
bool create(std::vector< std::string > paths, CBuild::fs::type what)
Create element.
std::string base(std::string file)
Get base file path (path to dir in what file is)
std::string normalize_relative_path(std::string path, std::string base_path="")
Get absolute path to file using relative path and base path.
@ FILE
Standard file.
std::vector< std::string > dir(std::string path, std::string search)
Search files using provided regex.
lib::map< std::string, uint64_t > old_hashes
Definition hash.cpp:138
std::vector< CBuild::types::file > filelist
Definition hash.cpp:136
lib::map< std::string, uint64_t > headers
Definition hash.cpp:137
Filebuffer for CBuild ecosystem.
Definition Build.hpp:34
uint64_t hash(std::string str)
FNV-1a hashing function for std::string.
Definition hash.cpp:218
CBuild::types::file_content get_file_data(std::string path, std::string included_from="")
Get content of file.
Definition hash.cpp:148
int write_file_hash(std::string target_id, std::string file, uint64_t *hash)
@ RED
Definition print.hpp:34
@ MAGENTA
Definition print.hpp:38
@ GREEN
Definition print.hpp:35
void load_hash(std::string toolchain_id)
Load old hashes.
Definition hash.cpp:329
void store_hash(std::string toolchain_id)
Store new hashes to file.
Definition hash.cpp:294
int read_file_metadata_direct(std::string target_id, std::string file, CBuild::source_metadata_file *metadata)
Load metadata for source file.
int write_file_metadata(std::string target_id, std::string src_file, CBuild::source_metadata_file *metadata)
Write a metadata for a file to a file.
void exit(int code)
std::vector< std::string > get_files(std::vector< std::string > files, std::vector< std::string > objects, std::string toolchain_id)
Get changed files.
Definition hash.cpp:395
void print_files()
Print temporary file array.
Definition hash.cpp:369
std::string get_file_metadata_path(std::string target_id, std::string file)
Get the path to a file metadata file.
void print_full(std::string msg, color fg=CBuild::WHITE)
Print colored text to STDOUT if verbose flag is set.
Definition print.cpp:75
void procces_files(std::vector< std::string > files, std::vector< std::string > objects, std::string toolchain_id)
Procces file data.
Definition hash.cpp:233
Custom print that support color codes.
Metadata for source files (.cpp/.c/etc) Structure of file:
std::string source
Source file path (relative to CBuild.run)
std::vector< std::string > deps
On what files this file depends.
uint64_t hash
Hash of this file.
Temporary struct for file content.
Definition hash.cpp:120
std::vector< std::string > includes
Includes.
Definition hash.cpp:132
std::string path
Absolute path to file.
Definition hash.cpp:128
std::string content
Content of file.
Definition hash.cpp:124
File structure.
Definition hash.cpp:68
file(std::string path)
Create new file structure, simply init all values.
Definition hash.cpp:102
uint64_t hash_new
New file hash.
Definition hash.cpp:80
bool cpp
Does file is cpp file.
Definition hash.cpp:88
std::vector< CBuild::types::file > includes
Project includes.
Definition hash.cpp:76
std::string object
Related objet file.
Definition hash.cpp:96
std::string abs_path
Absolute file path.
Definition hash.cpp:72
lib::optional< uint64_t > hash_old
Old file hash.
Definition hash.cpp:84
bool change
Does file changed.
Definition hash.cpp:92