Compare commits

...

10 Commits

Author SHA1 Message Date
Thraix b112ab4501 Fix relative paths being put in the wrong intermediate directory 2026-01-20 23:24:27 +01:00
Thraix 1edcfb570b Fix project compilation failure
- Fix project compilation failure when the project contains two files
  with the same name, causing the intermediate file to be in the same
  directory with the same name
- Fix small print errors in makegen --help
2026-01-20 22:27:42 +01:00
Thraix 7c68a839fc Format code based on clang format 2025-11-26 22:06:55 +01:00
Thraix 6976d330fc Add --target=<target> flag
- Used to compile using a specific target, without the need of modifying
  the makegen.xml file
2025-08-05 20:45:36 +02:00
Thraix 658d6df8a5 Add includedirexcldep makgen.xml flag
- New flag is used to add include directories without making them part
  of the include dependency graph.
- Can be used to remove dependency graphs for include directories that
  aren't generally modified, like operating system library include
  directories
2025-06-04 22:20:09 +02:00
Thraix aa0b390379 Fix simple flag and excludesource
- Fix simple flag not generating the correct Makefile
- Fix excludesource not excluding the correct files
2025-06-04 22:09:33 +02:00
Thraix d3c334dc79 Fix absolute paths causing Makefile errors 2025-06-04 21:31:33 +02:00
Thraix f6caefb078 Add sourcefile as makegen.xml option
- sourcefile will add additional individual files. Useful for when the
  user needs to manually specify files from existing repositories. If
  those repositories contain multiple files for different platforms
- Rework IncludeDeps to support sourcefiles
2025-05-25 16:07:32 +02:00
Thraix 61f9c3ee0d Fix relative paths not being included as include dependency 2020-04-26 20:13:52 +02:00
Thraix febfda55cc Release v1.3.0 2020-03-07 22:06:57 +01:00
27 changed files with 1490 additions and 843 deletions
+334
View File
@@ -0,0 +1,334 @@
---
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: true
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AllowShortNamespacesOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AttributeMacros:
- __capability
- absl_nonnull
- absl_nullable
- absl_nullability_unknown
BinPackArguments: false
BinPackLongBracedList: true
BinPackParameters: false
BitFieldColonSpacing: Both
BracedInitializerIndentWidth: -1
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Allman
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTemplateCloser: false
BreakBeforeTernaryOperators: true
BreakBinaryOperations: Never
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
BreakTemplateDeclarations: Yes
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
EnumTrailingComma: Leave
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 3
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: true
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: false
AtStartOfFile: true
KeepFormFeed: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
OneLineFormatOffRegex: ''
PackConstructorInitializers: Never
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakBeforeMemberAccess: 150
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
PPIndentWidth: -1
QualifierAlignment: Leave
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: pb
BasedOnStyle: google
ReferenceAlignment: Pointer
ReflowComments: Always
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Always
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes:
Enabled: true
IgnoreCase: false
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterOperatorKeyword: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterNot: false
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Auto
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 2
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
...
+23 -22
View File
@@ -1,4 +1,4 @@
# This Makefile was generated using MakeGen v1.3.0 made by Tim Håkansson
# This Makefile was generated using MakeGen v1.3.8 made by Tim Håkansson
# and is licensed under MIT. Full source of the project can be found at
# https://github.com/Thraix/MakeGen
CC=@g++
@@ -7,59 +7,60 @@ MKDIR_P=mkdir -p
BIN=bin/
OBJPATH=$(BIN)intermediates
INCLUDES=
OBJECTS=$(OBJPATH)/ConfigCLI.o $(OBJPATH)/ConfigFile.o $(OBJPATH)/HFileGen.o $(OBJPATH)/IncludeDeps.o $(OBJPATH)/Makefile.o $(OBJPATH)/Utils.o $(OBJPATH)/ConfigFileConf.o $(OBJPATH)/main.o $(OBJPATH)/XML.o $(OBJPATH)/XMLObject.o
CFLAGS=$(INCLUDES) -std=c++17 -c -D_DEBUG -g3 -w
OBJECTS=$(OBJPATH)/src/ConfigCLI.o $(OBJPATH)/src/ConfigFile.o $(OBJPATH)/src/HFileGen.o $(OBJPATH)/src/IncludeDeps.o $(OBJPATH)/src/Makefile.o $(OBJPATH)/src/Utils.o $(OBJPATH)/src/compatibility/ConfigFileConf.o $(OBJPATH)/src/main.o $(OBJPATH)/src/xml/XML.o $(OBJPATH)/src/xml/XMLObject.o
CFLAGS=$(INCLUDES) -std=c++17 -c
LIBDIR=
LDFLAGS=
LIBS=$(LIBDIR)
OUTPUT=$(BIN)makegen
.PHONY: all directories rebuild clean run
all: directories $(OUTPUT)
directories: $(BIN) $(OBJPATH)
$(BIN):
$(info Creating output directories)
@$(MKDIR_P) $(BIN)
$(OBJPATH):
@$(MKDIR_P) $(OBJPATH)
directories: $(OBJPATH)/src $(OBJPATH)/src/compatibility $(OBJPATH)/src/xml
$(OBJPATH)/src:
@$(MKDIR_P) $@
$(OBJPATH)/src/compatibility:
@$(MKDIR_P) $@
$(OBJPATH)/src/xml:
@$(MKDIR_P) $@
run: all
@./$(OUTPUT)
rebuild: clean all
clean:
$(info Removing intermediates)
rm -rf $(OBJPATH)/*.o
$(info Removing $(OBJPATH))
@rm -rf $(OBJPATH)/
$(OUTPUT): $(OBJECTS)
$(info Generating output file)
$(info Generating output file $(OUTPUT))
$(CO) $(OUTPUT) $(OBJECTS) $(LDFLAGS) $(LIBS)
install: all
$(info Installing MakeGen to /usr/bin/)
@cp $(OUTPUT) /usr/bin/makegen
$(OBJPATH)/ConfigCLI.o : src/ConfigCLI.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h
$(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/FlagData.h src/xml/XMLObject.h
$(info -[10%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/ConfigFile.o : src/ConfigFile.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h src/xml/XML.h
$(OBJPATH)/src/ConfigFile.o: src/ConfigFile.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/FlagData.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h src/xml/XML.h
$(info -[20%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/HFileGen.o : src/HFileGen.cpp src/FileUtils.h src/Common.h src/Utils.h src/HFileGen.h src/ConfigFile.h src/ConfigUtils.h src/xml/XMLObject.h
$(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/FlagData.h src/xml/XMLObject.h
$(info -[30%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/IncludeDeps.o : src/IncludeDeps.cpp src/Common.h src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h
$(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/FlagData.h src/xml/XMLObject.h
$(info -[40%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/Makefile.o : src/Makefile.cpp src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h src/Makefile.h
$(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/FlagData.h src/xml/XMLObject.h src/Makefile.h
$(info -[50%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/Utils.o : src/Utils.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h
$(OBJPATH)/src/Utils.o: src/Utils.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/FlagData.h src/xml/XMLObject.h
$(info -[60%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/ConfigFileConf.o : src/compatibility/ConfigFileConf.cpp src/compatibility/ConfigFileConf.h
$(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/FlagData.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h
$(info -[70%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/main.o : src/main.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.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/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/FlagData.h src/xml/XMLObject.h src/HFileGen.h src/Makefile.h src/Timer.h
$(info -[80%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/XML.o : src/xml/XML.cpp src/xml/XML.h src/xml/XMLObject.h src/xml/XMLException.h
$(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)/XMLObject.o : src/xml/XMLObject.cpp src/xml/XMLException.h src/xml/XMLObject.h
$(OBJPATH)/src/xml/XMLObject.o: src/xml/XMLObject.cpp src/Common.h src/Utils.h src/xml/XMLException.h src/xml/XMLObject.h
$(info -[100%]- $<)
$(CC) $(CFLAGS) -o $@ $<
+2 -2
View File
@@ -18,6 +18,6 @@
<projectname>MakeGen</projectname>
<srcdir>src/</srcdir>
</configuration>
<target>Debug</target>
<version>v1.3.0</version>
<target>Release</target>
<version>v1.3.8</version>
</makegen>
Executable → Regular
+40 -8
View File
@@ -1,8 +1,10 @@
#pragma once
#include <iostream>
#include <set>
#include <vector>
#define BIT(x) (1<<x)
#define BIT(x) (1 << x)
#define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x)
@@ -12,7 +14,7 @@
// Release, should be backwards compatible with any minor version
#define MAKEGEN_VERSION_RELEASE 3
// Minor changes, generally bug fixes
#define MAKEGEN_VERSION_MINOR 0
#define MAKEGEN_VERSION_MINOR 8
#define MAKEGEN_VERSION ("v" STR(MAKEGEN_VERSION_MAJOR) "." STR(MAKEGEN_VERSION_RELEASE) "." STR(MAKEGEN_VERSION_MINOR))
@@ -27,7 +29,7 @@ const static unsigned int FLAG_SINGLE_THREAD = BIT(7);
const static unsigned int FLAG_DEPENDENCY = BIT(8);
const static unsigned int FLAG_SIMPLE = BIT(9);
const static unsigned int FLAG_CONFIG = BIT(10);
const static unsigned int FLAG_TARGET = BIT(11);
#define LOG_INFO(...) LogHelper(__VA_ARGS__)
#define LOG_WARNING(...) LogHelper(__VA_ARGS__)
@@ -39,24 +41,54 @@ void Log(const T& var)
std::cout << var;
}
template <typename T, typename ...Ts>
void Log(const T& var, const Ts& ...vars)
template <typename T, typename... Ts>
void Log(const T& var, const Ts&... vars)
{
Log(var);
Log(vars...);
}
template <typename T, typename ...Ts>
template <typename T, typename... Ts>
void LogHelper(const T& var)
{
Log(var);
std::cout << std::endl;
}
template <typename T, typename ...Ts>
void LogHelper(const T& var, const Ts& ...vars)
template <typename T, typename... Ts>
void LogHelper(const T& var, const Ts&... vars)
{
Log(var);
Log(vars...);
std::cout << std::endl;
}
template <typename T>
std::ostream& operator<<(std::ostream& ostream, const std::vector<T>& vec)
{
ostream << "[" << std::endl;
for (size_t i = 0; i < vec.size(); i++)
{
if (i != 0)
ostream << ", " << std::endl;
ostream << vec[i];
}
ostream << std::endl << "]";
return ostream;
}
template <typename T>
std::ostream& operator<<(std::ostream& ostream, const std::set<T>& set)
{
ostream << "[" << std::endl;
int i = 0;
for (const auto& elem : set)
{
if (i != 0)
ostream << ", " << std::endl;
ostream << " " << elem;
i++;
}
ostream << std::endl << "]";
return ostream;
}
+45 -48
View File
@@ -3,11 +3,9 @@
#include "Common.h"
#include "ConfigFile.h"
#include <set>
void ConfigCLI::DisplayCLIHelp()
{
LOG_INFO(1+(char*)R"(
LOG_INFO(1 + (char*)R"(
MakeGen conf is used to create, modify and query the makegen.xml file.
Usage: makegen conf <command> [<args>] [--help]
@@ -27,7 +25,7 @@ Querying config settings
void ConfigCLI::DisplayGenHelp()
{
LOG_INFO(1+(char*)R"(
LOG_INFO(1 + (char*)R"(
Generate a config file from prompts
Usage: makegen conf gen <option>
@@ -41,7 +39,7 @@ options:
void ConfigCLI::DisplayAddHelp()
{
LOG_INFO(1+(char*)R"(
LOG_INFO(1 + (char*)R"(
Add values to config settings which support multiple arguments
Usage: makegen conf add <setting> <value> [<values>]
@@ -62,7 +60,7 @@ Valid settings are:
void ConfigCLI::DisplayRemoveHelp()
{
LOG_INFO(1+(char*)R"(
LOG_INFO(1 + (char*)R"(
Remove values to config settings which support multiple
Usage: makegen conf remove <setting> <value> [<
@@ -83,7 +81,7 @@ Valid settings are
void ConfigCLI::DisplaySetHelp()
{
LOG_INFO(1+(char*)R"(
LOG_INFO(1 + (char*)R"(
Set value to config settings which only support one argument
Usage: makegen conf set <setting> <value>
@@ -104,7 +102,7 @@ Boolean values can be set to either true/t/yes/y or false/f/no/n)");
void ConfigCLI::DisplayGetHelp()
{
LOG_INFO(1+(char*)R"(
LOG_INFO(1 + (char*)R"(
Get value of the config setting
Usage: makegen conf get <setting>
@@ -130,7 +128,6 @@ Valid settings are:
genhfile Specifies if MakeGen should generate a project h-file)");
}
ConfigSetting ConfigCLI::CLIStringToSetting(const std::string& s)
{
static std::map<std::string, ConfigSetting> map{
@@ -154,32 +151,32 @@ ConfigSetting ConfigCLI::CLIStringToSetting(const std::string& s)
{"genhfile", ConfigSetting::GenerateHFile},
};
auto it = map.find(s);
if(it == map.end())
if (it == map.end())
return ConfigSetting::Invalid;
return it->second;
}
int ConfigCLI::Gen(int argc, char** argv)
{
if(argc < 2 || std::string(argv[1]) == "--help")
if (argc < 2 || std::string(argv[1]) == "--help")
{
DisplayGenHelp();
return 0;
}
if(argc < 2)
if (argc < 2)
{
LOG_ERROR("gen needs exactly one parameter");
return 1;
}
std::string option = argv[1];
if(option == "prompt")
if (option == "prompt")
{
ConfigFile::Gen().Save();
ConfigFile::Gen(FlagData{}).Save();
return 0;
}
if(option == "default")
if (option == "default")
{
ConfigFile{FileUtils::GetRealPath("."),0}.Save();
ConfigFile{FileUtils::GetRealPath("."), FlagData{}, 0}.Save();
return 0;
}
else
@@ -191,21 +188,21 @@ int ConfigCLI::Gen(int argc, char** argv)
int ConfigCLI::Add(int argc, char** argv, ConfigFile& config)
{
if(argc < 2 || std::string(argv[1]) == "--help")
if (argc < 2 || std::string(argv[1]) == "--help")
{
DisplayAddHelp();
return 0;
}
if(argc < 3)
if (argc < 3)
{
LOG_ERROR("add needs at least two parameters");
return 1;
}
ConfigSetting setting = CLIStringToSetting(argv[1]);
if(!ConfigUtils::IsVectorSetting(setting))
if (!ConfigUtils::IsVectorSetting(setting))
{
if(setting == ConfigSetting::Invalid)
if (setting == ConfigSetting::Invalid)
{
LOG_ERROR("No such setting: ", argv[1]);
}
@@ -216,7 +213,7 @@ int ConfigCLI::Add(int argc, char** argv, ConfigFile& config)
}
return 1;
}
for(int i = 2; i<argc;++i)
for (int i = 2; i < argc; ++i)
{
config.AddSettingVectorString(setting, argv[i]);
}
@@ -227,21 +224,21 @@ int ConfigCLI::Add(int argc, char** argv, ConfigFile& config)
int ConfigCLI::Remove(int argc, char** argv, ConfigFile& config)
{
if(argc < 2 || std::string(argv[1]) == "--help")
if (argc < 2 || std::string(argv[1]) == "--help")
{
DisplayRemoveHelp();
return 0;
}
if(argc < 3)
if (argc < 3)
{
LOG_ERROR("remove needs at least two parameters");
return 1;
}
ConfigSetting setting = CLIStringToSetting(argv[1]);
if(!ConfigUtils::IsVectorSetting(setting))
if (!ConfigUtils::IsVectorSetting(setting))
{
if(setting == ConfigSetting::Invalid)
if (setting == ConfigSetting::Invalid)
{
LOG_ERROR("No such setting: ", argv[1]);
}
@@ -253,7 +250,7 @@ int ConfigCLI::Remove(int argc, char** argv, ConfigFile& config)
return 1;
}
for(int i = 2; i<argc;++i)
for (int i = 2; i < argc; ++i)
{
config.RemoveSettingVectorString(setting, argv[i]);
}
@@ -264,21 +261,21 @@ int ConfigCLI::Remove(int argc, char** argv, ConfigFile& config)
int ConfigCLI::Set(int argc, char** argv, ConfigFile& config)
{
if(argc < 2 || std::string(argv[1]) == "--help")
if (argc < 2 || std::string(argv[1]) == "--help")
{
DisplaySetHelp();
return 0;
}
if(argc != 3)
if (argc != 3)
{
LOG_ERROR("set needs exactly two parameters");
return 1;
}
ConfigSetting setting = CLIStringToSetting(argv[1]);
if(!ConfigUtils::IsStringSetting(setting) && !ConfigUtils::IsBoolSetting(setting))
if (!ConfigUtils::IsStringSetting(setting) && !ConfigUtils::IsBoolSetting(setting))
{
if(setting == ConfigSetting::Invalid)
if (setting == ConfigSetting::Invalid)
{
LOG_ERROR("No such setting: ", argv[1]);
}
@@ -297,19 +294,19 @@ int ConfigCLI::Set(int argc, char** argv, ConfigFile& config)
int ConfigCLI::Get(int argc, char** argv, ConfigFile& config)
{
if(argc < 2 || std::string(argv[1]) == "--help")
if (argc < 2 || std::string(argv[1]) == "--help")
{
DisplayGetHelp();
return 0;
}
if(argc != 2)
if (argc != 2)
{
LOG_ERROR("get needs exactly one parameter");
return 1;
}
ConfigSetting setting = CLIStringToSetting(argv[1]);
std::vector<std::string> vector = config.GetSetting(setting);
for(auto it = vector.begin(); it != vector.end(); ++it)
for (auto it = vector.begin(); it != vector.end(); ++it)
{
LOG_INFO(*it);
}
@@ -319,39 +316,39 @@ int ConfigCLI::Get(int argc, char** argv, ConfigFile& config)
int ConfigCLI::Main(int argc, char** argv)
{
// Do nothing
if(argc < 2 || std::string(argv[1]) == "--help")
if (argc < 2 || std::string(argv[1]) == "--help")
{
DisplayCLIHelp();
return 0;
}
std::optional<ConfigFile> config = ConfigFile::GetConfigFile();
std::optional<ConfigFile> config = ConfigFile::GetConfigFile("./", FlagData{});
std::string command = argv[1];
if(command == "gen")
if (command == "gen")
{
if(config)
if (config)
{
LOG_ERROR("Config file already exist (", CONFIG_FILENAME, ")");
return 1;
}
return Gen(argc-1, &argv[1]);
return Gen(argc - 1, &argv[1]);
}
else if(config)
else if (config)
{
if(command == "add")
return Add(argc-1, &argv[1], *config);
else if(command == "remove")
return Remove(argc-1, &argv[1], *config);
else if(command == "set")
return Set(argc-1, &argv[1], *config);
else if(command == "get")
return Get(argc-1, &argv[1], *config);
if (command == "add")
return Add(argc - 1, &argv[1], *config);
else if (command == "remove")
return Remove(argc - 1, &argv[1], *config);
else if (command == "set")
return Set(argc - 1, &argv[1], *config);
else if (command == "get")
return Get(argc - 1, &argv[1], *config);
else
{
LOG_ERROR("Unknown config command: ", command);
return 1;
}
}
else
else
{
LOG_ERROR("There is no config file in the current directory");
return 1;
+16 -16
View File
@@ -2,24 +2,24 @@
#include "ConfigFile.h"
struct ConfigCLI
struct ConfigCLI
{
public:
static int Main(int argc, char** argv);
private:
static void DisplayCLIHelp();
static void DisplayGenHelp();
static void DisplayAddHelp();
static void DisplayRemoveHelp();
static void DisplaySetHelp();
static void DisplayGetHelp();
public:
static int Main(int argc, char** argv);
static ConfigSetting CLIStringToSetting(const std::string& s);
private:
static void DisplayCLIHelp();
static void DisplayGenHelp();
static void DisplayAddHelp();
static void DisplayRemoveHelp();
static void DisplaySetHelp();
static void DisplayGetHelp();
static int Gen(int argc, char** argv);
static int Add(int argc, char** argv, ConfigFile& config);
static int Remove(int argc, char** argv, ConfigFile& config);
static int Set(int argc, char** argv, ConfigFile& config);
static int Get(int argc, char** argv, ConfigFile& config);
static ConfigSetting CLIStringToSetting(const std::string& s);
static int Gen(int argc, char** argv);
static int Add(int argc, char** argv, ConfigFile& config);
static int Remove(int argc, char** argv, ConfigFile& config);
static int Set(int argc, char** argv, ConfigFile& config);
static int Get(int argc, char** argv, ConfigFile& config);
};
Executable → Regular
+123 -111
View File
@@ -1,13 +1,12 @@
#include "ConfigFile.h"
#include <fstream>
#include "FileUtils.h"
#include "compatibility/ConfigFileConf.h"
#include "xml/XML.h"
#include <algorithm>
#include <fstream>
ConfigFile::ConfigFile(const std::string& path, int)
ConfigFile::ConfigFile(const std::string& path, const FlagData& flagData, int)
: configPath{path}
{
// Converts project name (current directory) to lowercase
@@ -17,7 +16,10 @@ ConfigFile::ConfigFile(const std::string& path, int)
// Version, target and configuration is probably going to be used in the future
makegen.AddXMLObject(XMLObject("version", {}, "v1.3.0"));
makegen.AddXMLObject(XMLObject("target", {}, "Release"));
if (flagData.flags & FLAG_TARGET)
makegen.AddXMLObject(XMLObject("target", {}, flagData.target));
else
makegen.AddXMLObject(XMLObject("target", {}, "Release"));
XMLObject configuration("configuration", {{"name", "Release"}}, std::map<std::string, std::vector<XMLObject>>{});
configuration.AddXMLObject(XMLObject("projectname", {}, ConfigUtils::GetDefaultProjectName(configPath)));
@@ -30,41 +32,49 @@ ConfigFile::ConfigFile(const std::string& path, int)
makegen.AddXMLObject(configuration);
config = makegen;
Init();
Init(flagData);
}
ConfigFile::ConfigFile(const std::string& path)
: config{XML::FromFile(path + CONFIG_FILENAME)}, configPath{path}
ConfigFile::ConfigFile(const std::string& path, const FlagData& flagData)
: config{XML::FromFile(path + CONFIG_FILENAME)},
configPath{path}
{
Init();
Init(flagData);
}
ConfigFile::ConfigFile(XMLObject& config, const std::string& path)
: config{config}, configPath{path}
ConfigFile::ConfigFile(XMLObject& config, const std::string& path, const FlagData& flagData)
: config{config},
configPath{path}
{
Init();
Init(flagData);
}
void ConfigFile::Init()
void ConfigFile::Init(const FlagData& flagData)
{
const std::vector<XMLObject>* targetXml = config.GetObjectPtr("target");
target = "Release";
if(!targetXml || targetXml->size() == 0)
if (flagData.flags & FLAG_TARGET)
{
LOG_ERROR("No target found in config file. Using target=", target);
return;
target = flagData.target;
}
else
{
const std::vector<XMLObject>* targetXml = config.GetObjectPtr("target");
target = "Release";
if (!targetXml || targetXml->size() == 0)
{
LOG_ERROR("No target found in config file. Using target=", target);
return;
}
if (targetXml->size() > 1)
LOG_ERROR("To many targets in config file. Using target=", (*targetXml)[0].GetText());
if (targetXml->size() > 0)
target = (*targetXml)[0].GetText();
}
if(targetXml->size() > 1)
LOG_ERROR("To many targets in config file. Using target=", (*targetXml)[0].GetText());
if(targetXml->size() > 0)
target = (*targetXml)[0].GetText();
}
std::string& ConfigFile::GetSettingString(ConfigSetting setting)
{
// Adding it to the cache since we need to return a reference
if(!ConfigUtils::IsStringSetting(setting))
if (!ConfigUtils::IsStringSetting(setting))
{
LOG_ERROR("Invalid string setting");
return cache.strings.emplace("invalid", "").first->second;
@@ -72,43 +82,43 @@ std::string& ConfigFile::GetSettingString(ConfigSetting setting)
std::string sSetting = ConfigUtils::GetSettingName(setting);
auto it = cache.strings.find(sSetting);
if(it != cache.strings.end())
if (it != cache.strings.end())
return it->second;
const std::vector<XMLObject>* values = GetConfiguration().GetObjectPtr(sSetting);
// No value found, using default
if(values == nullptr)
if (values == nullptr)
return cache.strings.emplace(sSetting, ConfigUtils::GetDefaultSettingString(setting, configPath)).first->second;
if(values->size() != 1)
if (values->size() != 1)
{
LOG_ERROR("To many arguments for setting using first: ", (int)setting, "=", (*values)[0].GetText());
}
std::string s = (*values)[0].GetText();
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
if (ConfigUtils::IsDirectory(setting) && !s.empty() && s[s.size() - 1] != '/')
s += '/';
return cache.strings.emplace(sSetting, s).first->second;
}
bool ConfigFile::GetSettingBool(ConfigSetting setting)
{
if(setting == ConfigSetting::Invalid)
if (setting == ConfigSetting::Invalid)
{
LOG_ERROR("Invalid config setting");
return false;
}
std::string sSetting = ConfigUtils::GetSettingName(setting);
auto it = cache.bools.find(sSetting);
if(it != cache.bools.end())
if (it != cache.bools.end())
return it->second;
const std::vector<XMLObject>* values = GetConfiguration().GetObjectPtr(sSetting);//,
const std::vector<XMLObject>* values = GetConfiguration().GetObjectPtr(sSetting); //,
if(values == nullptr)
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());
}
@@ -119,21 +129,21 @@ std::vector<std::string>& ConfigFile::GetSettingVectorString(ConfigSetting setti
{
std::string sSetting = ConfigUtils::GetSettingName(setting);
auto it = cache.vecStrings.find(sSetting);
if(it != cache.vecStrings.end())
if (it != cache.vecStrings.end())
return it->second;
const std::vector<XMLObject>* values = GetConfiguration().GetObjectPtr(sSetting);
if(values == nullptr)
if (values == nullptr)
return cache.vecStrings.emplace(sSetting, std::vector<std::string>{}).first->second;
std::vector<std::string> strings;
strings.reserve(values->size());
for(auto it = values->begin(); it != values->end(); ++it)
for (auto it = values->begin(); it != values->end(); ++it)
{
if(it->GetText() == "")
if (it->GetText() == "")
continue;
std::string s = it->GetText();
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
if (ConfigUtils::IsDirectory(setting) && s[s.size() - 1] != '/')
s += '/';
strings.push_back(s);
}
@@ -143,11 +153,11 @@ std::vector<std::string>& ConfigFile::GetSettingVectorString(ConfigSetting setti
std::vector<std::string> ConfigFile::GetSetting(ConfigSetting setting)
{
if(ConfigUtils::IsStringSetting(setting))
if (ConfigUtils::IsStringSetting(setting))
return {GetSettingString(setting)};
else if(ConfigUtils::IsVectorSetting(setting))
else if (ConfigUtils::IsVectorSetting(setting))
return GetSettingVectorString(setting);
else if(ConfigUtils::IsBoolSetting(setting))
else if (ConfigUtils::IsBoolSetting(setting))
return {GetSettingBool(setting) ? "true" : "false"};
else
{
@@ -161,24 +171,24 @@ bool ConfigFile::SetSettingString(ConfigSetting setting, const std::string& valu
// Check if valid enum
std::string s = value;
std::string sSetting = ConfigUtils::GetSettingName(setting);
if(ConfigUtils::IsStringSetting(setting))
if (ConfigUtils::IsStringSetting(setting))
{
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
if (ConfigUtils::IsDirectory(setting) && s[s.size() - 1] != '/')
{
s += '/';
}
auto it = cache.strings.find(sSetting);
// Update cache
if(it != cache.strings.end())
if (it != cache.strings.end())
it->second = s;
else
cache.strings.emplace(sSetting, s);
}
else if(ConfigUtils::IsBoolSetting(setting))
else if (ConfigUtils::IsBoolSetting(setting))
{
if(s == "true" || s == "t" || s == "yes" || s == "y")
if (s == "true" || s == "t" || s == "yes" || s == "y")
s = "true";
else if(s == "false" || s == "f" || s == "no" || s == "n")
else if (s == "false" || s == "f" || s == "no" || s == "n")
s = "false";
else
{
@@ -188,7 +198,7 @@ bool ConfigFile::SetSettingString(ConfigSetting setting, const std::string& valu
auto it = cache.bools.find(sSetting);
// Update cache
if(it != cache.bools.end())
if (it != cache.bools.end())
it->second = s == "true";
else
cache.bools.emplace(sSetting, value == "true");
@@ -201,9 +211,9 @@ bool ConfigFile::SetSettingString(ConfigSetting setting, const std::string& valu
XMLObject& configuration = GetConfiguration();
std::vector<XMLObject>* values = configuration.GetObjectPtr(sSetting);
if(values == nullptr)
if (values == nullptr)
configuration.AddXMLObject({sSetting, {}, s});
else if(values->size() > 1)
else if (values->size() > 1)
LOG_ERROR("Multiple values of setting, changing first: ", sSetting, "=", s);
else
(*values)[0].SetText(s);
@@ -213,10 +223,10 @@ bool ConfigFile::SetSettingString(ConfigSetting setting, const std::string& valu
bool ConfigFile::AddSettingVectorString(ConfigSetting setting, const std::string& value)
{
// Check if valid enum
if(ConfigUtils::IsVectorSetting(setting))
if (ConfigUtils::IsVectorSetting(setting))
{
std::string s = value;
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
if (ConfigUtils::IsDirectory(setting) && s[s.size() - 1] != '/')
{
s += '/';
}
@@ -224,7 +234,7 @@ bool ConfigFile::AddSettingVectorString(ConfigSetting setting, const std::string
auto it = cache.vecStrings.find(sSetting);
// Update cache
if(it != cache.vecStrings.end())
if (it != cache.vecStrings.end())
it->second.push_back(s);
else
cache.vecStrings.emplace(sSetting, std::vector<std::string>{s});
@@ -242,22 +252,22 @@ bool ConfigFile::AddSettingVectorString(ConfigSetting setting, const std::string
bool ConfigFile::RemoveSettingVectorString(ConfigSetting setting, const std::string& value)
{
// Check if valid enum
if(ConfigUtils::IsVectorSetting(setting))
if (ConfigUtils::IsVectorSetting(setting))
{
std::string s = value;
if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
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())
if (it != cache.vecStrings.end())
{
// Update cache
for(auto itVec = it->second.begin(); itVec != it->second.end(); ++itVec)
for (auto itVec = it->second.begin(); itVec != it->second.end(); ++itVec)
{
if(*itVec == s)
if (*itVec == s)
{
it->second.erase(itVec);
}
@@ -266,16 +276,16 @@ bool ConfigFile::RemoveSettingVectorString(ConfigSetting setting, const std::str
std::vector<XMLObject>* values = GetConfiguration().GetObjectPtr(sSetting);
bool found = false;
for(auto it = values->begin(); it != values->end();++it)
for (auto it = values->begin(); it != values->end(); ++it)
{
if(it->GetText() == s)
if (it->GetText() == s)
{
values->erase(it);
found = true;
break;
}
}
if(!found)
if (!found)
{
LOG_ERROR("Couldn't find value: ", s);
return false;
@@ -292,25 +302,26 @@ bool ConfigFile::RemoveSettingVectorString(ConfigSetting setting, const std::str
XMLObject& ConfigFile::GetConfiguration()
{
std::vector<XMLObject>* configurations = config.GetObjectPtr("configuration");
if(configurations == nullptr || configurations->size() == 0)
if (configurations == nullptr || configurations->size() == 0)
{
LOG_ERROR("No configuration in makegen.xml");
assert(false);
}
for(auto it = configurations->begin(); it != configurations->end(); ++it)
for (auto it = configurations->begin(); it != configurations->end(); ++it)
{
if(!it->HasAttribute("name"))
if (!it->HasAttribute("name"))
{
LOG_ERROR("No name attribute in configuration tag");
continue;
}
if(it->GetAttribute("name") == target)
if (it->GetAttribute("name") == target)
{
return *it;
}
}
LOG_ERROR("Couldn\'t find given target in config file. Using target=", (*configurations)[0].HasAttribute("name") ? (*configurations)[0].GetAttribute("name") : "");
LOG_ERROR("Couldn\'t find given target in config file. Using target=",
(*configurations)[0].HasAttribute("name") ? (*configurations)[0].GetAttribute("name") : "");
return (*configurations)[0];
}
@@ -324,26 +335,28 @@ ConfigFile& ConfigFile::GetDependencyConfig(size_t i)
return dependencyConfigs[i];
}
std::optional<ConfigFile> ConfigFile::GetConfigFile(const std::string& filepath)
std::optional<ConfigFile> ConfigFile::GetConfigFile(const std::string& filepath, const FlagData& flagData)
{
std::map<std::string, ConfigFile> loadedConfigs;
return GetConfigFile(filepath, loadedConfigs);
return GetConfigFile(filepath, loadedConfigs, flagData);
}
std::optional<ConfigFile> ConfigFile::GetConfigFile(const std::string& filepath, std::map<std::string, ConfigFile>& loadedConfigs)
std::optional<ConfigFile> ConfigFile::GetConfigFile(const std::string& filepath,
std::map<std::string, ConfigFile>& loadedConfigs,
const FlagData& flagData)
{
std::string realPath = FileUtils::GetRealPath(filepath);
if(realPath == "")
if (realPath == "")
return {};
auto it = loadedConfigs.find(realPath);
if(it != loadedConfigs.end())
if (it != loadedConfigs.end())
{
return {};
}
bool oldFile = false;
std::ifstream f(filepath + CONFIG_FILENAME);
if(!f.good())
if (!f.good())
{
ConfigFileConf::CreateXMLFile(realPath);
// try to read an old config file
@@ -352,20 +365,20 @@ std::optional<ConfigFile> ConfigFile::GetConfigFile(const std::string& filepath,
}
// Check if the file exists
if(f.good())
if (f.good())
{
f.close();
ConfigFile conf = ConfigFile(filepath);
if(conf.hasInitError)
ConfigFile conf = ConfigFile(filepath, flagData);
if (conf.hasInitError)
return {};
loadedConfigs.emplace(realPath, conf);
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
// Create dependency config files.
for(size_t i = 0; i < dependencies.size();++i)
for (size_t i = 0; i < dependencies.size(); ++i)
{
std::optional<ConfigFile> dep = GetConfigFile(conf.configPath + dependencies[i], loadedConfigs);
if(dep)
std::optional<ConfigFile> dep = GetConfigFile(conf.configPath + dependencies[i], loadedConfigs, flagData);
if (dep)
{
conf.dependencyConfigs.push_back(*dep);
dependencies[i] = dep->configPath;
@@ -385,13 +398,13 @@ std::optional<ConfigFile> ConfigFile::GetConfigFile(const std::string& filepath,
void ConfigFile::InputBoolean(const std::string& inputText, bool& b)
{
std::string input;
while(true)
while (true)
{
LOG_INFO(inputText);
std::getline(std::cin, input);
if(input.length() > 0)
if (input.length() > 0)
{
if(input[0] == 'y' || input[0] == 'n')
if (input[0] == 'y' || input[0] == 'n')
{
b = input[0] == 'y';
return;
@@ -403,13 +416,13 @@ void ConfigFile::InputBoolean(const std::string& inputText, bool& b)
void ConfigFile::InputString(const std::string& inputText, std::string& str, bool needEnding, bool allowEmpty)
{
str = "";
while(true)
while (true)
{
LOG_INFO(inputText);
std::getline(std::cin, str);
if(needEnding && str[str.length()-1] != '/' && !str.empty())
if (needEnding && str[str.length() - 1] != '/' && !str.empty())
str += '/';
if(allowEmpty || !str.empty())
if (allowEmpty || !str.empty())
return;
}
}
@@ -417,34 +430,35 @@ void ConfigFile::InputString(const std::string& inputText, std::string& str, boo
void ConfigFile::InputMultiple(const std::string& inputText, std::vector<std::string>& vec, bool needEnding)
{
std::string input;
while(true)
while (true)
{
InputString(inputText, input, needEnding, true);
if(input == "")
if (input == "")
break;
vec.push_back(input);
}
}
ConfigFile ConfigFile::Gen()
ConfigFile ConfigFile::Gen(const FlagData& flagData)
{
bool executable, shared, generateHFile;
std::vector<std::string> libs, libdirs, includedirs, defines, compileFlags, linkingFlags, dependencies, excludeSources, excludeHeaders;
std::vector<std::string> libs, libdirs, includedirs, defines, compileFlags, linkingFlags, dependencies,
excludeSources, excludeHeaders;
std::string srcdir, outputdir, projectname, outputname, hFile;
InputBoolean("Should it be compiled as an executable? (y/n)", executable);
// If it isn't an executable there is not need to have libraries
if(executable)
if (executable)
{
InputMultiple("Enter library:", libs,false);
InputMultiple("Enter library directory:", libdirs,true);
InputMultiple("Enter project dependencies:", dependencies,true);
InputMultiple("Enter library:", libs, false);
InputMultiple("Enter library directory:", libdirs, true);
InputMultiple("Enter project dependencies:", dependencies, true);
}
else
{
InputBoolean("Should it be compiled as a shared library? (y/n)", shared);
InputBoolean("Should it compile a project h-file? (y/n):", generateHFile);
if(generateHFile)
if (generateHFile)
{
InputString("Enter the project h-file name (relative to source directory): ", hFile, false, false);
}
@@ -457,18 +471,20 @@ ConfigFile ConfigFile::Gen()
InputMultiple("Enter excluded source files flags:", excludeSources, false);
InputMultiple("Enter excluded header files flags:", excludeHeaders, false);
InputString("Enter output directory (default: bin):", outputdir, true, true);
if(outputdir == "")
if (outputdir == "")
outputdir = "bin/";
InputString("Enter a name for the project:", projectname, false, false);
InputString("Enter a name for the output file:", outputname, false, false);
// Create xml
XMLObject makegen("makegen", {}, std::map<std::string, std::vector<XMLObject>>{});
// Version, target and configuration is probably going to be used in the future
makegen.AddXMLObject(XMLObject("version", {}, "v1.3.0"));
makegen.AddXMLObject(XMLObject("target", {}, "Release"));
if (flagData.flags & FLAG_TARGET)
makegen.AddXMLObject(XMLObject("target", {}, flagData.target));
else
makegen.AddXMLObject(XMLObject("target", {}, "Release"));
XMLObject configuration("configuration", {{"name", "Release"}}, std::map<std::string, std::vector<XMLObject>>{});
configuration.AddXMLObject(XMLObject("projectname", {}, projectname));
@@ -476,25 +492,21 @@ ConfigFile ConfigFile::Gen()
configuration.AddXMLObject(XMLObject("srcdir", {}, srcdir));
configuration.AddXMLObject(XMLObject("outputdir", {}, outputdir));
configuration.AddXMLObject(XMLObject("hfilename", {}, hFile));
configuration.AddXMLObject(XMLObject("outputtype", {},
executable ? "executable" : (shared ? "sharedlibrary" : "staticlibrary")));
configuration.AddXMLObject(
XMLObject("outputtype", {}, executable ? "executable" : (shared ? "sharedlibrary" : "staticlibrary")));
configuration.AddXMLObject(XMLObject("generatehfile", {}, generateHFile ? "true" : "false"));
for(auto it = libs.begin();it != libs.end(); ++it)
configuration.AddXMLObject({"library",{},*it});
for(auto it = libdirs.begin();it != libdirs.end(); ++it)
configuration.AddXMLObject({"librarydir",{},*it});
for(auto it = includedirs.begin();it != includedirs.end(); ++it)
configuration.AddXMLObject({"includedir",{},*it});
for(auto it = defines.begin();it != defines.end(); ++it)
configuration.AddXMLObject({"define",{},*it});
for(auto it = compileFlags.begin();it != compileFlags.end(); ++it)
configuration.AddXMLObject({"cflag",{},*it});
for(auto it = dependencies.begin();it != dependencies.end(); ++it)
configuration.AddXMLObject({"dependency",{},*it});
for (auto it = libs.begin(); it != libs.end(); ++it) configuration.AddXMLObject({"library", {}, *it});
for (auto it = libdirs.begin(); it != libdirs.end(); ++it) configuration.AddXMLObject({"librarydir", {}, *it});
for (auto it = includedirs.begin(); it != includedirs.end(); ++it)
configuration.AddXMLObject({"includedir", {}, *it});
for (auto it = defines.begin(); it != defines.end(); ++it) configuration.AddXMLObject({"define", {}, *it});
for (auto it = compileFlags.begin(); it != compileFlags.end(); ++it) configuration.AddXMLObject({"cflag", {}, *it});
for (auto it = dependencies.begin(); it != dependencies.end(); ++it)
configuration.AddXMLObject({"dependency", {}, *it});
makegen.AddXMLObject(configuration);
return ConfigFile{makegen, FileUtils::GetRealPath(".")};
return ConfigFile{makegen, FileUtils::GetRealPath("."), flagData};
}
void ConfigFile::Save() const
Executable → Regular
+43 -38
View File
@@ -1,59 +1,64 @@
#pragma once
#include "ConfigUtils.h"
#include "xml/XMLObject.h"
#include <map>
#include <optional>
#include <string>
#include <vector>
#include "ConfigUtils.h"
#include "FlagData.h"
#include "xml/XMLObject.h"
static const std::string CONFIG_FILENAME = "makegen.xml";
class ConfigFile
{
private:
ConfigCache cache;
private:
ConfigCache cache;
XMLObject config;
// Current configuration
std::string target;
XMLObject config;
// Current configuration
std::string target;
std::string configPath;
std::vector<ConfigFile> dependencyConfigs;
std::string configPath;
std::vector<ConfigFile> dependencyConfigs;
bool hasInitError = false;
bool hasInitError = false;
public:
// Generates a new default config file
ConfigFile(const std::string& path, int);
ConfigFile(const std::string& path);
ConfigFile(XMLObject& config, const std::string& path);
public:
// Generates a new default config file
ConfigFile(const std::string& path, const FlagData& flagData, int);
ConfigFile(const std::string& path, const FlagData& flagData);
ConfigFile(XMLObject& config, const std::string& path, const FlagData& flagData);
void Save() const;
void Save() const;
std::string& GetSettingString(ConfigSetting setting);
bool GetSettingBool(ConfigSetting setting);
std::vector<std::string>& GetSettingVectorString(ConfigSetting setting);
std::vector<std::string> GetSetting(ConfigSetting setting);
std::string& GetSettingString(ConfigSetting setting);
bool GetSettingBool(ConfigSetting setting);
std::vector<std::string>& GetSettingVectorString(ConfigSetting setting);
std::vector<std::string> GetSetting(ConfigSetting setting);
bool SetSettingString(ConfigSetting setting, const std::string& value);
bool AddSettingVectorString(ConfigSetting setting, const std::string& value);
bool RemoveSettingVectorString(ConfigSetting setting, const std::string& value);
bool SetSettingString(ConfigSetting setting, const std::string& value);
bool AddSettingVectorString(ConfigSetting setting, const std::string& value);
bool RemoveSettingVectorString(ConfigSetting setting, const std::string& value);
XMLObject& GetConfiguration();
const std::string& GetConfigPath() const;
ConfigFile& GetDependencyConfig(size_t i);
private:
void Init();
XMLObject& GetConfiguration();
const std::string& GetConfigPath() const;
ConfigFile& GetDependencyConfig(size_t i);
public:
static ConfigFile Gen();
static std::optional<ConfigFile> GetConfigFile(const std::string& filepath = "./");
private:
static std::optional<ConfigFile> GetConfigFile(const std::string& filepath, std::map<std::string, ConfigFile>& loadedConfigs);
static std::optional<ConfigFile> Load(const std::string& filename);
static void InputBoolean(const std::string& inputText, bool& b);
static void InputMultiple(const std::string& inputText, std::vector<std::string>& vec, bool needEnding);
static void InputString(const std::string& inputText, std::string& vec, bool needEnding, bool allowEmpty);
private:
void Init(const FlagData& flagData);
public:
static ConfigFile Gen(const FlagData& flagData);
static std::optional<ConfigFile> GetConfigFile(const std::string& filepath, const FlagData& flagData);
private:
static std::optional<ConfigFile> GetConfigFile(const std::string& filepath,
std::map<std::string, ConfigFile>& loadedConfigs,
const FlagData& flagData);
static std::optional<ConfigFile> Load(const std::string& filename);
static void InputBoolean(const std::string& inputText, bool& b);
static void InputMultiple(const std::string& inputText, std::vector<std::string>& vec, bool needEnding);
static void InputString(const std::string& inputText, std::string& vec, bool needEnding, bool allowEmpty);
};
+65 -40
View File
@@ -1,13 +1,14 @@
#pragma once
#include <assert.h>
#include <map>
#include <string>
#include <vector>
#include "Common.h"
#include "FileUtils.h"
#include <assert.h>
#include <map>
#include <vector>
#include <string>
struct ConfigCache
{
std::map<std::string, std::string> strings;
@@ -18,9 +19,26 @@ struct ConfigCache
enum class ConfigSetting
{
// vectors
Library = 0, LibraryDir = 1, IncludeDir = 2, Define = 3, Dependency = 4, CFlag = 5, LFlag = 6, ExcludeSource = 7, ExcludeHeader = 8, ExecPreArgument = 9, ExecArgument = 10,
Library = 0,
LibraryDir = 1,
IncludeDir = 2,
Define = 3,
Dependency = 4,
CFlag = 5,
LFlag = 6,
ExcludeSource = 7,
ExcludeHeader = 8,
ExecPreArgument = 9,
ExecArgument = 10,
SourceFile = 11,
IncludeDirExclDep = 12,
// Strings
SourceDir = 32, OutputDir = 33, OutputName = 34, OutputType = 35, ProjectName = 36, HFileName = 37,
SourceDir = 32,
OutputDir = 33,
OutputName = 34,
OutputType = 35,
ProjectName = 36,
HFileName = 37,
// Bools
GenerateHFile = 64,
// Other
@@ -31,7 +49,7 @@ struct ConfigUtils
{
static std::string GetSettingName(ConfigSetting setting)
{
switch(setting)
switch (setting)
{
case ConfigSetting::SourceDir:
return "srcdir";
@@ -69,20 +87,26 @@ struct ConfigUtils
return "argument";
case ConfigSetting::GenerateHFile:
return "generatehfile";
case ConfigSetting::SourceFile:
return "sourcefile";
case ConfigSetting::IncludeDirExclDep:
return "includedirexcldep";
case ConfigSetting::Invalid:
return "invalid";
}
return "";
}
static bool IsDirectory(ConfigSetting setting)
{
switch(setting)
switch (setting)
{
case ConfigSetting::SourceDir:
case ConfigSetting::OutputDir:
case ConfigSetting::LibraryDir:
case ConfigSetting::IncludeDir:
case ConfigSetting::Dependency:
case ConfigSetting::IncludeDirExclDep:
return true;
case ConfigSetting::OutputName:
case ConfigSetting::OutputType:
@@ -97,16 +121,16 @@ struct ConfigUtils
case ConfigSetting::ExecPreArgument:
case ConfigSetting::ExecArgument:
case ConfigSetting::GenerateHFile:
case ConfigSetting::SourceFile:
case ConfigSetting::Invalid:
return false;
default:
LOG_ERROR("INVALID ENUM: ", (int)setting);
assert(false);
}
return false;
}
static bool IsStringSetting(ConfigSetting setting)
{
switch(setting)
switch (setting)
{
case ConfigSetting::SourceDir:
case ConfigSetting::OutputDir:
@@ -127,14 +151,17 @@ struct ConfigUtils
case ConfigSetting::ExecPreArgument:
case ConfigSetting::ExecArgument:
case ConfigSetting::GenerateHFile:
case ConfigSetting::SourceFile:
case ConfigSetting::IncludeDirExclDep:
case ConfigSetting::Invalid:
return false;
}
return false;
}
static bool IsVectorSetting(ConfigSetting setting)
{
switch(setting)
switch (setting)
{
case ConfigSetting::LibraryDir:
case ConfigSetting::IncludeDir:
@@ -147,6 +174,8 @@ struct ConfigUtils
case ConfigSetting::ExcludeSource:
case ConfigSetting::ExecPreArgument:
case ConfigSetting::ExecArgument:
case ConfigSetting::SourceFile:
case ConfigSetting::IncludeDirExclDep:
return true;
case ConfigSetting::SourceDir:
case ConfigSetting::OutputDir:
@@ -158,10 +187,12 @@ struct ConfigUtils
case ConfigSetting::Invalid:
return false;
}
return false;
}
static bool IsBoolSetting(ConfigSetting setting)
{
switch(setting)
switch (setting)
{
case ConfigSetting::GenerateHFile:
return true;
@@ -182,14 +213,17 @@ struct ConfigUtils
case ConfigSetting::ExcludeSource:
case ConfigSetting::ExecPreArgument:
case ConfigSetting::ExecArgument:
case ConfigSetting::SourceFile:
case ConfigSetting::Invalid:
case ConfigSetting::IncludeDirExclDep:
return false;
}
return false;
}
static std::string GetDefaultSettingString(ConfigSetting setting, const std::string& path)
{
switch(setting)
switch (setting)
{
case ConfigSetting::SourceDir:
return "src/";
@@ -209,11 +243,12 @@ struct ConfigUtils
LOG_ERROR("INVALID STRING ENUM: ", (int)setting);
assert(false);
}
return "";
}
static bool GetDefaultSettingBool(ConfigSetting setting)
{
switch(setting)
switch (setting)
{
case ConfigSetting::GenerateHFile:
return false;
@@ -232,23 +267,18 @@ struct ConfigUtils
{
std::string projectname = GetDefaultProjectName(path);
std::string outputname;
std::transform(
projectname.begin(),
projectname.end(),
std::back_inserter(outputname),
[](unsigned char c)
{
if(c == ' ')
return '_';
return (char)std::tolower(c);
});
auto it = std::remove_if(
outputname.begin(),
outputname.end(),
[](unsigned char c)
{
return (c < '0' || c > '9') && (c < 'a' || c > 'z') && c != '_';
});
std::transform(projectname.begin(),
projectname.end(),
std::back_inserter(outputname),
[](unsigned char c)
{
if (c == ' ')
return '_';
return (char)std::tolower(c);
});
auto it = std::remove_if(outputname.begin(),
outputname.end(),
[](unsigned char c) { return (c < '0' || c > '9') && (c < 'a' || c > 'z') && c != '_'; });
outputname.erase(it, outputname.end());
outputname += ".out";
return outputname;
@@ -258,12 +288,7 @@ struct ConfigUtils
{
std::string hfile = GetDefaultProjectName(path);
auto it = std::remove_if(
hfile.begin(),
hfile.end(),
[](unsigned char c)
{
return (c < 'a' || c > 'z') && (c < 'A' || c > 'Z');
});
hfile.begin(), hfile.end(), [](unsigned char c) { return (c < 'a' || c > 'z') && (c < 'A' || c > 'Z'); });
hfile.erase(it, hfile.end());
hfile += ".h";
return hfile;
+54 -44
View File
@@ -1,17 +1,20 @@
#pragma once
#include <assert.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <algorithm>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <string>
#include <vector>
#include "Common.h"
#include "Utils.h"
#include <algorithm>
#include <assert.h>
#include <cstring>
#include <dirent.h>
#include <fstream>
#include <sys/stat.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <unistd.h>
struct FileUtils
{
@@ -19,7 +22,7 @@ struct FileUtils
{
struct stat info;
if(stat(path.c_str(), &info) != 0)
if (stat(path.c_str(), &info) != 0)
return false;
else
return true;
@@ -32,23 +35,23 @@ struct FileUtils
static std::string GetCurrentDirectory()
{
static char path[256]; // Usual maximum filename
static char path[256]; // Usual maximum filename
getcwd(path, sizeof(path));
return GetTopDirectory(path);
}
static std::string GetTopDirectory(const std::string& dir)
{
if(dir.size() == 0)
if (dir.size() == 0)
{
LOG_ERROR("Cannot send empty string to FileUtils::GetTopDirectory()");
assert(false);
}
size_t dirEnd = std::string::npos;
if(dir[dir.size()-1] == '/')
dirEnd = dir.size()-2;
if (dir[dir.size() - 1] == '/')
dirEnd = dir.size() - 2;
size_t pos = dir.find_last_of("/", dirEnd);
if(pos == std::string::npos)
if (pos == std::string::npos)
{
LOG_ERROR("Couldn't find / (slash) in directory. This shouldn't occur.");
assert(false);
@@ -59,11 +62,11 @@ struct FileUtils
static std::string GetRealPath(const std::string& filename)
{
#if defined(__linux__)
if(access(filename.c_str(), F_OK ) != -1)
if (access(filename.c_str(), F_OK) != -1)
{
char* path = realpath(filename.c_str(), NULL);
std::string sPath = path;
sPath+="/";
sPath += "/";
free(path);
return sPath;
}
@@ -80,30 +83,30 @@ struct FileUtils
static std::string GetRelativePath(std::string from, std::string to)
{
std::string result;
if(to[to.size()-1] == '/')
if (to[to.size() - 1] == '/')
to.pop_back();
if(from[from.size()-1] == '/')
if (from[from.size() - 1] == '/')
from.pop_back();
// Check if the directory is inside 'from'
if(strncmp(to.c_str(), from.c_str(), from.size()) == 0)
if (strncmp(to.c_str(), from.c_str(), from.size()) == 0)
{
// Same directory
if(to.size() == from.size())
if (to.size() == from.size())
return "";
// Remove the 'from' path
return to.substr(from.size()+1);
return to.substr(from.size() + 1);
}
// Check if the directory is a child of from
else if(strncmp(from.c_str(), to.c_str(), to.size()) == 0)
else if (strncmp(from.c_str(), to.c_str(), to.size()) == 0)
{
std::string sub = from.substr(to.size());
size_t n = std::count(sub.begin(), sub.end(), '/');
for(int i = 0;i<n;i++)
for (int i = 0; i < n; i++)
{
result+="..";
if(i != n-1)
result+="/";
result += "..";
if (i != n - 1)
result += "/";
}
return result;
}
@@ -111,19 +114,20 @@ struct FileUtils
else
{
// Find the most common directory
std::string commonPath = Utils::CommonPrefix(from,to);
while(commonPath.back() != '/')
commonPath.pop_back();
std::string commonPath = Utils::CommonPrefix(from, to);
if (commonPath.empty())
return "";
while (commonPath.back() != '/') commonPath.pop_back();
commonPath.pop_back();
// Go back to the common directory
std::string sub = from.substr(commonPath.size());
size_t n = std::count(sub.begin(), sub.end(), '/');
for(int i = 0;i<n;i++)
for (int i = 0; i < n; i++)
{
result+="..";
if(i != n-1)
result+="/";
result += "..";
if (i != n - 1)
result += "/";
}
// Add the path which diverges
result += to.substr(commonPath.size());
@@ -134,26 +138,32 @@ struct FileUtils
static void GetAllFiles(const std::string& folder, std::vector<std::string>& files)
{
DIR* dp;
struct dirent *dirp;
if((dp = opendir(folder.c_str())) == NULL){
LOG_ERROR(errno);
struct dirent* dirp;
if ((dp = opendir(folder.c_str())) == NULL)
{
LOG_ERROR("Failed to open directory: ", folder);
return;
}
while((dirp = readdir(dp)) != NULL)
while ((dirp = readdir(dp)) != NULL)
{
if(dirp->d_type == DT_DIR)
if (dirp->d_type == DT_DIR)
{
if(strcmp(dirp->d_name,".") == 0)
if (strcmp(dirp->d_name, ".") == 0)
continue;
if(strcmp(dirp->d_name,"..") == 0)
if (strcmp(dirp->d_name, "..") == 0)
continue;
GetAllFiles(folder+dirp->d_name+"/", files);
GetAllFiles(folder + dirp->d_name + "/", files);
}
else
{
files.push_back(folder+dirp->d_name);
files.push_back(folder + dirp->d_name);
}
}
closedir(dp);
}
static bool FileExists(const std::string& filename)
{
return std::filesystem::exists(filename) && !std::filesystem::is_directory(filename);
}
};
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include <string>
struct FlagData
{
unsigned int flags{0};
std::string target{""}; // Only set if flags contain FLAG_TARGET
};
+10 -8
View File
@@ -1,23 +1,25 @@
#include "HFileGen.h"
#include "FileUtils.h"
#include <set>
#include "FileUtils.h"
void HFileGen::Create(ConfigFile& conf)
{
std::set<std::string> hFiles;
std::vector<std::string> files;
std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir);
FileUtils::GetAllFiles(path,files);
FileUtils::GetAllFiles(path, files);
// include paramenter with the path of the file
// For example src/graphics/Window.h -> graphics/Window.h if src is a src folder
for(auto it = files.begin(); it!=files.end();++it)
for (auto it = files.begin(); it != files.end(); ++it)
{
size_t extensionPos = it->find_last_of(".");
if(extensionPos != std::string::npos)
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() + conf.GetSettingString(ConfigSetting::HFileName))
{
// Make files sorted in alphabetical order
hFiles.emplace(filename);
@@ -28,11 +30,11 @@ void HFileGen::Create(ConfigFile& conf)
const std::vector<std::string>& excludeHeaders = conf.GetSettingVectorString(ConfigSetting::ExcludeHeader);
std::ofstream os(path + "/" + conf.GetSettingString(ConfigSetting::HFileName));
os << "#pragma once" << std::endl << std::endl;
for(auto&& hFile : hFiles)
for (auto&& hFile : hFiles)
{
std::string headerFile = conf.GetSettingString(ConfigSetting::SourceDir) + hFile;
std::string headerFile = conf.GetSettingString(ConfigSetting::SourceDir) + hFile;
auto it = std::find(excludeHeaders.begin(), excludeHeaders.end(), headerFile);
if(it == excludeHeaders.end())
if (it == excludeHeaders.end())
os << "#include <" << hFile << ">" << std::endl;
}
}
+3 -3
View File
@@ -2,8 +2,8 @@
#include "ConfigFile.h"
class HFileGen
class HFileGen
{
public:
static void Create(ConfigFile& conf);
public:
static void Create(ConfigFile& conf);
};
Executable → Regular
+64 -29
View File
@@ -1,64 +1,99 @@
#include "IncludeDeps.h"
#include <sstream>
#include "Common.h"
std::set<std::string> IncludeDeps::printSet;
int IncludeDeps::printCounter = 0;
IncludeDeps::IncludeDeps(const std::string& filename, const std::string& dir, const std::set<HFile>& files, std::map<std::string, IncludeDeps*>& allDeps)
: IncludeDeps{filename, dir, false, files, allDeps}
{}
IncludeDeps::IncludeDeps(const std::string& filename, const std::string& dir, bool projectHFile, const std::set<HFile>& files, std::map<std::string, IncludeDeps*>& allDeps)
: filepath(dir+filename), projectHFile{projectHFile}
IncludeDeps::IncludeDeps(const std::string& filename,
const std::set<HFile>& files,
std::map<std::string, IncludeDeps*>& allDeps)
: IncludeDeps{filename, false, files, allDeps}
{
if(Utils::IsHeaderFile(filename))
}
IncludeDeps::IncludeDeps(const std::string& filename,
bool projectHFile,
const std::set<HFile>& files,
std::map<std::string, IncludeDeps*>& allDeps)
: filepath(filename),
projectHFile{projectHFile}
{
std::filesystem::path path{filepath};
if (Utils::IsHeaderFile(filename))
{
allDeps.emplace(filepath, this);
}
std::ifstream file(filepath);
std::string line;
while(std::getline(file,line))
while (std::getline(file, line))
{
size_t pos = line.find("#include");
if(pos != std::string::npos)
std::string start;
std::stringstream ss{line};
ss >> start;
if (start == "#include")
{
std::string include = GetIncludeFile(line, pos, filename);
auto it = files.find({include, "", false});
if(it != files.end())
std::string include = GetIncludeFile(line);
std::filesystem::path includeFileRelativeToSource;
if (path.is_absolute())
includeFileRelativeToSource = std::filesystem::relative("/", ".").string() + "/" + include;
else
includeFileRelativeToSource = std::filesystem::relative(path.parent_path(), ".").string() + "/" + include;
// Check if file can be found relative to current file:
if (FileUtils::FileExists(includeFileRelativeToSource.string()))
{
auto itD = allDeps.find(it->filepath);
if(itD == allDeps.end())
auto itD = allDeps.find(includeFileRelativeToSource.string());
if (itD == allDeps.end())
{
IncludeDeps* inc = new IncludeDeps(includeFileRelativeToSource.string(), false, files, allDeps);
dependencies.emplace(includeFileRelativeToSource, inc);
}
else
{
IncludeDeps* inc = new IncludeDeps(it->filename,it->directory, it->isProjectHFile, files,allDeps);
dependencies.emplace(it->filepath, inc);
}else{
dependencies.emplace(itD->first, itD->second);
}
}
else
{
auto it = files.find({include, "", false});
if (it != files.end())
{
auto itD = allDeps.find(it->filepath);
if (itD == allDeps.end())
{
IncludeDeps* inc = new IncludeDeps(it->filepath, it->isProjectHFile, files, allDeps);
dependencies.emplace(it->filepath, inc);
}
else
{
dependencies.emplace(itD->first, itD->second);
}
}
}
}
}
}
std::string IncludeDeps::GetIncludeFile(const std::string& line, size_t pos, const std::string& filename)
std::string IncludeDeps::GetIncludeFile(const std::string& line)
{
size_t bracket = line.find('<',pos);
if(bracket == std::string::npos)
size_t bracket = line.find('<');
if (bracket == std::string::npos)
{
bracket = line.find('\"',pos);
if(bracket == std::string::npos)
bracket = line.find('\"');
if (bracket == std::string::npos)
{
return "";
}
size_t slash = filename.find_last_of("/");
std::string include = line.substr(bracket+1, line.find('\"',bracket+1)-bracket-1);
if(slash == std::string::npos)
slash = -1;
return filename.substr(0,slash+1)+include;
std::string include = line.substr(bracket + 1, line.find('\"', bracket + 1) - bracket - 1);
return include;
}
else
{
return line.substr(bracket+1, line.find('>',bracket+1)-bracket-1);
return line.substr(bracket + 1, line.find('>', bracket + 1) - bracket - 1);
}
}
Executable → Regular
+41 -28
View File
@@ -1,61 +1,74 @@
#pragma once
#include "ConfigFile.h"
#include "FileUtils.h"
#include <filesystem>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include "ConfigFile.h"
#include "FileUtils.h"
struct CompareIncludeDeps;
class IncludeDeps
{
public:
std::map<std::string, IncludeDeps*> dependencies;
std::string filepath;
bool projectHFile;
static std::set<std::string> printSet;
static int printCounter;
public:
std::map<std::string, IncludeDeps*> dependencies;
std::filesystem::path filepath;
bool projectHFile;
static std::set<std::string> printSet;
static int printCounter;
IncludeDeps(const std::string& filename, const std::string& dir, const std::set<HFile>& files, std::map<std::string, IncludeDeps*>& allDeps);
IncludeDeps(const std::string& filename, const std::set<HFile>& files, std::map<std::string, IncludeDeps*>& allDeps);
IncludeDeps(const std::string& filename, const std::string& dir, bool projectHFile, const std::set<HFile>& files, std::map<std::string, IncludeDeps*>& allDeps);
IncludeDeps(const std::string& filename,
bool projectHFile,
const std::set<HFile>& files,
std::map<std::string, IncludeDeps*>& allDeps);
std::string GetIncludeFile(const std::string& line, size_t pos, const std::string& filename);
std::string GetIncludeFile(const std::string& line);
std::ostream& Output(std::ostream& stream, const ConfigFile& conf)
{
if(printSet.find(filepath) != printSet.end())
return stream;
printCounter++;
printSet.emplace(filepath);
if(!projectHFile)
stream << FileUtils::GetRelativePath(conf.GetConfigPath(), filepath);
for(auto it = dependencies.begin();it!=dependencies.end();++it)
{
stream << " ";
(it->second)->Output(stream, conf);
}
printCounter--;
if(printCounter == 0)
printSet.clear();
std::ostream& Output(std::ostream& stream, const ConfigFile& conf)
{
std::string filePathInMakeFile = filepath;
if (!filepath.is_absolute())
filePathInMakeFile = std::filesystem::relative(conf.GetConfigPath() + "/" + filepath.string(), "./").string();
if (printSet.find(filePathInMakeFile) != printSet.end())
return stream;
printSet.emplace(filePathInMakeFile);
printCounter++;
if (!projectHFile)
{
stream << " " << filePathInMakeFile;
}
for (auto it = dependencies.begin(); it != dependencies.end(); ++it)
{
(it->second)->Output(stream, conf);
}
printCounter--;
if (printCounter == 0)
printSet.clear();
return stream;
}
};
struct CompareIncludeDeps
{
using is_transparent = void;
bool operator()(const IncludeDeps* d1, const IncludeDeps* d2) const
{
return d1->filepath < d2->filepath;
}
bool operator()(const IncludeDeps* d, const std::string& filepath) const
{
return d->filepath < filepath;
}
bool operator()(const std::string& filepath, const IncludeDeps* d) const
{
return filepath < d->filepath;
+88 -55
View File
@@ -1,29 +1,31 @@
#include "Makefile.h"
#include "IncludeDeps.h"
#include "Utils.h"
#include <fstream>
#include <map>
#include "Common.h"
#include "IncludeDeps.h"
#include "Utils.h"
void Makefile::Save(ConfigFile& conf, unsigned int flags)
{
std::set<HFile> hFiles; // hFile, directory
std::set<HFile> hFiles; // hFile, directory
std::set<std::string> cppFiles;
if(flags & FLAG_SIMPLE)
if (flags & FLAG_SIMPLE)
Utils::GetCppFiles(conf, cppFiles);
else
Utils::GetCppAndHFiles(conf, hFiles, cppFiles);
std::ofstream outputFile(conf.GetConfigPath()+ "Makefile");
outputFile << "# This Makefile was generated using MakeGen "<< MAKEGEN_VERSION << " made by Tim Håkansson" << std::endl;
std::ofstream outputFile(conf.GetConfigPath() + "Makefile");
outputFile << "# This Makefile was generated using MakeGen " << MAKEGEN_VERSION << " made by Tim Håkansson"
<< std::endl;
outputFile << "# and is licensed under MIT. Full source of the project can be found at" << std::endl;
outputFile << "# https://github.com/Thraix/MakeGen" << std::endl;
outputFile << "CC=@g++" << std::endl;
std::string outputtype = conf.GetSettingString(ConfigSetting::OutputType);
if(outputtype != "executable")
if (outputtype != "executable")
{
if(outputtype == "sharedlibrary")
if (outputtype == "sharedlibrary")
outputFile << "CO=@g++ -shared -o" << std::endl;
else
outputFile << "CO=@g++ -o" << std::endl;
@@ -36,20 +38,28 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags)
outputFile << "OBJPATH=$(BIN)intermediates" << std::endl;
outputFile << "INCLUDES=";
std::vector<std::string>& includedirs = conf.GetSettingVectorString(ConfigSetting::IncludeDir);
for(auto it = includedirs.begin(); it != includedirs.end(); ++it)
for (auto it = includedirs.begin(); it != includedirs.end(); ++it)
{
outputFile << "-I " << *it << " ";
}
std::vector<std::string>& includedirsexcldep = conf.GetSettingVectorString(ConfigSetting::IncludeDirExclDep);
for (auto it = includedirsexcldep.begin(); it != includedirsexcldep.end(); ++it)
{
outputFile << "-I " << *it << " ";
}
outputFile << std::endl;
outputFile << "OBJECTS=";
for(auto it = cppFiles.begin();it!=cppFiles.end();++it)
for (auto it = cppFiles.begin(); it != cppFiles.end(); ++it)
{
size_t extensionPos = it->find_last_of(".");
size_t slash = it->find_last_of("/")+1;
outputFile << "$(OBJPATH)/" << it->substr(slash, extensionPos - slash) << ".o ";
std::filesystem::path cppFile(*it);
std::filesystem::path oFile = cppFile.replace_extension("o");
std::string oFileStr = oFile.string();
Utils::Replace(oFileStr, "..", "dotdot");
outputFile << "$(OBJPATH)/" << oFileStr << " ";
}
outputFile << std::endl;
if(outputtype == "executable" || outputtype != "sharedlibrary")
if (outputtype == "executable" || outputtype != "sharedlibrary")
{
outputFile << "CFLAGS=$(INCLUDES) -std=c++17 -c ";
}
@@ -58,48 +68,48 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags)
outputFile << "CFLAGS=$(INCLUDES) -fPIC -std=c++17 -c ";
}
std::vector<std::string>& defines = conf.GetSettingVectorString(ConfigSetting::Define);
for(auto it = defines.begin(); it != defines.end(); ++it)
for (auto it = defines.begin(); it != defines.end(); ++it)
{
outputFile << "-D" << *it << " ";
}
std::vector<std::string>& cflags = conf.GetSettingVectorString(ConfigSetting::CFlag);
for(auto it = cflags.begin(); it != cflags.end(); ++it)
for (auto it = cflags.begin(); it != cflags.end(); ++it)
{
outputFile << *it << " ";
}
outputFile << std::endl;
if(outputtype == "executable")
if (outputtype == "executable")
{
std::vector<std::string>& libdirs= conf.GetSettingVectorString(ConfigSetting::LibraryDir);
std::vector<std::string>& libdirs = conf.GetSettingVectorString(ConfigSetting::LibraryDir);
outputFile << "LIBDIR=";
for(auto it = libdirs.begin();it!=libdirs.end();++it)
for (auto it = libdirs.begin(); it != libdirs.end(); ++it)
{
outputFile << "-L " << *it << " ";
}
outputFile << std::endl;
std::vector<std::string>& lflags = conf.GetSettingVectorString(ConfigSetting::LFlag);
outputFile << "LDFLAGS=";
for(auto it = lflags.begin(); it != lflags.end(); ++it)
for (auto it = lflags.begin(); it != lflags.end(); ++it)
{
outputFile << *it << " ";
}
for(auto it = libdirs.begin(); it != libdirs.end(); ++it)
for (auto it = libdirs.begin(); it != libdirs.end(); ++it)
{
outputFile << "-Wl,-rpath=" << *it << " ";
}
outputFile << std::endl;
std::vector<std::string>& libs = conf.GetSettingVectorString(ConfigSetting::Library);
outputFile << "LIBS=$(LIBDIR) ";
for(auto it = libs.begin(); it != libs.end(); ++it)
for (auto it = libs.begin(); it != libs.end(); ++it)
{
outputFile << "-l" << *it << " ";
}
outputFile << std::endl;
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
if(!dependencies.empty())
if (!dependencies.empty())
{
outputFile << "DEPENDENCIES=";
for(auto it = dependencies.begin();it!=dependencies.end();++it)
for (auto it = dependencies.begin(); it != dependencies.end(); ++it)
{
outputFile << *it << " ";
}
@@ -113,30 +123,32 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags)
outputFile << "all: directories $(OUTPUT)" << std::endl;
// Directories
outputFile << "directories: $(BIN) $(OBJPATH)" << std::endl;
std::set<std::string> intermediateDirectories = GetIntermediateDirectories(cppFiles);
outputFile << "directories: ";
for (const auto& intermediateDirectory : intermediateDirectories)
{
outputFile << intermediateDirectory << " ";
}
outputFile << std::endl;
// Bin path
outputFile << "$(BIN):" << std::endl;
outputFile << "\t$(info Creating output directories)" << std::endl;
outputFile << "\t@$(MKDIR_P) $(BIN)" << std::endl;
// Object path
outputFile << "$(OBJPATH):" << std::endl;
outputFile << "\t@$(MKDIR_P) $(OBJPATH)" << std::endl;
// Intermediate directories
for (const auto& intermediateDirectory : intermediateDirectories)
{
outputFile << intermediateDirectory << ":" << std::endl;
outputFile << "\t@$(MKDIR_P) $@" << std::endl;
}
// Run
outputFile << "run: all" << std::endl;
if(outputtype == "executable")
if (outputtype == "executable")
{
std::vector<std::string>& prearguments = conf.GetSettingVectorString(ConfigSetting::ExecPreArgument);
std::vector<std::string>& arguments = conf.GetSettingVectorString(ConfigSetting::ExecArgument);
outputFile << "\t@";
for(auto&& preargument : prearguments)
outputFile << preargument << " ";
for (auto&& preargument : prearguments) outputFile << preargument << " ";
outputFile << "./$(OUTPUT)";
for(auto&& argument : arguments)
outputFile << " " << argument;
for (auto&& argument : arguments) outputFile << " " << argument;
outputFile << std::endl;
}
@@ -145,41 +157,62 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags)
// Clean
outputFile << "clean:" << std::endl;
outputFile << "\t$(info Removing intermediates)" << std::endl;
outputFile << "\trm -rf $(OBJPATH)/*.o" << std::endl;
outputFile << "\t$(info Removing $(OBJPATH))" << std::endl;
outputFile << "\t@rm -rf $(OBJPATH)/" << std::endl;
// Output file
outputFile << "$(OUTPUT): $(OBJECTS)" << std::endl;
outputFile << "\t$(info Generating output file)" << std::endl;
if(outputtype == "executable")
outputFile << "\t$(info Generating output file $(OUTPUT))" << std::endl;
if (outputtype == "executable")
outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS) $(LDFLAGS) $(LIBS)" << std::endl;
else
outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS)" << std::endl;
// Install
outputFile << "install: all" << std::endl;
outputFile << "\t$(info Installing " << conf.GetSettingString(ConfigSetting::ProjectName) <<" to /usr/bin/)" << std::endl;
outputFile << "\t$(info Installing " << conf.GetSettingString(ConfigSetting::ProjectName) << " to /usr/bin/)"
<< std::endl;
outputFile << "\t@cp $(OUTPUT) /usr/bin/" << conf.GetSettingString(ConfigSetting::OutputName) << std::endl;
std::map<std::string, IncludeDeps*> dependencies;
size_t i = 0;
for(auto it = cppFiles.begin(); it != cppFiles.end();++it)
for (auto it = cppFiles.begin(); it != cppFiles.end(); ++it)
{
i++;
std::string& srcdir = conf.GetSettingString(ConfigSetting::SourceDir);
auto itD = dependencies.find(srcdir + *it);
if(itD == dependencies.end())
auto itD = dependencies.find(*it);
if (itD == dependencies.end())
{
IncludeDeps* deps = new IncludeDeps(*it, conf.GetConfigPath() + srcdir,hFiles,dependencies);
size_t extensionPos = it->find_last_of(".");
size_t slash = it->find_last_of("/")+1;
std::string oFile = it->substr(slash, extensionPos - slash)+".o ";
outputFile << "$(OBJPATH)/" << oFile << ": ";
deps->Output(outputFile, conf);
std::filesystem::path cppFile(*it);
std::filesystem::path oFile = cppFile.replace_extension("o");
std::string oFileStr = oFile.string();
Utils::Replace(oFileStr, "..", "dotdot");
outputFile << "$(OBJPATH)/" << oFileStr << ":";
if (flags & FLAG_SIMPLE)
{
outputFile << " " << *it;
}
else
{
IncludeDeps* deps = new IncludeDeps(*it, hFiles, dependencies);
deps->Output(outputFile, conf);
}
outputFile << std::endl;
outputFile << "\t$(info -[" << (int)(i / (float)cppFiles.size() * 100) << "%]- $<)" << std::endl;
outputFile << "\t$(CC) $(CFLAGS) -o $@ $<" << std::endl;
}
}
}
std::set<std::string> Makefile::GetIntermediateDirectories(const std::set<std::string>& cppFiles)
{
std::set<std::string> intermediateDirectories;
for (const auto& cppFile : cppFiles)
{
std::filesystem::path cppPath{cppFile};
std::filesystem::path oFile = cppPath.replace_extension("o");
std::string parentPathStr = oFile.parent_path().string();
Utils::Replace(parentPathStr, "..", "dotdot");
intermediateDirectories.emplace("$(OBJPATH)/" + parentPathStr);
}
return intermediateDirectories;
}
Executable → Regular
+5 -2
View File
@@ -4,6 +4,9 @@
class Makefile
{
public:
static void Save(ConfigFile& conf, unsigned int flags);
public:
static void Save(ConfigFile& conf, unsigned int flags);
private:
static std::set<std::string> GetIntermediateDirectories(const std::set<std::string>& cppFiles);
};
Executable → Regular
+19 -14
View File
@@ -4,20 +4,25 @@
class Timer
{
private:
std::chrono::time_point<std::chrono::high_resolution_clock> m_start;
public:
Timer(){
Reset();
}
private:
std::chrono::time_point<std::chrono::high_resolution_clock> m_start;
void Reset()
{
m_start = std::chrono::high_resolution_clock::now();
}
public:
Timer()
{
Reset();
}
float Elapsed()
{
return std::chrono::duration_cast<std::chrono::duration<float,std::milli>>(std::chrono::high_resolution_clock::now() - m_start).count() / 1000.0f;
}
void Reset()
{
m_start = std::chrono::high_resolution_clock::now();
}
float Elapsed()
{
return std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
std::chrono::high_resolution_clock::now() - m_start)
.count() /
1000.0f;
}
};
+109 -35
View File
@@ -1,5 +1,7 @@
#include "Utils.h"
#include <filesystem>
#include "ConfigFile.h"
#include "FileUtils.h"
@@ -8,7 +10,7 @@ bool Utils::IsSourceFile(const std::string& filepath)
std::string_view extension(filepath);
size_t pSlash = filepath.find_last_of('/');
size_t pDot = filepath.find_last_of('.');
if(pDot == std::string::npos || (pSlash != std::string::npos && pSlash > pDot))
if (pDot == std::string::npos || (pSlash != std::string::npos && pSlash > pDot))
{
LOG_ERROR("No file extension for file: ", filepath);
return false;
@@ -22,21 +24,41 @@ bool Utils::IsHeaderFile(const std::string& filepath)
std::string_view extension(filepath);
size_t pSlash = filepath.find_last_of('/');
size_t pDot = filepath.find_last_of('.');
if(pDot == std::string::npos || (pSlash != std::string::npos && pSlash > pDot))
if (pDot == std::string::npos || (pSlash != std::string::npos && pSlash > pDot))
{
LOG_ERROR("No file extension for file: ", filepath);
return false;
}
extension.remove_prefix(pDot + 1);
return extension == "hpp" || extension == "h" || extension == "hxx";
}
bool Utils::StartsWith(const std::string& str, const std::string& prefix)
{
if (str.size() < prefix.size())
return false;
return str.compare(0, prefix.size(), prefix) == 0;
}
void Utils::Replace(std::string& str, const std::string& from, const std::string& to)
{
if (from.empty())
return;
size_t pos = str.find(from, 0);
while (pos != std::string::npos)
{
str.replace(pos, from.length(), to);
pos = str.find(from, pos + to.length());
}
}
std::string Utils::CommonPrefix(const std::string& s1, const std::string& s2)
{
size_t n = 0;
for(size_t i = 0; i<s1.size() && i<s2.size();++i)
for (size_t i = 0; i < s1.size() && i < s2.size(); ++i)
{
if(s1[i] != s2[i])
if (s1[i] != s2[i])
{
n = i;
break;
@@ -48,20 +70,31 @@ std::string Utils::CommonPrefix(const std::string& s1, const std::string& s2)
void Utils::GetCppFiles(ConfigFile& conf, std::set<std::string>& cppFiles)
{
std::vector<std::string> files;
std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir);
FileUtils::GetAllFiles(path, files);
std::string sourceDir = conf.GetSettingString(ConfigSetting::SourceDir);
std::string path = conf.GetConfigPath() + sourceDir;
if (!sourceDir.empty())
{
FileUtils::GetAllFiles(path, files);
}
const std::vector<std::string>& excludeSources = conf.GetSettingVectorString(ConfigSetting::ExcludeSource);
for(auto it = files.begin(); it!=files.end();++it)
for (const auto& sourceFile : conf.GetSettingVectorString(ConfigSetting::SourceFile))
{
std::string filename = it->substr(path.length());
if(IsSourceFile(filename))
if (FileUtils::FileExists(conf.GetConfigPath() + sourceFile))
cppFiles.emplace(conf.GetConfigPath() + sourceFile);
else
LOG_WARNING("Source file doesn't exist: ", sourceFile);
}
for (auto& filename : files)
{
std::filesystem::path filepath = std::filesystem::relative(filename, "./");
if (IsSourceFile(filename))
{
std::string sourceFile =conf.GetSettingString(ConfigSetting::SourceDir) + filename;
auto it = std::find(excludeSources.begin(), excludeSources.end(), sourceFile);
if(it == excludeSources.end())
auto it = std::find(excludeSources.begin(), excludeSources.end(), filename);
if (it == excludeSources.end())
{
cppFiles.emplace(filename);
cppFiles.emplace(filepath.string());
}
}
}
@@ -70,31 +103,54 @@ void Utils::GetCppFiles(ConfigFile& conf, std::set<std::string>& cppFiles)
void Utils::GetCppAndHFiles(ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles)
{
std::vector<std::string> files;
std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir);
FileUtils::GetAllFiles(path,files);
const std::vector<std::string>& excludeSources = conf.GetSettingVectorString(ConfigSetting::ExcludeSource);
// include paramenter with the path of the file
// For example src/graphics/Window.h -> graphics/Window.h if src is a src folder
for(auto it = files.begin(); it!=files.end();++it)
std::string sourceDir = conf.GetSettingString(ConfigSetting::SourceDir);
std::string path = conf.GetConfigPath() + sourceDir;
if (!sourceDir.empty())
{
std::string filename = it->substr(path.length());
if(IsSourceFile(filename))
FileUtils::GetAllFiles(path, files);
}
const std::vector<std::string>& excludeSources = conf.GetSettingVectorString(ConfigSetting::ExcludeSource);
for (const auto& sourceFile : conf.GetSettingVectorString(ConfigSetting::SourceFile))
{
if (FileUtils::FileExists(conf.GetConfigPath() + sourceFile))
cppFiles.emplace(conf.GetConfigPath() + sourceFile);
else
LOG_WARNING("Source file doesn't exist: ", sourceFile);
}
for (const auto& filename : files)
{
if (IsSourceFile(filename))
{
std::string sourceFile =conf.GetSettingString(ConfigSetting::SourceDir) + filename;
auto it = std::find(excludeSources.begin(), excludeSources.end(), sourceFile);
if(it == excludeSources.end())
std::filesystem::path filepath = std::filesystem::relative(filename, "./");
auto it = std::find(excludeSources.begin(), excludeSources.end(), filepath.string());
if (it == excludeSources.end())
{
cppFiles.emplace(filename);
cppFiles.emplace(filepath.string());
}
}
else if(IsHeaderFile(filename))
else if (IsHeaderFile(filename))
{
hFiles.emplace(HFile{filename,path,false});
std::filesystem::path path = std::filesystem::relative(filename, sourceDir);
hFiles.emplace(HFile{path.string(), sourceDir, false});
}
}
for (const auto& includePath : conf.GetSettingVectorString(ConfigSetting::IncludeDir))
{
std::vector<std::string> 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});
}
}
}
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
for(size_t i = 0; i < dependencies.size(); ++i)
for (size_t i = 0; i < dependencies.size(); ++i)
{
GetHFiles(dependencies[i], conf.GetDependencyConfig(i), hFiles);
}
@@ -106,7 +162,7 @@ void Utils::GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::s
// Cyclic dependencies probably shouldn't exist.
// so just warn the user that it does and terminate.
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
for(size_t i = 0; i < dependencies.size(); ++i)
for (size_t i = 0; i < dependencies.size(); ++i)
{
GetHFiles(dependencies[i], conf.GetDependencyConfig(i), hFiles);
}
@@ -114,15 +170,33 @@ void Utils::GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::s
std::vector<std::string> files;
std::string depSrcDir = dependencyDir + conf.GetSettingString(ConfigSetting::SourceDir);
FileUtils::GetAllFiles(depSrcDir, files);
for(auto it = files.begin(); it!=files.end();++it)
for (auto it = files.begin(); it != files.end(); ++it)
{
if(IsHeaderFile(*it))
if (IsHeaderFile(*it))
{
std::string filename = it->substr(depSrcDir.length());
hFiles.emplace(HFile{filename, depSrcDir, conf.GetSettingBool(ConfigSetting::GenerateHFile) && filename == conf.GetSettingString(ConfigSetting::HFileName)});
auto it = hFiles.find({filename, "", false});
if (it != hFiles.end())
{
if (filename == conf.GetSettingString(ConfigSetting::HFileName) && !it->isProjectHFile)
{
HFile hfile = *it;
hfile.isProjectHFile = true;
hFiles.erase(it);
hFiles.emplace(hfile);
}
}
else
{
hFiles.emplace(HFile{filename,
depSrcDir,
conf.GetSettingBool(ConfigSetting::GenerateHFile) &&
filename == conf.GetSettingString(ConfigSetting::HFileName)});
}
}
}
}
bool Utils::IsWhiteSpace(char c)
{
return c == '\n' || c == '\t' || c == '\r' || c == ' ' || c == '\t';
@@ -135,9 +209,9 @@ bool Utils::IsLetter(char c)
bool Utils::IsWord(const std::string& string)
{
for(auto it{string.begin()}; it != string.end();++it)
for (auto it{string.begin()}; it != string.end(); ++it)
{
if(!IsLetter(*it))
if (!IsLetter(*it))
return false;
}
return true;
+17 -5
View File
@@ -1,25 +1,33 @@
#pragma once
#include <filesystem>
#include <iostream>
#include <set>
#include <string>
struct HFile
{
std::string filename;
std::string directory;
bool isProjectHFile;
std::string filepath;
std::filesystem::path filepath;
HFile(const std::string& filename, const std::string& directory, bool isProjectHFile)
: filename{filename}, directory{directory}, isProjectHFile{isProjectHFile}, filepath{directory+filename}
{}
: filename{filename},
isProjectHFile{isProjectHFile},
filepath{directory + filename}
{
}
friend bool operator<(const HFile& h1, const HFile& h2)
{
return h1.filename < h2.filename;
}
friend std::ostream& operator<<(std::ostream& ostream, const HFile& hFile)
{
return ostream << "filename: " << hFile.filename << "\tfilepath: " << hFile.filepath.string();
}
};
class ConfigFile;
@@ -28,7 +36,11 @@ struct Utils
{
static bool IsSourceFile(const std::string& filepath);
static bool IsHeaderFile(const std::string& filepath);
static std::string CommonPrefix(const std::string& s1, const std::string& s2);
static bool StartsWith(const std::string& str, const std::string& prefix);
static void Replace(std::string& str, const std::string& from, const std::string& to);
static void GetCppFiles(ConfigFile& conf, std::set<std::string>& cppFiles);
static void GetCppAndHFiles(ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles);
static void GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::set<HFile>& hFiles);
+58 -58
View File
@@ -2,41 +2,42 @@
const std::string CONFIG_FILENAME_CONF = "makegen.conf";
#include "../ConfigFile.h"
#include "../FileUtils.h"
#include <algorithm>
#include <fstream>
#include "../ConfigFile.h"
#include "../FileUtils.h"
#define FLAG_NONE 0
#define FLAG_VECTOR 1
#define FLAG_STRING 2
#define FLAG_BOOL 3
ConfigFileConf::ConfigFileConf()
: outputdir("bin/"), srcdir("src/"), outputname(""), projectname(FileUtils::GetCurrentDirectory()), hFile(""), executable(true), shared(true), generateHFile(false)
: outputdir("bin/"),
srcdir("src/"),
outputname(""),
projectname(FileUtils::GetCurrentDirectory()),
hFile(""),
executable(true),
shared(true),
generateHFile(false)
{
// Converts project name (current directory) to lowercase
// and replace whitespace with underscore
std::transform(
projectname.begin(),
projectname.end(),
std::back_inserter(outputname),
[](unsigned char c)
{
if(c == ' ')
return '_';
return (char)std::tolower(c);
});
std::transform(projectname.begin(),
projectname.end(),
std::back_inserter(outputname),
[](unsigned char c)
{
if (c == ' ')
return '_';
return (char)std::tolower(c);
});
// Removes all other characters
std::remove_if(
outputdir.begin(),
outputdir.end(),
[](unsigned char c)
{
return (c < 'a' || c > 'z') && c != '_';
});
outputdir.erase(std::remove_if(
outputdir.begin(), outputdir.end(), [](unsigned char c) { return (c < 'a' || c > 'z') && c != '_'; }));
// Add suffix
outputname += ".out";
@@ -57,11 +58,10 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
std::ifstream file(filepath + CONFIG_FILENAME_CONF);
std::string line;
if(file.is_open())
if (file.is_open())
{
// config name, { pointer to memory, isDirectory}
std::map<std::string, std::pair<std::string*, bool>> strings =
{
std::map<std::string, std::pair<std::string*, bool>> strings = {
{"#srcdir", {&conf.srcdir, true}},
{"#outputdir", {&conf.outputdir, true}},
{"#outputname", {&conf.outputname, false}},
@@ -70,33 +70,32 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
};
// config name, { pointer to memory, isDirectory}
std::map<std::string, std::pair<std::vector<std::string>*, bool>> vectors =
{
std::map<std::string, std::pair<std::vector<std::string>*, bool>> vectors = {
{"#libs", {&conf.libs, false}},
{"#libdirs", {&conf.libdirs, true}},
{"#includedirs", {&conf.includedirs, true}},
{"#compileflags", {&conf.flags, false}},
{"#defines", {&conf.defines, false}},
{"#dependencies", {&conf.dependencies, true}},
{"#sourcefiles", {&conf.sourceFiles, false}},
};
std::map<std::string, bool*> booleans =
{
std::map<std::string, bool*> booleans = {
{"#executable", &conf.executable},
{"#shared", &conf.shared},
{"#generatehfile", &conf.generateHFile},
};
while(std::getline(file,line))
while (std::getline(file, line))
{
if(line == "")
if (line == "")
continue;
if(line[0]=='#')
if (line[0] == '#')
{
// The format is a bit wacky, but it is this way since we do not want
// to use map::find for all maps. This way we gain some optimization.
auto&& itStr{strings.find(line)};
if(itStr != strings.end())
if (itStr != strings.end())
{
s = itStr->second.first;
isDirectory = itStr->second.second;
@@ -105,7 +104,7 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
else
{
auto&& itVec{vectors.find(line)};
if(itVec != vectors.end())
if (itVec != vectors.end())
{
vec = itVec->second.first;
isDirectory = itVec->second.second;
@@ -114,7 +113,7 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
else
{
auto&& itBool{booleans.find(line)};
if(itBool != booleans.end())
if (itBool != booleans.end())
{
b = itBool->second;
loadFlag = FLAG_BOOL;
@@ -129,23 +128,24 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
}
else
{
if(loadFlag == FLAG_STRING)
if (loadFlag == FLAG_STRING)
{
if(isDirectory && line[line.size()-1] != '/')
if (isDirectory && line[line.size() - 1] != '/')
line += '/';
*s = line;
}
else if(loadFlag == FLAG_VECTOR)
else if (loadFlag == FLAG_VECTOR)
{
if(isDirectory && line[line.size()-1] != '/')
{;
if (isDirectory && line[line.size() - 1] != '/')
{
;
line += '/';
}
vec->push_back(line);
}
else if(loadFlag == FLAG_BOOL)
else if (loadFlag == FLAG_BOOL)
{
if(line == "true")
if (line == "true")
*b = true;
else
*b = false;
@@ -155,13 +155,13 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
LOG_INFO("------ COULDN\'T FIND makegen.xml. BUT FOUND OLD makegen.conf.");
LOG_INFO("------ GENERATING NEW CONFIGURATION FILE");
if(conf.hFile == "")
conf.hFile = conf.projectname+".h";
if (conf.hFile == "")
conf.hFile = conf.projectname + ".h";
XMLObject makegen("makegen", {}, std::map<std::string, std::vector<XMLObject>>{});
// Version, target and configuration is probably going to be used in the future
makegen.AddXMLObject(XMLObject("version", {}, "v1.3.0"));
makegen.AddXMLObject(XMLObject("version", {}, "v1.3.2"));
makegen.AddXMLObject(XMLObject("target", {}, "Release"));
XMLObject configuration("configuration", {{"name", "Release"}}, std::map<std::string, std::vector<XMLObject>>{});
@@ -170,22 +170,22 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
configuration.AddXMLObject(XMLObject("srcdir", {}, conf.srcdir));
configuration.AddXMLObject(XMLObject("outputdir", {}, conf.outputdir));
configuration.AddXMLObject(XMLObject("hfilename", {}, conf.hFile));
configuration.AddXMLObject(XMLObject("outputtype", {},
conf.executable ? "executable" : (conf.shared ? "sharedlibrary" : "staticlibrary")));
configuration.AddXMLObject(
XMLObject("outputtype", {}, conf.executable ? "executable" : (conf.shared ? "sharedlibrary" : "staticlibrary")));
configuration.AddXMLObject(XMLObject("generatehfile", {}, conf.generateHFile ? "true" : "false"));
for(auto it = conf.libs.begin();it != conf.libs.end(); ++it)
configuration.AddXMLObject({"library",{},*it});
for(auto it = conf.libdirs.begin();it != conf.libdirs.end(); ++it)
configuration.AddXMLObject({"librarydir",{},*it});
for(auto it = conf.includedirs.begin();it != conf.includedirs.end(); ++it)
configuration.AddXMLObject({"includedir",{},*it});
for(auto it = conf.defines.begin();it != conf.defines.end(); ++it)
configuration.AddXMLObject({"define",{},*it});
for(auto it = conf.flags.begin();it != conf.flags.end(); ++it)
configuration.AddXMLObject({"cflag",{},*it});
for(auto it = conf.dependencies.begin();it != conf.dependencies.end(); ++it)
configuration.AddXMLObject({"dependency",{},*it});
for (auto it = conf.libs.begin(); it != conf.libs.end(); ++it) configuration.AddXMLObject({"library", {}, *it});
for (auto it = conf.libdirs.begin(); it != conf.libdirs.end(); ++it)
configuration.AddXMLObject({"librarydir", {}, *it});
for (auto it = conf.includedirs.begin(); it != conf.includedirs.end(); ++it)
configuration.AddXMLObject({"includedir", {}, *it});
for (auto it = conf.defines.begin(); it != conf.defines.end(); ++it)
configuration.AddXMLObject({"define", {}, *it});
for (auto it = conf.flags.begin(); it != conf.flags.end(); ++it) configuration.AddXMLObject({"cflag", {}, *it});
for (auto it = conf.dependencies.begin(); it != conf.dependencies.end(); ++it)
configuration.AddXMLObject({"dependency", {}, *it});
for (auto it = conf.sourceFiles.begin(); it != conf.sourceFiles.end(); ++it)
configuration.AddXMLObject({"sourcefile", {}, *it});
makegen.AddXMLObject(configuration);
std::ofstream xmlFile(conf.configPath + "makegen.xml");
+23 -20
View File
@@ -9,26 +9,29 @@ class ConfigFile;
class ConfigFileConf
{
public:
std::string configPath;
std::vector<std::string> libs;
std::vector<std::string> libdirs;
std::vector<std::string> includedirs;
std::vector<std::string> defines;
std::vector<std::string> flags;
std::vector<std::string> dependencies;
public:
std::string configPath;
std::vector<std::string> libs;
std::vector<std::string> libdirs;
std::vector<std::string> includedirs;
std::vector<std::string> defines;
std::vector<std::string> flags;
std::vector<std::string> dependencies;
std::vector<std::string> sourceFiles;
std::string outputdir;
std::string srcdir;
std::string outputname;
std::string projectname;
std::string hFile;
bool executable;
bool shared;
bool generateHFile;
public:
ConfigFileConf();
std::string outputdir;
std::string srcdir;
std::string outputname;
std::string projectname;
std::string hFile;
bool executable;
bool shared;
bool generateHFile;
static void CreateXMLFile(const std::string& filename);
private:
public:
ConfigFileConf();
static void CreateXMLFile(const std::string& filename);
private:
};
Executable → Regular
+104 -80
View File
@@ -1,22 +1,24 @@
#include <cmath>
#include <filesystem>
#include <thread>
#include "Common.h"
#include "ConfigCLI.h"
#include "ConfigFile.h"
#include "FileUtils.h"
#include "FlagData.h"
#include "HFileGen.h"
#include "Makefile.h"
#include "Timer.h"
#include <cmath>
#include <thread>
#define RETURN_IF(x, b) \
if(x)\
return b;
if (x) \
return b;
void PrintHelp()
{
LOG_INFO("MakeGen ", MAKEGEN_VERSION);
LOG_INFO(1+(char*)R"(
LOG_INFO(1 + (char*)R"(
MakeGen is a utility tool to generate and run Makefiles in a simple manner.
By default it always compiles code with parallell jobs.
@@ -24,171 +26,193 @@ By default it always compiles code with parallell jobs.
Usage: makegen [options]
Options:
-h, --help Displays this information
-v, --version Displays the version of this program
-m,-a, make, all Generates a Makefile and runs
make all
-i, install Generates a Makefile and runs
make all && make install
-c, clean Generates a Makefile and runs
make clean
-r, rebuild Generates a Makefile and runs
make clean && make all
-e, run, execute Generates a Makefile and runs
make all && make run
-s, single Runs additional makegen options as single thread
(no --jobs=X flag)
--simple Creates a simple Makefile without include dependencies
(no --jobs=X flag)
-h, --help Displays this information
-v, --version Displays the version of this program
-m,-a, make, all Generates a Makefile and runs
make all
-i, install Generates a Makefile and runs
make all && make install
-c, clean Generates a Makefile and runs
make clean
-r, rebuild Generates a Makefile and runs
make clean && make all
-e, run, execute Generates a Makefile and runs
make all && make run
-s, single Runs additional makegen options as single thread
(no --jobs=X flag)
--simple Creates a simple Makefile without include dependencies
--target=<target> Run the makegen.xml file with the specified target
If no option is given it will run \"make all\"
If no option is given it will run "make all"
If multiple make options are given it will run in the following order:
clean all install run, rebuild will be translated to \"clean make\")");
clean all install run, rebuild will be translated to "clean make")");
}
void GenMakefile(ConfigFile& conf, unsigned int flags)
{
if(conf.GetSettingBool(ConfigSetting::GenerateHFile))
if (conf.GetSettingBool(ConfigSetting::GenerateHFile))
HFileGen::Create(conf);
Makefile::Save(conf, flags);
}
unsigned int ReadFlags(int argc, char** argv)
FlagData ReadFlags(int argc, char** argv)
{
if(argc >= 2 && std::string(argv[1]) == "conf")
return FLAG_CONFIG;
unsigned int flags = 0;
if (argc >= 2 && std::string(argv[1]) == "conf")
return FlagData{FLAG_CONFIG};
FlagData flagData{};
bool make = true;
for(int i = 1;i<argc;i++)
for (int i = 1; i < argc; i++)
{
if(strlen(argv[i]) > 1)
if (strlen(argv[i]) > 1)
{
std::string flag(argv[i]);
if(flag == "-h" || flag == "--help")
if (flag == "-h" || flag == "--help")
{
flags |= FLAG_HELP;
flagData.flags |= FLAG_HELP;
}
else if(flag == "-v" || flag == "--version")
else if (flag == "-v" || flag == "--version")
{
flags |= FLAG_VERSION;
flagData.flags |= FLAG_VERSION;
}
else if(flag == "make" || flag == "-m" || flag == "all" || flag == "-a")
else if (flag == "make" || flag == "-m" || flag == "all" || flag == "-a")
{
flags |= FLAG_MAKE;
flagData.flags |= FLAG_MAKE;
}
else if(flag == "clean" || flag == "-c")
else if (flag == "clean" || flag == "-c")
{
make = false;
flags |= FLAG_CLEAN;
flagData.flags |= FLAG_CLEAN;
}
else if(flag == "run" || flag == "-e" || flag == "execute")
else if (flag == "run" || flag == "-e" || flag == "execute")
{
flags |= FLAG_RUN;
flagData.flags |= FLAG_RUN;
}
else if(flag == "install" || flag == "-i")
else if (flag == "install" || flag == "-i")
{
flags |= FLAG_INSTALL;
flagData.flags |= FLAG_INSTALL;
}
else if(flag == "rebuild" || flag == "-r")
else if (flag == "rebuild" || flag == "-r")
{
flags |= FLAG_CLEAN;
flags |= FLAG_MAKE;
flagData.flags |= FLAG_CLEAN;
flagData.flags |= FLAG_MAKE;
}
else if(flag == "single" || flag == "-s")
else if (flag == "single" || flag == "-s")
{
flags |= FLAG_SINGLE_THREAD;
flagData.flags |= FLAG_SINGLE_THREAD;
}
else if(flag == "--simple")
else if (flag == "--simple")
{
flags |= FLAG_SIMPLE;
flagData.flags |= FLAG_SIMPLE;
}
else if(flag != "")
else if (Utils::StartsWith(flag, "--target="))
{
std::string prefix("--target=");
if (flag.size() < prefix.size() + 1)
{
LOG_ERROR("No target specified in --target=<target>");
return FlagData{FLAG_HELP};
}
flagData.flags |= FLAG_TARGET;
flagData.target = flag.substr(std::string("--target=").size());
}
else if (flag != "")
{
LOG_ERROR("Unknown argument ", flag);
return FLAG_HELP;
return FlagData{FLAG_HELP};
}
}
}
if(make)
flags |= FLAG_MAKE;
return flags;
if (make)
flagData.flags |= FLAG_MAKE;
return flagData;
}
bool RunMake(const std::string& filepath, unsigned int flags, ConfigFile& conf)
{
std::string make = "make --no-print-directory -C " + filepath;
if(!(flags & FLAG_SINGLE_THREAD))
if (!(flags & FLAG_SINGLE_THREAD))
make += " -j" + std::to_string(std::thread::hardware_concurrency()) + " ";
if(flags & FLAG_CLEAN)
if (flags & FLAG_CLEAN)
{
RETURN_IF(system(std::string(make + " clean").c_str()) != 0, false);
}
if(flags & FLAG_MAKE)
if (flags & FLAG_MAKE)
{
RETURN_IF(system(std::string(make + " all").c_str()) != 0, false);
}
if(flags & FLAG_INSTALL)
if (flags & FLAG_INSTALL)
{
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.GetSettingString(ConfigSetting::OutputType) == "executable")
{
RETURN_IF(system(std::string(make + " run").c_str()) != 0, false);
}
return true;
}
bool MakeGen(const std::string& filepath, unsigned int flags, ConfigFile& conf)
bool MakeGen(const std::string& filepath, const FlagData& flagData, ConfigFile& conf)
{
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
for(size_t i = 0;i<dependencies.size();++i)
for (size_t i = 0; i < dependencies.size(); ++i)
{
bool success = MakeGen(dependencies[i], flags, conf.GetDependencyConfig(i));
if(!success)
return success;
std::filesystem::path currentPath = std::filesystem::current_path();
std::filesystem::current_path(dependencies[i]);
auto conf = ConfigFile::GetConfigFile("./", flagData);
if (conf)
{
bool success = MakeGen("./", flagData, conf.value());
if (!success)
{
std::filesystem::current_path(currentPath);
return success;
}
}
std::filesystem::current_path(currentPath);
}
LOG_INFO("-----------------------------------");
LOG_INFO("Building ", conf.GetSettingString(ConfigSetting::ProjectName));
LOG_INFO("Generating Makefile...");
Timer timer;
GenMakefile(conf, flags);
LOG_INFO("Took ", round(timer.Elapsed()*1000.0)/1000.0,"s");
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);
if(!FileUtils::HasPath(outputPath))
if (!FileUtils::HasPath(outputPath))
{
FileUtils::CreateDirectory(outputPath);
std::string intermediatePath = outputPath + "intermediates";
if(!FileUtils::HasPath(intermediatePath ))
FileUtils::CreateDirectory(intermediatePath );
if (!FileUtils::HasPath(intermediatePath))
FileUtils::CreateDirectory(intermediatePath);
}
return RunMake(filepath, flags, conf);
return RunMake(filepath, flagData.flags, conf);
}
int main(int argc, char** argv)
{
unsigned int flags = ReadFlags(argc,argv);
if(flags & FLAG_HELP)
FlagData flagData = ReadFlags(argc, argv);
if (flagData.flags & FLAG_HELP)
{
PrintHelp();
return 0;
}
if(flags & FLAG_VERSION)
if (flagData.flags & FLAG_VERSION)
{
LOG_INFO("MakeGen ",MAKEGEN_VERSION);
LOG_INFO("MakeGen ", MAKEGEN_VERSION);
return 0;
}
if(flags & FLAG_CONFIG)
if (flagData.flags & FLAG_CONFIG)
{
return ConfigCLI::Main(argc-1, &argv[1]);
return ConfigCLI::Main(argc - 1, &argv[1]);
}
std::map<std::string, ConfigFile> files{};
auto conf = ConfigFile::GetConfigFile();
if(conf)
auto conf = ConfigFile::GetConfigFile("./", flagData);
if (conf)
{
bool success = MakeGen("./", flags, *conf);
bool success = MakeGen("./", flagData, *conf);
return success ? 0 : 1;
}
else
+9 -9
View File
@@ -1,28 +1,28 @@
#include "XML.h"
#include <algorithm>
#include <fstream>
#include "XMLException.h"
#include <fstream>
#include <algorithm>
XMLObject XML::FromString(const std::string& string, const std::string& filename="")
XMLObject XML::FromString(const std::string& string, const std::string& filename = "")
{
int startLine = 1;
int startPos = 0;
// Remove version tag.
if(string.find("<?") != std::string::npos)
if (string.find("<?") != std::string::npos)
{
startPos = string.find("?>") + 3;
startLine = std::count(string.begin(), string.begin()+startPos, '\n') + 1;
startLine = std::count(string.begin(), string.begin() + startPos, '\n') + 1;
}
return XMLObject(string, startPos, startLine,filename);
return XMLObject(string, startPos, startLine, filename);
}
XMLObject XML::FromFile(const std::string& filename)
{
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if(!file)
throw XMLException("Could not read file \""+filename+"\"");
if (!file)
throw XMLException("Could not read file \"" + filename + "\"");
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
std::string buffer;
+19 -13
View File
@@ -1,22 +1,28 @@
#pragma once
#include "XMLObject.h"
#include <exception>
#include <string>
#include "XMLObject.h"
class XMLException : public std::exception
{
private:
std::string m_message;
public:
explicit XMLException(const std::string& message) : m_message("XMLException: " + message) {}
explicit XMLException(const std::string& message, const XMLObject::XMLLoadData& data)
: m_message("XMLException(" + data.file + ":" + std::to_string(data.line) + "): " + message)
{}
private:
std::string m_message;
virtual const char* what() const throw()
{
return m_message.c_str();
}
public:
explicit XMLException(const std::string& message)
: m_message("XMLException: " + message)
{
}
explicit XMLException(const std::string& message, const XMLObject::XMLLoadData& data)
: m_message("XMLException(" + data.file + ":" + std::to_string(data.line) + "): " + message)
{
}
virtual const char* what() const throw()
{
return m_message.c_str();
}
};
+63 -59
View File
@@ -1,9 +1,9 @@
#include "XMLObject.h"
#include <cstring>
#include "../Common.h"
#include "../Utils.h"
#include <cstring>
#include "XMLException.h"
XMLObject::XMLObject(const std::string& string)
@@ -11,7 +11,7 @@ XMLObject::XMLObject(const std::string& string)
int pos = 0;
int line = 1;
XMLLoadData data{pos, line, ""};
if(!ReadHead(string, data))
if (!ReadHead(string, data))
ReadBodyTail(string, data);
}
@@ -28,16 +28,22 @@ XMLObject::XMLObject(const std::string& string, XMLLoadData& data)
ReadBodyTail(string, data);
}
XMLObject::XMLObject(const std::string& name, const std::map<std::string, std::string>& attributes, const std::string& text)
:name(name), attributes(attributes), text(text)
XMLObject::XMLObject(const std::string& name,
const std::map<std::string, std::string>& attributes,
const std::string& text)
: name(name),
attributes(attributes),
text(text)
{
}
XMLObject::XMLObject(const std::string& name, const std::map<std::string, std::string>& attributes, const std::map<std::string,std::vector<XMLObject>>& objects)
: name(name), attributes(attributes), objects(objects)
XMLObject::XMLObject(const std::string& name,
const std::map<std::string, std::string>& attributes,
const std::map<std::string, std::vector<XMLObject>>& objects)
: name(name),
attributes(attributes),
objects(objects)
{
}
bool XMLObject::HasAttribute(const std::string& property) const
@@ -69,7 +75,7 @@ unsigned int XMLObject::GetObjectCount() const
std::vector<XMLObject>* XMLObject::GetObjectPtr(const std::string& name)
{
auto it = objects.find(name);
if(it == objects.end())
if (it == objects.end())
return nullptr;
return &it->second;
@@ -92,7 +98,7 @@ const std::string& XMLObject::GetText() const
void XMLObject::SetName(const std::string& name)
{
if(Utils::IsWord(name))
if (Utils::IsWord(name))
this->name = name;
else
LOG_ERROR("XML Head can only be made up of letters");
@@ -105,7 +111,7 @@ void XMLObject::SetText(const std::string& text)
void XMLObject::AddAttribute(const std::string& property, const std::string& value)
{
if(Utils::IsWord(property))
if (Utils::IsWord(property))
attributes.emplace(property, value);
else
LOG_ERROR("XML property name can only be made up of letters");
@@ -114,7 +120,7 @@ void XMLObject::AddAttribute(const std::string& property, const std::string& val
void XMLObject::AddXMLObject(const XMLObject& object)
{
auto it = objects.find(object.name);
if(it == objects.end())
if (it == objects.end())
objects.emplace(object.name, std::vector<XMLObject>{object});
else
it->second.push_back(object);
@@ -123,18 +129,18 @@ void XMLObject::AddXMLObject(const XMLObject& object)
bool XMLObject::RemoveXMLObject(const XMLObject& object)
{
auto it = objects.find(object.name);
if(it == objects.end())
if (it == objects.end())
return false;
bool removed = false;
for(auto it2 = it->second.begin(); it2 != it->second.end();)
for (auto it2 = it->second.begin(); it2 != it->second.end();)
{
if(*it2 == object)
if (*it2 == object)
{
it2 = it->second.erase(it2);
removed = true;
}
else
else
++it2;
}
return removed;
@@ -142,7 +148,7 @@ bool XMLObject::RemoveXMLObject(const XMLObject& object)
XMLObject XMLObject::GetStrippedXMLObject() const
{
if(text == "")
if (text == "")
return XMLObject(name, attributes, objects);
else
return XMLObject(name, attributes, text);
@@ -154,7 +160,6 @@ XMLObject XMLObject::GetStrippedXMLObject() const
// //
////////////////////////////////////////////////////////////
bool XMLObject::ReadHead(const std::string& string, XMLLoadData& data)
{
// Check if the first character is the start of and xml tag.
@@ -179,7 +184,8 @@ bool XMLObject::ReadHead(const std::string& string, XMLLoadData& data)
data.pos++;
ReadWhiteSpace(string, data);
if (string[data.pos] != '>')
throw XMLException((std::string("Invalid character proceeding / in opening XML Tag \"") + string[data.pos] + "\".").c_str(), data);
throw XMLException(
(std::string("Invalid character proceeding / in opening XML Tag \"") + string[data.pos] + "\".").c_str(), data);
data.pos++;
// nothing more to read.
return true;
@@ -187,7 +193,9 @@ bool XMLObject::ReadHead(const std::string& string, XMLLoadData& data)
ReadWhiteSpace(string, data);
if (string[data.pos] != '>')
throw XMLException((std::string("Invalid character proceeding attributes in opening XML Tag \"") + string[data.pos] + "\".").c_str(), data);
throw XMLException(
(std::string("Invalid character proceeding attributes in opening XML Tag \"") + string[data.pos] + "\".").c_str(),
data);
(data.pos)++;
return false;
}
@@ -203,7 +211,8 @@ void XMLObject::ReadName(const std::string& string, XMLLoadData& data)
ReadWhiteSpace(string, data);
if (string[data.pos] != '/' && string[data.pos] != '>' && Utils::IsWhiteSpace(string[data.pos]))
{
throw XMLException((std::string("Invalid character proceeding name in XML Tag \"") + string[data.pos] + "\".").c_str(), data);
throw XMLException(
(std::string("Invalid character proceeding name in XML Tag \"") + string[data.pos] + "\".").c_str(), data);
}
}
@@ -230,7 +239,9 @@ void XMLObject::ReadAttribute(const std::string& string, XMLLoadData& data)
// Read =
if (string[data.pos] != '=')
throw XMLException((std::string("Invalid character proceeding property name in XML Tag \"") + string[data.pos] + "\".").c_str(), data);
throw XMLException(
(std::string("Invalid character proceeding property name in XML Tag \"") + string[data.pos] + "\".").c_str(),
data);
(data.pos)++;
ReadWhiteSpace(string, data);
@@ -256,7 +267,10 @@ void XMLObject::ReadBodyTail(const std::string& string, XMLLoadData& data)
ReadWhiteSpace(string, data);
std::string closeTag = GetClosingTag(string, data);
if (closeTag.length() == 0)
throw XMLException("Tag after XML Test was not a closing tag. XMLObject doesn't support text and other XMLObjects at the same time.", data);
throw XMLException(
"Tag after XML Test was not a closing tag. XMLObject doesn't support text and other XMLObjects at the same "
"time.",
data);
return;
}
// Check if we can read the closing tag.
@@ -279,14 +293,14 @@ void XMLObject::ReadText(const std::string& string, XMLLoadData& data)
void XMLObject::ReadWhiteSpace(const std::string& string, XMLLoadData& data)
{
while (Utils::IsWhiteSpace(string[data.pos])) {
while (Utils::IsWhiteSpace(string[data.pos]))
{
if (string[data.pos] == '\n')
(data.line)++;
(data.pos)++;
}
}
std::string XMLObject::GetClosingTag(const std::string& string, XMLLoadData& data)
{
int startPos = data.pos;
@@ -307,7 +321,8 @@ std::string XMLObject::GetClosingTag(const std::string& string, XMLLoadData& dat
ReadWhiteSpace(string, data);
std::string tag = Utils::GetWord(string, data.pos);
if (tag != name)
throw XMLException((std::string("Closing tag doesn't match opening tag. (\"") + name + "\" != \"" + tag+ "\")").c_str(), data);
throw XMLException(
(std::string("Closing tag doesn't match opening tag. (\"") + name + "\" != \"" + tag + "\")").c_str(), data);
data.pos += tag.length();
ReadWhiteSpace(string, data);
if (string[data.pos] != '>')
@@ -318,82 +333,72 @@ std::string XMLObject::GetClosingTag(const std::string& string, XMLLoadData& dat
void XMLObject::ReplacePredefinedEntities(std::string& string, XMLLoadData& data)
{
std::vector<std::pair<std::string, std::string>> entities
{
{"&quot;","\""},
{"&apos;", "\'"},
{"&lt;", "<"},
{"&gt;",">"},
{"&amp;", "&"}
};
std::vector<std::pair<std::string, std::string>> entities{
{"&quot;", "\""}, {"&apos;", "\'"}, {"&lt;", "<"}, {"&gt;", ">"}, {"&amp;", "&"}};
size_t pos = string.find('&');
while(pos != std::string::npos)
while (pos != std::string::npos)
{
bool found = false;
for(auto entity : entities)
for (auto entity : entities)
{
if(strncmp(&string[pos], entity.first.c_str(), entity.first.length()) == 0)
if (strncmp(&string[pos], entity.first.c_str(), entity.first.length()) == 0)
{
string.replace(pos, entity.first.length(), entity.second);
found = true;
}
}
if(!found)
LOG_ERROR("(" + data.file + ":" + std::to_string(data.line) + "): ""Ampersand found in xml but isn't a predefined entity.");
pos = string.find('&', pos+1);
if (!found)
LOG_ERROR("(" + data.file + ":" + std::to_string(data.line) +
"): "
"Ampersand found in xml but isn't a predefined entity.");
pos = string.find('&', pos + 1);
}
}
std::string XMLObject::ReadXMLName(const std::string& string, XMLLoadData& data)
{
if(!(Utils::IsLetter(string[data.pos]) ||
string[data.pos] == '_' ||
string[data.pos] == ':'))
if (!(Utils::IsLetter(string[data.pos]) || string[data.pos] == '_' || string[data.pos] == ':'))
throw XMLException(std::string("Name doesn't start with a letter."), data);
int endPos = data.pos + 1;
while (endPos < string.length() && (
Utils::IsLetter(string[endPos]) ||
string[endPos] == '_' ||
string[endPos] == '-' ||
string[endPos] == ':' ||
string[endPos] == '.'))
while (endPos < string.length() && (Utils::IsLetter(string[endPos]) || string[endPos] == '_' ||
string[endPos] == '-' || string[endPos] == ':' || string[endPos] == '.'))
endPos++;
return string.substr(data.pos, endPos - data.pos);
}
std::ostream& XMLObject::WriteToStream(std::ostream& stream, int indent) const
{
for(int i = 0;i<indent;i++)
for (int i = 0; i < indent; i++)
{
stream << " ";
}
stream << "<" << name;
for(auto it = attributes.begin();it!=attributes.end();++it)
for (auto it = attributes.begin(); it != attributes.end(); ++it)
{
stream << " " << it->first << "=\"" << it->second << "\"";
}
stream << ">";
if(text != "")
if (text != "")
{
stream << text;
}
else
{
bool hasChild = false;
for(auto it = objects.begin(); it != objects.end();++it)
for (auto it = objects.begin(); it != objects.end(); ++it)
{
for(auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2)
{
stream << "\n";
it2->WriteToStream(stream, indent+1);
it2->WriteToStream(stream, indent + 1);
hasChild = true;
}
}
if(hasChild)
if (hasChild)
{
stream << "\n";
for(int i = 0;i<indent;i++)
for (int i = 0; i < indent; i++)
{
stream << " ";
}
@@ -403,4 +408,3 @@ std::ostream& XMLObject::WriteToStream(std::ostream& stream, int indent) const
return stream;
}
+104 -96
View File
@@ -1,110 +1,118 @@
#pragma once
#include <string>
#include <map>
#include <set>
#include <string>
#include <vector>
class XMLObject
{
public:
friend class XMLexception;
struct XMLLoadData
public:
friend class XMLexception;
struct XMLLoadData
{
int pos;
int line;
const std::string& file;
};
private:
std::string name;
std::string text;
std::map<std::string, std::string> attributes;
std::map<std::string, std::vector<XMLObject>> objects;
public:
XMLObject()
{
}
XMLObject(const std::string& string);
XMLObject(const std::string& string, int pos, int line, const std::string& file);
XMLObject(const std::string& string, XMLLoadData& data);
XMLObject(const std::string& name, const std::map<std::string, std::string>& properties, const std::string& text);
XMLObject(const std::string& name,
const std::map<std::string, std::string>& properties,
const std::map<std::string, std::vector<XMLObject>>& objects);
bool HasAttribute(const std::string& property) const;
const std::string& GetAttribute(const std::string& property) const;
const std::string& GetAttribute(const std::string& property, const std::string& defaultValue) const;
unsigned int GetObjectCount() const;
std::vector<XMLObject>* GetObjectPtr(const std::string& name);
const std::map<std::string, std::vector<XMLObject>>& GetObjects() const;
const std::string& GetName() const;
const std::string& GetText() const;
XMLObject GetStrippedXMLObject() const;
void SetName(const std::string& name);
void SetText(const std::string& text);
void AddAttribute(const std::string& property, const std::string& value);
void AddXMLObject(const XMLObject& object);
bool RemoveXMLObject(const XMLObject& object);
friend bool operator<(const XMLObject& obj1, const XMLObject& obj2)
{
return obj1.name < obj2.name;
}
std::ostream& WriteToStream(std::ostream& stream, int indent = 0) const;
friend std::ostream& operator<<(std::ostream& stream, const XMLObject& object)
{
return object.WriteToStream(stream);
}
friend bool operator==(const XMLObject& object1, const XMLObject& object2)
{
if (object1.attributes.size() != object2.attributes.size())
return false;
if (object1.objects.size() != object2.objects.size())
return false;
if (object1.name != object2.name)
return false;
if (object1.GetText() != object2.GetText())
return false;
{
int pos;
int line;
const std::string& file;
};
private:
std::string name;
std::string text;
std::map<std::string, std::string> attributes;
std::map<std::string, std::vector<XMLObject>> objects;
public:
XMLObject() {}
XMLObject(const std::string& string);
XMLObject(const std::string& string, int pos, int line, const std::string& file);
XMLObject(const std::string& string, XMLLoadData& data);
XMLObject(const std::string& name, const std::map<std::string, std::string>& properties, const std::string& text);
XMLObject(const std::string& name, const std::map<std::string, std::string>& properties, const std::map<std::string, std::vector<XMLObject>>& objects);
bool HasAttribute(const std::string& property) const;
const std::string& GetAttribute(const std::string& property) const;
const std::string& GetAttribute(const std::string& property, const std::string& defaultValue) const;
unsigned int GetObjectCount() const;
std::vector<XMLObject>* GetObjectPtr(const std::string& name);
const std::map<std::string, std::vector<XMLObject>>& GetObjects() const;
const std::string& GetName() const;
const std::string& GetText() const;
XMLObject GetStrippedXMLObject() const;
void SetName(const std::string& name);
void SetText(const std::string& text);
void AddAttribute(const std::string& property, const std::string& value);
void AddXMLObject(const XMLObject& object);
bool RemoveXMLObject(const XMLObject& object);
friend bool operator<(const XMLObject& obj1, const XMLObject& obj2)
{
return obj1.name < obj2.name;
}
std::ostream& WriteToStream(std::ostream& stream, int indent = 0) const;
friend std::ostream& operator<<(std::ostream& stream, const XMLObject& object)
{
return object.WriteToStream(stream);
}
friend bool operator==(const XMLObject& object1, const XMLObject& object2)
{
if(object1.attributes.size() != object2.attributes.size())
return false;
if(object1.objects.size() != object2.objects.size())
return false;
if(object1.name != object2.name)
return false;
if(object1.GetText() != object2.GetText())
return false;
auto it1 = object1.attributes.begin();
auto it2 = object2.attributes.begin();
while (it1 != object1.attributes.end())
{
auto it1 = object1.attributes.begin();
auto it2 = object2.attributes.begin();
while(it1 != object1.attributes.end())
{
if(it1->first != it2->first || it1->second != it1->second)
return false;
++it1;
++it2;
}
if (it1->first != it2->first || it1->second != it1->second)
return false;
++it1;
++it2;
}
{
auto it1 = object1.objects.begin();
auto it2 = object2.objects.begin();
while(it1 != object1.objects.end())
{
if(it1->second != it2->second)
return false;
++it1;
++it2;
}
}
return true;
}
private:
std::string GetClosingTag(const std::string& string, XMLLoadData& data);
// Returns true if the head contained closing tag.
bool ReadHead(const std::string& string, XMLLoadData& data);
void ReadName(const std::string& string, XMLLoadData& data);
void ReadAttribute(const std::string& string, XMLLoadData& data);
void ReadAttributes(const std::string& string, XMLLoadData& data);
void ReadBodyTail(const std::string& string, XMLLoadData& data);
void ReadText(const std::string& string, XMLLoadData& data);
void ReadWhiteSpace(const std::string& string, XMLLoadData& data);
void ReplacePredefinedEntities(std::string& string, XMLLoadData& data);
std::string ReadXMLName(const std::string& string, XMLLoadData& data);
{
auto it1 = object1.objects.begin();
auto it2 = object2.objects.begin();
while (it1 != object1.objects.end())
{
if (it1->second != it2->second)
return false;
++it1;
++it2;
}
}
return true;
}
private:
std::string GetClosingTag(const std::string& string, XMLLoadData& data);
// Returns true if the head contained closing tag.
bool ReadHead(const std::string& string, XMLLoadData& data);
void ReadName(const std::string& string, XMLLoadData& data);
void ReadAttribute(const std::string& string, XMLLoadData& data);
void ReadAttributes(const std::string& string, XMLLoadData& data);
void ReadBodyTail(const std::string& string, XMLLoadData& data);
void ReadText(const std::string& string, XMLLoadData& data);
void ReadWhiteSpace(const std::string& string, XMLLoadData& data);
void ReplacePredefinedEntities(std::string& string, XMLLoadData& data);
std::string ReadXMLName(const std::string& string, XMLLoadData& data);
};