- [NEW] Llevada opció "--clean" per ara
- [NEW] Soport per a varies configuracions - [NEW] Soport per a configuració per defecte - [FIX] Arreglats alguns bugs en la detecció de includes
This commit is contained in:
324
main.cpp
324
main.cpp
@@ -1,5 +1,6 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
@@ -65,61 +66,71 @@ char *getBufferFromFile(const char* filename)
|
||||
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;
|
||||
case EXCLUDE:
|
||||
exclude = split(token);
|
||||
//std::cout << "BUILDPATH: " << build_path << std::endl;
|
||||
break;
|
||||
static inline void trim(std::string &s) {
|
||||
while (!s.empty() && isspace(s.front())) s.erase(s.begin());
|
||||
while (!s.empty() && isspace(s.back())) s.pop_back();
|
||||
}
|
||||
|
||||
static inline std::string trim_copy(std::string s) {
|
||||
trim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool loadLagueirtoFile(const std::string §ion_to_load)
|
||||
{
|
||||
std::ifstream f("lagueirtofile");
|
||||
if (!f) { std::cerr << "Cannot open lagueirtofile\n"; exit(1); }
|
||||
|
||||
std::string line;
|
||||
std::string current_section {"@none@"};
|
||||
bool found_any_section = false;
|
||||
bool found_default = false;
|
||||
bool active = false;
|
||||
|
||||
while (std::getline(f, line))
|
||||
{
|
||||
// Quitar espacios al inicio y final
|
||||
trim(line);
|
||||
|
||||
if (line.empty() || line[0] == '#')
|
||||
continue;
|
||||
|
||||
// Detectar sección
|
||||
if (line.front() == '[')
|
||||
{
|
||||
auto end = line.find(']');
|
||||
if (end == std::string::npos) continue;
|
||||
|
||||
current_section = line.substr(1, end - 1);
|
||||
|
||||
// Detectar si es default
|
||||
std::string rest = trim_copy(line.substr(end + 1));
|
||||
found_any_section = true;
|
||||
if (rest == "default") found_default = true;
|
||||
if (section_to_load.empty() && rest == "default") active = true;
|
||||
else active = (current_section == section_to_load);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Clave = valor
|
||||
auto pos = line.find('=');
|
||||
if (pos == std::string::npos)
|
||||
continue;
|
||||
|
||||
std::string key = trim_copy(line.substr(0, pos));
|
||||
std::string value = trim_copy(line.substr(pos + 1));
|
||||
|
||||
if (!active && current_section != "@none@") continue;
|
||||
|
||||
if (key == "libs") libs = value;
|
||||
else if (key == "cppflags") cppflags = value;
|
||||
else if (key == "executable") executable = value;
|
||||
else if (key == "sourcepath") source_path = value;
|
||||
else if (key == "buildpath") build_path = value;
|
||||
else if (key == "exclude") exclude = split(value);
|
||||
}
|
||||
free(buffer);
|
||||
return !(found_any_section && section_to_load.empty() && !found_default);
|
||||
}
|
||||
|
||||
std::string getFileExtension(std::string path)
|
||||
@@ -154,73 +165,64 @@ const bool textFound(char *buffer, const char *text)
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> getIncludes(std::string filename)
|
||||
{
|
||||
char *buffer = getBufferFromFile(filename.c_str());
|
||||
std::vector<std::string> getIncludes(const std::string &filename) {
|
||||
std::ifstream f(filename);
|
||||
if (!f) return {};
|
||||
|
||||
std::vector<std::string> includes;
|
||||
std::string line;
|
||||
|
||||
char *p = buffer;
|
||||
while (*p != 0)
|
||||
{
|
||||
// Ignore commented lines
|
||||
if ( (*p=='/') && (*(p+1)!=0) && (*(p+1)=='/')) while( (*p != 0) && (*p != 13) ) p++;
|
||||
while (std::getline(f, line)) {
|
||||
// Quitar comentarios de línea
|
||||
auto pos = line.find("//");
|
||||
if (pos != std::string::npos)
|
||||
line.resize(pos);
|
||||
|
||||
// Ignore comment blocks
|
||||
if ( (*p=='/') && (*(p+1)!=0) && (*(p+1)=='*')) {
|
||||
p+=2;
|
||||
while( (*p != 0) && (*p != '*') && (*(p+1)!=0) && (*(p+1)!='/') ) p++;
|
||||
// Buscar #include
|
||||
pos = line.find("#include");
|
||||
if (pos == std::string::npos)
|
||||
continue;
|
||||
|
||||
// Avanzar tras "#include"
|
||||
pos += 8;
|
||||
|
||||
// Saltar espacios
|
||||
while (pos < line.size() && (line[pos] == ' ' || line[pos] == '\t'))
|
||||
pos++;
|
||||
|
||||
// Solo queremos includes con comillas
|
||||
if (pos >= line.size() || line[pos] != '"')
|
||||
continue;
|
||||
|
||||
pos++; // saltar la primera comilla
|
||||
size_t start = pos;
|
||||
|
||||
// Buscar la comilla de cierre
|
||||
while (pos < line.size() && line[pos] != '"')
|
||||
pos++;
|
||||
|
||||
if (pos < line.size())
|
||||
includes.push_back(line.substr(start, pos - start));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool HeadersNeedRecompile(std::string file, std::filesystem::file_time_type object_file_write_time)
|
||||
{
|
||||
bool HeadersNeedRecompile(std::string file, std::filesystem::file_time_type object_file_write_time) {
|
||||
auto include_files = getIncludes(file);
|
||||
for (auto include : include_files)
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (!std::filesystem::exists(include_file)) {
|
||||
std::cout << "WARNING: Include file '" << include_file << "' not found." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
} 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if (HeadersNeedRecompile(include_file, object_file_write_time)) return true;
|
||||
}
|
||||
}
|
||||
@@ -228,39 +230,29 @@ bool HeadersNeedRecompile(std::string file, std::filesystem::file_time_type obje
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MustRecompile(std::string source_file)
|
||||
{
|
||||
bool MustRecompile(std::string source_file) {
|
||||
std::string object_file = build_path + folder_char + getFileNameWithoutExtension(source_file)+".o";
|
||||
|
||||
// si el objecte no existeix, fa falta recompilar
|
||||
if (!std::filesystem::exists(object_file))
|
||||
{
|
||||
if (!std::filesystem::exists(object_file)) {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} 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))
|
||||
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))
|
||||
{
|
||||
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;
|
||||
@@ -269,46 +261,42 @@ void MaybeRecompile(std::string source_file)
|
||||
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
|
||||
{
|
||||
} 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]);
|
||||
}
|
||||
}
|
||||
void processCommand(std::string arg) {
|
||||
// Do nothing for now
|
||||
}
|
||||
|
||||
loadLagueirtoFile();
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
std::string configuration_to_use;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
std::string arg = argv[i];
|
||||
if (!arg.empty() && arg[0] == '-') processCommand(arg);
|
||||
else configuration_to_use = arg;
|
||||
}
|
||||
|
||||
if (!loadLagueirtoFile(configuration_to_use)) {
|
||||
std::cerr << "No default section found.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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);
|
||||
auto source_paths = split(source_path);
|
||||
|
||||
for (auto src_path : source_paths)
|
||||
{
|
||||
for (auto src_path : source_paths) {
|
||||
bool recursive = false;
|
||||
|
||||
if (!src_path.empty() && src_path.back() == '+')
|
||||
{
|
||||
if (!src_path.empty() && src_path.back() == '+') {
|
||||
recursive = true;
|
||||
src_path.pop_back();
|
||||
}
|
||||
@@ -317,59 +305,42 @@ for (auto src_path : source_paths)
|
||||
std::replace(src_path.begin(), src_path.end(), '/', '\\');
|
||||
#endif
|
||||
|
||||
if (!std::filesystem::is_directory(src_path))
|
||||
{
|
||||
if (std::filesystem::is_regular_file(src_path))
|
||||
{
|
||||
if (!std::filesystem::is_directory(src_path)) {
|
||||
if (std::filesystem::is_regular_file(src_path)) {
|
||||
std::string ext = getFileExtension(src_path);
|
||||
if (ext == "cpp" || ext == "c")
|
||||
{
|
||||
|
||||
if (ext == "cpp" || ext == "c") {
|
||||
MaybeRecompile(src_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
std::cout << "ERROR: '" << src_path << "' is not a .c/.cpp file." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
std::cout << "ERROR: '" << src_path << "' does not exist." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
std::string path = "." + folder_char + src_path;
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
for (const auto &entry : std::filesystem::recursive_directory_iterator(path))
|
||||
{
|
||||
if (recursive) {
|
||||
for (const auto &entry : std::filesystem::recursive_directory_iterator(path)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
|
||||
std::string source_file = entry.path().string();
|
||||
std::string ext = getFileExtension(source_file);
|
||||
|
||||
if ((ext == "cpp" || ext == "c") &&
|
||||
!contains(exclude, entry.path().filename()))
|
||||
{
|
||||
if ((ext == "cpp" || ext == "c") && !contains(exclude, entry.path().filename())) {
|
||||
MaybeRecompile(source_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto &entry : std::filesystem::directory_iterator(path))
|
||||
{
|
||||
} else {
|
||||
for (const auto &entry : std::filesystem::directory_iterator(path)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
|
||||
std::string source_file = entry.path().string();
|
||||
std::string ext = getFileExtension(source_file);
|
||||
|
||||
if ((ext == "cpp" || ext == "c") &&
|
||||
!contains(exclude, entry.path().filename()))
|
||||
{
|
||||
if ((ext == "cpp" || ext == "c") && !contains(exclude, entry.path().filename())) {
|
||||
MaybeRecompile(source_file);
|
||||
}
|
||||
}
|
||||
@@ -377,8 +348,7 @@ for (auto src_path : source_paths)
|
||||
}
|
||||
}
|
||||
|
||||
if (must_link)
|
||||
{
|
||||
if (must_link) {
|
||||
std::string command = "g++ " + build_path + folder_char + "*.o " + libs + " -o " + executable;
|
||||
std::cout << command << std::endl;
|
||||
if (system(command.c_str()) != 0) {
|
||||
@@ -388,9 +358,7 @@ for (auto src_path : source_paths)
|
||||
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
|
||||
{
|
||||
} else {
|
||||
std::cout << "Everything is up to date. Nothing to do." << std::endl;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user