diff --git a/main.cpp b/main.cpp index 1e03f7c..5fb59f6 100644 --- a/main.cpp +++ b/main.cpp @@ -3,9 +3,9 @@ #include #include #include +#include #include #include - #include std::string libs = ""; @@ -25,6 +25,68 @@ std::vector keys = {"libs", "cppflags", "executable", "sourcepath", enum tokens {LIBS, CPPFLAGS, EXECUTABLE, SOURCEPATH, BUILDPATH, EXCLUDE}; bool must_link = false; +bool must_recompile_all = false; + +struct FileInfo { + std::string filename; + std::filesystem::file_time_type time; + std::vector included_headers; +}; +std::vector headers; +std::unordered_map header_index; + +bool has_header(const std::string& name) { + return header_index.find(name) != header_index.end(); +} +int get_header_index(const std::string& name) { + auto it = header_index.find(name); + return (it != header_index.end()) ? it->second : -1; +} +int add_header(const std::string& name) { + auto it = header_index.find(name); + if (it != header_index.end()) + return it->second; + + int index = headers.size(); + headers.push_back({name, std::filesystem::last_write_time(name), {}}); + header_index[name] = index; + return index; +} +void add_include_to_header(int header_id, const std::string& header_name) { + int h = add_header(header_name); + headers[header_id].included_headers.push_back(h); +} +/*bool is_header_changed(const std::string& name) { + auto it = header_index.find(name); + if (it == header_index.end()) return false; + return headers[it->second].changed; +}*/ + +std::vector cpp_files; +std::unordered_map cpp_index; + +bool has_cpp(const std::string& name) { + return cpp_index.find(name) != cpp_index.end(); +} +int get_cpp_index(const std::string& name) { + auto it = cpp_index.find(name); + return (it != cpp_index.end()) ? it->second : -1; +} +int add_cpp(const std::string& name) { + auto it = cpp_index.find(name); + if (it != cpp_index.end()) + return it->second; + + int index = cpp_files.size(); + cpp_files.push_back({name, std::filesystem::last_write_time(name), {}}); + cpp_index[name] = index; + return index; +} +void add_include_to_cpp(int cpp_id, const std::string& header_name) { + int h = add_header(header_name); + cpp_files[cpp_id].included_headers.push_back(h); +} + bool contains(const std::vector& v, const std::string& s) { return std::find(v.begin(), v.end(), s) != v.end(); } @@ -234,40 +296,20 @@ std::vector getIncludes(const std::string &filename) { return includes; } -bool HeadersNeedRecompile(std::string file, std::filesystem::file_time_type object_file_write_time) { - auto include_files = getIncludes(file); - for (auto include : include_files) { - std::filesystem::path fullpath(file); - auto path_without_filename = fullpath.remove_filename(); - std::string src_path = path_without_filename.string(); - - std::string include_file = src_path + include; - bool found = std::filesystem::exists(include_file); - if (!found) { - for (auto path : source_paths) { - include_file = path + "/" + include; - if (std::filesystem::exists(include_file)) { - found = true; - break; - } - } - } - if (!found) { - std::cout << "WARNING: Include file '" << include << "' not found in '" << file << "'." << std::endl; - } else { - auto include_file_write_time = std::filesystem::last_write_time(include_file); +bool HeadersNeedRecompile(FileInfo file, std::filesystem::file_time_type object_file_write_time) { + for (auto include : file.included_headers) { + auto include_file_write_time = headers[include].time; if (include_file_write_time > object_file_write_time) { return true; } else { - if (HeadersNeedRecompile(include_file, object_file_write_time)) return true; + if (HeadersNeedRecompile(headers[include], object_file_write_time)) return true; } - } } return false; } -bool MustRecompile(std::string source_file) { - std::string object_file = build_path + folder_char + getFileNameWithoutExtension(source_file)+".o"; +bool MustRecompile(FileInfo file) { + std::string object_file = build_path + folder_char + std::filesystem::path(file.filename).stem().string() + ".o"; // si el objecte no existeix, fa falta recompilar if (!std::filesystem::exists(object_file)) { @@ -277,41 +319,111 @@ bool MustRecompile(std::string source_file) { auto object_file_write_time = std::filesystem::last_write_time(object_file); // Si la data de modificació del cpp es major que la del objecte, fa falta recompilar - auto source_file_write_time = std::filesystem::last_write_time(source_file); + auto source_file_write_time = file.time; if (source_file_write_time > object_file_write_time) { return true; } else { - if (HeadersNeedRecompile(source_file, object_file_write_time)) return true; + if (HeadersNeedRecompile(file, object_file_write_time)) return true; } } return false; } -void MaybeRecompile(std::string source_file) { - if (MustRecompile(source_file)) { - std::string object_file = build_path + folder_char + getFileNameWithoutExtension(source_file)+".o"; - must_link = true; - std::string command = "g++ " + source_file + " " + cppflags + " -c -o " + object_file; - std::cout << command << std::endl; +void Recompile(std::string source_file) { + std::string object_file = build_path + folder_char + std::filesystem::path(source_file).stem().string() + ".o"; + must_link = true; + std::string command = "g++ " + source_file + " " + cppflags + " -c -o " + object_file; + //std::cout << command << std::endl; - std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); - int result = system(command.c_str()); - std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); - - float t = float(std::chrono::duration_cast(end - begin).count())/1000000; - std::cout << "(" << t << " seconds)" << std::endl; - - if (result != 0) { - std::cout << "Compilation failed! Aborting..." << std::endl; - exit(1); - } - } else { - //std::cout << object_file << " està actualitzat" << std::endl; + if (system(command.c_str()) != 0) { + std::cout << "Compilation failed! Aborting..." << std::endl; + exit(1); } } +void process_includes(int index, std::string& file, bool is_cpp = false) +{ + // Trobem els includes en l'arxiu + auto include_files = getIncludes(file); + + // Per a cada include... + for (auto& include : include_files) { + // montem la ruta al include a partir de la del arxiu que l'inclou + std::string include_file = std::filesystem::path(file).remove_filename().string() + include; + // Comprobem si existeix relativament a l'arxiu que l'inclou + bool found = std::filesystem::exists(include_file); + if (!found) { + // Si no, comprobem si existeix relativament a cada un dels source paths especificats + for (auto path : source_paths) { + include_file = path + "/" + include; + if (std::filesystem::exists(include_file)) { + found = true; + break; + } + } + } + // Si existeix l'incloguem + if (found) { + auto header_absolute_path = std::filesystem::weakly_canonical(include_file).string(); + const bool already_exists = (has_header(header_absolute_path)); + if (is_cpp) + add_include_to_cpp(index, header_absolute_path); + else + add_include_to_header(index, header_absolute_path); + if (!already_exists) process_includes(get_header_index(header_absolute_path), header_absolute_path); + } else { + std::cout << "WARNING: file '" << include <<"' not found" << std::endl; + } + } +} + +void process_cpp(std::string& file) +{ + std::string absolute_path = std::filesystem::weakly_canonical(file); + //std::cout << absolute_path << std::endl; + int index = add_cpp(absolute_path); + + process_includes(index, absolute_path, true); +} + +void print_header_tree(int indent, const std::vector& files) +{ + for (auto index : files) { + std::cout << std::string(indent*2, ' ') << headers[index].filename << std::endl; + auto &include_list = headers[index].included_headers; + if (!include_list.empty()) print_header_tree(indent+1, include_list); + } +} +void print_file_tree(int indent, const std::vector& files) +{ + for (auto& file : files) { + std::cout << std::string(indent*2, ' ') << file.filename << std::endl; + auto &include_list = file.included_headers; + if (!include_list.empty()) { + print_header_tree(indent+1, include_list); + } else { + std::cout << std::string((indent+1)*2, ' ') << "" << std::endl; + } + } +} + +void progress_bar(int percent) { + const int width = 50; // ancho de la barra + int filled = (percent * width) / 100; + + printf("\r["); + for (int i = 0; i < width; i++) { + if (i < filled) printf("#"); + else printf(" "); + } + printf("] %3d%%", percent); + + fflush(stdout); +} + void processCommand(std::string arg) { - // Do nothing for now + std::cout << "command: '" << arg << "'" << std::endl; + if (arg == "-r") must_recompile_all = true; } int main(int argc, char *argv[]) @@ -329,11 +441,18 @@ int main(int argc, char *argv[]) exit(1); } + if (must_recompile_all) { + std::cout << "remove: '" << build_path << "'" << std::endl; + std::filesystem::remove_all(build_path); + } + std::chrono::steady_clock::time_point begin_all = std::chrono::steady_clock::now(); if (!std::filesystem::is_directory(build_path)) std::filesystem::create_directory(build_path); source_paths = split(source_path); + // Recopilem tots els arxius cpp i capçaleres + // =================================================================== for (auto &src_path : source_paths) { bool recursive = false; @@ -351,7 +470,8 @@ int main(int argc, char *argv[]) std::string ext = getFileExtension(src_path); if (ext == "cpp" || ext == "c") { - MaybeRecompile(src_path); + process_cpp(src_path); + //MaybeRecompile(src_path); } else { std::cout << "ERROR: '" << src_path << "' is not a .c/.cpp file." << std::endl; exit(1); @@ -371,7 +491,8 @@ int main(int argc, char *argv[]) std::string ext = getFileExtension(source_file); if ((ext == "cpp" || ext == "c") && !contains(exclude, entry.path().filename().string())) { - MaybeRecompile(source_file); + process_cpp(source_file); + //MaybeRecompile(source_file); } } } else { @@ -382,20 +503,36 @@ int main(int argc, char *argv[]) std::string ext = getFileExtension(source_file); if ((ext == "cpp" || ext == "c") && !contains(exclude, entry.path().filename().string())) { - MaybeRecompile(source_file); + process_cpp(source_file); + //MaybeRecompile(source_file); } } } } } + //print_file_tree(0, cpp_files); + + int i = 0; + int total = cpp_files.size(); + progress_bar(0); + for (auto& file : cpp_files) { + if (MustRecompile(file)) Recompile(file.filename); + progress_bar(100*float(float(i)/float(total))); + i++; + } + progress_bar(100); + std::cout << std::endl; + if (must_link) { std::string command = "g++ " + build_path + folder_char + "*.o " + libs + " -o " + executable; - std::cout << command << std::endl; + //std::cout << command << std::endl; + std::cout << "Linking..."; fflush(stdout); if (system(command.c_str()) != 0) { std::cout << "ABORTED!" << std::endl; exit(1); } + std::cout << "DONE!" << std::endl; std::chrono::steady_clock::time_point end_all = std::chrono::steady_clock::now(); float t = float(std::chrono::duration_cast(end_all - begin_all).count())/1000000; std::cout << "(" << t << " seconds)" << std::endl;