Create system for generating Makefiles
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
bin/*
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import fnmatch
|
||||||
|
import logging
|
||||||
|
import ycm_core
|
||||||
|
import re
|
||||||
|
|
||||||
|
BASE_FLAGS = [
|
||||||
|
'-Wall',
|
||||||
|
'-Wuninitialized',
|
||||||
|
'-Wextra',
|
||||||
|
'-Wno-long-long',
|
||||||
|
'-Wno-variadic-macros',
|
||||||
|
'-fexceptions',
|
||||||
|
'-ferror-limit=10000',
|
||||||
|
'-DNDEBUG',
|
||||||
|
'-std=c++17',
|
||||||
|
'-xc++',
|
||||||
|
'-I/usr/lib/',
|
||||||
|
'-I/usr/include/',
|
||||||
|
]
|
||||||
|
|
||||||
|
SOURCE_EXTENSIONS = [
|
||||||
|
'.cpp',
|
||||||
|
]
|
||||||
|
|
||||||
|
SOURCE_DIRECTORIES = [
|
||||||
|
'src'
|
||||||
|
]
|
||||||
|
|
||||||
|
HEADER_EXTENSIONS = [
|
||||||
|
'.h',
|
||||||
|
]
|
||||||
|
|
||||||
|
HEADER_DIRECTORIES = [
|
||||||
|
]
|
||||||
|
|
||||||
|
def IsHeaderFile(filename):
|
||||||
|
extension = os.path.splitext(filename)[1]
|
||||||
|
return extension in HEADER_EXTENSIONS
|
||||||
|
|
||||||
|
def GetCompilationInfoForFile(database, filename):
|
||||||
|
if IsHeaderFile(filename):
|
||||||
|
basename = os.path.splitext(filename)[0]
|
||||||
|
for extension in SOURCE_EXTENSIONS:
|
||||||
|
# Get info from the source files by replacing the extension.
|
||||||
|
replacement_file = basename + extension
|
||||||
|
if os.path.exists(replacement_file):
|
||||||
|
compilation_info = database.GetCompilationInfoForFile(replacement_file)
|
||||||
|
if compilation_info.compiler_flags_:
|
||||||
|
return compilation_info
|
||||||
|
# If that wasn't successful, try replacing possible header directory with possible source directories.
|
||||||
|
for header_dir in HEADER_DIRECTORIES:
|
||||||
|
for source_dir in SOURCE_DIRECTORIES:
|
||||||
|
src_file = replacement_file.replace(header_dir, source_dir)
|
||||||
|
if os.path.exists(src_file):
|
||||||
|
compilation_info = database.GetCompilationInfoForFile(src_file)
|
||||||
|
if compilation_info.compiler_flags_:
|
||||||
|
return compilation_info
|
||||||
|
return None
|
||||||
|
return database.GetCompilationInfoForFile(filename)
|
||||||
|
|
||||||
|
def FindNearest(path, target, build_folder):
|
||||||
|
candidate = os.path.join(path, target)
|
||||||
|
if(os.path.isfile(candidate) or os.path.isdir(candidate)):
|
||||||
|
logging.info("Found nearest " + target + " at " + candidate)
|
||||||
|
return candidate;
|
||||||
|
|
||||||
|
parent = os.path.dirname(os.path.abspath(path));
|
||||||
|
if(parent == path):
|
||||||
|
raise RuntimeError("Could not find " + target);
|
||||||
|
|
||||||
|
if(build_folder):
|
||||||
|
candidate = os.path.join(parent, build_folder, target)
|
||||||
|
if(os.path.isfile(candidate) or os.path.isdir(candidate)):
|
||||||
|
logging.info("Found nearest " + target + " in build folder at " + candidate)
|
||||||
|
return candidate;
|
||||||
|
|
||||||
|
return FindNearest(parent, target, build_folder)
|
||||||
|
|
||||||
|
def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
|
||||||
|
if not working_directory:
|
||||||
|
return list(flags)
|
||||||
|
new_flags = []
|
||||||
|
make_next_absolute = False
|
||||||
|
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
|
||||||
|
for flag in flags:
|
||||||
|
new_flag = flag
|
||||||
|
|
||||||
|
if make_next_absolute:
|
||||||
|
make_next_absolute = False
|
||||||
|
if not flag.startswith('/'):
|
||||||
|
new_flag = os.path.join(working_directory, flag)
|
||||||
|
|
||||||
|
for path_flag in path_flags:
|
||||||
|
if flag == path_flag:
|
||||||
|
make_next_absolute = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if flag.startswith(path_flag):
|
||||||
|
path = flag[ len(path_flag): ]
|
||||||
|
new_flag = path_flag + os.path.join(working_directory, path)
|
||||||
|
break
|
||||||
|
|
||||||
|
if new_flag:
|
||||||
|
new_flags.append(new_flag)
|
||||||
|
return new_flags
|
||||||
|
|
||||||
|
|
||||||
|
def FlagsForClangComplete(root):
|
||||||
|
try:
|
||||||
|
clang_complete_path = FindNearest(root, '.clang_complete')
|
||||||
|
clang_complete_flags = open(clang_complete_path, 'r').read().splitlines()
|
||||||
|
return clang_complete_flags
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def FlagsForInclude(root):
|
||||||
|
try:
|
||||||
|
include_path = FindNearest(root, 'include')
|
||||||
|
flags = []
|
||||||
|
for dirroot, dirnames, filenames in os.walk(include_path):
|
||||||
|
for dir_path in dirnames:
|
||||||
|
real_path = os.path.join(dirroot, dir_path)
|
||||||
|
flags = flags + ["-I" + real_path]
|
||||||
|
return flags
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def FlagsForCompilationDatabase(root, filename):
|
||||||
|
try:
|
||||||
|
# Last argument of next function is the name of the build folder for
|
||||||
|
# out of source projects
|
||||||
|
compilation_db_path = FindNearest(root, 'compile_commands.json', 'build')
|
||||||
|
compilation_db_dir = os.path.dirname(compilation_db_path)
|
||||||
|
logging.info("Set compilation database directory to " + compilation_db_dir)
|
||||||
|
compilation_db = ycm_core.CompilationDatabase(compilation_db_dir)
|
||||||
|
if not compilation_db:
|
||||||
|
logging.info("Compilation database file found but unable to load")
|
||||||
|
return None
|
||||||
|
compilation_info = GetCompilationInfoForFile(compilation_db, filename)
|
||||||
|
if not compilation_info:
|
||||||
|
logging.info("No compilation info for " + filename + " in compilation database")
|
||||||
|
return None
|
||||||
|
return MakeRelativePathsInFlagsAbsolute(
|
||||||
|
compilation_info.compiler_flags_,
|
||||||
|
compilation_info.compiler_working_dir_)
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def FlagsForFile(filename):
|
||||||
|
root = os.path.realpath(filename);
|
||||||
|
compilation_db_flags = FlagsForCompilationDatabase(root, filename)
|
||||||
|
confPath = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
for dir in HEADER_DIRECTORIES:
|
||||||
|
BASE_FLAGS.append('-I'+confPath+'/'+dir)
|
||||||
|
|
||||||
|
if compilation_db_flags:
|
||||||
|
final_flags = compilation_db_flags
|
||||||
|
else:
|
||||||
|
final_flags = BASE_FLAGS
|
||||||
|
clang_flags = FlagsForClangComplete(root)
|
||||||
|
if clang_flags:
|
||||||
|
final_flags = final_flags + clang_flags
|
||||||
|
include_flags = FlagsForInclude(root)
|
||||||
|
if include_flags:
|
||||||
|
final_flags = final_flags + include_flags
|
||||||
|
return {
|
||||||
|
'flags': final_flags,
|
||||||
|
'do_cache': True
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
CC=@g++
|
||||||
|
CO=@g++ -o
|
||||||
|
BIN=bin/
|
||||||
|
OBJPATH=$(BIN)intermediates
|
||||||
|
INCLUDES=
|
||||||
|
OBJECTS=$(OBJPATH)/ConfigFile.o $(OBJPATH)/IncludeDeps.o $(OBJPATH)/Makefile.o $(OBJPATH)/main.o
|
||||||
|
CFLAGS=$(INCLUDES) -std=c++17 -c -w -g3 -D_DEBUG
|
||||||
|
LIBS=
|
||||||
|
OUTPUT=$(BIN)makegen
|
||||||
|
all: $(OUTPUT)
|
||||||
|
$(info ------------------------)
|
||||||
|
$(info ---- Done Compiling ----)
|
||||||
|
$(info ------------------------)
|
||||||
|
rebuid: clean all
|
||||||
|
clean:
|
||||||
|
$(info Removing intermediates)
|
||||||
|
rm -rf $(OBJPATH)/*.o
|
||||||
|
$(OUTPUT): $(OBJECTS)
|
||||||
|
$(info Generating output file)
|
||||||
|
$(CO) $(OUTPUT) $(OBJECTS) $(LIBS)
|
||||||
|
install: all
|
||||||
|
cp $(OUTPUT) /usr/bin/makegen
|
||||||
|
$(OBJPATH)/ConfigFile.o : src/ConfigFile.cpp src/ConfigFile.h src/Logging.h
|
||||||
|
$(info ---- $<)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
$(OBJPATH)/IncludeDeps.o : src/IncludeDeps.cpp src/IncludeDeps.h
|
||||||
|
$(info ---- $<)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
$(OBJPATH)/Makefile.o : src/Makefile.cpp src/IncludeDeps.h src/Logging.h src/Makefile.h src/ConfigFile.h
|
||||||
|
$(info ---- $<)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
$(OBJPATH)/main.o : src/main.cpp src/ConfigFile.h src/IncludeDeps.h src/Logging.h src/Makefile.h
|
||||||
|
$(info ---- $<)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#srcdirs
|
||||||
|
src/
|
||||||
|
#outputdir
|
||||||
|
bin/
|
||||||
|
#outputname
|
||||||
|
makegen
|
||||||
|
#defines
|
||||||
|
_DEBUG
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#include "ConfigFile.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include "Logging.h"
|
||||||
|
|
||||||
|
#define FLAG_NONE 0
|
||||||
|
#define FLAG_VECTOR 1
|
||||||
|
#define FLAG_STRING 2
|
||||||
|
#define FLAG_BOOL 3
|
||||||
|
|
||||||
|
ConfigFile::ConfigFile()
|
||||||
|
: outputdir("bin"), outputname("out.a"),executable(true)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigFile ConfigFile::Load()
|
||||||
|
{
|
||||||
|
ConfigFile conf;
|
||||||
|
unsigned int loadFlag = 0;
|
||||||
|
|
||||||
|
std::vector<std::string>* vec;
|
||||||
|
std::string* s;
|
||||||
|
bool* b;
|
||||||
|
|
||||||
|
std::ifstream file("makegen.conf");
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while(std::getline(file,line))
|
||||||
|
{
|
||||||
|
if(line[0]=='#')
|
||||||
|
{
|
||||||
|
if(line == "#libs")
|
||||||
|
{
|
||||||
|
vec = &conf.libs;
|
||||||
|
loadFlag = FLAG_VECTOR;
|
||||||
|
}
|
||||||
|
else if(line == "#libdirs")
|
||||||
|
{
|
||||||
|
vec = &conf.libdirs;
|
||||||
|
loadFlag = FLAG_VECTOR;
|
||||||
|
}
|
||||||
|
else if(line == "#includedirs")
|
||||||
|
{
|
||||||
|
vec = &conf.includedirs;
|
||||||
|
loadFlag = FLAG_VECTOR;
|
||||||
|
}
|
||||||
|
else if(line == "#srcdirs")
|
||||||
|
{
|
||||||
|
vec = &conf.srcdirs;
|
||||||
|
loadFlag = FLAG_VECTOR;
|
||||||
|
}
|
||||||
|
else if(line == "#defines")
|
||||||
|
{
|
||||||
|
vec = &conf.defines;
|
||||||
|
loadFlag = FLAG_VECTOR;
|
||||||
|
}
|
||||||
|
else if(line == "#outputdir")
|
||||||
|
{
|
||||||
|
s = &conf.outputdir;
|
||||||
|
loadFlag = FLAG_STRING;
|
||||||
|
}
|
||||||
|
else if(line == "#outputname")
|
||||||
|
{
|
||||||
|
s = &conf.outputname;
|
||||||
|
loadFlag = FLAG_STRING;
|
||||||
|
}
|
||||||
|
else if(line == "#executable")
|
||||||
|
{
|
||||||
|
b = &conf.executable;
|
||||||
|
loadFlag = FLAG_BOOL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("Invalid flag");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(loadFlag == FLAG_STRING)
|
||||||
|
{
|
||||||
|
*s = line;
|
||||||
|
}
|
||||||
|
else if(loadFlag == FLAG_VECTOR)
|
||||||
|
{
|
||||||
|
vec->push_back(line);
|
||||||
|
}
|
||||||
|
else if(loadFlag == FLAG_BOOL)
|
||||||
|
{
|
||||||
|
if(line == "true")
|
||||||
|
*b = true;
|
||||||
|
else
|
||||||
|
*b = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class ConfigFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<std::string> libs;
|
||||||
|
std::vector<std::string> libdirs;
|
||||||
|
std::vector<std::string> includedirs;
|
||||||
|
std::vector<std::string> srcdirs;
|
||||||
|
std::vector<std::string> defines;
|
||||||
|
std::string outputdir;
|
||||||
|
std::string outputname;
|
||||||
|
bool executable;
|
||||||
|
public:
|
||||||
|
ConfigFile();
|
||||||
|
void Save() const;
|
||||||
|
static ConfigFile Gen();
|
||||||
|
static ConfigFile Load();
|
||||||
|
};
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#include "IncludeDeps.h"
|
||||||
|
|
||||||
|
std::set<std::string> IncludeDeps::printSet;
|
||||||
|
int IncludeDeps::printCounter = 0;
|
||||||
|
IncludeDeps::IncludeDeps(const std::string& filename, const std::string& dir, const std::map<std::string, std::string>& files, std::map<std::string, IncludeDeps*>& allDeps)
|
||||||
|
: filepath(dir+filename)
|
||||||
|
{
|
||||||
|
if(filename[filename.length() - 1] =='h')
|
||||||
|
{
|
||||||
|
allDeps.emplace(filepath, this);
|
||||||
|
}
|
||||||
|
std::ifstream file(filepath);
|
||||||
|
std::string line;
|
||||||
|
while(std::getline(file,line))
|
||||||
|
{
|
||||||
|
size_t pos = line.find("#include");
|
||||||
|
if(pos != std::string::npos)
|
||||||
|
{
|
||||||
|
std::string include = GetIncludeFile(line, pos, filename);
|
||||||
|
auto it = files.find(include);
|
||||||
|
if(it != files.end())
|
||||||
|
{
|
||||||
|
auto itD = allDeps.find(it->second + it->first);
|
||||||
|
if(itD == allDeps.end())
|
||||||
|
{
|
||||||
|
IncludeDeps* inc = new IncludeDeps(it->first, it->second,files,allDeps);
|
||||||
|
dependencies.emplace(it->second+ it->first, inc);
|
||||||
|
}else{
|
||||||
|
dependencies.emplace(itD->first, itD->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string IncludeDeps::GetIncludeFile(const std::string& line, size_t pos, const std::string& filename)
|
||||||
|
{
|
||||||
|
size_t bracket = line.find('<',pos);
|
||||||
|
if(bracket == std::string::npos)
|
||||||
|
{
|
||||||
|
bracket = line.find('\"',pos);
|
||||||
|
if(bracket == std::string::npos)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
size_t slash = filename.find_last_of("/");
|
||||||
|
|
||||||
|
std::string include = line.substr(bracket+1, line.find('\"',bracket+1)-bracket-1);
|
||||||
|
if(slash == std::string::npos)
|
||||||
|
slash = -1;
|
||||||
|
return filename.substr(0,slash+1)+include;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return line.substr(bracket+1, line.find('>',bracket+1)-bracket-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
struct CompareIncludeDeps;
|
||||||
|
|
||||||
|
class IncludeDeps
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::map<std::string, IncludeDeps*> dependencies;
|
||||||
|
std::string filepath;
|
||||||
|
static std::set<std::string> printSet;
|
||||||
|
static int printCounter;
|
||||||
|
|
||||||
|
IncludeDeps(const std::string& filename, const std::string& dir, const std::map<std::string, std::string>& files, std::map<std::string, IncludeDeps*>& allDeps);
|
||||||
|
|
||||||
|
std::string GetIncludeFile(const std::string& line, size_t pos, const std::string& filename);
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& stream, const IncludeDeps& deps)
|
||||||
|
{
|
||||||
|
if(printSet.find(deps.filepath) != printSet.end())
|
||||||
|
return stream;
|
||||||
|
printCounter++;
|
||||||
|
printSet.emplace(deps.filepath);
|
||||||
|
stream << deps.filepath;
|
||||||
|
for(auto it = deps.dependencies.begin();it!=deps.dependencies.end();++it)
|
||||||
|
{
|
||||||
|
stream << " " << *(it->second);
|
||||||
|
}
|
||||||
|
printCounter--;
|
||||||
|
if(printCounter == 0)
|
||||||
|
printSet.clear();
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
IncludeDeps(const std::string& filename, const std::string& dir)
|
||||||
|
: filepath(dir+filename){}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompareIncludeDeps
|
||||||
|
{
|
||||||
|
using is_transparent = void;
|
||||||
|
bool operator()(const IncludeDeps* d1, const IncludeDeps* d2) const
|
||||||
|
{
|
||||||
|
return d1->filepath < d2->filepath;
|
||||||
|
}
|
||||||
|
bool operator()(const IncludeDeps* d, const std::string& filepath) const
|
||||||
|
{
|
||||||
|
return d->filepath < filepath;
|
||||||
|
}
|
||||||
|
bool operator()(const std::string& filepath, const IncludeDeps* d) const
|
||||||
|
{
|
||||||
|
return filepath < d->filepath;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define LOG_INFO(...) Log(__VA_ARGS__); std::cout << std::endl
|
||||||
|
#define LOG_WARNING(...) Log(__VA_ARGS__); std::cout << std::endl
|
||||||
|
#define LOG_ERROR(...) Log(__VA_ARGS__); std::cout << std::endl
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Log(const T& var)
|
||||||
|
{
|
||||||
|
std::cout << var;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename ...Ts>
|
||||||
|
void Log(const T& var, const Ts& ...vars)
|
||||||
|
{
|
||||||
|
Log(var);
|
||||||
|
Log(vars...);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
#include "Makefile.h"
|
||||||
|
#include <map>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include "Logging.h"
|
||||||
|
#include "IncludeDeps.h"
|
||||||
|
|
||||||
|
void Makefile::GetAllFiles(const std::string& folder, std::vector<std::string>& files)
|
||||||
|
{
|
||||||
|
DIR* dp;
|
||||||
|
struct dirent *dirp;
|
||||||
|
if((dp = opendir(folder.c_str())) == NULL){
|
||||||
|
LOG_ERROR(errno);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while((dirp = readdir(dp)) != NULL)
|
||||||
|
{
|
||||||
|
if(dirp->d_type == DT_DIR)
|
||||||
|
{
|
||||||
|
if(strcmp(dirp->d_name,".") == 0)
|
||||||
|
continue;
|
||||||
|
if(strcmp(dirp->d_name,"..") == 0)
|
||||||
|
continue;
|
||||||
|
GetAllFiles(folder+dirp->d_name+"/", files);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
files.push_back(folder+dirp->d_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Makefile::Save(const ConfigFile& conf)
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string> hFiles;
|
||||||
|
std::map<std::string, std::string> cppFiles;
|
||||||
|
PreSave(conf,hFiles,cppFiles);
|
||||||
|
|
||||||
|
std::ofstream outputFile("Makefile");
|
||||||
|
outputFile << "CC=@g++" << std::endl;
|
||||||
|
if(!conf.executable)
|
||||||
|
outputFile << "CO=@ar rs" << std::endl;
|
||||||
|
else
|
||||||
|
outputFile << "CO=@g++ -o" << std::endl;
|
||||||
|
|
||||||
|
outputFile << "BIN=" << conf.outputdir << std::endl;
|
||||||
|
outputFile << "OBJPATH=$(BIN)intermediates" << std::endl;
|
||||||
|
outputFile << "INCLUDES=";
|
||||||
|
for(auto it = conf.includedirs.begin();it!=conf.includedirs.end();++it)
|
||||||
|
{
|
||||||
|
outputFile << "-I./" << *it << " ";
|
||||||
|
}
|
||||||
|
outputFile << std::endl;
|
||||||
|
outputFile << "OBJECTS=";
|
||||||
|
for(auto it = cppFiles.begin();it!=cppFiles.end();++it)
|
||||||
|
{
|
||||||
|
size_t extensionPos = it->first.find_last_of(".");
|
||||||
|
size_t slash = it->first.find_last_of("/")+1;
|
||||||
|
outputFile << "$(OBJPATH)/" << it->first.substr(slash, extensionPos - slash) << ".o ";
|
||||||
|
}
|
||||||
|
outputFile << std::endl;
|
||||||
|
outputFile << "CFLAGS=$(INCLUDES) -std=c++17 -c -w -g3 ";
|
||||||
|
for(auto it = conf.defines.begin();it!=conf.defines.end();++it)
|
||||||
|
{
|
||||||
|
outputFile << "-D" << *it << " ";
|
||||||
|
}
|
||||||
|
outputFile << std::endl;
|
||||||
|
outputFile << "LIBS=";
|
||||||
|
for(auto it = conf.libs.begin();it!=conf.libs.end();++it)
|
||||||
|
{
|
||||||
|
outputFile << "-l:" << *it << " ";
|
||||||
|
}
|
||||||
|
outputFile << std::endl;
|
||||||
|
outputFile << "OUTPUT=$(BIN)" << conf.outputname << std::endl;
|
||||||
|
outputFile << "all: $(OUTPUT)" << std::endl;
|
||||||
|
outputFile << "\t$(info ------------------------)" << std::endl;
|
||||||
|
outputFile << "\t$(info ---- Done Compiling ----)" << std::endl;
|
||||||
|
outputFile << "\t$(info ------------------------)" << std::endl;
|
||||||
|
outputFile << "rebuid: clean all" << std::endl;
|
||||||
|
outputFile << "clean:" << std::endl;
|
||||||
|
outputFile << "\t$(info Removing intermediates)" << std::endl;
|
||||||
|
outputFile << "\trm -rf $(OBJPATH)/*.o" << std::endl;
|
||||||
|
outputFile << "$(OUTPUT): $(OBJECTS)" << std::endl;
|
||||||
|
outputFile << "\t$(info Generating output file)" << std::endl;
|
||||||
|
outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS) $(LIBS)" << std::endl;
|
||||||
|
outputFile << "install: all" << std::endl;
|
||||||
|
outputFile << "\tcp $(OUTPUT) /usr/bin/" << conf.outputname << std::endl;
|
||||||
|
std::map<std::string, IncludeDeps*> dependencies;
|
||||||
|
for(auto it = cppFiles.begin(); it!=cppFiles.end();++it)
|
||||||
|
{
|
||||||
|
auto itD = dependencies.find(it->first+it->second);
|
||||||
|
if(itD == dependencies.end())
|
||||||
|
{
|
||||||
|
IncludeDeps* deps = new IncludeDeps(it->first, it->second,hFiles,dependencies);
|
||||||
|
size_t extensionPos = it->first.find_last_of(".");
|
||||||
|
size_t slash = it->first.find_last_of("/")+1;
|
||||||
|
std::string oFile = it->first.substr(slash, extensionPos - slash)+".o ";
|
||||||
|
outputFile << "$(OBJPATH)/" << oFile << ": " << *deps << std::endl;
|
||||||
|
outputFile << "\t$(info ---- $<)" << std::endl;
|
||||||
|
outputFile << "\t$(CC) $(CFLAGS) -o $@ $<" << std::endl;
|
||||||
|
//std::cout << *deps << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Makefile::PreSave(const ConfigFile& conf, std::map<std::string, std::string>& hFiles,
|
||||||
|
std::map<std::string, std::string>& cppFiles)
|
||||||
|
{
|
||||||
|
for(auto itSrc = conf.srcdirs.begin();itSrc != conf.srcdirs.end();++itSrc)
|
||||||
|
{
|
||||||
|
std::vector<std::string> files;
|
||||||
|
GetAllFiles(*itSrc,files);
|
||||||
|
// include paramenter with the path of the file
|
||||||
|
// For example src/graphics/Window.h -> graphics/Window.h if src is a src folder
|
||||||
|
for(auto it = files.begin(); it!=files.end();++it)
|
||||||
|
{
|
||||||
|
size_t extensionPos = it->find_last_of(".");
|
||||||
|
if(extensionPos != std::string::npos)
|
||||||
|
{
|
||||||
|
if(it->substr(extensionPos+1) == "cpp")
|
||||||
|
{
|
||||||
|
cppFiles.emplace(it->substr(itSrc->length()), *itSrc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hFiles.emplace(it->substr(itSrc->length()), *itSrc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ConfigFile.h"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class Makefile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void Save(const ConfigFile& conf);
|
||||||
|
private:
|
||||||
|
static void PreSave(const ConfigFile& conf, std::map<std::string, std::string>& hFiles, std::map<std::string, std::string>& cppFiles);
|
||||||
|
static void GetAllFiles(const std::string& folder, std::vector<std::string>& files);
|
||||||
|
};
|
||||||
+141
@@ -0,0 +1,141 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <fstream>
|
||||||
|
#include "IncludeDeps.h"
|
||||||
|
#include "ConfigFile.h"
|
||||||
|
#include "Makefile.h"
|
||||||
|
#include "Logging.h"
|
||||||
|
|
||||||
|
#define BIT(x) (1<<x)
|
||||||
|
|
||||||
|
const static unsigned int FLAG_HELP = BIT(0);
|
||||||
|
const static unsigned int FLAG_GEN= BIT(1);
|
||||||
|
|
||||||
|
// Flags for loading conf file
|
||||||
|
const static unsigned int LOAD_FLAG_ERROR= BIT(0);
|
||||||
|
const static unsigned int LOAD_FLAG_VECTOR = BIT(1);
|
||||||
|
const static unsigned int LOAD_FLAG_STRING = BIT(2);
|
||||||
|
|
||||||
|
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
void GenMakefile()
|
||||||
|
{
|
||||||
|
ConfigFile conf = ConfigFile::Load();
|
||||||
|
Makefile::Save(conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadFlags(int argc, char** argv)
|
||||||
|
{
|
||||||
|
for(int i = 1;i<argc;i++)
|
||||||
|
{
|
||||||
|
if(strlen(argv[i]) > 1)
|
||||||
|
{
|
||||||
|
if(argv[i][0] == '-' && argv[i][1] == '-')
|
||||||
|
{
|
||||||
|
std::string flag(argv[i]);
|
||||||
|
if(flag == "--help")
|
||||||
|
{
|
||||||
|
flags |= FLAG_HELP;
|
||||||
|
}
|
||||||
|
else if(flag == "--gen")
|
||||||
|
{
|
||||||
|
flags |= FLAG_GEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputMultiple(const std::string& inputText, std::vector<std::string>& ret)
|
||||||
|
{
|
||||||
|
std::string input;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
LOG_INFO(inputText);
|
||||||
|
std::getline(std::cin, input);
|
||||||
|
if(input == "")
|
||||||
|
break;
|
||||||
|
ret.push_back(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenConfFile()
|
||||||
|
{
|
||||||
|
std::vector<std::string> libs;
|
||||||
|
std::vector<std::string> libdirs;
|
||||||
|
std::vector<std::string> includedirs;
|
||||||
|
std::vector<std::string> srcdirs;
|
||||||
|
std::string outputDir;
|
||||||
|
InputMultiple("Enter library:", libs);
|
||||||
|
InputMultiple("Enter library directory:", libdirs);
|
||||||
|
InputMultiple("Enter include directory:", includedirs);
|
||||||
|
InputMultiple("Enter source directories:", srcdirs);
|
||||||
|
LOG_INFO("Enter output directory (default: bin):");
|
||||||
|
std::getline(std::cin, outputDir);
|
||||||
|
if(outputDir == "")
|
||||||
|
outputDir = "bin";
|
||||||
|
|
||||||
|
std::ofstream file("makegen.conf");
|
||||||
|
file << "#libs" << std::endl;
|
||||||
|
for(auto it = libs.begin();it!=libs.end();++it)
|
||||||
|
{
|
||||||
|
file << *it << std::endl;
|
||||||
|
}
|
||||||
|
file << "#libdirs" << std::endl;
|
||||||
|
for(auto it = libdirs.begin();it!=libdirs.end();++it)
|
||||||
|
{
|
||||||
|
file << *it << std::endl;
|
||||||
|
}
|
||||||
|
file << "#includedirs" << std::endl;
|
||||||
|
for(auto it = includedirs.begin();it!=includedirs.end();++it)
|
||||||
|
{
|
||||||
|
file << *it << std::endl;
|
||||||
|
}
|
||||||
|
file << "#srcdirs" << std::endl;
|
||||||
|
for(auto it = srcdirs.begin();it!=srcdirs.end();++it)
|
||||||
|
{
|
||||||
|
file << *it << std::endl;
|
||||||
|
}
|
||||||
|
file << "#outputdir" << std::endl;
|
||||||
|
file << outputDir << std::endl;
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
ReadFlags(argc,argv);
|
||||||
|
if((flags & FLAG_HELP))
|
||||||
|
{
|
||||||
|
LOG_INFO("Usage: makegen [options]");
|
||||||
|
LOG_INFO(" Options:");
|
||||||
|
LOG_INFO(" -h, --help\tDisplays this information");
|
||||||
|
LOG_INFO(" -g, --gen\tGenerate a config file for the project");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(flags & FLAG_GEN)
|
||||||
|
{
|
||||||
|
GenConfFile();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
LOG_INFO("Generating Makefile...");
|
||||||
|
GenMakefile();
|
||||||
|
LOG_INFO("Running Makefile...");
|
||||||
|
for(int i = 1;i<argc;i++)
|
||||||
|
{
|
||||||
|
if(argv[i][0] != '-')
|
||||||
|
{
|
||||||
|
std::string make = std::string("make ") + argv[i];
|
||||||
|
system(make.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
system("make");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user