diff --git a/Makefile b/Makefile
index 4b09f9f..92ef820 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# This Makefile was generated using MakeGen v1.3.9 made by Tim Håkansson
+# This Makefile was generated using MakeGen v1.3.10 made by Tim Håkansson
# and is licensed under MIT. Full source of the project can be found at
# https://gitea.timha.se/Thraix/MakeGen
CC=@g++
@@ -34,33 +34,33 @@ $(OUTPUT): $(OBJECTS)
install: all
$(info Installing MakeGen to /usr/bin/)
@cp $(OUTPUT) /usr/bin/makegen
-$(OBJPATH)/src/ConfigCLI.o: src/ConfigCLI.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h
+$(OBJPATH)/src/ConfigCLI.o: src/ConfigCLI.cpp src/Common.h src/AssertException.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h
$(info -[10%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/src/ConfigFile.o: src/ConfigFile.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h src/xml/XML.h
+$(OBJPATH)/src/ConfigFile.o: src/ConfigFile.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/AssertException.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h src/xml/XML.h
$(info -[20%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/src/HFileGen.o: src/HFileGen.cpp src/FileUtils.h src/Common.h src/Utils.h src/HFileGen.h src/ConfigFile.h src/ConfigUtils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h
+$(OBJPATH)/src/HFileGen.o: src/HFileGen.cpp src/FileUtils.h src/Common.h src/AssertException.h src/Utils.h src/HFileGen.h src/ConfigFile.h src/ConfigUtils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h
$(info -[30%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/src/IncludeDeps.o: src/IncludeDeps.cpp src/Common.h src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h
+$(OBJPATH)/src/IncludeDeps.o: src/IncludeDeps.cpp src/Common.h src/AssertException.h src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h
$(info -[40%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/src/Makefile.o: src/Makefile.cpp src/Common.h src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/Makefile.h
+$(OBJPATH)/src/Makefile.o: src/Makefile.cpp src/Common.h src/AssertException.h src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/Makefile.h
$(info -[50%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/src/Utils.o: src/Utils.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h
+$(OBJPATH)/src/Utils.o: src/Utils.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/AssertException.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h
$(info -[60%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/src/compatibility/ConfigFileConf.o: src/compatibility/ConfigFileConf.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h
+$(OBJPATH)/src/compatibility/ConfigFileConf.o: src/compatibility/ConfigFileConf.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/AssertException.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h
$(info -[70%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/src/main.o: src/main.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/HFileGen.h src/Makefile.h src/Timer.h
+$(OBJPATH)/src/main.o: src/main.cpp src/Common.h src/AssertException.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/HFileGen.h src/Makefile.h src/Timer.h
$(info -[80%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/src/xml/XML.o: src/xml/XML.cpp src/xml/XML.h src/xml/XMLObject.h src/xml/XMLException.h
$(info -[90%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/src/xml/XMLObject.o: src/xml/XMLObject.cpp src/Common.h src/Utils.h src/xml/XMLException.h src/xml/XMLObject.h
+$(OBJPATH)/src/xml/XMLObject.o: src/xml/XMLObject.cpp src/Common.h src/AssertException.h src/Utils.h src/xml/XMLException.h src/xml/XMLObject.h
$(info -[100%]- $<)
$(CC) $(CFLAGS) -o $@ $<
diff --git a/makegen.xml b/makegen.xml
index 8924304..ef44938 100644
--- a/makegen.xml
+++ b/makegen.xml
@@ -1,6 +1,5 @@
- false
bin/Release/
makegen
executable
@@ -11,7 +10,6 @@
-g3
-w
_DEBUG
- false
bin/Debug/
makegen
executable
@@ -19,5 +17,5 @@
src/
Release
- v1.3.9
+ v1.3.10
diff --git a/src/AssertException.h b/src/AssertException.h
new file mode 100644
index 0000000..c7520a3
--- /dev/null
+++ b/src/AssertException.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include
+
+struct AssertException : public std::runtime_error
+{
+ AssertException()
+ : std::runtime_error{"assertion failed"}
+ {
+ }
+};
diff --git a/src/Common.h b/src/Common.h
index 3984a68..4e76033 100644
--- a/src/Common.h
+++ b/src/Common.h
@@ -4,6 +4,8 @@
#include
#include
+#include "AssertException.h"
+
#define BIT(x) (1 << x)
#define STRINGIFY(x) #x
@@ -14,7 +16,7 @@
// Release, should be backwards compatible with any minor version
#define MAKEGEN_VERSION_RELEASE 3
// Minor changes, generally bug fixes
-#define MAKEGEN_VERSION_MINOR 9
+#define MAKEGEN_VERSION_MINOR 10
#define MAKEGEN_VERSION ("v" STR(MAKEGEN_VERSION_MAJOR) "." STR(MAKEGEN_VERSION_RELEASE) "." STR(MAKEGEN_VERSION_MINOR))
@@ -33,7 +35,22 @@ const static unsigned int FLAG_TARGET = BIT(11);
#define LOG_INFO(...) LogHelper(__VA_ARGS__)
#define LOG_WARNING(...) LogHelper(__VA_ARGS__)
-#define LOG_ERROR(...) LogHelper(__VA_ARGS__)
+#define LOG_ERROR(...) LogHelper("\033[1;31m[ERROR] ", __VA_ARGS__, "\033[0m")
+#define ASSERT(expr, ...) \
+ if (!(expr)) \
+ { \
+ LOG_ERROR(__VA_ARGS__); \
+ throw AssertException{}; \
+ } \
+ { \
+ } \
+ while (false)
+#define ABORT(...) \
+ { \
+ LOG_ERROR(__VA_ARGS__); \
+ throw AssertException{}; \
+ } \
+ while (false)
template
void Log(const T& var)
diff --git a/src/ConfigCLI.cpp b/src/ConfigCLI.cpp
index d099340..a7c40c8 100644
--- a/src/ConfigCLI.cpp
+++ b/src/ConfigCLI.cpp
@@ -54,8 +54,8 @@ Valid settings are:
dependency Project which current project depends on
excludesource Exclude source file from compiling
excludeheader Exclude header file from project h-file
- argument Command line argument for the executable
- preargument Command line argument before the executabe, e.g. gdb)");
+ argument Command line argument for the executable
+ preargument Command line argument before the executabe, e.g. gdb)");
}
void ConfigCLI::DisplayRemoveHelp()
@@ -75,8 +75,8 @@ Valid settings are
dependency Project which current project depends on
excludesource Exclude source file from compiling
excludeheader Exclude header file from project h-file
- argument Command line argument for the executable
- preargument Command line argument before the executabe, e.g. gdb)");
+ argument Command line argument for the executable
+ preargument Command line argument before the executabe, e.g. gdb)");
}
void ConfigCLI::DisplaySetHelp()
@@ -151,8 +151,7 @@ ConfigSetting ConfigCLI::CLIStringToSetting(const std::string& s)
{"genhfile", ConfigSetting::GenerateHFile},
};
auto it = map.find(s);
- if (it == map.end())
- return ConfigSetting::Invalid;
+ ASSERT(it != map.end(), "Invalid config setting: ", s)
return it->second;
}
@@ -202,15 +201,8 @@ int ConfigCLI::Add(int argc, char** argv, ConfigFile& config)
ConfigSetting setting = CLIStringToSetting(argv[1]);
if (!ConfigUtils::IsVectorSetting(setting))
{
- 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.");
- }
+ LOG_ERROR("Cannot remove setting which only supports one argument");
+ LOG_ERROR("use set instead.");
return 1;
}
for (int i = 2; i < argc; ++i)
@@ -238,15 +230,8 @@ int ConfigCLI::Remove(int argc, char** argv, ConfigFile& config)
ConfigSetting setting = CLIStringToSetting(argv[1]);
if (!ConfigUtils::IsVectorSetting(setting))
{
- 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.");
- }
+ LOG_ERROR("Cannot remove setting which only supports one argument");
+ LOG_ERROR("use set instead.");
return 1;
}
@@ -275,15 +260,8 @@ int ConfigCLI::Set(int argc, char** argv, ConfigFile& config)
ConfigSetting setting = CLIStringToSetting(argv[1]);
if (!ConfigUtils::IsStringSetting(setting) && !ConfigUtils::IsBoolSetting(setting))
{
- if (setting == ConfigSetting::Invalid)
- {
- LOG_ERROR("No such setting: ", argv[1]);
- }
- else
- {
- LOG_ERROR("Cannot set setting which supports multiple arguments");
- LOG_ERROR("use add or remove instead.");
- }
+ LOG_ERROR("Cannot set setting which supports multiple arguments");
+ LOG_ERROR("use add or remove instead.");
return 1;
}
@@ -321,8 +299,22 @@ int ConfigCLI::Main(int argc, char** argv)
DisplayCLIHelp();
return 0;
}
- std::optional config = ConfigFile::GetConfigFile("./", FlagData{});
- std::string command = argv[1];
+ std::string target = "";
+ int commandIndex = 1;
+ if (argc >= 1 && Utils::StartsWith(argv[1], "--target="))
+ {
+ std::string prefix("--target=");
+ std::string flag(argv[1]);
+ if (flag.size() < prefix.size() + 1)
+ {
+ LOG_ERROR("No target specified in --target=");
+ return 1;
+ }
+ target = flag.substr(std::string("--target=").size());
+ commandIndex++;
+ }
+ std::optional config = ConfigFile::GetConfigFile("./", FlagData{target == "" ? 0 : FLAG_TARGET, target});
+ std::string command = argv[commandIndex];
if (command == "gen")
{
if (config)
@@ -330,18 +322,18 @@ int ConfigCLI::Main(int argc, char** argv)
LOG_ERROR("Config file already exist (", CONFIG_FILENAME, ")");
return 1;
}
- return Gen(argc - 1, &argv[1]);
+ return Gen(argc - commandIndex, &argv[commandIndex]);
}
else if (config)
{
if (command == "add")
- return Add(argc - 1, &argv[1], *config);
+ return Add(argc - commandIndex, &argv[commandIndex], *config);
else if (command == "remove")
- return Remove(argc - 1, &argv[1], *config);
+ return Remove(argc - commandIndex, &argv[commandIndex], *config);
else if (command == "set")
- return Set(argc - 1, &argv[1], *config);
+ return Set(argc - commandIndex, &argv[commandIndex], *config);
else if (command == "get")
- return Get(argc - 1, &argv[1], *config);
+ return Get(argc - commandIndex, &argv[commandIndex], *config);
else
{
LOG_ERROR("Unknown config command: ", command);
diff --git a/src/ConfigFile.cpp b/src/ConfigFile.cpp
index d763808..d2e744a 100644
--- a/src/ConfigFile.cpp
+++ b/src/ConfigFile.cpp
@@ -7,21 +7,20 @@
#include "xml/XML.h"
ConfigFile::ConfigFile(const std::string& path, const FlagData& flagData, int)
- : configPath{path}
+ : makegen{"makegen", {}, std::map>{}},
+ configPath{std::filesystem::canonical(path)}
{
- // Converts project name (current directory) to lowercase
- // and replace whitespace with underscore
- // Create xml
- XMLObject makegen("makegen", {}, std::map>{});
-
// Version, target and configuration is probably going to be used in the future
- makegen.AddXMLObject(XMLObject("version", {}, "v1.3.0"));
+ makegen.AddXMLObject(XMLObject("version", {}, MAKEGEN_VERSION));
+ std::string target;
if (flagData.flags & FLAG_TARGET)
- makegen.AddXMLObject(XMLObject("target", {}, flagData.target));
+ target = flagData.target;
else
- makegen.AddXMLObject(XMLObject("target", {}, "Release"));
+ target = "Release";
- XMLObject configuration("configuration", {{"name", "Release"}}, std::map>{});
+ makegen.AddXMLObject(XMLObject("target", {}, target));
+
+ XMLObject configuration("configuration", {{"name", target}}, std::map>{});
configuration.AddXMLObject(XMLObject("projectname", {}, ConfigUtils::GetDefaultProjectName(configPath)));
configuration.AddXMLObject(XMLObject("outputname", {}, ConfigUtils::GetDefaultOutputName(configPath)));
configuration.AddXMLObject(XMLObject("srcdir", {}, "src/"));
@@ -31,50 +30,109 @@ ConfigFile::ConfigFile(const std::string& path, const FlagData& flagData, int)
configuration.AddXMLObject(XMLObject("generatehfile", {}, "false"));
makegen.AddXMLObject(configuration);
- config = makegen;
Init(flagData);
}
ConfigFile::ConfigFile(const std::string& path, const FlagData& flagData)
- : config{XML::FromFile(path + CONFIG_FILENAME)},
- configPath{path}
+ : makegen{XML::FromFile(path + CONFIG_FILENAME)},
+ configPath{std::filesystem::canonical(path)}
{
Init(flagData);
}
ConfigFile::ConfigFile(XMLObject& config, const std::string& path, const FlagData& flagData)
- : config{config},
- configPath{path}
+ : makegen{config},
+ configPath{std::filesystem::canonical(path)}
{
Init(flagData);
}
void ConfigFile::Init(const FlagData& flagData)
+{
+ InitTarget(flagData);
+ InitTargetConfig();
+ InitDependencies();
+ InitStringSetting("outputname", &outputName);
+ InitStringSetting("outputtype", &outputType);
+ InitStringSetting("outputdir", &outputDir);
+ InitStringSetting("projectname", &projectName);
+ InitOptionalStringSetting("srcdir", &sourceDir);
+ InitOptionalStringSetting("hfilename", &hFileName);
+ InitStringListSetting("librarydir", &libraryDirs);
+ InitStringListSetting("includedir", &includeDirs);
+ InitStringListSetting("library", &libraries);
+ InitStringListSetting("define", &defines);
+ InitStringListSetting("cflag", &cFlags);
+ InitStringListSetting("lflag", &lFlags);
+ InitStringListSetting("excludeheader", &excludeHeaders);
+ InitStringListSetting("excludesource", &excludeSources);
+ InitStringListSetting("sourcefile", &sourceFiles);
+ InitStringListSetting("preargument", &preArguments);
+ InitStringListSetting("argument", &arguments);
+ InitStringListSetting("includedirexcldep", &includeDirExclDeps);
+ InitBoolSetting("generatehfile", &generateHFile);
+
+ InitDir(outputDir);
+ InitOptionalDir(sourceDir);
+ InitDirs(libraryDirs);
+ InitDirs(includeDirs);
+}
+
+void ConfigFile::InitTarget(const FlagData& flagData)
{
if (flagData.flags & FLAG_TARGET)
{
target = flagData.target;
+ return;
}
- else
+
+ const std::vector& targetXml = makegen.GetObjects("target");
+ if (targetXml.empty())
{
- const std::vector* 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();
+ LOG_ERROR("No target found in makegen file. Using target=", target);
+ return;
}
- InitDependencies();
+
+ if (targetXml.size() > 1)
+ LOG_ERROR("Too many targets in makegen file. Using target=", targetXml.front().GetText());
+
+ target = targetXml.front().GetText();
+}
+
+void ConfigFile::InitTargetConfig()
+{
+ config = GetTargetConfig();
+}
+
+XMLObject& ConfigFile::GetTargetConfig()
+{
+ std::vector& configurations = makegen.GetObjects("configuration");
+ ASSERT(!configurations.empty(), "No configuration in makegen.xml");
+
+ for (auto& configuration : configurations)
+ {
+ if (!configuration.HasAttribute("name"))
+ {
+ LOG_ERROR("No name attribute in configuration tag");
+ continue;
+ }
+ if (configuration.GetAttribute("name") == target)
+ {
+ return configuration;
+ }
+ }
+
+ LOG_ERROR("Couldn\'t find given target=",
+ target,
+ " in config file. Using target=",
+ configurations.front().GetAttribute("name", ""));
+ return configurations.front();
}
void ConfigFile::InitDependencies()
{
- const std::vector& values = GetConfiguration().GetObjects("dependency");
+ const std::vector& values = config.GetObjects("dependency");
for (const auto& value : values)
{
@@ -83,275 +141,498 @@ void ConfigFile::InitDependencies()
}
}
-std::string& ConfigFile::GetSettingString(ConfigSetting setting)
+void ConfigFile::InitStringSetting(const std::string& name, std::string* output)
{
- // Adding it to the cache since we need to return a reference
- if (!ConfigUtils::IsStringSetting(setting))
+ const std::vector& values = config.GetObjects(name);
+ ASSERT(!values.empty(), "No ", name, " defined in makegen.xml")
+
+ if (values.size() > 1)
{
- LOG_ERROR("Invalid string setting");
- return cache.strings.emplace("invalid", "").first->second;
+ LOG_ERROR("Only one instance of ", name, " allowed using ", values.front().GetText());
}
- std::string sSetting = ConfigUtils::GetSettingName(setting);
- auto it = cache.strings.find(sSetting);
- if (it != cache.strings.end())
- return it->second;
-
- const std::vector* 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.empty() && s[s.size() - 1] != '/')
- s += '/';
- return cache.strings.emplace(sSetting, s).first->second;
+ *output = values.front().GetText();
}
-bool ConfigFile::GetSettingBool(ConfigSetting setting)
+void ConfigFile::InitOptionalStringSetting(const std::string& name, std::optional* output)
{
- if (setting == ConfigSetting::Invalid)
+ const std::vector& values = config.GetObjects(name);
+ if (values.empty())
{
- LOG_ERROR("Invalid config setting");
- return false;
+ *output = std::nullopt;
+ return;
}
- std::string sSetting = ConfigUtils::GetSettingName(setting);
- auto it = cache.bools.find(sSetting);
- if (it != cache.bools.end())
- return it->second;
- const std::vector* values = GetConfiguration().GetObjectPtr(sSetting); //,
-
- if (values == nullptr)
- return cache.bools.emplace(sSetting, ConfigUtils::GetDefaultSettingBool(setting)).first->second;
-
- if (values->size() != 1)
+ if (values.size() > 1)
{
- LOG_ERROR("To many arguments for setting using first: ", (int)setting, "=", (*values)[0].GetText());
+ LOG_ERROR("Only one instance of ", name, " allowed using ", values.front().GetText());
}
- return cache.bools.emplace(sSetting, (*values)[0].GetText() == "true").first->second;
+
+ if (values.front().GetText().empty())
+ {
+ *output = std::nullopt;
+ return;
+ }
+
+ *output = values.front().GetText();
}
-std::vector& ConfigFile::GetSettingVectorString(ConfigSetting setting)
+void ConfigFile::InitStringListSetting(const std::string& name, std::vector* output)
{
- std::string sSetting = ConfigUtils::GetSettingName(setting);
- auto it = cache.vecStrings.find(sSetting);
- if (it != cache.vecStrings.end())
- return it->second;
-
- const std::vector* values = GetConfiguration().GetObjectPtr(sSetting);
- if (values == nullptr)
- return cache.vecStrings.emplace(sSetting, std::vector{}).first->second;
-
- std::vector strings;
- strings.reserve(values->size());
- for (auto it = values->begin(); it != values->end(); ++it)
+ const std::vector& objects = config.GetObjects(name);
+ for (const auto& object : objects)
{
- if (it->GetText() == "")
- continue;
- std::string s = it->GetText();
- if (ConfigUtils::IsDirectory(setting) && s[s.size() - 1] != '/')
- s += '/';
- strings.push_back(s);
+ output->emplace_back(object.GetText());
}
-
- return cache.vecStrings.emplace(sSetting, strings).first->second;
}
-std::vector ConfigFile::GetSetting(ConfigSetting setting)
+void ConfigFile::InitBoolSetting(const std::string& name, bool* output)
{
- 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"};
+ const std::vector& values = config.GetObjects(name);
+ if (values.empty())
+ {
+ return;
+ }
+
+ if (values.size() > 1)
+ {
+ LOG_ERROR("Only one instance of ", name, " allowed using ", values.front().GetText());
+ }
+
+ if (values.front().GetText() == "true")
+ *output = true;
+ else if (values.front().GetText() == "false")
+ *output = false;
else
+ LOG_ERROR("Invalid bool value: ", values.front().GetText(), " for ", name);
+}
+
+void ConfigFile::InitDir(std::string& dir) const
+{
+ if (!dir.empty() && dir.back() != '/')
{
- LOG_ERROR("Invalid config setting");
- return {};
+ dir += '/';
}
}
+void ConfigFile::InitOptionalDir(std::optional& dir) const
+{
+ if (dir.has_value() && !dir.value().empty() && dir.value().back() != '/')
+ {
+ dir.value() += '/';
+ }
+}
+
+void ConfigFile::InitDirs(std::vector& dirs) const
+{
+ for (auto& dir : dirs)
+ {
+ InitDir(dir);
+ }
+}
+
+const std::string& ConfigFile::GetOutputDir() const
+{
+ return outputDir;
+}
+
+const std::string& ConfigFile::GetOutputName() const
+{
+ return outputName;
+}
+
+const std::string& ConfigFile::GetProjectName() const
+{
+ return projectName;
+}
+
+const std::string& ConfigFile::GetOutputType() const
+{
+ return outputType;
+}
+
+const std::optional& ConfigFile::GetSourceDir() const
+{
+ return sourceDir;
+}
+
+const std::optional& ConfigFile::GetHFileName() const
+{
+ return hFileName;
+}
+
+const std::vector& ConfigFile::GetLibraryDirs() const
+{
+ return libraryDirs;
+}
+
+const std::vector& ConfigFile::GetIncludeDirs() const
+{
+ return includeDirs;
+}
+
+const std::vector& ConfigFile::GetLibraries() const
+{
+ return libraries;
+}
+
+const std::vector& ConfigFile::GetDefines() const
+{
+ return defines;
+}
+
+const std::vector& ConfigFile::GetCFlags() const
+{
+ return cFlags;
+}
+
+const std::vector& ConfigFile::GetLFlags() const
+{
+ return lFlags;
+}
+
+const std::vector& ConfigFile::GetExcludeHeaders() const
+{
+ return excludeHeaders;
+}
+
+const std::vector& ConfigFile::GetExcludeSources() const
+{
+ return excludeSources;
+}
+
+const std::vector& ConfigFile::GetSourceFiles() const
+{
+ return sourceFiles;
+}
+
+const std::vector& ConfigFile::GetPreArguments() const
+{
+ return preArguments;
+}
+
+const std::vector& ConfigFile::GetArguments() const
+{
+ return arguments;
+}
+
+const std::vector& ConfigFile::GetIncludeDirExclDeps() const
+{
+ return includeDirExclDeps;
+}
+
const std::vector& ConfigFile::GetDependencies() const
{
return dependencies;
}
-bool ConfigFile::SetSettingString(ConfigSetting setting, const std::string& value)
+bool ConfigFile::IsGenerateHFile() const
+{
+ return generateHFile;
+}
+
+std::vector ConfigFile::GetSetting(ConfigSetting setting) const
+{
+ switch (setting)
+ {
+ case ConfigSetting::SourceDir:
+ {
+ if (sourceDir.has_value())
+ return {sourceDir.value()};
+ return {};
+ }
+ case ConfigSetting::OutputDir:
+ return {outputDir};
+ case ConfigSetting::OutputName:
+ return {outputName};
+ case ConfigSetting::OutputType:
+ return {outputType};
+ case ConfigSetting::ProjectName:
+ return {projectName};
+ case ConfigSetting::HFileName:
+ {
+ if (hFileName.has_value())
+ return {hFileName.value()};
+ return {};
+ }
+ case ConfigSetting::LibraryDir:
+ return libraryDirs;
+ case ConfigSetting::IncludeDir:
+ return includeDirs;
+ case ConfigSetting::Dependency:
+ {
+ std::vector list;
+ for (const auto& [path, target] : dependencies)
+ {
+ list.emplace_back(path);
+ }
+ return list;
+ }
+ case ConfigSetting::Library:
+ return libraries;
+ case ConfigSetting::Define:
+ return defines;
+ case ConfigSetting::CFlag:
+ return cFlags;
+ case ConfigSetting::LFlag:
+ return lFlags;
+ case ConfigSetting::ExcludeSource:
+ return excludeSources;
+ case ConfigSetting::ExcludeHeader:
+ return excludeHeaders;
+ case ConfigSetting::ExecPreArgument:
+ return preArguments;
+ case ConfigSetting::ExecArgument:
+ return arguments;
+ case ConfigSetting::GenerateHFile:
+ return {generateHFile ? "true" : "false"};
+ case ConfigSetting::SourceFile:
+ return sourceFiles;
+ case ConfigSetting::IncludeDirExclDep:
+ return includeDirExclDeps;
+ }
+ return {};
+}
+
+bool ConfigFile::SetSettingString(ConfigSetting setting, 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))
{
- 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);
+ InitDir(value);
}
- else if (ConfigUtils::IsBoolSetting(setting))
+
+ 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";
+ if (value == "true" || value == "t" || value == "yes" || value == "y")
+ {
+ value = "true";
+ }
+ else if (value == "false" || value == "f" || value == "no" || value == "n")
+ {
+ value = "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* 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{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* 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);
+ LOG_ERROR("Invalid boolean value: ", value);
return false;
}
}
- else
+
+ switch (setting)
{
- LOG_ERROR("Not a vector setting");
+ case ConfigSetting::SourceDir:
+ sourceDir = value;
+ break;
+ case ConfigSetting::OutputDir:
+ outputDir = value;
+ break;
+ case ConfigSetting::OutputName:
+ outputName = value;
+ break;
+ case ConfigSetting::OutputType:
+ outputType = value;
+ break;
+ case ConfigSetting::ProjectName:
+ projectName = value;
+ break;
+ case ConfigSetting::HFileName:
+ hFileName = value;
+ break;
+ case ConfigSetting::GenerateHFile:
+ generateHFile = value == "true";
+ break;
+ default:
+ LOG_ERROR("Not a string setting");
+ return false;
+ }
+
+ XMLObject& config = GetTargetConfig();
+ std::vector& values = config.GetObjects(sSetting);
+ if (values.empty())
+ {
+ config.AddXMLObject({sSetting, {}, value});
+ return true;
+ }
+
+ if (values.size() > 1)
+ LOG_ERROR("Multiple values of setting, changing first: ", sSetting, "=", value);
+
+ values.front().SetText(value);
+ return true;
+}
+
+bool ConfigFile::AddSettingVectorString(ConfigSetting setting, std::string value)
+{
+ if (ConfigUtils::IsDirectory(setting))
+ {
+ InitDir(value);
+ }
+
+ switch (setting)
+ {
+ case ConfigSetting::LibraryDir:
+ libraryDirs.emplace_back(value);
+ break;
+ case ConfigSetting::IncludeDir:
+ includeDirs.emplace_back(value);
+ break;
+ case ConfigSetting::Dependency:
+ dependencies.emplace_back(value, target);
+ break;
+ case ConfigSetting::Library:
+ libraries.emplace_back(value);
+ break;
+ case ConfigSetting::Define:
+ defines.emplace_back(value);
+ break;
+ case ConfigSetting::CFlag:
+ cFlags.emplace_back(value);
+ break;
+ case ConfigSetting::LFlag:
+ lFlags.emplace_back(value);
+ break;
+ case ConfigSetting::ExcludeHeader:
+ excludeHeaders.emplace_back(value);
+ break;
+ case ConfigSetting::ExcludeSource:
+ excludeSources.emplace_back(value);
+ break;
+ case ConfigSetting::ExecPreArgument:
+ preArguments.emplace_back(value);
+ break;
+ case ConfigSetting::ExecArgument:
+ arguments.emplace_back(value);
+ break;
+ case ConfigSetting::SourceFile:
+ sourceFiles.emplace_back(value);
+ break;
+ case ConfigSetting::IncludeDirExclDep:
+ includeDirExclDeps.emplace_back(value);
+ break;
+ default:
+ LOG_ERROR("Not a vector setting");
+ return false;
+ }
+
+ std::string sSetting = ConfigUtils::GetSettingName(setting);
+ XMLObject& config = GetTargetConfig();
+ config.AddXMLObject({sSetting, {}, value});
+
+ return true;
+}
+
+bool ConfigFile::RemoveSettingVectorString(ConfigSetting setting, std::string value)
+{
+ switch (setting)
+ {
+ case ConfigSetting::LibraryDir:
+ RemoveFromVector(libraryDirs, value);
+ break;
+ case ConfigSetting::IncludeDir:
+ RemoveFromVector(includeDirs, value);
+ break;
+ case ConfigSetting::Dependency:
+ RemoveFromVector(dependencies, value);
+ break;
+ case ConfigSetting::Library:
+ RemoveFromVector(libraries, value);
+ break;
+ case ConfigSetting::Define:
+ RemoveFromVector(defines, value);
+ break;
+ case ConfigSetting::CFlag:
+ RemoveFromVector(cFlags, value);
+ break;
+ case ConfigSetting::LFlag:
+ RemoveFromVector(lFlags, value);
+ break;
+ case ConfigSetting::ExcludeHeader:
+ RemoveFromVector(excludeHeaders, value);
+ break;
+ case ConfigSetting::ExcludeSource:
+ RemoveFromVector(excludeSources, value);
+ break;
+ case ConfigSetting::ExecPreArgument:
+ RemoveFromVector(preArguments, value);
+ break;
+ case ConfigSetting::ExecArgument:
+ RemoveFromVector(arguments, value);
+ break;
+ case ConfigSetting::SourceFile:
+ RemoveFromVector(sourceFiles, value);
+ break;
+ case ConfigSetting::IncludeDirExclDep:
+ RemoveFromVector(includeDirExclDeps, value);
+ break;
+ default:
+ LOG_ERROR("Not a vector setting");
+ return false;
+ }
+
+ std::string sSetting = ConfigUtils::GetSettingName(setting);
+
+ XMLObject& config = GetTargetConfig();
+ std::vector& values = config.GetObjects(sSetting);
+ bool found = false;
+ for (auto it = values.begin(); it != values.end(); ++it)
+ {
+ if (it->GetText() == value)
+ {
+ values.erase(it);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ LOG_ERROR("Couldn't find value: ", value);
return false;
}
- return false;
+
+ return true;
}
-XMLObject& ConfigFile::GetConfiguration()
+void ConfigFile::RemoveFromVector(std::vector& vector, const std::string& string)
{
- std::vector* configurations = config.GetObjectPtr("configuration");
- if (configurations == nullptr || configurations->size() == 0)
+ for (auto it = vector.begin(); it != vector.end(); it++)
{
- LOG_ERROR("No configuration in makegen.xml");
- assert(false);
- }
- for (auto it = configurations->begin(); it != configurations->end(); ++it)
- {
- if (!it->HasAttribute("name"))
+ if (*it == string)
{
- LOG_ERROR("No name attribute in configuration tag");
- continue;
- }
- if (it->GetAttribute("name") == target)
- {
- return *it;
+ vector.erase(it);
+ return;
}
}
-
- LOG_ERROR("Couldn\'t find given target=",
- target,
- " in config file. Using target=",
- (*configurations)[0].HasAttribute("name") ? (*configurations)[0].GetAttribute("name") : "");
- return (*configurations)[0];
}
-const std::string& ConfigFile::GetConfigPath() const
+void ConfigFile::RemoveFromVector(std::vector& vector, const std::string& string)
+{
+ for (auto it = vector.begin(); it != vector.end(); it++)
+ {
+ if (it->path == string)
+ {
+ vector.erase(it);
+ return;
+ }
+ }
+}
+
+const std::filesystem::path& ConfigFile::GetConfigPath() const
{
return configPath;
}
-ConfigFile& ConfigFile::GetDependencyConfig(size_t i)
+ConfigFile& ConfigFile::GetDependencyConfig(const std::string& path)
{
- return dependencyConfigs[i];
+ std::filesystem::path fullPath = std::filesystem::canonical(path);
+ for (auto& config : dependencyConfigs)
+ {
+ if (config.configPath == fullPath)
+ return config;
+ }
+ ABORT("Failed to find config file: ", fullPath.string());
}
std::optional ConfigFile::GetConfigFile(const std::string& filepath, const FlagData& flagData)
@@ -364,57 +645,39 @@ std::optional ConfigFile::GetConfigFile(const std::string& filepath,
std::map& loadedConfigs,
const FlagData& flagData)
{
- std::string realPath = FileUtils::GetRealPath(filepath);
- if (realPath == "")
- return {};
- auto it = loadedConfigs.find(realPath);
+ std::filesystem::path configPath = std::filesystem::canonical(filepath) / CONFIG_FILENAME;
+
+ auto it = loadedConfigs.find(configPath);
if (it != loadedConfigs.end())
+ return std::nullopt;
+
+ if (!FileUtils::FileExists(configPath))
{
- return {};
+ ConfigFileConf::CreateXMLFile(configPath);
+ if (!FileUtils::FileExists(configPath))
+ return std::nullopt;
}
- bool oldFile = false;
- 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 + CONFIG_FILENAME);
- }
+ ConfigFile config{filepath, flagData};
+ loadedConfigs.emplace(configPath, config);
- // Check if the file exists
- if (f.good())
+ const std::vector& dependencies = config.GetDependencies();
+ for (size_t i = 0; i < dependencies.size(); ++i)
{
- f.close();
- ConfigFile conf = ConfigFile(filepath, flagData);
- if (conf.hasInitError)
- return {};
- loadedConfigs.emplace(realPath, conf);
-
- std::vector dependencies = conf.GetDependencies();
- // Create dependency config files.
- for (size_t i = 0; i < dependencies.size(); ++i)
+ FlagData dependencyFlagData = flagData;
+ if (!dependencies[i].target.empty())
{
- FlagData dependencyFlagData = flagData;
dependencyFlagData.target = dependencies[i].target;
- std::optional dep =
- GetConfigFile(conf.configPath + dependencies[i].path, loadedConfigs, dependencyFlagData);
- if (dep)
- {
- conf.dependencyConfigs.push_back(*dep);
- dependencies[i].path = dep->configPath;
- }
- else
- {
- // Remove the dependency since it is already accounted for
- dependencies.erase(dependencies.begin() + i);
- --i;
- }
+ dependencyFlagData.flags |= FLAG_TARGET;
+ }
+ std::filesystem::path dependencyFilePath = config.configPath / dependencies[i].path;
+ std::optional dependencyConfig = GetConfigFile(dependencyFilePath, loadedConfigs, dependencyFlagData);
+ if (dependencyConfig.has_value())
+ {
+ config.dependencyConfigs.emplace_back(dependencyConfig.value());
}
- return conf;
}
- return {};
+ return config;
}
void ConfigFile::InputBoolean(const std::string& inputText, bool& b)
@@ -461,6 +724,7 @@ void ConfigFile::InputMultiple(const std::string& inputText, std::vector dependencyConfigs;
-
- std::vector dependencies;
-
- bool hasInitError = false;
-
public:
// Generates a new default config file
ConfigFile(const std::string& path, const FlagData& flagData, int);
@@ -36,33 +22,89 @@ public:
void Save() const;
- std::string& GetSettingString(ConfigSetting setting);
- bool GetSettingBool(ConfigSetting setting);
- std::vector& GetSettingVectorString(ConfigSetting setting);
- std::vector GetSetting(ConfigSetting setting);
+ const std::string& GetOutputDir() const;
+ const std::string& GetOutputName() const;
+ const std::string& GetProjectName() const;
+ const std::string& GetOutputType() const;
+ const std::optional& GetSourceDir() const;
+ const std::optional& GetHFileName() const;
+ const std::vector& GetLibraryDirs() const;
+ const std::vector& GetIncludeDirs() const;
+ const std::vector& GetLibraries() const;
+ const std::vector& GetDefines() const;
+ const std::vector& GetCFlags() const;
+ const std::vector& GetLFlags() const;
+ const std::vector& GetExcludeHeaders() const;
+ const std::vector& GetExcludeSources() const;
+ const std::vector& GetSourceFiles() const;
+ const std::vector& GetPreArguments() const;
+ const std::vector& GetArguments() const;
+ const std::vector& GetIncludeDirExclDeps() const;
const std::vector& GetDependencies() const;
+ bool IsGenerateHFile() const;
- bool SetSettingString(ConfigSetting setting, const std::string& value);
- bool AddSettingVectorString(ConfigSetting setting, const std::string& value);
- bool RemoveSettingVectorString(ConfigSetting setting, const std::string& value);
+ std::vector GetSetting(ConfigSetting setting) const;
- XMLObject& GetConfiguration();
- const std::string& GetConfigPath() const;
- ConfigFile& GetDependencyConfig(size_t i);
+ bool SetSettingString(ConfigSetting setting, std::string value);
+ bool AddSettingVectorString(ConfigSetting setting, std::string value);
+ bool RemoveSettingVectorString(ConfigSetting setting, std::string value);
-private:
- void Init(const FlagData& flagData);
- void InitDependencies();
+ const std::filesystem::path& GetConfigPath() const;
+ ConfigFile& GetDependencyConfig(const std::string& path);
-public:
static ConfigFile Gen(const FlagData& flagData);
static std::optional GetConfigFile(const std::string& filepath, const FlagData& flagData);
private:
+ XMLObject makegen;
+ XMLObject config;
+ // Current configuration
+ std::string target;
+
+ std::filesystem::path configPath;
+ std::vector dependencyConfigs;
+
+ std::vector dependencies;
+ std::string outputName;
+ std::string outputDir;
+ std::string projectName;
+ std::string outputType;
+ std::optional sourceDir;
+ std::optional hFileName;
+ std::vector libraryDirs;
+ std::vector includeDirs;
+ std::vector libraries;
+ std::vector defines;
+ std::vector cFlags;
+ std::vector lFlags;
+ std::vector excludeHeaders;
+ std::vector excludeSources;
+ std::vector sourceFiles;
+ std::vector preArguments;
+ std::vector arguments;
+ std::vector includeDirExclDeps;
+ bool generateHFile{false};
+
+private:
+ void Init(const FlagData& flagData);
+ void InitTarget(const FlagData& flagData);
+ void InitTargetConfig();
+ XMLObject& GetTargetConfig();
+ void InitDependencies();
+ void InitStringSetting(const std::string& name, std::string* output);
+ void InitOptionalStringSetting(const std::string& name, std::optional* output);
+ void InitStringListSetting(const std::string& name, std::vector* output);
+ void InitBoolSetting(const std::string& name, bool* output);
+
+ void InitDir(std::string& dir) const;
+ void InitOptionalDir(std::optional& dir) const;
+ void InitDirs(std::vector& dirs) const;
+ void RemoveFromVector(std::vector& vector, const std::string& string);
+ void RemoveFromVector(std::vector& vector, const std::string& string);
+
static std::optional GetConfigFile(const std::string& filepath,
std::map& loadedConfigs,
const FlagData& flagData);
- static std::optional Load(const std::string& filename);
static void InputBoolean(const std::string& inputText, bool& b);
static void InputMultiple(const std::string& inputText, std::vector& vec, bool needEnding);
static void InputString(const std::string& inputText, std::string& vec, bool needEnding, bool allowEmpty);
diff --git a/src/ConfigUtils.h b/src/ConfigUtils.h
index 449a5c8..838bdf2 100644
--- a/src/ConfigUtils.h
+++ b/src/ConfigUtils.h
@@ -1,7 +1,5 @@
#pragma once
-#include
-
#include