Files
lagueirto/main.cpp
Raimon Zamora 151c2d66b4 - [FIX] Estava mirant en el buffer equivocat i nomes veïa com a molt el primer include
- [NEW] Ara també mira els includes dels includes recursivament, per a recompilar si canvien.
2025-10-11 15:58:57 +02:00

329 lines
9.6 KiB
C++

#include <string>
#include <iostream>
#include <filesystem>
#include <vector>
#include <chrono>
#include <string.h>
std::string libs = "";
std::string cppflags = "";
std::string executable = "out";
std::string source_path = "";
std::string build_path = "";
std::vector<std::string> keys = {"libs", "cppflags", "executable", "sourcepath", "buildpath"};
enum tokens {LIBS, CPPFLAGS, EXECUTABLE, SOURCEPATH, BUILDPATH};
bool must_link = false;
char *getBufferFromFile(const char* filename)
{
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
char *buffer = (char*)malloc(size+1);
fread(buffer, size, 1, f);
buffer[size] = 0;
return buffer;
}
#define IGNOREWHITESPACE while (*p!=0 && *p <= 32) { p++; }
void loadLagueirtoFile()
{
char *buffer = getBufferFromFile("lagueirtofile");
char *p = buffer;
char token[255];
while (*p!=0)
{
IGNOREWHITESPACE; // Ignore whitespace
int i=0;
while (*p>32 && *p!='=') { token[i]=*p; i++; p++; }
IGNOREWHITESPACE
if (*p=='=')
{
token[i]=0;
int tokennum = -1;
for (int j=0;j<keys.size();++j) if (keys[j]==token) tokennum = j;
if (tokennum!=-1)
{
p++;
IGNOREWHITESPACE
i=0;
while (*p!='\r' && *p!='\n' && *p!=0) { token[i]=*p; i++; p++; }
token[i]=0;
switch (tokennum)
{
case LIBS:
libs = token;
//std::cout << "LIBS: " << libs << std::endl;
break;
case CPPFLAGS:
cppflags = token;
//std::cout << "CPPFLAGS: " << cppflags << std::endl;
break;
case EXECUTABLE:
executable = token;
//std::cout << "EXECUTABLE: " << executable << std::endl;
break;
case SOURCEPATH:
source_path = token;
//std::cout << "SOURCEPATH: " << source_path << std::endl;
break;
case BUILDPATH:
build_path = token;
//std::cout << "BUILDPATH: " << build_path << std::endl;
break;
}
}
}
}
free(buffer);
}
std::string getFileExtension(std::string path)
{
std::size_t dotpos = path.find_last_of(".");
return dotpos <= 0 ? "" : path.substr(dotpos + 1);
}
std::string getFileNameWithoutExtension(std::string path)
{
std::size_t slashpos = path.find_last_of("/");
std::string filename = path.substr(slashpos+1);
std::size_t dotpos = filename.find_last_of(".");
if (dotpos <= 0) return filename;
return filename.substr(0, dotpos);
}
const bool textFound(char *buffer, const char *text)
{
const int strsize = strlen(text);
int i = 0;
bool equal=true;
while (equal && i<strsize)
{
if (buffer[i]!=text[i]) equal = false;
++i;
}
return equal;
}
std::vector<std::string> getIncludes(std::string filename)
{
char *buffer = getBufferFromFile(filename.c_str());
std::vector<std::string> includes;
char *p = buffer;
while (*p != 0)
{
// Ignore commented lines
if ( (*p=='/') && (*(p+1)!=0) && (*(p+1)=='/')) while( (*p != 0) && (*p != 13) ) p++;
// Ignore comment blocks
if ( (*p=='/') && (*(p+1)!=0) && (*(p+1)=='*')) {
p+=2;
while( (*p != 0) && (*p != '*') && (*(p+1)!=0) && (*(p+1)!='/') ) p++;
}
if (*p=='#')
{
if (textFound(p, "#include"))
{
p+=8;
while(strchr(" \t", *p)) p++; // Ignore whitespace (spaces and tabs)
if (*p == '"')
{
p++;
char *p2 = p;
while (*p2!='"' && *p2!=0 ) p2++;
if (*p2!=0) {
*p2=0;
includes.push_back(std::string(p));
p = p2+1;
}
}
}
}
p++;
}
free(buffer);
return includes;
}
std::vector<std::string> split(std::string str)
{
std::vector<std::string> strings;
char tmp[100];
int tmp_p = 0, str_p = 0;
while (str[str_p]!=0)
{
if (str[str_p]!=32)
tmp[tmp_p++] = str[str_p++];
else
{
tmp[tmp_p]=0;
strings.push_back(tmp);
tmp_p=0; while (str[str_p]==32) str_p++;
}
}
tmp[tmp_p]=0;
strings.push_back(tmp);
return strings;
}
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;
if (!std::filesystem::exists(include_file))
{
std::cout << "WARNING: Include file '" << include_file << "' not found." << std::endl;
}
else
{
auto include_file_write_time = std::filesystem::last_write_time(include_file);
if (include_file_write_time > object_file_write_time)
{
return true;
}
else
{
if (HeadersNeedRecompile(include_file, object_file_write_time)) return true;
}
}
}
return false;
}
bool MustRecompile(std::string source_file)
{
std::string object_file = build_path + "/" + getFileNameWithoutExtension(source_file)+".o";
// si el objecte no existeix, fa falta recompilar
if (!std::filesystem::exists(object_file))
{
return true;
}
else
{
// Si sí que existeix, agafem la data de modificació
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);
if (source_file_write_time > object_file_write_time)
{
return true;
}
else
{
if (HeadersNeedRecompile(source_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 + "/" + getFileNameWithoutExtension(source_file)+".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();
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;
}
else
{
//std::cout << object_file << " està actualitzat" << std::endl;
}
}
int main(int argc, char *argv[])
{
if (argc>1) {
for (int i=1; i<argc; ++i) {
if (argv[i][0] == '-') {
if (strcmp(argv[i], "--clean")==0) {
system("rm -rf build");
}
} else {
std::filesystem::current_path(argv[i]);
}
}
}
loadLagueirtoFile();
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);
}
auto source_paths = split(source_path);
for (auto src_path : source_paths)
{
if (!std::filesystem::is_directory(src_path))
{
if (std::filesystem::is_regular_file(src_path) && getFileExtension(src_path)=="cpp")
{
MaybeRecompile(src_path);
} else {
std::cout << "ERROR: '" << src_path <<"' does not exists." << std::endl;
exit(1);
}
} else {
std::string path = "./" + src_path;
for (const auto & entry : std::filesystem::directory_iterator(path))
{
std::string source_file = entry.path();
std::string file_extension = getFileExtension(source_file);
if (file_extension=="cpp" || file_extension=="c")
{
MaybeRecompile(source_file);
}
}
}
}
if (must_link)
{
std::string command = "g++ " + build_path + "/*.o " + libs + " -o " + executable;
std::cout << command << std::endl;
if (system(command.c_str()) != 0) {
std::cout << "ABORTED!" << std::endl;
exit(1);
}
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;
std::cout << "(" << t << " seconds)" << std::endl;
}
else
{
std::cout << "Everything is up to date. Nothing to do." << std::endl;
}
}