Rework how the config file is read

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