Rework how the config file is read
Still need to remove reduntant code and test it much more thoroughly.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# This Makefile was generated using MakeGen v1.2.0 made by Tim Håkansson
|
||||
# This Makefile was generated using MakeGen v1.3.0 made by Tim Håkansson
|
||||
# and is licensed under MIT. Full source of the project can be found at
|
||||
# https://github.com/Thraix/MakeGen
|
||||
CC=@g++
|
||||
@@ -8,7 +8,7 @@ BIN=bin/
|
||||
OBJPATH=$(BIN)intermediates
|
||||
INCLUDES=
|
||||
OBJECTS=$(OBJPATH)/ConfigCLI.o $(OBJPATH)/ConfigFile.o $(OBJPATH)/HFileGen.o $(OBJPATH)/IncludeDeps.o $(OBJPATH)/Makefile.o $(OBJPATH)/Utils.o $(OBJPATH)/ConfigFileConf.o $(OBJPATH)/main.o $(OBJPATH)/XML.o $(OBJPATH)/XMLObject.o
|
||||
CFLAGS=$(INCLUDES) -std=c++17 -c -w -g3 -D_DEBUG
|
||||
CFLAGS=$(INCLUDES) -std=c++17 -c -w -g3
|
||||
LIBDIR=
|
||||
LDFLAGS=
|
||||
LIBS=$(LIBDIR)
|
||||
@@ -33,28 +33,28 @@ $(OUTPUT): $(OBJECTS)
|
||||
install: all
|
||||
$(info Installing MakeGen to /usr/bin/)
|
||||
@cp $(OUTPUT) /usr/bin/makegen
|
||||
$(OBJPATH)/ConfigCLI.o : src/ConfigCLI.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/xml/XMLObject.h
|
||||
$(OBJPATH)/ConfigCLI.o : src/ConfigCLI.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h
|
||||
$(info -[10%]- $<)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
$(OBJPATH)/ConfigFile.o : src/ConfigFile.cpp src/ConfigFile.h src/xml/XMLObject.h src/FileUtils.h src/Common.h src/Utils.h src/compatibility/ConfigFileConf.h src/xml/XML.h
|
||||
$(OBJPATH)/ConfigFile.o : src/ConfigFile.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h src/xml/XML.h
|
||||
$(info -[20%]- $<)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
$(OBJPATH)/HFileGen.o : src/HFileGen.cpp src/FileUtils.h src/Common.h src/Utils.h src/ConfigFile.h src/xml/XMLObject.h src/HFileGen.h
|
||||
$(OBJPATH)/HFileGen.o : src/HFileGen.cpp src/FileUtils.h src/Common.h src/Utils.h src/HFileGen.h src/ConfigFile.h src/ConfigUtils.h src/xml/XMLObject.h
|
||||
$(info -[30%]- $<)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
$(OBJPATH)/IncludeDeps.o : src/IncludeDeps.cpp src/Common.h src/IncludeDeps.h src/ConfigFile.h src/xml/XMLObject.h src/FileUtils.h src/Utils.h
|
||||
$(OBJPATH)/IncludeDeps.o : src/IncludeDeps.cpp src/Common.h src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h
|
||||
$(info -[40%]- $<)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
$(OBJPATH)/Makefile.o : src/Makefile.cpp src/IncludeDeps.h src/ConfigFile.h src/xml/XMLObject.h src/FileUtils.h src/Common.h src/Utils.h src/Makefile.h
|
||||
$(OBJPATH)/Makefile.o : src/Makefile.cpp src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h src/Makefile.h
|
||||
$(info -[50%]- $<)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
$(OBJPATH)/Utils.o : src/Utils.cpp src/FileUtils.h src/Common.h src/Utils.h src/ConfigFile.h src/xml/XMLObject.h
|
||||
$(OBJPATH)/Utils.o : src/Utils.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h
|
||||
$(info -[60%]- $<)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
$(OBJPATH)/ConfigFileConf.o : src/compatibility/ConfigFileConf.cpp src/compatibility/ConfigFileConf.h
|
||||
$(info -[70%]- $<)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
$(OBJPATH)/main.o : src/main.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/xml/XMLObject.h src/FileUtils.h src/Utils.h src/HFileGen.h src/Makefile.h src/Timer.h
|
||||
$(OBJPATH)/main.o : src/main.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h src/HFileGen.h src/Makefile.h src/Timer.h
|
||||
$(info -[80%]- $<)
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
$(OBJPATH)/XML.o : src/xml/XML.cpp src/xml/XML.h src/xml/XMLObject.h src/xml/XMLException.h
|
||||
|
||||
+12
-4
@@ -1,14 +1,22 @@
|
||||
<makegen>
|
||||
<configuration name="Release">
|
||||
<define>_DEBUG</define>
|
||||
<generatehfile>false</generatehfile>
|
||||
<hfile>MakeGen.h</hfile>
|
||||
<hfilename>MakeGen.h</hfilename>
|
||||
<outputdir>bin/</outputdir>
|
||||
<outputname>makegen</outputname>
|
||||
<outputtype>executable</outputtype>
|
||||
<projectname>MakeGen</projectname>
|
||||
<srcdir>src/</srcdir>
|
||||
</configuration>
|
||||
<configuration name="Debug">
|
||||
<define>_DEBUG</define>
|
||||
<generatehfile>false</generatehfile>
|
||||
<hfilename>MakeGen.h</hfilename>
|
||||
<outputdir>bin/</outputdir>
|
||||
<outputname>makegen</outputname>
|
||||
<outputtype>executable</outputtype>
|
||||
<projectname>MakeGen</projectname>
|
||||
<srcdir>src/</srcdir>
|
||||
</configuration>
|
||||
<target>Release</target>
|
||||
<version>v1.3.0</version>
|
||||
</makegen>
|
||||
</makegen>
|
||||
|
||||
+18
-3
@@ -28,9 +28,9 @@ const static unsigned int FLAG_SIMPLE = BIT(9);
|
||||
const static unsigned int FLAG_CONFIG = BIT(10);
|
||||
|
||||
|
||||
#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
|
||||
#define LOG_INFO(...) LogHelper(__VA_ARGS__)
|
||||
#define LOG_WARNING(...) LogHelper(__VA_ARGS__)
|
||||
#define LOG_ERROR(...) LogHelper(__VA_ARGS__)
|
||||
|
||||
template <typename T>
|
||||
void Log(const T& var)
|
||||
@@ -44,3 +44,18 @@ void Log(const T& var, const Ts& ...vars)
|
||||
Log(var);
|
||||
Log(vars...);
|
||||
}
|
||||
|
||||
template <typename T, typename ...Ts>
|
||||
void LogHelper(const T& var)
|
||||
{
|
||||
Log(var);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template <typename T, typename ...Ts>
|
||||
void LogHelper(const T& var, const Ts& ...vars)
|
||||
{
|
||||
Log(var);
|
||||
Log(vars...);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
+69
-109
@@ -8,7 +8,7 @@
|
||||
void ConfigCLI::DisplayCLIHelp()
|
||||
{
|
||||
LOG_INFO(1+(char*)R"(
|
||||
MakeGen conf is used to create, modify and query the makegen.conf file.
|
||||
MakeGen conf is used to create, modify and query the makegen.xml file.
|
||||
|
||||
Usage: makegen conf <command> [<args>] [--help]
|
||||
|
||||
@@ -49,7 +49,7 @@ Usage: makegen conf add <setting> <value> [<values>]
|
||||
|
||||
Valid settings are:
|
||||
library Library
|
||||
libdir Library directory
|
||||
librarydir Library directory
|
||||
includedir Include directory
|
||||
define Preprocessor define
|
||||
cflag g++ compiler flags
|
||||
@@ -65,7 +65,7 @@ Usage: makegen conf remove <setting> <value> [<
|
||||
|
||||
Valid settings are
|
||||
library Library name
|
||||
libdir Library directory
|
||||
librarydir Library directory
|
||||
includedir Include directory
|
||||
define Preprocessor define
|
||||
cflag g++ compiler flags
|
||||
@@ -81,13 +81,13 @@ Usage: makegen conf set <setting> <value>
|
||||
|
||||
Valid string settings are:
|
||||
outputdir Directory of the compiled output
|
||||
output Name of the output executable/library
|
||||
name Name of the project
|
||||
outputname Name of the output executable/library
|
||||
projectname Name of the project
|
||||
outputtype Type of the output, valid values are executable, sharedlibrary
|
||||
and staticlibrary
|
||||
hfile Name of the generated project h-file
|
||||
|
||||
Valid boolean settings are:
|
||||
executable Specifies if the project be compiled as executable or library
|
||||
shared Specifies if the library should be compiled as shared.
|
||||
genhfile Specifies if MakeGen should generate a project h-file
|
||||
|
||||
Boolean values can be set to either true/t/yes/y or false/f/no/n)");
|
||||
@@ -102,50 +102,42 @@ Usage: makegen conf get <setting>
|
||||
|
||||
Valid settings are:
|
||||
library Library name
|
||||
libdir Library directory
|
||||
librarydir Library directory
|
||||
includedir Include directory
|
||||
define Preprocessor define
|
||||
cflag g++ compiler flags
|
||||
dependency Project which current project depends on
|
||||
outputdir Directory of the compiled output
|
||||
output Name of the output executable/library
|
||||
name Name of the project
|
||||
outputname Name of the output executable/library
|
||||
outputtype Type of the output, valid values are executable, sharedlibrary
|
||||
and staticlibrary
|
||||
projectname Name of the project
|
||||
hfile Name of the generated project h-file
|
||||
executable Specifies if the project be compiled as executable or library
|
||||
shared Specifies if the library should be compiled as shared.
|
||||
genhfile Specifies if MakeGen should generate a project h-file)");
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<std::string>*> ConfigCLI::GetSettingVectorMap(ConfigFile& config)
|
||||
{
|
||||
return {
|
||||
{"library",&config.libs},
|
||||
{"libdir",&config.libdirs},
|
||||
{"includedir",&config.includedirs},
|
||||
{"define",&config.defines},
|
||||
{"cflag",&config.flags},
|
||||
{"dependency",&config.dependencies}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
std::map<std::string, std::string*> ConfigCLI::GetSettingStringMap(ConfigFile& config)
|
||||
ConfigSetting ConfigCLI::CLIStringToSetting(const std::string& s)
|
||||
{
|
||||
return {
|
||||
{"outputdir", &config.outputdir},
|
||||
{"output", &config.outputname},
|
||||
{"name", &config.projectname},
|
||||
{"hfile", &config.hFile},
|
||||
};
|
||||
}
|
||||
|
||||
std::map<std::string, bool*> ConfigCLI::GetSettingBoolMap(ConfigFile& config)
|
||||
{
|
||||
return {
|
||||
{"executable", &config.executable},
|
||||
{"shared", &config.shared},
|
||||
{"genhfile", &config.generateHFile}
|
||||
static std::map<std::string, ConfigSetting> map{
|
||||
{"srcdir", ConfigSetting::SourceDir},
|
||||
{"outputdir", ConfigSetting::OutputDir},
|
||||
{"outputname", ConfigSetting::OutputName},
|
||||
{"outputtype", ConfigSetting::OutputType},
|
||||
{"projectname", ConfigSetting::ProjectName},
|
||||
{"hfile", ConfigSetting::HFileName},
|
||||
{"library", ConfigSetting::Library},
|
||||
{"librarydir", ConfigSetting::LibraryDir},
|
||||
{"includedir", ConfigSetting::IncludeDir},
|
||||
{"define", ConfigSetting::Define},
|
||||
{"cflag", ConfigSetting::CFlag},
|
||||
{"dependency", ConfigSetting::Dependency},
|
||||
{"genhfile", ConfigSetting::GenerateHFile},
|
||||
};
|
||||
auto it = map.find(s);
|
||||
if(it == map.end())
|
||||
return ConfigSetting::Invalid;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
int ConfigCLI::Gen(int argc, char** argv)
|
||||
@@ -168,7 +160,7 @@ int ConfigCLI::Gen(int argc, char** argv)
|
||||
}
|
||||
if(option == "default")
|
||||
{
|
||||
ConfigFile{}.Save();
|
||||
ConfigFile{FileUtils::GetRealPath("."),0}.Save();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@@ -191,25 +183,24 @@ int ConfigCLI::Add(int argc, char** argv, ConfigFile& config)
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto settingMap = GetSettingVectorMap(config);
|
||||
auto it = settingMap.find(argv[1]);
|
||||
if(it == settingMap.end())
|
||||
ConfigSetting setting = CLIStringToSetting(argv[1]);
|
||||
if(!ConfigUtils::IsVectorSetting(setting))
|
||||
{
|
||||
LOG_ERROR("Invalid setting: ", argv[1]);
|
||||
if(setting == ConfigSetting::Invalid)
|
||||
{
|
||||
LOG_ERROR("No such setting: ", argv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Cannot remove setting which only supports one argument");
|
||||
LOG_ERROR("use set instead.");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<std::string>* setting = it->second;
|
||||
std::set<std::string> settingSet{setting->begin(), setting->end()};
|
||||
for(int i = 2; i<argc;++i)
|
||||
{
|
||||
auto res = settingSet.emplace(argv[i]);
|
||||
if(!res.second)
|
||||
{
|
||||
LOG_ERROR("Duplicate value: ", argv[i]);
|
||||
}
|
||||
config.AddSettingVectorString(setting, argv[i]);
|
||||
}
|
||||
*setting = {settingSet.begin(), settingSet.end()};
|
||||
|
||||
config.Save();
|
||||
return 0;
|
||||
@@ -228,27 +219,25 @@ int ConfigCLI::Remove(int argc, char** argv, ConfigFile& config)
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto settingMap = GetSettingVectorMap(config);
|
||||
auto it = settingMap.find(argv[1]);
|
||||
if(it == settingMap.end())
|
||||
ConfigSetting setting = CLIStringToSetting(argv[1]);
|
||||
if(!ConfigUtils::IsVectorSetting(setting))
|
||||
{
|
||||
LOG_ERROR("Invalid setting: ", argv[1]);
|
||||
if(setting == ConfigSetting::Invalid)
|
||||
{
|
||||
LOG_ERROR("No such setting: ", argv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Cannot remove setting which only supports one argument");
|
||||
LOG_ERROR("use set instead.");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<std::string>* setting = it->second;
|
||||
std::set<std::string> settingSet{setting->begin(), setting->end()};
|
||||
for(int i = 2; i<argc;++i)
|
||||
{
|
||||
auto it = settingSet.find(argv[i]);
|
||||
if(it == settingSet.end())
|
||||
{
|
||||
LOG_ERROR("No such value in setting: ", argv[i]);
|
||||
}
|
||||
else
|
||||
settingSet.erase(it);
|
||||
config.RemoveSettingVectorString(setting, argv[i]);
|
||||
}
|
||||
*setting = {settingSet.begin(), settingSet.end()};
|
||||
|
||||
config.Save();
|
||||
return 0;
|
||||
@@ -267,31 +256,22 @@ int ConfigCLI::Set(int argc, char** argv, ConfigFile& config)
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto settingStringMap = GetSettingStringMap(config);
|
||||
auto it1 = settingStringMap.find(argv[1]);
|
||||
if(it1 == settingStringMap.end())
|
||||
ConfigSetting setting = CLIStringToSetting(argv[1]);
|
||||
if(!ConfigUtils::IsStringSetting(setting) && !ConfigUtils::IsBoolSetting(setting))
|
||||
{
|
||||
auto settingBoolMap = GetSettingBoolMap(config);
|
||||
auto it2 = settingBoolMap.find(argv[1]);
|
||||
if(it2 == settingBoolMap.end())
|
||||
if(setting == ConfigSetting::Invalid)
|
||||
{
|
||||
LOG_ERROR("Invalid setting: ", argv[1]);
|
||||
return 1;
|
||||
LOG_ERROR("No such setting: ", argv[1]);
|
||||
}
|
||||
std::string b = argv[2];
|
||||
if(b == "true" || b == "t" || b == "yes" || b == "y")
|
||||
*(it2->second) = true;
|
||||
else if(b == "false" || b == "f" || b == "no" || b == "n")
|
||||
*it2->second = false;
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Invalid boolean value: ", argv[2]);
|
||||
return 1;
|
||||
LOG_ERROR("Cannot set setting which supports multiple arguments");
|
||||
LOG_ERROR("use add or remove instead.");
|
||||
}
|
||||
config.Save();
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
*it1->second = argv[2];
|
||||
|
||||
config.SetSettingString(setting, argv[2]);
|
||||
config.Save();
|
||||
return 0;
|
||||
}
|
||||
@@ -308,29 +288,9 @@ int ConfigCLI::Get(int argc, char** argv, ConfigFile& config)
|
||||
LOG_ERROR("get needs exactly one parameter");
|
||||
return 1;
|
||||
}
|
||||
auto settingVectorMap = GetSettingVectorMap(config);
|
||||
auto itV = settingVectorMap.find(argv[1]);
|
||||
if(itV == settingVectorMap.end())
|
||||
{
|
||||
auto settingStringMap = GetSettingStringMap(config);
|
||||
auto itS = settingStringMap.find(argv[1]);
|
||||
if(itS == settingStringMap.end())
|
||||
{
|
||||
auto settingBoolMap = GetSettingBoolMap(config);
|
||||
auto itB = settingBoolMap.find(argv[1]);
|
||||
if(itB == settingBoolMap.end())
|
||||
{
|
||||
LOG_ERROR("Invalid setting: ", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
bool* t = itB->second;
|
||||
LOG_INFO(*itB->second ? "true" : "false");
|
||||
return 0;
|
||||
}
|
||||
LOG_INFO(*itS->second);
|
||||
return 0;
|
||||
}
|
||||
for(auto it = itV->second->begin(); it != itV->second->end(); ++it)
|
||||
ConfigSetting setting = CLIStringToSetting(argv[1]);
|
||||
std::vector<std::string> vector = config.GetSetting(setting);
|
||||
for(auto it = vector.begin(); it != vector.end(); ++it)
|
||||
{
|
||||
LOG_INFO(*it);
|
||||
}
|
||||
@@ -351,7 +311,7 @@ int ConfigCLI::Main(int argc, char** argv)
|
||||
{
|
||||
if(config)
|
||||
{
|
||||
LOG_ERROR("Config file already exist (makegen.conf)");
|
||||
LOG_ERROR("Config file already exist (", CONFIG_FILENAME, ")");
|
||||
return 1;
|
||||
}
|
||||
return Gen(argc-1, &argv[1]);
|
||||
|
||||
+1
-3
@@ -14,9 +14,7 @@ struct ConfigCLI
|
||||
static void DisplaySetHelp();
|
||||
static void DisplayGetHelp();
|
||||
|
||||
static std::map<std::string, std::vector<std::string>*> GetSettingVectorMap(ConfigFile& config);
|
||||
static std::map<std::string, std::string*> GetSettingStringMap(ConfigFile& config);
|
||||
static std::map<std::string, bool*> GetSettingBoolMap(ConfigFile& config);
|
||||
static ConfigSetting CLIStringToSetting(const std::string& s);
|
||||
|
||||
static int Gen(int argc, char** argv);
|
||||
static int Add(int argc, char** argv, ConfigFile& config);
|
||||
|
||||
+356
-162
@@ -7,33 +7,321 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
ConfigFile::ConfigFile()
|
||||
: outputdir("bin/"), srcdir("src/"), outputname(""), projectname(FileUtils::GetCurrentDirectory()), hFile(projectname+".h"), executable(true), shared(true), generateHFile(false)
|
||||
ConfigFile::ConfigFile(const std::string& path, int)
|
||||
: configPath{path}
|
||||
{
|
||||
// Converts project name (current directory) to lowercase
|
||||
// and replace whitespace with underscore
|
||||
std::transform(
|
||||
projectname.begin(),
|
||||
projectname.end(),
|
||||
std::back_inserter(outputname),
|
||||
[](unsigned char c)
|
||||
{
|
||||
if(c == ' ')
|
||||
return '_';
|
||||
return (char)std::tolower(c);
|
||||
});
|
||||
// Create xml
|
||||
XMLObject makegen("makegen", {}, std::map<std::string, std::vector<XMLObject>>{});
|
||||
|
||||
// Removes all other characters
|
||||
std::remove_if(
|
||||
outputdir.begin(),
|
||||
outputdir.end(),
|
||||
[](unsigned char c)
|
||||
{
|
||||
return (c < 'a' || c > 'z') && c != '_';
|
||||
});
|
||||
// Version, target and configuration is probably going to be used in the future
|
||||
makegen.AddXMLObject(XMLObject("version", {}, "v1.3.0"));
|
||||
makegen.AddXMLObject(XMLObject("target", {}, "Release"));
|
||||
|
||||
// Add suffix
|
||||
outputname += ".out";
|
||||
XMLObject configuration("configuration", {{"name", "Release"}}, std::map<std::string, std::vector<XMLObject>>{});
|
||||
configuration.AddXMLObject(XMLObject("projectname", {}, ConfigUtils::GetDefaultProjectName(configPath)));
|
||||
configuration.AddXMLObject(XMLObject("outputname", {}, ConfigUtils::GetDefaultOutputName(configPath)));
|
||||
configuration.AddXMLObject(XMLObject("srcdir", {}, "src/"));
|
||||
configuration.AddXMLObject(XMLObject("outputdir", {}, "bin/"));
|
||||
configuration.AddXMLObject(XMLObject("hfilename", {}, ConfigUtils::GetDefaultHFileName(configPath)));
|
||||
configuration.AddXMLObject(XMLObject("outputtype", {}, "executable"));
|
||||
configuration.AddXMLObject(XMLObject("generatehfile", {}, "false"));
|
||||
|
||||
makegen.AddXMLObject(configuration);
|
||||
config = makegen;
|
||||
Init();
|
||||
}
|
||||
|
||||
ConfigFile::ConfigFile(const std::string& path)
|
||||
: config{XML::FromFile(path + CONFIG_FILENAME)}, configPath{path}
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
ConfigFile::ConfigFile(XMLObject& config, const std::string& path)
|
||||
: config{config}, configPath{path}
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void ConfigFile::Init()
|
||||
{
|
||||
const std::vector<XMLObject>* targetXml = config.GetObjectPtr("target");
|
||||
target = "Release";
|
||||
if(!targetXml || targetXml->size() == 0)
|
||||
{
|
||||
LOG_ERROR("No target found in config file. Using target=", target);
|
||||
return;
|
||||
}
|
||||
|
||||
if(targetXml->size() > 1)
|
||||
LOG_ERROR("To many targets in config file. Using target=", (*targetXml)[0].GetText());
|
||||
if(targetXml->size() > 0)
|
||||
target = (*targetXml)[0].GetText();
|
||||
}
|
||||
|
||||
std::string& ConfigFile::GetSettingString(ConfigSetting setting)
|
||||
{
|
||||
// Adding it to the cache since we need to return a reference
|
||||
if(!ConfigUtils::IsStringSetting(setting))
|
||||
{
|
||||
LOG_ERROR("Invalid string setting");
|
||||
return cache.strings.emplace("invalid", "").first->second;
|
||||
}
|
||||
|
||||
std::string sSetting = ConfigUtils::GetSettingName(setting);
|
||||
auto it = cache.strings.find(sSetting);
|
||||
if(it != cache.strings.end())
|
||||
return it->second;
|
||||
|
||||
const std::vector<XMLObject>* values = GetConfiguration().GetObjectPtr(sSetting);
|
||||
|
||||
// No value found, using default
|
||||
if(values == nullptr)
|
||||
return cache.strings.emplace(sSetting, ConfigUtils::GetDefaultSettingString(setting, configPath)).first->second;
|
||||
|
||||
if(values->size() != 1)
|
||||
{
|
||||
LOG_ERROR("To many arguments for setting using first: ", (int)setting, "=", (*values)[0].GetText());
|
||||
}
|
||||
std::string s = (*values)[0].GetText();
|
||||
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
|
||||
s += '/';
|
||||
return cache.strings.emplace(sSetting, s).first->second;
|
||||
}
|
||||
|
||||
bool ConfigFile::GetSettingBool(ConfigSetting setting)
|
||||
{
|
||||
if(setting == ConfigSetting::Invalid)
|
||||
{
|
||||
LOG_ERROR("Invalid config setting");
|
||||
return false;
|
||||
}
|
||||
std::string sSetting = ConfigUtils::GetSettingName(setting);
|
||||
auto it = cache.bools.find(sSetting);
|
||||
if(it != cache.bools.end())
|
||||
return it->second;
|
||||
|
||||
const std::vector<XMLObject>* values = GetConfiguration().GetObjectPtr(sSetting);//,
|
||||
|
||||
if(values == nullptr)
|
||||
return cache.bools.emplace(sSetting, ConfigUtils::GetDefaultSettingBool(setting)).first->second;
|
||||
|
||||
if(values->size() != 1)
|
||||
{
|
||||
LOG_ERROR("To many arguments for setting using first: ", (int)setting, "=", (*values)[0].GetText());
|
||||
}
|
||||
return cache.bools.emplace(sSetting, (*values)[0].GetText() == "true").first->second;
|
||||
}
|
||||
|
||||
std::vector<std::string>& ConfigFile::GetSettingVectorString(ConfigSetting setting)
|
||||
{
|
||||
std::string sSetting = ConfigUtils::GetSettingName(setting);
|
||||
auto it = cache.vecStrings.find(sSetting);
|
||||
if(it != cache.vecStrings.end())
|
||||
return it->second;
|
||||
|
||||
const std::vector<XMLObject>* values = GetConfiguration().GetObjectPtr(sSetting);
|
||||
if(values == nullptr)
|
||||
return cache.vecStrings.emplace(sSetting, std::vector<std::string>{}).first->second;
|
||||
|
||||
std::vector<std::string> strings;
|
||||
strings.reserve(values->size());
|
||||
for(auto it = values->begin(); it != values->end(); ++it)
|
||||
{
|
||||
if(it->GetText() == "")
|
||||
continue;
|
||||
std::string s = it->GetText();
|
||||
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
|
||||
s += '/';
|
||||
strings.push_back(s);
|
||||
}
|
||||
|
||||
return cache.vecStrings.emplace(sSetting, strings).first->second;
|
||||
}
|
||||
|
||||
std::vector<std::string> ConfigFile::GetSetting(ConfigSetting setting)
|
||||
{
|
||||
if(ConfigUtils::IsStringSetting(setting))
|
||||
return {GetSettingString(setting)};
|
||||
else if(ConfigUtils::IsVectorSetting(setting))
|
||||
return GetSettingVectorString(setting);
|
||||
else if(ConfigUtils::IsBoolSetting(setting))
|
||||
return {GetSettingBool(setting) ? "true" : "false"};
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Invalid config setting");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool ConfigFile::SetSettingString(ConfigSetting setting, const std::string& value)
|
||||
{
|
||||
// Check if valid enum
|
||||
std::string s = value;
|
||||
std::string sSetting = ConfigUtils::GetSettingName(setting);
|
||||
if(ConfigUtils::IsStringSetting(setting))
|
||||
{
|
||||
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
|
||||
{
|
||||
s += '/';
|
||||
}
|
||||
auto it = cache.strings.find(sSetting);
|
||||
// Update cache
|
||||
if(it != cache.strings.end())
|
||||
it->second = s;
|
||||
else
|
||||
cache.strings.emplace(sSetting, s);
|
||||
}
|
||||
else if(ConfigUtils::IsBoolSetting(setting))
|
||||
{
|
||||
if(s == "true" || s == "t" || s == "yes" || s == "y")
|
||||
s = "true";
|
||||
else if(s == "false" || s == "f" || s == "no" || s == "n")
|
||||
s = "false";
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Invalid boolean value: ", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = cache.bools.find(sSetting);
|
||||
// Update cache
|
||||
if(it != cache.bools.end())
|
||||
it->second = s == "true";
|
||||
else
|
||||
cache.bools.emplace(sSetting, value == "true");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Not a string setting");
|
||||
return false;
|
||||
}
|
||||
|
||||
XMLObject& configuration = GetConfiguration();
|
||||
std::vector<XMLObject>* values = configuration.GetObjectPtr(sSetting);
|
||||
if(values == nullptr)
|
||||
configuration.AddXMLObject({sSetting, {}, s});
|
||||
else if(values->size() > 1)
|
||||
LOG_ERROR("Multiple values of setting, changing first: ", sSetting, "=", s);
|
||||
else
|
||||
(*values)[0].SetText(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigFile::AddSettingVectorString(ConfigSetting setting, const std::string& value)
|
||||
{
|
||||
// Check if valid enum
|
||||
if(ConfigUtils::IsVectorSetting(setting))
|
||||
{
|
||||
std::string s = value;
|
||||
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
|
||||
{
|
||||
s += '/';
|
||||
}
|
||||
std::string sSetting = ConfigUtils::GetSettingName(setting);
|
||||
auto it = cache.vecStrings.find(sSetting);
|
||||
|
||||
// Update cache
|
||||
if(it != cache.vecStrings.end())
|
||||
it->second.push_back(s);
|
||||
else
|
||||
cache.vecStrings.emplace(sSetting, std::vector<std::string>{s});
|
||||
|
||||
GetConfiguration().AddXMLObject({sSetting, {}, s});
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Not a vector setting");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfigFile::RemoveSettingVectorString(ConfigSetting setting, const std::string& value)
|
||||
{
|
||||
// Check if valid enum
|
||||
if(ConfigUtils::IsVectorSetting(setting))
|
||||
{
|
||||
std::string s = value;
|
||||
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
|
||||
{
|
||||
s += '/';
|
||||
}
|
||||
std::string sSetting = ConfigUtils::GetSettingName(setting);
|
||||
|
||||
auto it = cache.vecStrings.find(sSetting);
|
||||
if(it != cache.vecStrings.end())
|
||||
{
|
||||
// Update cache
|
||||
for(auto itVec = it->second.begin(); itVec != it->second.end(); ++itVec)
|
||||
{
|
||||
if(*itVec == s)
|
||||
{
|
||||
it->second.erase(itVec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<XMLObject>* values = GetConfiguration().GetObjectPtr(sSetting);
|
||||
bool found = false;
|
||||
for(auto it = values->begin(); it != values->end();++it)
|
||||
{
|
||||
if(it->GetText() == s)
|
||||
{
|
||||
values->erase(it);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
{
|
||||
LOG_ERROR("Couldn't find value: ", s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Not a vector setting");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
XMLObject& ConfigFile::GetConfiguration()
|
||||
{
|
||||
std::vector<XMLObject>* configurations = config.GetObjectPtr("configuration");
|
||||
if(configurations == nullptr || configurations->size() == 0)
|
||||
{
|
||||
LOG_ERROR("No configuration in makegen.xml");
|
||||
assert(false);
|
||||
}
|
||||
for(auto it = configurations->begin(); it != configurations->end(); ++it)
|
||||
{
|
||||
if(!it->HasAttribute("name"))
|
||||
{
|
||||
LOG_ERROR("No name attribute in configuration tag");
|
||||
continue;
|
||||
}
|
||||
if(it->GetAttribute("name") == target)
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR("Couldn\'t find given target in config file. Using target=", (*configurations)[0].HasAttribute("name") ? (*configurations)[0].GetAttribute("name") : "");
|
||||
return (*configurations)[0];
|
||||
}
|
||||
|
||||
const std::string& ConfigFile::GetConfigPath() const
|
||||
{
|
||||
return configPath;;
|
||||
}
|
||||
|
||||
ConfigFile& ConfigFile::GetDependencyConfig(size_t i)
|
||||
{
|
||||
return dependencyConfigs[i];
|
||||
}
|
||||
|
||||
std::optional<ConfigFile> ConfigFile::GetConfigFile(const std::string& filepath)
|
||||
@@ -55,38 +343,35 @@ std::optional<ConfigFile> ConfigFile::GetConfigFile(const std::string& filepath,
|
||||
std::ifstream f(filepath + CONFIG_FILENAME);
|
||||
if(!f.good())
|
||||
{
|
||||
ConfigFileConf::CreateXMLFile(realPath);
|
||||
// try to read an old config file
|
||||
f.close();
|
||||
f = std::ifstream(filepath + "makegen.conf");
|
||||
oldFile = true;
|
||||
f = std::ifstream(filepath + CONFIG_FILENAME);
|
||||
}
|
||||
|
||||
// Check if the file exists
|
||||
if(f.good())
|
||||
{
|
||||
f.close();
|
||||
std::optional<ConfigFile> conf;
|
||||
if(oldFile)
|
||||
conf = ConfigFileConf::Load(realPath);
|
||||
else
|
||||
conf = ConfigFile::Load(realPath);
|
||||
if(!conf)
|
||||
ConfigFile conf = ConfigFile(filepath);
|
||||
if(conf.hasInitError)
|
||||
return {};
|
||||
loadedConfigs.emplace(realPath, *conf);
|
||||
loadedConfigs.emplace(realPath, conf);
|
||||
|
||||
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
|
||||
// Create dependency config files.
|
||||
for(size_t i = 0; i < conf->dependencies.size();++i)
|
||||
for(size_t i = 0; i < dependencies.size();++i)
|
||||
{
|
||||
std::optional<ConfigFile> dep = GetConfigFile(conf->configPath + conf->dependencies[i], loadedConfigs);
|
||||
std::optional<ConfigFile> dep = GetConfigFile(conf.configPath + dependencies[i], loadedConfigs);
|
||||
if(dep)
|
||||
{
|
||||
conf->dependencyConfigs.push_back(*dep);
|
||||
conf->dependencies[i] = dep->configPath;
|
||||
conf.dependencyConfigs.push_back(*dep);
|
||||
dependencies[i] = dep->configPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove the dependency since it is already accounted for
|
||||
conf->dependencies.erase(conf->dependencies.begin() + i);
|
||||
dependencies.erase(dependencies.begin() + i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
@@ -95,103 +380,6 @@ std::optional<ConfigFile> ConfigFile::GetConfigFile(const std::string& filepath,
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
std::optional<ConfigFile> ConfigFile::Load(const std::string& filedir)
|
||||
{
|
||||
XMLObject object{XML::FromFile(filedir + CONFIG_FILENAME)};
|
||||
|
||||
const std::string& target = object.GetObject("target", {XMLObject{"target", {}, "Release"}})[0].GetText();
|
||||
const std::vector<XMLObject>& configurations = object.GetObject("configuration");
|
||||
const XMLObject* configuration = nullptr;
|
||||
for(auto it = configurations.begin(); it != configurations.end(); ++it)
|
||||
{
|
||||
if(!it->HasAttribute("name"))
|
||||
{
|
||||
LOG_ERROR("No name attribute in configuration tag");
|
||||
continue;
|
||||
}
|
||||
if(it->GetAttribute("name") == target)
|
||||
{
|
||||
configuration = &(*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(configuration == nullptr)
|
||||
{
|
||||
LOG_ERROR("No configuration matching target: ", target);
|
||||
return {};
|
||||
}
|
||||
|
||||
ConfigFile conf;
|
||||
conf.configPath = filedir;
|
||||
conf.projectname = configuration->GetObject("projectname",
|
||||
{XMLObject{"projectname", {}, conf.projectname}})[0].GetText();
|
||||
conf.outputname = configuration->GetObject("outputname",
|
||||
{XMLObject{"outputname", {}, conf.outputname}})[0].GetText();
|
||||
conf.srcdir = configuration->GetObject("srcdir",
|
||||
{XMLObject{"srcdir", {}, conf.srcdir}})[0].GetText();
|
||||
conf.outputdir = configuration->GetObject("outputdir",
|
||||
{XMLObject{"outputdir", {}, conf.outputdir}})[0].GetText();
|
||||
conf.hFile = configuration->GetObject("hfile",
|
||||
{XMLObject{"hfile", {}, conf.hFile}})[0].GetText();
|
||||
std::string outputtype = configuration->GetObject("outputtype",
|
||||
{XMLObject{"outputtype", {}, "executable"}})[0].GetText();
|
||||
|
||||
if(conf.srcdir[conf.srcdir.size()-1] != '/')
|
||||
conf.srcdir += '/';
|
||||
if(conf.outputdir[conf.srcdir.size()-1] != '/')
|
||||
conf.outputdir += '/';
|
||||
|
||||
if(outputtype == "executable")
|
||||
conf.executable = true;
|
||||
else if(outputtype == "staticlibrary")
|
||||
{
|
||||
conf.executable = false;
|
||||
conf.shared = false;
|
||||
}
|
||||
else if(outputtype == "sharedlibrary")
|
||||
{
|
||||
conf.executable = false;
|
||||
conf.shared = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Invalid outputtype: ", outputtype);
|
||||
LOG_ERROR("Valid arguments are executable, staticlibrary and sharedlibrary");
|
||||
}
|
||||
conf.generateHFile = configuration->GetObject("generatehfile",
|
||||
{XMLObject{"generatehfile", {}, conf.generateHFile ? "true" : "false"}})[0].GetText() == "true";
|
||||
|
||||
const int vectorCount = 6;
|
||||
std::tuple<std::vector<XMLObject>, std::vector<std::string>*, bool> vectors[vectorCount] = {
|
||||
{configuration->GetObject("library"), &conf.libs, false},
|
||||
{configuration->GetObject("libdir"), &conf.libdirs, true},
|
||||
{configuration->GetObject("includedir"), &conf.includedirs, true},
|
||||
{configuration->GetObject("define"), &conf.defines, false},
|
||||
{configuration->GetObject("compileflag"), &conf.flags, false},
|
||||
{configuration->GetObject("dependency"), &conf.dependencies, true}
|
||||
};
|
||||
|
||||
for(int i = 0;i<vectorCount;++i)
|
||||
{
|
||||
const std::vector<XMLObject>& xmls = std::get<0>(vectors[i]);
|
||||
std::vector<std::string>* vec = std::get<1>(vectors[i]);
|
||||
bool isDir = std::get<2>(vectors[i]);
|
||||
for(auto it = xmls.begin(); it != xmls.end();++it)
|
||||
{
|
||||
if(it->GetText() != "")
|
||||
{
|
||||
std::string s = it->GetText();
|
||||
if(isDir && s[s.size()-1] != '/')
|
||||
s += '/';
|
||||
vec->push_back(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return conf;
|
||||
}
|
||||
|
||||
void ConfigFile::InputBoolean(const std::string& inputText, bool& b)
|
||||
{
|
||||
std::string input;
|
||||
@@ -238,38 +426,39 @@ void ConfigFile::InputMultiple(const std::string& inputText, std::vector<std::st
|
||||
|
||||
ConfigFile ConfigFile::Gen()
|
||||
{
|
||||
ConfigFile conf;
|
||||
InputBoolean("Should it be compiled as an executable? (y/n)", conf.executable);
|
||||
bool executable, shared, generateHFile;
|
||||
std::vector<std::string> libs, libdirs, includedirs, defines, compileFlags, dependencies;
|
||||
std::string srcdir, outputdir, projectname, outputname, hFile;
|
||||
|
||||
InputBoolean("Should it be compiled as an executable? (y/n)", executable);
|
||||
// If it isn't an executable there is not need to have libraries
|
||||
if(conf.executable)
|
||||
if(executable)
|
||||
{
|
||||
InputMultiple("Enter library:", conf.libs,false);
|
||||
InputMultiple("Enter library directory:", conf.libdirs,true);
|
||||
InputMultiple("Enter project dependencies:", conf.dependencies,true);
|
||||
InputMultiple("Enter library:", libs,false);
|
||||
InputMultiple("Enter library directory:", libdirs,true);
|
||||
InputMultiple("Enter project dependencies:", dependencies,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
InputBoolean("Should it be compiled as a shared library? (y/n)", conf.shared);
|
||||
InputBoolean("Should it compile a project h-file? (y/n):", conf.generateHFile);
|
||||
if(conf.generateHFile)
|
||||
InputBoolean("Should it be compiled as a shared library? (y/n)", shared);
|
||||
InputBoolean("Should it compile a project h-file? (y/n):", generateHFile);
|
||||
if(generateHFile)
|
||||
{
|
||||
InputString("Enter the project h-file name (relative to source directory): ", conf.hFile, false, false);
|
||||
InputString("Enter the project h-file name (relative to source directory): ", hFile, false, false);
|
||||
}
|
||||
}
|
||||
InputMultiple("Enter include directory:", conf.includedirs, true);
|
||||
InputString("Enter source directories:", conf.srcdir, true, false);
|
||||
InputMultiple("Enter preprocessor definitions:", conf.defines, false);
|
||||
InputMultiple("Enter compile flags:", conf.flags, false);
|
||||
InputString("Enter output directory (default: bin):", conf.outputdir, true, true);
|
||||
if(conf.outputdir == "")
|
||||
conf.outputdir = "bin/";
|
||||
InputString("Enter a name for the project:", conf.projectname, false, false);
|
||||
InputString("Enter a name for the output file:", conf.outputname, false, false);
|
||||
return conf;
|
||||
}
|
||||
InputMultiple("Enter include directory:", includedirs, true);
|
||||
InputString("Enter source directories:", srcdir, true, false);
|
||||
InputMultiple("Enter preprocessor definitions:", defines, false);
|
||||
InputMultiple("Enter compile flags:", compileFlags, false);
|
||||
InputString("Enter output directory (default: bin):", outputdir, true, true);
|
||||
if(outputdir == "")
|
||||
outputdir = "bin/";
|
||||
InputString("Enter a name for the project:", projectname, false, false);
|
||||
InputString("Enter a name for the output file:", outputname, false, false);
|
||||
|
||||
void ConfigFile::Save() const
|
||||
{
|
||||
|
||||
// Create xml
|
||||
XMLObject makegen("makegen", {}, std::map<std::string, std::vector<XMLObject>>{});
|
||||
|
||||
// Version, target and configuration is probably going to be used in the future
|
||||
@@ -281,7 +470,7 @@ void ConfigFile::Save() const
|
||||
configuration.AddXMLObject(XMLObject("outputname", {}, outputname));
|
||||
configuration.AddXMLObject(XMLObject("srcdir", {}, srcdir));
|
||||
configuration.AddXMLObject(XMLObject("outputdir", {}, outputdir));
|
||||
configuration.AddXMLObject(XMLObject("hfile", {}, hFile));
|
||||
configuration.AddXMLObject(XMLObject("hfilename", {}, hFile));
|
||||
configuration.AddXMLObject(XMLObject("outputtype", {},
|
||||
executable ? "executable" : (shared ? "sharedlibrary" : "staticlibrary")));
|
||||
configuration.AddXMLObject(XMLObject("generatehfile", {}, generateHFile ? "true" : "false"));
|
||||
@@ -289,17 +478,22 @@ void ConfigFile::Save() const
|
||||
for(auto it = libs.begin();it != libs.end(); ++it)
|
||||
configuration.AddXMLObject({"library",{},*it});
|
||||
for(auto it = libdirs.begin();it != libdirs.end(); ++it)
|
||||
configuration.AddXMLObject({"libdir",{},*it});
|
||||
configuration.AddXMLObject({"librarydir",{},*it});
|
||||
for(auto it = includedirs.begin();it != includedirs.end(); ++it)
|
||||
configuration.AddXMLObject({"includedir",{},*it});
|
||||
for(auto it = defines.begin();it != defines.end(); ++it)
|
||||
configuration.AddXMLObject({"define",{},*it});
|
||||
for(auto it = flags.begin();it != flags.end(); ++it)
|
||||
configuration.AddXMLObject({"compileflag",{},*it});
|
||||
for(auto it = compileFlags.begin();it != compileFlags.end(); ++it)
|
||||
configuration.AddXMLObject({"cflag",{},*it});
|
||||
for(auto it = dependencies.begin();it != dependencies.end(); ++it)
|
||||
configuration.AddXMLObject({"dependency",{},*it});
|
||||
|
||||
makegen.AddXMLObject(configuration);
|
||||
std::ofstream file("makegen.xml");
|
||||
file << makegen;
|
||||
return ConfigFile{makegen, FileUtils::GetRealPath("./")};
|
||||
}
|
||||
|
||||
void ConfigFile::Save() const
|
||||
{
|
||||
std::ofstream file("makegen.xml");
|
||||
file << config;
|
||||
}
|
||||
|
||||
+33
-19
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "ConfigUtils.h"
|
||||
#include "xml/XMLObject.h"
|
||||
|
||||
#include <map>
|
||||
@@ -11,29 +12,42 @@ static const std::string CONFIG_FILENAME = "makegen.xml";
|
||||
|
||||
class ConfigFile
|
||||
{
|
||||
public:
|
||||
private:
|
||||
ConfigCache cache;
|
||||
|
||||
XMLObject config;
|
||||
// Current configuration
|
||||
std::string target;
|
||||
|
||||
std::string configPath;
|
||||
|
||||
std::vector<std::string> libs;
|
||||
std::vector<std::string> libdirs;
|
||||
std::vector<std::string> includedirs;
|
||||
std::vector<std::string> defines;
|
||||
std::vector<std::string> flags;
|
||||
std::vector<std::string> dependencies;
|
||||
|
||||
std::string outputdir;
|
||||
std::string srcdir;
|
||||
std::string outputname;
|
||||
std::string projectname;
|
||||
std::string hFile;
|
||||
bool executable;
|
||||
bool shared;
|
||||
bool generateHFile;
|
||||
|
||||
std::vector<ConfigFile> dependencyConfigs;
|
||||
|
||||
bool hasInitError = false;
|
||||
|
||||
public:
|
||||
ConfigFile();
|
||||
// Generates a new default config file
|
||||
ConfigFile(const std::string& path, int);
|
||||
ConfigFile(const std::string& path);
|
||||
ConfigFile(XMLObject& config, const std::string& path);
|
||||
|
||||
void Save() const;
|
||||
|
||||
std::string& GetSettingString(ConfigSetting setting);
|
||||
bool GetSettingBool(ConfigSetting setting);
|
||||
std::vector<std::string>& GetSettingVectorString(ConfigSetting setting);
|
||||
std::vector<std::string> GetSetting(ConfigSetting setting);
|
||||
|
||||
bool SetSettingString(ConfigSetting setting, const std::string& value);
|
||||
bool AddSettingVectorString(ConfigSetting setting, const std::string& value);
|
||||
bool RemoveSettingVectorString(ConfigSetting setting, const std::string& value);
|
||||
|
||||
XMLObject& GetConfiguration();
|
||||
const std::string& GetConfigPath() const;
|
||||
ConfigFile& GetDependencyConfig(size_t i);
|
||||
private:
|
||||
void Init();
|
||||
|
||||
public:
|
||||
static ConfigFile Gen();
|
||||
static std::optional<ConfigFile> GetConfigFile(const std::string& filepath = "./");
|
||||
private:
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
#pragma once
|
||||
|
||||
#include "Common.h"
|
||||
#include "FileUtils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
struct ConfigCache
|
||||
{
|
||||
std::map<std::string, std::string> strings;
|
||||
std::map<std::string, std::vector<std::string>> vecStrings;
|
||||
std::map<std::string, bool> bools;
|
||||
};
|
||||
|
||||
enum class ConfigSetting
|
||||
{
|
||||
// vectors
|
||||
Library = 0, LibraryDir = 1, IncludeDir = 2, Define = 3, CFlag = 4, Dependency = 5,
|
||||
// Strings
|
||||
SourceDir = 32, OutputDir = 33, OutputName = 34, OutputType = 35, ProjectName = 36, HFileName = 37,
|
||||
// Bools
|
||||
GenerateHFile = 64,
|
||||
// Other
|
||||
Invalid = 1024
|
||||
};
|
||||
|
||||
struct ConfigUtils
|
||||
{
|
||||
static std::string GetSettingName(ConfigSetting setting)
|
||||
{
|
||||
switch(setting)
|
||||
{
|
||||
case ConfigSetting::SourceDir:
|
||||
return "srcdir";
|
||||
case ConfigSetting::OutputDir:
|
||||
return "outputdir";
|
||||
case ConfigSetting::OutputName:
|
||||
return "outputname";
|
||||
case ConfigSetting::OutputType:
|
||||
return "outputtype";
|
||||
case ConfigSetting::ProjectName:
|
||||
return "projectname";
|
||||
case ConfigSetting::HFileName:
|
||||
return "hfilename";
|
||||
case ConfigSetting::LibraryDir:
|
||||
return "librarydir";
|
||||
case ConfigSetting::IncludeDir:
|
||||
return "includedir";
|
||||
case ConfigSetting::Dependency:
|
||||
return "dependency";
|
||||
case ConfigSetting::Library:
|
||||
return "library";
|
||||
case ConfigSetting::Define:
|
||||
return "define";
|
||||
case ConfigSetting::CFlag:
|
||||
return "cflag";
|
||||
case ConfigSetting::GenerateHFile:
|
||||
return "generatehfile";
|
||||
case ConfigSetting::Invalid:
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsDirectory(ConfigSetting setting)
|
||||
{
|
||||
// Library, LibraryDir, IncludeDir, Define, CFlag, Dependency,
|
||||
switch(setting)
|
||||
{
|
||||
case ConfigSetting::SourceDir:
|
||||
case ConfigSetting::OutputDir:
|
||||
case ConfigSetting::LibraryDir:
|
||||
case ConfigSetting::IncludeDir:
|
||||
case ConfigSetting::Dependency:
|
||||
return true;
|
||||
case ConfigSetting::OutputName:
|
||||
case ConfigSetting::OutputType:
|
||||
case ConfigSetting::ProjectName:
|
||||
case ConfigSetting::HFileName:
|
||||
case ConfigSetting::Library:
|
||||
case ConfigSetting::Define:
|
||||
case ConfigSetting::CFlag:
|
||||
case ConfigSetting::GenerateHFile:
|
||||
return false;
|
||||
default:
|
||||
LOG_ERROR("INVALID ENUM: ", (int)setting);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsStringSetting(ConfigSetting setting)
|
||||
{
|
||||
switch(setting)
|
||||
{
|
||||
case ConfigSetting::SourceDir:
|
||||
case ConfigSetting::OutputDir:
|
||||
case ConfigSetting::OutputName:
|
||||
case ConfigSetting::OutputType:
|
||||
case ConfigSetting::ProjectName:
|
||||
case ConfigSetting::HFileName:
|
||||
return true;
|
||||
case ConfigSetting::LibraryDir:
|
||||
case ConfigSetting::IncludeDir:
|
||||
case ConfigSetting::Dependency:
|
||||
case ConfigSetting::Library:
|
||||
case ConfigSetting::Define:
|
||||
case ConfigSetting::CFlag:
|
||||
case ConfigSetting::GenerateHFile:
|
||||
case ConfigSetting::Invalid:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsVectorSetting(ConfigSetting setting)
|
||||
{
|
||||
switch(setting)
|
||||
{
|
||||
case ConfigSetting::LibraryDir:
|
||||
case ConfigSetting::IncludeDir:
|
||||
case ConfigSetting::Dependency:
|
||||
case ConfigSetting::Library:
|
||||
case ConfigSetting::Define:
|
||||
case ConfigSetting::CFlag:
|
||||
return true;
|
||||
case ConfigSetting::SourceDir:
|
||||
case ConfigSetting::OutputDir:
|
||||
case ConfigSetting::OutputName:
|
||||
case ConfigSetting::OutputType:
|
||||
case ConfigSetting::ProjectName:
|
||||
case ConfigSetting::HFileName:
|
||||
case ConfigSetting::GenerateHFile:
|
||||
case ConfigSetting::Invalid:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static bool IsBoolSetting(ConfigSetting setting)
|
||||
{
|
||||
switch(setting)
|
||||
{
|
||||
case ConfigSetting::GenerateHFile:
|
||||
return true;
|
||||
case ConfigSetting::SourceDir:
|
||||
case ConfigSetting::OutputDir:
|
||||
case ConfigSetting::OutputName:
|
||||
case ConfigSetting::OutputType:
|
||||
case ConfigSetting::ProjectName:
|
||||
case ConfigSetting::HFileName:
|
||||
case ConfigSetting::LibraryDir:
|
||||
case ConfigSetting::IncludeDir:
|
||||
case ConfigSetting::Dependency:
|
||||
case ConfigSetting::Library:
|
||||
case ConfigSetting::Define:
|
||||
case ConfigSetting::CFlag:
|
||||
case ConfigSetting::Invalid:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GetDefaultSettingString(ConfigSetting setting, const std::string& path)
|
||||
{
|
||||
switch(setting)
|
||||
{
|
||||
case ConfigSetting::SourceDir:
|
||||
return "src/";
|
||||
case ConfigSetting::OutputDir:
|
||||
return "bin/";
|
||||
case ConfigSetting::OutputName:
|
||||
return GetDefaultOutputName(path);
|
||||
case ConfigSetting::OutputType:
|
||||
return "executable";
|
||||
case ConfigSetting::ProjectName:
|
||||
return GetDefaultProjectName(path);
|
||||
case ConfigSetting::HFileName:
|
||||
return GetDefaultHFileName(path);
|
||||
case ConfigSetting::GenerateHFile:
|
||||
return GetDefaultSettingBool(setting) ? "true" : "false";
|
||||
default:
|
||||
LOG_ERROR("INVALID STRING ENUM: ", (int)setting);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static bool GetDefaultSettingBool(ConfigSetting setting)
|
||||
{
|
||||
switch(setting)
|
||||
{
|
||||
case ConfigSetting::GenerateHFile:
|
||||
return false;
|
||||
default:
|
||||
LOG_ERROR("NOT BOOLEAN VALUE: ", (int)setting);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GetDefaultProjectName(const std::string& path)
|
||||
{
|
||||
return FileUtils::GetTopDirectory(path);
|
||||
}
|
||||
|
||||
static std::string GetDefaultOutputName(const std::string& path)
|
||||
{
|
||||
std::string projectname = GetDefaultProjectName(path);
|
||||
std::string outputname;
|
||||
std::transform(
|
||||
projectname.begin(),
|
||||
projectname.end(),
|
||||
std::back_inserter(outputname),
|
||||
[](unsigned char c)
|
||||
{
|
||||
if(c == ' ')
|
||||
return '_';
|
||||
return (char)std::tolower(c);
|
||||
});
|
||||
auto it = std::remove_if(
|
||||
outputname.begin(),
|
||||
outputname.end(),
|
||||
[](unsigned char c)
|
||||
{
|
||||
return (c < '0' || c > '9') && (c < 'a' || c > 'z') && c != '_';
|
||||
});
|
||||
outputname.erase(it, outputname.end());
|
||||
outputname += ".out";
|
||||
return outputname;
|
||||
}
|
||||
|
||||
static std::string GetDefaultHFileName(const std::string& path)
|
||||
{
|
||||
std::string hfile = GetDefaultProjectName(path);
|
||||
auto it = std::remove_if(
|
||||
hfile.begin(),
|
||||
hfile.end(),
|
||||
[](unsigned char c)
|
||||
{
|
||||
return (c < 'a' || c > 'z') && (c < 'A' || c > 'Z');
|
||||
});
|
||||
hfile.erase(it, hfile.end());
|
||||
hfile += ".h";
|
||||
return hfile;
|
||||
}
|
||||
};
|
||||
+15
-3
@@ -34,14 +34,26 @@ struct FileUtils
|
||||
{
|
||||
static char path[256]; // Usual maximum filename
|
||||
getcwd(path, sizeof(path));
|
||||
std::string dir = path;
|
||||
size_t pos = dir.find_last_of("/");
|
||||
return GetTopDirectory(path);
|
||||
}
|
||||
|
||||
static std::string GetTopDirectory(const std::string& dir)
|
||||
{
|
||||
if(dir.size() == 0)
|
||||
{
|
||||
LOG_ERROR("Cannot send empty string to FileUtils::GetTopDirectory()");
|
||||
assert(false);
|
||||
}
|
||||
size_t dirEnd = std::string::npos;
|
||||
if(dir[dir.size()-1] == '/')
|
||||
dirEnd = dir.size()-2;
|
||||
size_t pos = dir.find_last_of("/", dirEnd);
|
||||
if(pos == std::string::npos)
|
||||
{
|
||||
LOG_ERROR("Couldn't find / (slash) in directory. This shouldn't occur.");
|
||||
assert(false);
|
||||
}
|
||||
return dir.substr(pos+1);
|
||||
return dir.substr(pos + 1, dirEnd - pos);
|
||||
}
|
||||
|
||||
static std::string GetRealPath(const std::string& filename)
|
||||
|
||||
+4
-4
@@ -3,11 +3,11 @@
|
||||
#include "FileUtils.h"
|
||||
#include <set>
|
||||
|
||||
void HFileGen::Create(const ConfigFile& conf)
|
||||
void HFileGen::Create(ConfigFile& conf)
|
||||
{
|
||||
std::set<std::string> hFiles;
|
||||
std::vector<std::string> files;
|
||||
std::string path = conf.configPath + conf.srcdir;
|
||||
std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir);
|
||||
FileUtils::GetAllFiles(path,files);
|
||||
// include paramenter with the path of the file
|
||||
// For example src/graphics/Window.h -> graphics/Window.h if src is a src folder
|
||||
@@ -17,7 +17,7 @@ void HFileGen::Create(const ConfigFile& conf)
|
||||
if(extensionPos != std::string::npos)
|
||||
{
|
||||
std::string filename = it->substr(path.length());
|
||||
if(it->substr(extensionPos+1) == "h" && filename != conf.configPath + conf.hFile)
|
||||
if(it->substr(extensionPos+1) == "h" && filename != conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::HFileName))
|
||||
{
|
||||
// Make files sorted in alphabetical order
|
||||
hFiles.emplace(filename);
|
||||
@@ -25,7 +25,7 @@ void HFileGen::Create(const ConfigFile& conf)
|
||||
}
|
||||
}
|
||||
|
||||
std::ofstream os(conf.configPath + conf.srcdir+"/"+conf.hFile);
|
||||
std::ofstream os(path + "/" + conf.GetSettingString(ConfigSetting::HFileName));
|
||||
os << "#pragma once" << std::endl << std::endl;
|
||||
for(auto&& hFile : hFiles)
|
||||
os << "#include <" << hFile << ">" << std::endl;
|
||||
|
||||
+1
-1
@@ -5,5 +5,5 @@
|
||||
class HFileGen
|
||||
{
|
||||
public:
|
||||
static void Create(const ConfigFile& conf);
|
||||
static void Create(ConfigFile& conf);
|
||||
};
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ class IncludeDeps
|
||||
printCounter++;
|
||||
printSet.emplace(filepath);
|
||||
if(!projectHFile)
|
||||
stream << FileUtils::GetRelativePath(conf.configPath, filepath);
|
||||
stream << FileUtils::GetRelativePath(conf.GetConfigPath(), filepath);
|
||||
for(auto it = dependencies.begin();it!=dependencies.end();++it)
|
||||
{
|
||||
stream << " ";
|
||||
|
||||
+32
-24
@@ -6,7 +6,7 @@
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
void Makefile::Save(const ConfigFile& conf, unsigned int flags)
|
||||
void Makefile::Save(ConfigFile& conf, unsigned int flags)
|
||||
{
|
||||
std::set<HFile> hFiles; // hFile, directory
|
||||
std::set<std::string> cppFiles;
|
||||
@@ -15,14 +15,15 @@ void Makefile::Save(const ConfigFile& conf, unsigned int flags)
|
||||
else
|
||||
Utils::GetCppAndHFiles(conf, hFiles, cppFiles);
|
||||
|
||||
std::ofstream outputFile(conf.configPath + "Makefile");
|
||||
outputFile << "# This Makefile was generated using MakeGen "<< MAKEGEN_VERSION<< " made by Tim Håkansson" << std::endl;
|
||||
std::ofstream outputFile(conf.GetConfigPath()+ "Makefile");
|
||||
outputFile << "# This Makefile was generated using MakeGen "<< MAKEGEN_VERSION << " made by Tim Håkansson" << std::endl;
|
||||
outputFile << "# and is licensed under MIT. Full source of the project can be found at" << std::endl;
|
||||
outputFile << "# https://github.com/Thraix/MakeGen" << std::endl;
|
||||
outputFile << "CC=@g++" << std::endl;
|
||||
if(!conf.executable)
|
||||
std::string outputtype = conf.GetSettingString(ConfigSetting::OutputType);
|
||||
if(outputtype != "executable")
|
||||
{
|
||||
if(conf.shared)
|
||||
if(outputtype == "sharedlibrary")
|
||||
outputFile << "CO=@g++ -shared -o" << std::endl;
|
||||
else
|
||||
outputFile << "CO=@g++ -o" << std::endl;
|
||||
@@ -31,10 +32,11 @@ void Makefile::Save(const ConfigFile& conf, unsigned int flags)
|
||||
outputFile << "CO=@g++ -o" << std::endl;
|
||||
|
||||
outputFile << "MKDIR_P=mkdir -p" << std::endl;
|
||||
outputFile << "BIN=" << conf.outputdir << std::endl;
|
||||
outputFile << "BIN=" << conf.GetSettingString(ConfigSetting::OutputDir) << std::endl;
|
||||
outputFile << "OBJPATH=$(BIN)intermediates" << std::endl;
|
||||
outputFile << "INCLUDES=";
|
||||
for(auto it = conf.includedirs.begin();it!=conf.includedirs.end();++it)
|
||||
std::vector<std::string>& includedirs = conf.GetSettingVectorString(ConfigSetting::IncludeDir);
|
||||
for(auto it = includedirs.begin(); it != includedirs.end(); ++it)
|
||||
{
|
||||
outputFile << "-I./" << *it << " ";
|
||||
}
|
||||
@@ -47,7 +49,7 @@ void Makefile::Save(const ConfigFile& conf, unsigned int flags)
|
||||
outputFile << "$(OBJPATH)/" << it->substr(slash, extensionPos - slash) << ".o ";
|
||||
}
|
||||
outputFile << std::endl;
|
||||
if(conf.executable || !conf.shared)
|
||||
if(outputtype == "executable" || outputtype != "sharedlibrary")
|
||||
{
|
||||
outputFile << "CFLAGS=$(INCLUDES) -std=c++17 -c -w -g3 ";
|
||||
}
|
||||
@@ -55,46 +57,51 @@ void Makefile::Save(const ConfigFile& conf, unsigned int flags)
|
||||
{
|
||||
outputFile << "CFLAGS=$(INCLUDES) -fPIC -std=c++17 -c -w -g3 ";
|
||||
}
|
||||
for(auto it = conf.defines.begin();it!=conf.defines.end();++it)
|
||||
std::vector<std::string>& defines = conf.GetSettingVectorString(ConfigSetting::Define);
|
||||
for(auto it = defines.begin(); it != defines.end(); ++it)
|
||||
{
|
||||
outputFile << "-D" << *it << " ";
|
||||
}
|
||||
for(auto it = conf.flags.begin();it!=conf.flags.end();++it)
|
||||
std::vector<std::string>& cflags = conf.GetSettingVectorString(ConfigSetting::CFlag);
|
||||
for(auto it = cflags.begin(); it != cflags.end(); ++it)
|
||||
{
|
||||
outputFile << *it << " ";
|
||||
}
|
||||
outputFile << std::endl;
|
||||
if(conf.executable)
|
||||
if(outputtype == "executable")
|
||||
{
|
||||
std::vector<std::string>& libdirs= conf.GetSettingVectorString(ConfigSetting::LibraryDir);
|
||||
outputFile << "LIBDIR=";
|
||||
for(auto it = conf.libdirs.begin();it!=conf.libdirs.end();++it)
|
||||
for(auto it = libdirs.begin();it!=libdirs.end();++it)
|
||||
{
|
||||
outputFile << "-L./" << *it << " ";
|
||||
}
|
||||
outputFile << std::endl;
|
||||
outputFile << "LDFLAGS=";
|
||||
for(auto it = conf.libdirs.begin();it!=conf.libdirs.end();++it)
|
||||
for(auto it = libdirs.begin(); it != libdirs.end(); ++it)
|
||||
{
|
||||
outputFile << "-Wl,-rpath=" << *it << " ";
|
||||
}
|
||||
outputFile << std::endl;
|
||||
std::vector<std::string>& libs = conf.GetSettingVectorString(ConfigSetting::Library);
|
||||
outputFile << "LIBS=$(LIBDIR) ";
|
||||
for(auto it = conf.libs.begin();it!=conf.libs.end();++it)
|
||||
for(auto it = libs.begin(); it != libs.end(); ++it)
|
||||
{
|
||||
outputFile << "-l" << *it << " ";
|
||||
}
|
||||
outputFile << std::endl;
|
||||
if(!conf.dependencies.empty())
|
||||
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
|
||||
if(!dependencies.empty())
|
||||
{
|
||||
outputFile << "DEPENDENCIES=";
|
||||
for(auto it = conf.dependencies.begin();it!=conf.dependencies.end();++it)
|
||||
for(auto it = dependencies.begin();it!=dependencies.end();++it)
|
||||
{
|
||||
outputFile << *it << " ";
|
||||
}
|
||||
outputFile << std::endl;
|
||||
}
|
||||
}
|
||||
outputFile << "OUTPUT=$(BIN)" << conf.outputname << std::endl;
|
||||
outputFile << "OUTPUT=$(BIN)" << conf.GetSettingString(ConfigSetting::OutputName) << std::endl;
|
||||
outputFile << ".PHONY: all directories rebuild clean run" << std::endl;
|
||||
|
||||
// All
|
||||
@@ -114,7 +121,7 @@ void Makefile::Save(const ConfigFile& conf, unsigned int flags)
|
||||
|
||||
// Run
|
||||
outputFile << "run: all" << std::endl;
|
||||
if(conf.executable)
|
||||
if(outputtype == "executable")
|
||||
{
|
||||
outputFile << "\t@./$(OUTPUT)" << std::endl;
|
||||
}
|
||||
@@ -130,25 +137,26 @@ void Makefile::Save(const ConfigFile& conf, unsigned int flags)
|
||||
// Output file
|
||||
outputFile << "$(OUTPUT): $(OBJECTS)" << std::endl;
|
||||
outputFile << "\t$(info Generating output file)" << std::endl;
|
||||
if(conf.executable)
|
||||
if(outputtype == "executable")
|
||||
outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS) $(LDFLAGS) $(LIBS)" << std::endl;
|
||||
else
|
||||
outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS)" << std::endl;
|
||||
|
||||
// Install
|
||||
outputFile << "install: all" << std::endl;
|
||||
outputFile << "\t$(info Installing " << conf.projectname <<" to /usr/bin/)" << std::endl;
|
||||
outputFile << "\t@cp $(OUTPUT) /usr/bin/" << conf.outputname << std::endl;
|
||||
outputFile << "\t$(info Installing " << conf.GetSettingString(ConfigSetting::ProjectName) <<" to /usr/bin/)" << std::endl;
|
||||
outputFile << "\t@cp $(OUTPUT) /usr/bin/" << conf.GetSettingString(ConfigSetting::OutputName) << std::endl;
|
||||
|
||||
std::map<std::string, IncludeDeps*> dependencies;
|
||||
size_t i = 0;
|
||||
for(auto it = cppFiles.begin(); it!= cppFiles.end();++it)
|
||||
for(auto it = cppFiles.begin(); it != cppFiles.end();++it)
|
||||
{
|
||||
i++;
|
||||
auto itD = dependencies.find(conf.srcdir + *it);
|
||||
std::string& srcdir = conf.GetSettingString(ConfigSetting::SourceDir);
|
||||
auto itD = dependencies.find(srcdir + *it);
|
||||
if(itD == dependencies.end())
|
||||
{
|
||||
IncludeDeps* deps = new IncludeDeps(*it, conf.configPath+conf.srcdir,hFiles,dependencies);
|
||||
IncludeDeps* deps = new IncludeDeps(*it, conf.GetConfigPath() + srcdir,hFiles,dependencies);
|
||||
size_t extensionPos = it->find_last_of(".");
|
||||
size_t slash = it->find_last_of("/")+1;
|
||||
std::string oFile = it->substr(slash, extensionPos - slash)+".o ";
|
||||
|
||||
+1
-1
@@ -5,5 +5,5 @@
|
||||
class Makefile
|
||||
{
|
||||
public:
|
||||
static void Save(const ConfigFile& conf, unsigned int flags);
|
||||
static void Save(ConfigFile& conf, unsigned int flags);
|
||||
};
|
||||
|
||||
+14
-11
@@ -1,5 +1,6 @@
|
||||
#include "Utils.h"
|
||||
|
||||
#include "ConfigFile.h"
|
||||
#include "FileUtils.h"
|
||||
|
||||
std::string Utils::CommonPrefix(const std::string& s1, const std::string& s2)
|
||||
@@ -16,10 +17,10 @@ std::string Utils::CommonPrefix(const std::string& s1, const std::string& s2)
|
||||
return s1.substr(0, n);
|
||||
}
|
||||
|
||||
void Utils::GetCppFiles(const ConfigFile& conf, std::set<std::string>& cppFiles)
|
||||
void Utils::GetCppFiles(ConfigFile& conf, std::set<std::string>& cppFiles)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
std::string path = conf.configPath + conf.srcdir;
|
||||
std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir);
|
||||
FileUtils::GetAllFiles(path, files);
|
||||
|
||||
for(auto it = files.begin(); it!=files.end();++it)
|
||||
@@ -37,10 +38,10 @@ void Utils::GetCppFiles(const ConfigFile& conf, std::set<std::string>& cppFiles)
|
||||
}
|
||||
}
|
||||
|
||||
void Utils::GetCppAndHFiles(const ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles)
|
||||
void Utils::GetCppAndHFiles(ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
std::string path = conf.configPath + conf.srcdir;
|
||||
std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir);
|
||||
FileUtils::GetAllFiles(path,files);
|
||||
// include paramenter with the path of the file
|
||||
// For example src/graphics/Window.h -> graphics/Window.h if src is a src folder
|
||||
@@ -62,24 +63,26 @@ void Utils::GetCppAndHFiles(const ConfigFile& conf, std::set<HFile>& hFiles, std
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < conf.dependencies.size(); ++i)
|
||||
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
|
||||
for(size_t i = 0; i < dependencies.size(); ++i)
|
||||
{
|
||||
GetHFiles(conf.dependencies[i], conf.dependencyConfigs[i], hFiles);
|
||||
GetHFiles(dependencies[i], conf.GetDependencyConfig(i), hFiles);
|
||||
}
|
||||
}
|
||||
|
||||
void Utils::GetHFiles(const std::string& dependencyDir, const ConfigFile& conf, std::set<HFile>& hFiles)
|
||||
void Utils::GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::set<HFile>& hFiles)
|
||||
{
|
||||
// TODO: Fix so that cyclic dependencies doesn't crash the tool.
|
||||
// Cyclic dependencies probably shouldn't exist.
|
||||
// so just warn the user that it does and terminate.
|
||||
for(size_t i = 0; i < conf.dependencies.size(); ++i)
|
||||
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
|
||||
for(size_t i = 0; i < dependencies.size(); ++i)
|
||||
{
|
||||
GetHFiles(conf.dependencies[i], conf.dependencyConfigs[i], hFiles);
|
||||
GetHFiles(dependencies[i], conf.GetDependencyConfig(i), hFiles);
|
||||
}
|
||||
|
||||
std::vector<std::string> files;
|
||||
std::string depSrcDir = dependencyDir + conf.srcdir;
|
||||
std::string depSrcDir = dependencyDir + conf.GetSettingString(ConfigSetting::SourceDir);
|
||||
FileUtils::GetAllFiles(depSrcDir, files);
|
||||
for(auto it = files.begin(); it!=files.end();++it)
|
||||
{
|
||||
@@ -90,7 +93,7 @@ void Utils::GetHFiles(const std::string& dependencyDir, const ConfigFile& conf,
|
||||
if(extension == "hpp" || extension == "h")
|
||||
{
|
||||
std::string filename = it->substr(depSrcDir.length());
|
||||
hFiles.emplace(HFile{filename, depSrcDir, conf.generateHFile && filename == conf.hFile});
|
||||
hFiles.emplace(HFile{filename, depSrcDir, conf.GetSettingBool(ConfigSetting::GenerateHFile) && filename == conf.GetSettingString(ConfigSetting::HFileName)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "ConfigFile.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
@@ -24,12 +22,14 @@ struct HFile
|
||||
}
|
||||
};
|
||||
|
||||
class ConfigFile;
|
||||
|
||||
struct Utils
|
||||
{
|
||||
static std::string CommonPrefix(const std::string& s1, const std::string& s2);
|
||||
static void GetCppFiles(const ConfigFile& conf, std::set<std::string>& cppFiles);
|
||||
static void GetCppAndHFiles(const ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles);
|
||||
static void GetHFiles(const std::string& dependencyDir, const ConfigFile& conf, std::set<HFile>& hFiles);
|
||||
static void GetCppFiles(ConfigFile& conf, std::set<std::string>& cppFiles);
|
||||
static void GetCppAndHFiles(ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles);
|
||||
static void GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::set<HFile>& hFiles);
|
||||
|
||||
// Used for parsing xml
|
||||
static bool IsWhiteSpace(char c);
|
||||
|
||||
@@ -42,9 +42,9 @@ ConfigFileConf::ConfigFileConf()
|
||||
outputname += ".out";
|
||||
}
|
||||
|
||||
ConfigFile ConfigFileConf::Load(const std::string& filepath)
|
||||
void ConfigFileConf::CreateXMLFile(const std::string& filepath)
|
||||
{
|
||||
ConfigFile conf;
|
||||
ConfigFileConf conf;
|
||||
conf.configPath = filepath;
|
||||
unsigned int loadFlag = 0;
|
||||
|
||||
@@ -152,13 +152,43 @@ ConfigFile ConfigFileConf::Load(const std::string& filepath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("------ COULDN\'T FIND makegen.xml. BUT FOUND OLD makegen.conf.");
|
||||
LOG_INFO("------ GENERATING NEW CONFIGURATION FILE");
|
||||
if(conf.hFile == "")
|
||||
conf.hFile = conf.projectname+".h";
|
||||
|
||||
XMLObject makegen("makegen", {}, std::map<std::string, std::vector<XMLObject>>{});
|
||||
|
||||
// Version, target and configuration is probably going to be used in the future
|
||||
makegen.AddXMLObject(XMLObject("version", {}, "v1.3.0"));
|
||||
makegen.AddXMLObject(XMLObject("target", {}, "Release"));
|
||||
|
||||
XMLObject configuration("configuration", {{"name", "Release"}}, std::map<std::string, std::vector<XMLObject>>{});
|
||||
configuration.AddXMLObject(XMLObject("projectname", {}, conf.projectname));
|
||||
configuration.AddXMLObject(XMLObject("outputname", {}, conf.outputname));
|
||||
configuration.AddXMLObject(XMLObject("srcdir", {}, conf.srcdir));
|
||||
configuration.AddXMLObject(XMLObject("outputdir", {}, conf.outputdir));
|
||||
configuration.AddXMLObject(XMLObject("hfilename", {}, conf.hFile));
|
||||
configuration.AddXMLObject(XMLObject("outputtype", {},
|
||||
conf.executable ? "executable" : (conf.shared ? "sharedlibrary" : "staticlibrary")));
|
||||
configuration.AddXMLObject(XMLObject("generatehfile", {}, conf.generateHFile ? "true" : "false"));
|
||||
|
||||
for(auto it = conf.libs.begin();it != conf.libs.end(); ++it)
|
||||
configuration.AddXMLObject({"library",{},*it});
|
||||
for(auto it = conf.libdirs.begin();it != conf.libdirs.end(); ++it)
|
||||
configuration.AddXMLObject({"librarydir",{},*it});
|
||||
for(auto it = conf.includedirs.begin();it != conf.includedirs.end(); ++it)
|
||||
configuration.AddXMLObject({"includedir",{},*it});
|
||||
for(auto it = conf.defines.begin();it != conf.defines.end(); ++it)
|
||||
configuration.AddXMLObject({"define",{},*it});
|
||||
for(auto it = conf.flags.begin();it != conf.flags.end(); ++it)
|
||||
configuration.AddXMLObject({"cflag",{},*it});
|
||||
for(auto it = conf.dependencies.begin();it != conf.dependencies.end(); ++it)
|
||||
configuration.AddXMLObject({"dependency",{},*it});
|
||||
|
||||
makegen.AddXMLObject(configuration);
|
||||
std::ofstream xmlFile("makegen.xml");
|
||||
xmlFile << makegen;
|
||||
}
|
||||
if(conf.hFile == "")
|
||||
conf.hFile = conf.projectname+".h";
|
||||
|
||||
LOG_INFO("------ COULDN\'T FIND makegen.xml. BUT FOUND OLD makegen.conf.");
|
||||
LOG_INFO("------ GENERATING NEW CONFIGURATION FILE");
|
||||
|
||||
conf.Save();
|
||||
return conf;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,6 @@ class ConfigFileConf
|
||||
public:
|
||||
ConfigFileConf();
|
||||
|
||||
static ConfigFile Load(const std::string& filename);
|
||||
static void CreateXMLFile(const std::string& filename);
|
||||
private:
|
||||
};
|
||||
|
||||
+16
-12
@@ -47,9 +47,9 @@ Usage: makegen [options]
|
||||
clean all install run, rebuild will be translated to \"clean make\")");
|
||||
}
|
||||
|
||||
void GenMakefile(const ConfigFile& conf, unsigned int flags)
|
||||
void GenMakefile(ConfigFile& conf, unsigned int flags)
|
||||
{
|
||||
if(conf.generateHFile)
|
||||
if(conf.GetSettingBool(ConfigSetting::GenerateHFile))
|
||||
HFileGen::Create(conf);
|
||||
Makefile::Save(conf, flags);
|
||||
}
|
||||
@@ -115,7 +115,7 @@ unsigned int ReadFlags(int argc, char** argv)
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool RunMake(const std::string& filepath, unsigned int flags, const ConfigFile& conf)
|
||||
bool RunMake(const std::string& filepath, unsigned int flags, ConfigFile& conf)
|
||||
{
|
||||
std::string make = "make --no-print-directory -C " + filepath;
|
||||
if(!(flags & FLAG_SINGLE_THREAD))
|
||||
@@ -132,33 +132,37 @@ bool RunMake(const std::string& filepath, unsigned int flags, const ConfigFile&
|
||||
{
|
||||
RETURN_IF(system(std::string(make + " install").c_str()) != 0, false);
|
||||
}
|
||||
if(flags & FLAG_RUN && conf.executable)
|
||||
if(flags & FLAG_RUN && conf.GetSettingString(ConfigSetting::OutputType) == "executable")
|
||||
{
|
||||
RETURN_IF(system(std::string(make + " run").c_str()) != 0, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MakeGen(const std::string& filepath, unsigned int flags, const ConfigFile& conf)
|
||||
bool MakeGen(const std::string& filepath, unsigned int flags, ConfigFile& conf)
|
||||
{
|
||||
for(size_t i = 0;i<conf.dependencies.size();++i)
|
||||
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
|
||||
for(size_t i = 0;i<dependencies.size();++i)
|
||||
{
|
||||
bool success = MakeGen(conf.dependencies[i], flags, conf.dependencyConfigs[i]);
|
||||
bool success = MakeGen(dependencies[i], flags, conf.GetDependencyConfig(i));
|
||||
if(!success)
|
||||
return success;
|
||||
}
|
||||
LOG_INFO("-----------------------------------");
|
||||
LOG_INFO("Building ", conf.projectname);
|
||||
LOG_INFO("Building ", conf.GetSettingString(ConfigSetting::ProjectName));
|
||||
LOG_INFO("Generating Makefile...");
|
||||
Timer timer;
|
||||
GenMakefile(conf, flags);
|
||||
LOG_INFO("Took ", round(timer.Elapsed()*1000.0)/1000.0,"s");
|
||||
LOG_INFO("Running Makefile...");
|
||||
|
||||
if(!FileUtils::HasPath(conf.configPath + conf.outputdir))
|
||||
std::string outputPath = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::OutputDir);
|
||||
if(!FileUtils::HasPath(outputPath))
|
||||
{
|
||||
FileUtils::CreateDirectory(conf.configPath + conf.outputdir);
|
||||
FileUtils::CreateDirectory(conf.configPath + conf.outputdir + "intermediates");
|
||||
FileUtils::CreateDirectory(outputPath);
|
||||
std::string intermediatePath = outputPath + "intermediates";
|
||||
if(!FileUtils::HasPath(intermediatePath ))
|
||||
FileUtils::CreateDirectory(intermediatePath );
|
||||
}
|
||||
return RunMake(filepath, flags, conf);
|
||||
}
|
||||
@@ -189,6 +193,6 @@ int main(int argc, char** argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("No ", CONFIG_FILENAME, " or Makefile found.");
|
||||
LOG_ERROR("Couldn\'t load config file");
|
||||
}
|
||||
}
|
||||
|
||||
+25
-4
@@ -66,13 +66,13 @@ unsigned int XMLObject::GetObjectCount() const
|
||||
return objects.size();
|
||||
}
|
||||
|
||||
const std::vector<XMLObject>& XMLObject::GetObject(const std::string& name, const std::vector<XMLObject>& defaults) const
|
||||
std::vector<XMLObject>* XMLObject::GetObjectPtr(const std::string& name)
|
||||
{
|
||||
auto it = objects.find(name);
|
||||
if(it == objects.end())
|
||||
return defaults;
|
||||
return nullptr;
|
||||
|
||||
return it->second;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
const std::map<std::string, std::vector<XMLObject>>& XMLObject::GetObjects() const
|
||||
@@ -110,6 +110,7 @@ void XMLObject::AddAttribute(const std::string& property, const std::string& val
|
||||
else
|
||||
LOG_ERROR("XML property name can only be made up of letters");
|
||||
}
|
||||
|
||||
void XMLObject::AddXMLObject(const XMLObject& object)
|
||||
{
|
||||
auto it = objects.find(object.name);
|
||||
@@ -119,6 +120,26 @@ void XMLObject::AddXMLObject(const XMLObject& object)
|
||||
it->second.push_back(object);
|
||||
}
|
||||
|
||||
bool XMLObject::RemoveXMLObject(const XMLObject& object)
|
||||
{
|
||||
auto it = objects.find(object.name);
|
||||
if(it == objects.end())
|
||||
return false;
|
||||
|
||||
bool removed = false;
|
||||
for(auto it2 = it->second.begin(); it2 != it->second.end();)
|
||||
{
|
||||
if(*it2 == object)
|
||||
{
|
||||
it2 = it->second.erase(it2);
|
||||
removed = true;
|
||||
}
|
||||
else
|
||||
++it2;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
XMLObject XMLObject::GetStrippedXMLObject() const
|
||||
{
|
||||
if(text == "")
|
||||
@@ -374,7 +395,7 @@ std::ostream& XMLObject::WriteToStream(std::ostream& stream, int indent) const
|
||||
stream << "\n";
|
||||
for(int i = 0;i<indent;i++)
|
||||
{
|
||||
stream << "\t";
|
||||
stream << " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+39
-1
@@ -35,7 +35,7 @@ class XMLObject
|
||||
const std::string& GetAttribute(const std::string& property, const std::string& defaultValue) const;
|
||||
|
||||
unsigned int GetObjectCount() const;
|
||||
const std::vector<XMLObject>& GetObject(const std::string& name, const std::vector<XMLObject>& defaults = {}) const;
|
||||
std::vector<XMLObject>* GetObjectPtr(const std::string& name);
|
||||
const std::map<std::string, std::vector<XMLObject>>& GetObjects() const;
|
||||
const std::string& GetName() const;
|
||||
const std::string& GetText() const;
|
||||
@@ -45,6 +45,7 @@ class XMLObject
|
||||
void SetText(const std::string& text);
|
||||
void AddAttribute(const std::string& property, const std::string& value);
|
||||
void AddXMLObject(const XMLObject& object);
|
||||
bool RemoveXMLObject(const XMLObject& object);
|
||||
|
||||
friend bool operator<(const XMLObject& obj1, const XMLObject& obj2)
|
||||
{
|
||||
@@ -57,6 +58,43 @@ class XMLObject
|
||||
return object.WriteToStream(stream);
|
||||
}
|
||||
|
||||
friend bool operator==(const XMLObject& object1, const XMLObject& object2)
|
||||
{
|
||||
if(object1.attributes.size() != object2.attributes.size())
|
||||
return false;
|
||||
if(object1.objects.size() != object2.objects.size())
|
||||
return false;
|
||||
if(object1.name != object2.name)
|
||||
return false;
|
||||
if(object1.GetText() != object2.GetText())
|
||||
return false;
|
||||
|
||||
{
|
||||
auto it1 = object1.attributes.begin();
|
||||
auto it2 = object2.attributes.begin();
|
||||
while(it1 != object1.attributes.end())
|
||||
{
|
||||
if(it1->first != it2->first || it1->second != it1->second)
|
||||
return false;
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto it1 = object1.objects.begin();
|
||||
auto it2 = object2.objects.begin();
|
||||
while(it1 != object1.objects.end())
|
||||
{
|
||||
if(it1->second != it2->second)
|
||||
return false;
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string GetClosingTag(const std::string& string, XMLLoadData& data);
|
||||
// Returns true if the head contained closing tag.
|
||||
|
||||
Reference in New Issue
Block a user