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 #include #include @@ -41,8 +39,6 @@ enum class ConfigSetting HFileName = 37, // Bools GenerateHFile = 64, - // Other - Invalid = 1024 }; struct ConfigUtils @@ -91,8 +87,6 @@ struct ConfigUtils return "sourcefile"; case ConfigSetting::IncludeDirExclDep: return "includedirexcldep"; - case ConfigSetting::Invalid: - return "invalid"; } return ""; } @@ -122,7 +116,6 @@ struct ConfigUtils case ConfigSetting::ExecArgument: case ConfigSetting::GenerateHFile: case ConfigSetting::SourceFile: - case ConfigSetting::Invalid: return false; } return false; @@ -153,7 +146,6 @@ struct ConfigUtils case ConfigSetting::GenerateHFile: case ConfigSetting::SourceFile: case ConfigSetting::IncludeDirExclDep: - case ConfigSetting::Invalid: return false; } return false; @@ -184,7 +176,6 @@ struct ConfigUtils case ConfigSetting::ProjectName: case ConfigSetting::HFileName: case ConfigSetting::GenerateHFile: - case ConfigSetting::Invalid: return false; } return false; @@ -214,7 +205,6 @@ struct ConfigUtils case ConfigSetting::ExecPreArgument: case ConfigSetting::ExecArgument: case ConfigSetting::SourceFile: - case ConfigSetting::Invalid: case ConfigSetting::IncludeDirExclDep: return false; } @@ -240,8 +230,7 @@ struct ConfigUtils case ConfigSetting::GenerateHFile: return GetDefaultSettingBool(setting) ? "true" : "false"; default: - LOG_ERROR("INVALID STRING ENUM: ", (int)setting); - assert(false); + ASSERT(false, "INVALID STRING ENUM: ", (int)setting); } return ""; } @@ -253,8 +242,7 @@ struct ConfigUtils case ConfigSetting::GenerateHFile: return false; default: - LOG_ERROR("NOT BOOLEAN VALUE: ", (int)setting); - assert(false); + ASSERT(false, "NOT BOOLEAN VALUE: ", (int)setting); } } diff --git a/src/FileUtils.h b/src/FileUtils.h index 7ea9ddd..15814fc 100644 --- a/src/FileUtils.h +++ b/src/FileUtils.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -42,42 +41,19 @@ struct FileUtils static std::string GetTopDirectory(const std::string& dir) { - if (dir.size() == 0) - { - LOG_ERROR("Cannot send empty string to FileUtils::GetTopDirectory()"); - assert(false); - } + ASSERT(!dir.empty(), "Cannot send empty string to FileUtils::GetTopDirectory()"); + size_t dirEnd = std::string::npos; if (dir[dir.size() - 1] == '/') dirEnd = dir.size() - 2; size_t pos = dir.find_last_of("/", dirEnd); - if (pos == std::string::npos) - { - LOG_ERROR("Couldn't find / (slash) in directory. This shouldn't occur."); - assert(false); - } + ASSERT(pos != std::string::npos, "Couldn't find / (slash) in directory. This shouldn't occur."); return dir.substr(pos + 1, dirEnd - pos); } static std::string GetRealPath(const std::string& filename) { -#if defined(__linux__) - if (access(filename.c_str(), F_OK) != -1) - { - char* path = realpath(filename.c_str(), NULL); - std::string sPath = path; - sPath += "/"; - free(path); - return sPath; - } - else - { - LOG_ERROR("Directory doesn't exist: ", filename); - return ""; - } -#endif - LOG_ERROR("GetRealPath not supported"); - return ""; + return std::filesystem::canonical(filename).string(); } static std::string GetRelativePath(std::string from, std::string to) diff --git a/src/HFileGen.cpp b/src/HFileGen.cpp index cb62e44..f99ef7f 100644 --- a/src/HFileGen.cpp +++ b/src/HFileGen.cpp @@ -4,11 +4,22 @@ #include "FileUtils.h" +// TODO: Consider removing this functionality, since its not really used anyways void HFileGen::Create(ConfigFile& conf) { + const std::optional& hFileName = conf.GetHFileName(); + if (!hFileName.has_value()) + { + LOG_ERROR("hfilename is not specified but generatehfile is true"); + return; + } + std::set hFiles; std::vector files; - std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir); + const std::optional& sourceDir = conf.GetSourceDir(); + std::string path = conf.GetConfigPath(); + if (sourceDir.has_value()) + path += sourceDir.value(); FileUtils::GetAllFiles(path, files); // include paramenter with the path of the file // For example src/graphics/Window.h -> graphics/Window.h if src is a src folder @@ -18,8 +29,7 @@ void HFileGen::Create(ConfigFile& conf) if (extensionPos != std::string::npos) { std::string filename = it->substr(path.length()); - if (Utils::IsHeaderFile(filename) && - filename != conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::HFileName)) + if (Utils::IsHeaderFile(filename) && filename != conf.GetConfigPath() / hFileName.value()) { // Make files sorted in alphabetical order hFiles.emplace(filename); @@ -27,12 +37,16 @@ void HFileGen::Create(ConfigFile& conf) } } - const std::vector& excludeHeaders = conf.GetSettingVectorString(ConfigSetting::ExcludeHeader); - std::ofstream os(path + "/" + conf.GetSettingString(ConfigSetting::HFileName)); + const std::vector& excludeHeaders = conf.GetExcludeHeaders(); + std::ofstream os(path + "/" + hFileName.value()); os << "#pragma once" << std::endl << std::endl; for (auto&& hFile : hFiles) { - std::string headerFile = conf.GetSettingString(ConfigSetting::SourceDir) + hFile; + const std::optional& srcDir = conf.GetSourceDir(); + std::string headerFile = hFile; + if (srcDir.has_value()) + headerFile = srcDir.value() + headerFile; + auto it = std::find(excludeHeaders.begin(), excludeHeaders.end(), headerFile); if (it == excludeHeaders.end()) os << "#include <" << hFile << ">" << std::endl; diff --git a/src/IncludeDeps.h b/src/IncludeDeps.h index 7d35acd..561f133 100644 --- a/src/IncludeDeps.h +++ b/src/IncludeDeps.h @@ -33,7 +33,7 @@ public: { std::string filePathInMakeFile = filepath; if (!filepath.is_absolute()) - filePathInMakeFile = std::filesystem::relative(conf.GetConfigPath() + "/" + filepath.string(), "./").string(); + filePathInMakeFile = std::filesystem::relative(conf.GetConfigPath() / filepath.string(), "./").string(); if (printSet.find(filePathInMakeFile) != printSet.end()) return stream; diff --git a/src/Makefile.cpp b/src/Makefile.cpp index 7569c6f..c53ea06 100755 --- a/src/Makefile.cpp +++ b/src/Makefile.cpp @@ -16,13 +16,13 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags) else Utils::GetCppAndHFiles(conf, hFiles, cppFiles); - std::ofstream outputFile(conf.GetConfigPath() + "Makefile"); + std::ofstream outputFile(conf.GetConfigPath() / "Makefile"); outputFile << "# This Makefile was generated using MakeGen " << MAKEGEN_VERSION << " made by Tim Håkansson" << std::endl; outputFile << "# and is licensed under MIT. Full source of the project can be found at" << std::endl; outputFile << "# https://gitea.timha.se/Thraix/MakeGen" << std::endl; outputFile << "CC=@g++" << std::endl; - std::string outputtype = conf.GetSettingString(ConfigSetting::OutputType); + std::string outputtype = conf.GetOutputType(); if (outputtype != "executable") { if (outputtype == "sharedlibrary") @@ -34,19 +34,19 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags) outputFile << "CO=@g++ -o" << std::endl; outputFile << "MKDIR_P=mkdir -p" << std::endl; - outputFile << "BIN=" << conf.GetSettingString(ConfigSetting::OutputDir) << std::endl; + outputFile << "BIN=" << conf.GetOutputDir() << std::endl; outputFile << "OBJPATH=$(BIN)intermediates" << std::endl; outputFile << "INCLUDES="; - std::vector& includedirs = conf.GetSettingVectorString(ConfigSetting::IncludeDir); - for (auto it = includedirs.begin(); it != includedirs.end(); ++it) + const std::vector& includeDirs = conf.GetIncludeDirs(); + for (const auto& includeDir : includeDirs) { - outputFile << "-I " << *it << " "; + outputFile << "-I " << includeDir << " "; } - std::vector& includedirsexcldep = conf.GetSettingVectorString(ConfigSetting::IncludeDirExclDep); - for (auto it = includedirsexcldep.begin(); it != includedirsexcldep.end(); ++it) + const std::vector& includeDirExclDeps = conf.GetIncludeDirExclDeps(); + for (const auto& includeDirExclDep : includeDirExclDeps) { - outputFile << "-I " << *it << " "; + outputFile << "-I " << includeDirExclDeps << " "; } outputFile << std::endl; outputFile << "OBJECTS="; @@ -67,42 +67,42 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags) { outputFile << "CFLAGS=$(INCLUDES) -fPIC -std=c++17 -c "; } - std::vector& defines = conf.GetSettingVectorString(ConfigSetting::Define); - for (auto it = defines.begin(); it != defines.end(); ++it) + const std::vector& defines = conf.GetDefines(); + for (const auto& define : defines) { - outputFile << "-D" << *it << " "; + outputFile << "-D" << define << " "; } - std::vector& cflags = conf.GetSettingVectorString(ConfigSetting::CFlag); - for (auto it = cflags.begin(); it != cflags.end(); ++it) + const std::vector& cFlags = conf.GetCFlags(); + for (const auto& cFlag : cFlags) { - outputFile << *it << " "; + outputFile << cFlag << " "; } outputFile << std::endl; if (outputtype == "executable") { - std::vector& libdirs = conf.GetSettingVectorString(ConfigSetting::LibraryDir); + const std::vector& libraryDirs = conf.GetLibraryDirs(); outputFile << "LIBDIR="; - for (auto it = libdirs.begin(); it != libdirs.end(); ++it) + for (const auto& libraryDir : libraryDirs) { - outputFile << "-L " << *it << " "; + outputFile << "-L " << libraryDir << " "; } outputFile << std::endl; - std::vector& lflags = conf.GetSettingVectorString(ConfigSetting::LFlag); + const std::vector& lFlags = conf.GetLFlags(); outputFile << "LDFLAGS="; - for (auto it = lflags.begin(); it != lflags.end(); ++it) + for (const auto& lFlag : lFlags) { - outputFile << *it << " "; + outputFile << lFlag << " "; } - for (auto it = libdirs.begin(); it != libdirs.end(); ++it) + for (const auto& libraryDir : libraryDirs) { - outputFile << "-Wl,-rpath=" << *it << " "; + outputFile << "-Wl,-rpath=" << libraryDir << " "; } outputFile << std::endl; - std::vector& libs = conf.GetSettingVectorString(ConfigSetting::Library); + const std::vector& libraries = conf.GetLibraries(); outputFile << "LIBS=$(LIBDIR) "; - for (auto it = libs.begin(); it != libs.end(); ++it) + for (const auto& library : libraries) { - outputFile << "-l" << *it << " "; + outputFile << "-l" << library << " "; } outputFile << std::endl; const std::vector& dependencies = conf.GetDependencies(); @@ -116,7 +116,7 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags) outputFile << std::endl; } } - outputFile << "OUTPUT=$(BIN)" << conf.GetSettingString(ConfigSetting::OutputName) << std::endl; + outputFile << "OUTPUT=$(BIN)" << conf.GetOutputName() << std::endl; outputFile << ".PHONY: all directories rebuild clean run" << std::endl; // All @@ -142,13 +142,19 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags) outputFile << "run: all" << std::endl; if (outputtype == "executable") { - std::vector& prearguments = conf.GetSettingVectorString(ConfigSetting::ExecPreArgument); - std::vector& arguments = conf.GetSettingVectorString(ConfigSetting::ExecArgument); + const std::vector& prearguments = conf.GetPreArguments(); + const std::vector& arguments = conf.GetArguments(); outputFile << "\t@"; - for (auto&& preargument : prearguments) outputFile << preargument << " "; + for (const auto& preargument : prearguments) + { + outputFile << preargument << " "; + } outputFile << "./$(OUTPUT)"; - for (auto&& argument : arguments) outputFile << " " << argument; + for (const auto& argument : arguments) + { + outputFile << " " << argument; + } outputFile << std::endl; } @@ -170,9 +176,8 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags) // Install outputFile << "install: all" << std::endl; - outputFile << "\t$(info Installing " << conf.GetSettingString(ConfigSetting::ProjectName) << " to /usr/bin/)" - << std::endl; - outputFile << "\t@cp $(OUTPUT) /usr/bin/" << conf.GetSettingString(ConfigSetting::OutputName) << std::endl; + outputFile << "\t$(info Installing " << conf.GetProjectName() << " to /usr/bin/)" << std::endl; + outputFile << "\t@cp $(OUTPUT) /usr/bin/" << conf.GetOutputName() << std::endl; std::map dependencies; size_t i = 0; diff --git a/src/Utils.cpp b/src/Utils.cpp index 90a3835..b20c1ae 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -70,18 +70,17 @@ std::string Utils::CommonPrefix(const std::string& s1, const std::string& s2) void Utils::GetCppFiles(ConfigFile& conf, std::set& cppFiles) { std::vector files; - std::string sourceDir = conf.GetSettingString(ConfigSetting::SourceDir); - std::string path = conf.GetConfigPath() + sourceDir; - if (!sourceDir.empty()) + const std::optional& sourceDir = conf.GetSourceDir(); + if (sourceDir.has_value()) { - FileUtils::GetAllFiles(path, files); + FileUtils::GetAllFiles(conf.GetConfigPath() / sourceDir.value(), files); } - const std::vector& excludeSources = conf.GetSettingVectorString(ConfigSetting::ExcludeSource); + const std::vector& excludeSources = conf.GetExcludeSources(); - for (const auto& sourceFile : conf.GetSettingVectorString(ConfigSetting::SourceFile)) + for (const auto& sourceFile : conf.GetSourceFiles()) { - if (FileUtils::FileExists(conf.GetConfigPath() + sourceFile)) - cppFiles.emplace(conf.GetConfigPath() + sourceFile); + if (FileUtils::FileExists(conf.GetConfigPath() / sourceFile)) + cppFiles.emplace(sourceFile); else LOG_WARNING("Source file doesn't exist: ", sourceFile); } @@ -102,61 +101,60 @@ void Utils::GetCppFiles(ConfigFile& conf, std::set& cppFiles) void Utils::GetCppAndHFiles(ConfigFile& conf, std::set& hFiles, std::set& cppFiles) { - std::vector files; - std::string sourceDir = conf.GetSettingString(ConfigSetting::SourceDir); - std::string path = conf.GetConfigPath() + sourceDir; - if (!sourceDir.empty()) + const std::vector& excludeSources = conf.GetExcludeSources(); + for (const auto& sourceFile : conf.GetSourceFiles()) { - FileUtils::GetAllFiles(path, files); - } - const std::vector& excludeSources = conf.GetSettingVectorString(ConfigSetting::ExcludeSource); - for (const auto& sourceFile : conf.GetSettingVectorString(ConfigSetting::SourceFile)) - { - if (FileUtils::FileExists(conf.GetConfigPath() + sourceFile)) - cppFiles.emplace(conf.GetConfigPath() + sourceFile); + if (FileUtils::FileExists(conf.GetConfigPath() / sourceFile)) + cppFiles.emplace(sourceFile); else LOG_WARNING("Source file doesn't exist: ", sourceFile); } - for (const auto& filename : files) - { - if (IsSourceFile(filename)) - { - std::filesystem::path filepath = std::filesystem::relative(filename, "./"); - auto it = std::find(excludeSources.begin(), excludeSources.end(), filepath.string()); - if (it == excludeSources.end()) - { - cppFiles.emplace(filepath.string()); - } - } - else if (IsHeaderFile(filename)) - { - std::filesystem::path path = std::filesystem::relative(filename, sourceDir); - hFiles.emplace(HFile{path.string(), sourceDir, false}); - } - } - for (const auto& includePath : conf.GetSettingVectorString(ConfigSetting::IncludeDir)) + const std::optional& sourceDir = conf.GetSourceDir(); + if (sourceDir.has_value()) { std::vector files; - FileUtils::GetAllFiles(includePath, files); - for (const auto& file : files) + FileUtils::GetAllFiles(conf.GetConfigPath() / sourceDir.value(), files); + for (const auto& filename : files) { - std::filesystem::path path = std::filesystem::relative(file, includePath); - if (IsHeaderFile(path.string())) + if (IsSourceFile(filename)) { - hFiles.emplace(HFile{path.string(), includePath, false}); + std::filesystem::path filepath = std::filesystem::relative(filename, "./"); + auto it = std::find(excludeSources.begin(), excludeSources.end(), filepath.string()); + if (it == excludeSources.end()) + { + cppFiles.emplace(filepath.string()); + } + } + else if (IsHeaderFile(filename)) + { + std::filesystem::path path = std::filesystem::relative(filename, sourceDir.value()); + hFiles.emplace(HFile{path.string(), sourceDir.value(), false}); + } + } + + for (const auto& includePath : conf.GetIncludeDirs()) + { + std::vector files; + FileUtils::GetAllFiles(includePath, files); + for (const auto& file : files) + { + std::filesystem::path path = std::filesystem::relative(file, includePath); + if (IsHeaderFile(path.string())) + { + hFiles.emplace(HFile{path.string(), includePath, false}); + } } } } - const std::vector& dependencies = conf.GetDependencies(); for (size_t i = 0; i < dependencies.size(); ++i) { - GetHFiles(dependencies[i].path, conf.GetDependencyConfig(i), hFiles); + GetHFiles(conf.GetDependencyConfig(dependencies[i].path), hFiles); } } -void Utils::GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::set& hFiles) +void Utils::GetHFiles(ConfigFile& conf, std::set& hFiles) { // TODO: Fix so that cyclic dependencies doesn't crash the tool. // Cyclic dependencies probably shouldn't exist. @@ -164,11 +162,19 @@ void Utils::GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::s const std::vector& dependencies = conf.GetDependencies(); for (size_t i = 0; i < dependencies.size(); ++i) { - GetHFiles(dependencyDir + dependencies[i].path, conf.GetDependencyConfig(i), hFiles); + std::filesystem::path dependencyConfigPath = + std::filesystem::canonical(conf.GetConfigPath() / dependencies[i].path); + GetHFiles(conf.GetDependencyConfig(dependencyConfigPath), hFiles); + } + + const std::optional& sourceDir = conf.GetSourceDir(); + if (!sourceDir.has_value()) + { + return; } std::vector files; - std::string depSrcDir = dependencyDir + conf.GetSettingString(ConfigSetting::SourceDir); + std::string depSrcDir = conf.GetConfigPath() / sourceDir.value(); FileUtils::GetAllFiles(depSrcDir, files); for (auto it = files.begin(); it != files.end(); ++it) { @@ -178,7 +184,7 @@ void Utils::GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::s auto it = hFiles.find({filename, "", false}); if (it != hFiles.end()) { - if (filename == conf.GetSettingString(ConfigSetting::HFileName) && !it->isProjectHFile) + if (filename == conf.GetHFileName() && !it->isProjectHFile) { HFile hfile = *it; hfile.isProjectHFile = true; @@ -188,10 +194,7 @@ void Utils::GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::s } else { - hFiles.emplace(HFile{filename, - depSrcDir, - conf.GetSettingBool(ConfigSetting::GenerateHFile) && - filename == conf.GetSettingString(ConfigSetting::HFileName)}); + hFiles.emplace(HFile{filename, depSrcDir, conf.IsGenerateHFile() && filename == conf.GetHFileName()}); } } } diff --git a/src/Utils.h b/src/Utils.h index 2d5cf2b..b50d61e 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -43,7 +43,7 @@ struct Utils static void Replace(std::string& str, const std::string& from, const std::string& to); static void GetCppFiles(ConfigFile& conf, std::set& cppFiles); static void GetCppAndHFiles(ConfigFile& conf, std::set& hFiles, std::set& cppFiles); - static void GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::set& hFiles); + static void GetHFiles(ConfigFile& conf, std::set& hFiles); // Used for parsing xml static bool IsWhiteSpace(char c); diff --git a/src/main.cpp b/src/main.cpp index 2546a3c..6b1a597 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,7 +51,7 @@ Usage: makegen [options] void GenMakefile(ConfigFile& conf, unsigned int flags) { - if (conf.GetSettingBool(ConfigSetting::GenerateHFile)) + if (conf.IsGenerateHFile()) HFileGen::Create(conf); Makefile::Save(conf, flags); } @@ -145,7 +145,7 @@ bool RunMake(const std::string& filepath, unsigned int flags, ConfigFile& conf) { RETURN_IF(system(std::string(make + " install").c_str()) != 0, false); } - if (flags & FLAG_RUN && conf.GetSettingString(ConfigSetting::OutputType) == "executable") + if (flags & FLAG_RUN && conf.GetOutputType() == "executable") { RETURN_IF(system(std::string(make + " run").c_str()) != 0, false); } @@ -175,14 +175,14 @@ bool MakeGen(const std::string& filepath, const FlagData& flagData, ConfigFile& std::filesystem::current_path(currentPath); } LOG_INFO("-----------------------------------"); - LOG_INFO("Building ", conf.GetSettingString(ConfigSetting::ProjectName)); + LOG_INFO("Building ", conf.GetProjectName()); LOG_INFO("Generating Makefile..."); Timer timer; GenMakefile(conf, flagData.flags); LOG_INFO("Took ", round(timer.Elapsed() * 1000.0) / 1000.0, "s"); LOG_INFO("Running Makefile..."); - std::string outputPath = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::OutputDir); + std::string outputPath = conf.GetConfigPath() / conf.GetOutputDir(); if (!FileUtils::HasPath(outputPath)) { FileUtils::CreateDirectory(outputPath); @@ -193,7 +193,7 @@ bool MakeGen(const std::string& filepath, const FlagData& flagData, ConfigFile& return RunMake(filepath, flagData.flags, conf); } -int main(int argc, char** argv) +int Run(int argc, char** argv) { FlagData flagData = ReadFlags(argc, argv); if (flagData.flags & FLAG_HELP) @@ -221,4 +221,19 @@ int main(int argc, char** argv) { LOG_ERROR("Couldn\'t load config file"); } + return 0; +} + +#include + +int main(int argc, char** argv) +{ + try + { + return Run(argc, argv); + } + catch (const AssertException& exception) + { + return 1; + } } diff --git a/src/xml/XMLObject.cpp b/src/xml/XMLObject.cpp index a3f8a3d..3cd3e13 100644 --- a/src/xml/XMLObject.cpp +++ b/src/xml/XMLObject.cpp @@ -81,6 +81,16 @@ std::vector* XMLObject::GetObjectPtr(const std::string& name) return &it->second; } +std::vector& XMLObject::GetObjects(const std::string& name) +{ + static std::vector empty{}; + auto it = objects.find(name); + if (it == objects.end()) + return empty; + + return it->second; +} + const std::vector& XMLObject::GetObjects(const std::string& name) const { static std::vector empty{}; diff --git a/src/xml/XMLObject.h b/src/xml/XMLObject.h index b225098..0084590 100644 --- a/src/xml/XMLObject.h +++ b/src/xml/XMLObject.h @@ -43,6 +43,8 @@ public: unsigned int GetObjectCount() const; std::vector* GetObjectPtr(const std::string& name); + + std::vector& GetObjects(const std::string& name); const std::vector& GetObjects(const std::string& name) const; const std::map>& GetObjects() const; const std::string& GetName() const;