- [NEW] Recopilació d'arxius abans de començar el procés

- [NEW] paràmetre "-r" per a forçar recompilació de tot
- [NEW] Menys verbós i amb barra de progrés
This commit is contained in:
2026-05-04 11:32:28 +02:00
parent 1f17e941df
commit 8adcf8a330

231
main.cpp
View File

@@ -3,9 +3,9 @@
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
#include <vector> #include <vector>
#include <unordered_map>
#include <chrono> #include <chrono>
#include <algorithm> #include <algorithm>
#include <string.h> #include <string.h>
std::string libs = ""; std::string libs = "";
@@ -25,6 +25,68 @@ std::vector<std::string> keys = {"libs", "cppflags", "executable", "sourcepath",
enum tokens {LIBS, CPPFLAGS, EXECUTABLE, SOURCEPATH, BUILDPATH, EXCLUDE}; enum tokens {LIBS, CPPFLAGS, EXECUTABLE, SOURCEPATH, BUILDPATH, EXCLUDE};
bool must_link = false; bool must_link = false;
bool must_recompile_all = false;
struct FileInfo {
std::string filename;
std::filesystem::file_time_type time;
std::vector<int> included_headers;
};
std::vector<FileInfo> headers;
std::unordered_map<std::string, int> 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<FileInfo> cpp_files;
std::unordered_map<std::string, int> 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<std::string>& v, const std::string& s) { return std::find(v.begin(), v.end(), s) != v.end(); } bool contains(const std::vector<std::string>& v, const std::string& s) { return std::find(v.begin(), v.end(), s) != v.end(); }
@@ -234,40 +296,20 @@ std::vector<std::string> getIncludes(const std::string &filename) {
return includes; return includes;
} }
bool HeadersNeedRecompile(std::string file, std::filesystem::file_time_type object_file_write_time) { bool HeadersNeedRecompile(FileInfo file, std::filesystem::file_time_type object_file_write_time) {
auto include_files = getIncludes(file); for (auto include : file.included_headers) {
for (auto include : include_files) { auto include_file_write_time = headers[include].time;
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);
if (include_file_write_time > object_file_write_time) { if (include_file_write_time > object_file_write_time) {
return true; return true;
} else { } else {
if (HeadersNeedRecompile(include_file, object_file_write_time)) return true; if (HeadersNeedRecompile(headers[include], object_file_write_time)) return true;
}
} }
} }
return false; return false;
} }
bool MustRecompile(std::string source_file) { bool MustRecompile(FileInfo file) {
std::string object_file = build_path + folder_char + getFileNameWithoutExtension(source_file)+".o"; std::string object_file = build_path + folder_char + std::filesystem::path(file.filename).stem().string() + ".o";
// si el objecte no existeix, fa falta recompilar // si el objecte no existeix, fa falta recompilar
if (!std::filesystem::exists(object_file)) { 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); 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 // 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) { if (source_file_write_time > object_file_write_time) {
return true; return true;
} else { } else {
if (HeadersNeedRecompile(source_file, object_file_write_time)) return true; if (HeadersNeedRecompile(file, object_file_write_time)) return true;
} }
} }
return false; return false;
} }
void MaybeRecompile(std::string source_file) { void Recompile(std::string source_file) {
if (MustRecompile(source_file)) { std::string object_file = build_path + folder_char + std::filesystem::path(source_file).stem().string() + ".o";
std::string object_file = build_path + folder_char + getFileNameWithoutExtension(source_file)+".o";
must_link = true; must_link = true;
std::string command = "g++ " + source_file + " " + cppflags + " -c -o " + object_file; std::string command = "g++ " + source_file + " " + cppflags + " -c -o " + object_file;
std::cout << command << std::endl; //std::cout << command << std::endl;
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); if (system(command.c_str()) != 0) {
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<std::chrono::microseconds>(end - begin).count())/1000000;
std::cout << "(" << t << " seconds)" << std::endl;
if (result != 0) {
std::cout << "Compilation failed! Aborting..." << std::endl; std::cout << "Compilation failed! Aborting..." << std::endl;
exit(1); 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 { } else {
//std::cout << object_file << " està actualitzat" << std::endl; 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<int>& 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<FileInfo>& 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, ' ') << "<no headers>" << 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) { 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[]) int main(int argc, char *argv[])
@@ -329,11 +441,18 @@ int main(int argc, char *argv[])
exit(1); 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(); 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); if (!std::filesystem::is_directory(build_path)) std::filesystem::create_directory(build_path);
source_paths = split(source_path); source_paths = split(source_path);
// Recopilem tots els arxius cpp i capçaleres
// ===================================================================
for (auto &src_path : source_paths) { for (auto &src_path : source_paths) {
bool recursive = false; bool recursive = false;
@@ -351,7 +470,8 @@ int main(int argc, char *argv[])
std::string ext = getFileExtension(src_path); std::string ext = getFileExtension(src_path);
if (ext == "cpp" || ext == "c") { if (ext == "cpp" || ext == "c") {
MaybeRecompile(src_path); process_cpp(src_path);
//MaybeRecompile(src_path);
} else { } else {
std::cout << "ERROR: '" << src_path << "' is not a .c/.cpp file." << std::endl; std::cout << "ERROR: '" << src_path << "' is not a .c/.cpp file." << std::endl;
exit(1); exit(1);
@@ -371,7 +491,8 @@ int main(int argc, char *argv[])
std::string ext = getFileExtension(source_file); std::string ext = getFileExtension(source_file);
if ((ext == "cpp" || ext == "c") && !contains(exclude, entry.path().filename().string())) { if ((ext == "cpp" || ext == "c") && !contains(exclude, entry.path().filename().string())) {
MaybeRecompile(source_file); process_cpp(source_file);
//MaybeRecompile(source_file);
} }
} }
} else { } else {
@@ -382,20 +503,36 @@ int main(int argc, char *argv[])
std::string ext = getFileExtension(source_file); std::string ext = getFileExtension(source_file);
if ((ext == "cpp" || ext == "c") && !contains(exclude, entry.path().filename().string())) { 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) { if (must_link) {
std::string command = "g++ " + build_path + folder_char + "*.o " + libs + " -o " + executable; 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) { if (system(command.c_str()) != 0) {
std::cout << "ABORTED!" << std::endl; std::cout << "ABORTED!" << std::endl;
exit(1); exit(1);
} }
std::cout << "DONE!" << std::endl;
std::chrono::steady_clock::time_point end_all = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point end_all = std::chrono::steady_clock::now();
float t = float(std::chrono::duration_cast<std::chrono::microseconds>(end_all - begin_all).count())/1000000; float t = float(std::chrono::duration_cast<std::chrono::microseconds>(end_all - begin_all).count())/1000000;
std::cout << "(" << t << " seconds)" << std::endl; std::cout << "(" << t << " seconds)" << std::endl;