Compare commits

..

16 Commits

Author SHA1 Message Date
Thraix d39536213b Add makegen.xml as dependency to all *.o compilations 2026-05-12 23:08:37 +02:00
Thraix 577ac677db Add generate-compile-flags as argument
- generate-compile-flags (or shorthand gcf), will generate a
  compile_flags.txt file based on the makegen.xml configuration.
- Fix IncludeDirExclDep not generating in the Makefile correctly
2026-05-12 21:53:50 +02:00
Thraix 736aae3d39 Add cppversion as makegen config parameter
- Add cppversion as makegen config parameter, making it possible to
  specify which cpp version to use
- General cleanup of unused code
2026-05-10 16:27:26 +02:00
Thraix 8ff0411952 Refactor ConfigFile.cpp to be simpler 2026-05-09 23:58:34 +02:00
Thraix 5d00ada431 Add support for specifying target for dependencies
- Use <dependency target="target"> to specify which target the dependency
should be compiled for.
- Fix binary not being removed when doing makegen clean
2026-05-08 19:09:00 +02:00
Thraix c0d6afbf1a Remove github reference in README.md 2026-05-06 21:10:26 +02:00
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
33 changed files with 2343 additions and 1334 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
...
+1
View File
@@ -1,2 +1,3 @@
bin/* bin/*
.ycm_extra_conf.py .ycm_extra_conf.py
compile_flags.txt
+36 -32
View File
@@ -1,65 +1,69 @@
# This Makefile was generated using MakeGen v1.3.0 made by Tim Håkansson # This Makefile was generated using MakeGen v1.3.12 made by Tim Håkansson
# and is licensed under MIT. Full source of the project can be found at # and is licensed under MIT. Full source of the project can be found at
# https://github.com/Thraix/MakeGen # https://gitea.timha.se/Thraix/MakeGen
CC=@g++ CC=@g++
CO=@g++ -o CO=@g++ -o
MKDIR_P=mkdir -p MKDIR_P=mkdir -p
BIN=bin/ BIN=bin/Release/
OBJPATH=$(BIN)intermediates OBJPATH=$(BIN)intermediates
INCLUDES= INCLUDES=
OBJECTS=$(OBJPATH)/ConfigCLI.o $(OBJPATH)/ConfigFile.o $(OBJPATH)/HFileGen.o $(OBJPATH)/IncludeDeps.o $(OBJPATH)/Makefile.o $(OBJPATH)/Utils.o $(OBJPATH)/ConfigFileConf.o $(OBJPATH)/main.o $(OBJPATH)/XML.o $(OBJPATH)/XMLObject.o OBJECTS=$(OBJPATH)/src/CompileFlags.o $(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 -D_DEBUG -g3 -w CFLAGS=$(INCLUDES) -std=c++17 -c
LIBDIR= LIBDIR=
LDFLAGS= LDFLAGS=
LIBS=$(LIBDIR) LIBS=$(LIBDIR)
OUTPUT=$(BIN)makegen OUTPUT=$(BIN)makegen
.PHONY: all directories rebuild clean run .PHONY: all directories rebuild clean run
all: directories $(OUTPUT) all: directories $(OUTPUT)
directories: $(BIN) $(OBJPATH) directories: $(OBJPATH)/src $(OBJPATH)/src/compatibility $(OBJPATH)/src/xml
$(BIN): $(OBJPATH)/src:
$(info Creating output directories) @$(MKDIR_P) $@
@$(MKDIR_P) $(BIN) $(OBJPATH)/src/compatibility:
$(OBJPATH): @$(MKDIR_P) $@
@$(MKDIR_P) $(OBJPATH) $(OBJPATH)/src/xml:
@$(MKDIR_P) $@
run: all run: all
@./$(OUTPUT) @./$(OUTPUT)
rebuild: clean all rebuild: clean all
clean: clean:
$(info Removing intermediates) $(info Removing $(OBJPATH) and $(OUTPUT))
rm -rf $(OBJPATH)/*.o @rm -rf $(OBJPATH)/ $(OUTPUT)
$(OUTPUT): $(OBJECTS) $(OUTPUT): $(OBJECTS)
$(info Generating output file) $(info Generating output file $(OUTPUT))
$(CO) $(OUTPUT) $(OBJECTS) $(LDFLAGS) $(LIBS) $(CO) $(OUTPUT) $(OBJECTS) $(LDFLAGS) $(LIBS)
install: all install: all
$(info Installing MakeGen to /usr/bin/) $(info Installing MakeGen to /usr/bin/)
@cp $(OUTPUT) /usr/bin/makegen @cp $(OUTPUT) /usr/bin/makegen
$(OBJPATH)/ConfigCLI.o : src/ConfigCLI.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h $(OBJPATH)/src/CompileFlags.o: src/CompileFlags.cpp src/CompileFlags.h src/ConfigFile.h src/ConfigUtils.h src/Common.h src/AssertException.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h makegen.xml
$(info -[10%]- $<) $(info -[9%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(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/ConfigCLI.o: src/ConfigCLI.cpp src/Common.h src/AssertException.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/FileUtils.h src/Utils.h makegen.xml
$(info -[20%]- $<) $(info -[18%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(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/ConfigFile.o: src/ConfigFile.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/AssertException.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/FileUtils.h src/Utils.h src/compatibility/ConfigFileConf.h src/xml/XML.h makegen.xml
$(info -[30%]- $<) $(info -[27%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(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/HFileGen.o: src/HFileGen.cpp src/FileUtils.h src/Common.h src/AssertException.h src/Utils.h src/HFileGen.h src/ConfigFile.h src/ConfigUtils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h makegen.xml
$(info -[40%]- $<) $(info -[36%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(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/IncludeDeps.o: src/IncludeDeps.cpp src/Common.h src/AssertException.h src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/FileUtils.h src/Utils.h makegen.xml
$(info -[50%]- $<) $(info -[45%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(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/Makefile.o: src/Makefile.cpp src/Common.h src/AssertException.h src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/FileUtils.h src/Utils.h src/Makefile.h makegen.xml
$(info -[60%]- $<) $(info -[54%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/ConfigFileConf.o : src/compatibility/ConfigFileConf.cpp src/compatibility/ConfigFileConf.h $(OBJPATH)/src/Utils.o: src/Utils.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/AssertException.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/FileUtils.h src/Utils.h makegen.xml
$(info -[70%]- $<) $(info -[63%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(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/compatibility/ConfigFileConf.o: src/compatibility/ConfigFileConf.cpp src/Common.h src/AssertException.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h makegen.xml
$(info -[80%]- $<) $(info -[72%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/XML.o : src/xml/XML.cpp src/xml/XML.h src/xml/XMLObject.h src/xml/XMLException.h $(OBJPATH)/src/main.o: src/main.cpp src/Common.h src/AssertException.h src/CompileFlags.h src/ConfigFile.h src/ConfigUtils.h src/Dependency.h src/FlagData.h src/xml/XMLObject.h src/ConfigCLI.h src/HFileGen.h src/Makefile.h src/Timer.h src/Utils.h makegen.xml
$(info -[81%]- $<)
$(CC) $(CFLAGS) -o $@ $<
$(OBJPATH)/src/xml/XML.o: src/xml/XML.cpp src/xml/XML.h src/xml/XMLObject.h src/xml/XMLException.h makegen.xml
$(info -[90%]- $<) $(info -[90%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(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/AssertException.h src/Utils.h src/xml/XMLException.h src/xml/XMLObject.h makegen.xml
$(info -[100%]- $<) $(info -[100%]- $<)
$(CC) $(CFLAGS) -o $@ $< $(CC) $(CFLAGS) -o $@ $<
+1 -4
View File
@@ -16,10 +16,7 @@ After MakeGen is installed it will always be able to generate a Makefile (even w
However it will not compile your code if those programs don't exist. However it will not compile your code if those programs don't exist.
## Installation ## Installation
To install MakeGen make sure you have the dependencies listed above. To install MakeGen make sure you have the dependencies listed above and clone this repository.
Then clone this repository:
git clone git@github.com:Thraix/MakeGen.git
Then navigate into the MakeGen folder (`cd MakeGen`) and run: Then navigate into the MakeGen folder (`cd MakeGen`) and run:
+6 -6
View File
@@ -1,7 +1,7 @@
<makegen> <makegen>
<configuration name="Release"> <configuration name="Release">
<generatehfile>false</generatehfile> <cppversion>c++17</cppversion>
<outputdir>bin/</outputdir> <outputdir>bin/Release/</outputdir>
<outputname>makegen</outputname> <outputname>makegen</outputname>
<outputtype>executable</outputtype> <outputtype>executable</outputtype>
<projectname>MakeGen</projectname> <projectname>MakeGen</projectname>
@@ -10,14 +10,14 @@
<configuration name="Debug"> <configuration name="Debug">
<cflag>-g3</cflag> <cflag>-g3</cflag>
<cflag>-w</cflag> <cflag>-w</cflag>
<cppversion>c++17</cppversion>
<define>_DEBUG</define> <define>_DEBUG</define>
<generatehfile>false</generatehfile> <outputdir>bin/Debug/</outputdir>
<outputdir>bin/</outputdir>
<outputname>makegen</outputname> <outputname>makegen</outputname>
<outputtype>executable</outputtype> <outputtype>executable</outputtype>
<projectname>MakeGen</projectname> <projectname>MakeGen</projectname>
<srcdir>src/</srcdir> <srcdir>src/</srcdir>
</configuration> </configuration>
<target>Debug</target> <target>Release</target>
<version>v1.3.0</version> <version>v1.3.11</version>
</makegen> </makegen>
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <stdexcept>
struct AssertException : public std::runtime_error
{
AssertException()
: std::runtime_error{"assertion failed"}
{
}
};
Executable → Regular
+57 -9
View File
@@ -1,8 +1,12 @@
#pragma once #pragma once
#include <iostream> #include <iostream>
#include <set>
#include <vector>
#define BIT(x) (1<<x) #include "AssertException.h"
#define BIT(x) (1 << x)
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x) #define STR(x) STRINGIFY(x)
@@ -12,7 +16,7 @@
// Release, should be backwards compatible with any minor version // Release, should be backwards compatible with any minor version
#define MAKEGEN_VERSION_RELEASE 3 #define MAKEGEN_VERSION_RELEASE 3
// Minor changes, generally bug fixes // Minor changes, generally bug fixes
#define MAKEGEN_VERSION_MINOR 0 #define MAKEGEN_VERSION_MINOR 12
#define MAKEGEN_VERSION ("v" STR(MAKEGEN_VERSION_MAJOR) "." STR(MAKEGEN_VERSION_RELEASE) "." STR(MAKEGEN_VERSION_MINOR)) #define MAKEGEN_VERSION ("v" STR(MAKEGEN_VERSION_MAJOR) "." STR(MAKEGEN_VERSION_RELEASE) "." STR(MAKEGEN_VERSION_MINOR))
@@ -27,11 +31,25 @@ const static unsigned int FLAG_SINGLE_THREAD = BIT(7);
const static unsigned int FLAG_DEPENDENCY = BIT(8); const static unsigned int FLAG_DEPENDENCY = BIT(8);
const static unsigned int FLAG_SIMPLE = BIT(9); const static unsigned int FLAG_SIMPLE = BIT(9);
const static unsigned int FLAG_CONFIG = BIT(10); const static unsigned int FLAG_CONFIG = BIT(10);
const static unsigned int FLAG_TARGET = BIT(11);
const static unsigned int FLAG_GEN_COMP_FLAGS = BIT(12);
#define LOG_INFO(...) LogHelper(__VA_ARGS__) #define LOG_INFO(...) LogHelper(__VA_ARGS__)
#define LOG_WARNING(...) LogHelper(__VA_ARGS__) #define LOG_WARNING(...) LogHelper(__VA_ARGS__)
#define LOG_ERROR(...) LogHelper(__VA_ARGS__) #define LOG_ERROR(...) LogHelper("\033[1;31m[ERROR] ", __VA_ARGS__, "\033[0m")
#define ASSERT(expr, ...) \
if (!(expr)) \
{ \
LOG_ERROR(__VA_ARGS__); \
throw AssertException{}; \
} \
false
#define ABORT(...) \
{ \
LOG_ERROR(__VA_ARGS__); \
throw AssertException{}; \
} \
false
template <typename T> template <typename T>
void Log(const T& var) void Log(const T& var)
@@ -39,24 +57,54 @@ void Log(const T& var)
std::cout << var; std::cout << var;
} }
template <typename T, typename ...Ts> template <typename T, typename... Ts>
void Log(const T& var, const Ts& ...vars) void Log(const T& var, const Ts&... vars)
{ {
Log(var); Log(var);
Log(vars...); Log(vars...);
} }
template <typename T, typename ...Ts> template <typename T, typename... Ts>
void LogHelper(const T& var) void LogHelper(const T& var)
{ {
Log(var); Log(var);
std::cout << std::endl; std::cout << std::endl;
} }
template <typename T, typename ...Ts> template <typename T, typename... Ts>
void LogHelper(const T& var, const Ts& ...vars) void LogHelper(const T& var, const Ts&... vars)
{ {
Log(var); Log(var);
Log(vars...); Log(vars...);
std::cout << std::endl; 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;
}
+28
View File
@@ -0,0 +1,28 @@
#include "CompileFlags.h"
#include <fstream>
void CompileFlags::Save(ConfigFile& conf)
{
std::ofstream file{"compile_flags.txt"};
file << "-xc++" << std::endl;
file << "-std=" << conf.GetCppVersion() << std::endl;
const std::vector<std::string>& includeDirs = conf.GetIncludeDirs();
for (const auto& includeDir : includeDirs)
{
file << "-I" << includeDir << std::endl;
}
const std::vector<std::string>& includeDirExclDeps = conf.GetIncludeDirExclDeps();
for (const auto& includeDirExclDep : includeDirExclDeps)
{
file << "-I" << includeDirExclDep << std::endl;
}
const std::vector<std::string>& defines = conf.GetDefines();
for (const auto& defines : defines)
{
file << "-D" << defines << std::endl;
}
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "ConfigFile.h"
class CompileFlags
{
public:
static void Save(ConfigFile& conf);
};
+73 -79
View File
@@ -2,12 +2,11 @@
#include "Common.h" #include "Common.h"
#include "ConfigFile.h" #include "ConfigFile.h"
#include "FileUtils.h"
#include <set>
void ConfigCLI::DisplayCLIHelp() void ConfigCLI::DisplayCLIHelp()
{ {
LOG_INFO(1+(char*)R"( LOG_INFO(1 + (char*)R"(
MakeGen conf is used to create, modify and query the makegen.xml file. MakeGen conf is used to create, modify and query the makegen.xml file.
Usage: makegen conf <command> [<args>] [--help] Usage: makegen conf <command> [<args>] [--help]
@@ -27,7 +26,7 @@ Querying config settings
void ConfigCLI::DisplayGenHelp() void ConfigCLI::DisplayGenHelp()
{ {
LOG_INFO(1+(char*)R"( LOG_INFO(1 + (char*)R"(
Generate a config file from prompts Generate a config file from prompts
Usage: makegen conf gen <option> Usage: makegen conf gen <option>
@@ -41,7 +40,7 @@ options:
void ConfigCLI::DisplayAddHelp() void ConfigCLI::DisplayAddHelp()
{ {
LOG_INFO(1+(char*)R"( LOG_INFO(1 + (char*)R"(
Add values to config settings which support multiple arguments Add values to config settings which support multiple arguments
Usage: makegen conf add <setting> <value> [<values>] Usage: makegen conf add <setting> <value> [<values>]
@@ -56,13 +55,13 @@ Valid settings are:
dependency Project which current project depends on dependency Project which current project depends on
excludesource Exclude source file from compiling excludesource Exclude source file from compiling
excludeheader Exclude header file from project h-file excludeheader Exclude header file from project h-file
argument Command line argument for the executable argument Command line argument for the executable
preargument Command line argument before the executabe, e.g. gdb)"); preargument Command line argument before the executabe, e.g. gdb)");
} }
void ConfigCLI::DisplayRemoveHelp() void ConfigCLI::DisplayRemoveHelp()
{ {
LOG_INFO(1+(char*)R"( LOG_INFO(1 + (char*)R"(
Remove values to config settings which support multiple Remove values to config settings which support multiple
Usage: makegen conf remove <setting> <value> [< Usage: makegen conf remove <setting> <value> [<
@@ -77,13 +76,13 @@ Valid settings are
dependency Project which current project depends on dependency Project which current project depends on
excludesource Exclude source file from compiling excludesource Exclude source file from compiling
excludeheader Exclude header file from project h-file excludeheader Exclude header file from project h-file
argument Command line argument for the executable argument Command line argument for the executable
preargument Command line argument before the executabe, e.g. gdb)"); preargument Command line argument before the executabe, e.g. gdb)");
} }
void ConfigCLI::DisplaySetHelp() void ConfigCLI::DisplaySetHelp()
{ {
LOG_INFO(1+(char*)R"( LOG_INFO(1 + (char*)R"(
Set value to config settings which only support one argument Set value to config settings which only support one argument
Usage: makegen conf set <setting> <value> Usage: makegen conf set <setting> <value>
@@ -95,6 +94,7 @@ Valid string settings are:
outputtype Type of the output, valid values are executable, sharedlibrary outputtype Type of the output, valid values are executable, sharedlibrary
and staticlibrary and staticlibrary
hfile Name of the generated project h-file hfile Name of the generated project h-file
cppversion Version of the c++ to use
Valid boolean settings are: Valid boolean settings are:
genhfile Specifies if MakeGen should generate a project h-file genhfile Specifies if MakeGen should generate a project h-file
@@ -104,7 +104,7 @@ Boolean values can be set to either true/t/yes/y or false/f/no/n)");
void ConfigCLI::DisplayGetHelp() void ConfigCLI::DisplayGetHelp()
{ {
LOG_INFO(1+(char*)R"( LOG_INFO(1 + (char*)R"(
Get value of the config setting Get value of the config setting
Usage: makegen conf get <setting> Usage: makegen conf get <setting>
@@ -127,10 +127,11 @@ Valid settings are:
and staticlibrary and staticlibrary
projectname Name of the project projectname Name of the project
hfile Name of the generated project h-file hfile Name of the generated project h-file
genhfile Specifies if MakeGen should generate a project h-file)"); genhfile Specifies if MakeGen should generate a project h-file
cppversion Specifies the version of c++ to use (default=c++17)
)");
} }
ConfigSetting ConfigCLI::CLIStringToSetting(const std::string& s) ConfigSetting ConfigCLI::CLIStringToSetting(const std::string& s)
{ {
static std::map<std::string, ConfigSetting> map{ static std::map<std::string, ConfigSetting> map{
@@ -152,34 +153,34 @@ ConfigSetting ConfigCLI::CLIStringToSetting(const std::string& s)
{"argument", ConfigSetting::ExecArgument}, {"argument", ConfigSetting::ExecArgument},
{"dependency", ConfigSetting::Dependency}, {"dependency", ConfigSetting::Dependency},
{"genhfile", ConfigSetting::GenerateHFile}, {"genhfile", ConfigSetting::GenerateHFile},
{"cppversion", ConfigSetting::CppVersion},
}; };
auto it = map.find(s); auto it = map.find(s);
if(it == map.end()) ASSERT(it != map.end(), "Invalid config setting: ", s);
return ConfigSetting::Invalid;
return it->second; return it->second;
} }
int ConfigCLI::Gen(int argc, char** argv) int ConfigCLI::Gen(int argc, char** argv)
{ {
if(argc < 2 || std::string(argv[1]) == "--help") if (argc < 2 || std::string(argv[1]) == "--help")
{ {
DisplayGenHelp(); DisplayGenHelp();
return 0; return 0;
} }
if(argc < 2) if (argc < 2)
{ {
LOG_ERROR("gen needs exactly one parameter"); LOG_ERROR("gen needs exactly one parameter");
return 1; return 1;
} }
std::string option = argv[1]; std::string option = argv[1];
if(option == "prompt") if (option == "prompt")
{ {
ConfigFile::Gen().Save(); ConfigFile::Gen(FlagData{}).Save();
return 0; return 0;
} }
if(option == "default") if (option == "default")
{ {
ConfigFile{FileUtils::GetRealPath("."),0}.Save(); ConfigFile{std::filesystem::current_path(), FlagData{}, 0}.Save();
return 0; return 0;
} }
else else
@@ -191,32 +192,25 @@ int ConfigCLI::Gen(int argc, char** argv)
int ConfigCLI::Add(int argc, char** argv, ConfigFile& config) 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(); DisplayAddHelp();
return 0; return 0;
} }
if(argc < 3) if (argc < 3)
{ {
LOG_ERROR("add needs at least two parameters"); LOG_ERROR("add needs at least two parameters");
return 1; return 1;
} }
ConfigSetting setting = CLIStringToSetting(argv[1]); ConfigSetting setting = CLIStringToSetting(argv[1]);
if(!ConfigUtils::IsVectorSetting(setting)) if (!ConfigUtils::IsVectorSetting(setting))
{ {
if(setting == ConfigSetting::Invalid) LOG_ERROR("Cannot remove setting which only supports one argument");
{ LOG_ERROR("use set instead.");
LOG_ERROR("No such setting: ", argv[1]);
}
else
{
LOG_ERROR("Cannot remove setting which only supports one argument");
LOG_ERROR("use set instead.");
}
return 1; return 1;
} }
for(int i = 2; i<argc;++i) for (int i = 2; i < argc; ++i)
{ {
config.AddSettingVectorString(setting, argv[i]); config.AddSettingVectorString(setting, argv[i]);
} }
@@ -227,33 +221,26 @@ int ConfigCLI::Add(int argc, char** argv, ConfigFile& config)
int ConfigCLI::Remove(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(); DisplayRemoveHelp();
return 0; return 0;
} }
if(argc < 3) if (argc < 3)
{ {
LOG_ERROR("remove needs at least two parameters"); LOG_ERROR("remove needs at least two parameters");
return 1; return 1;
} }
ConfigSetting setting = CLIStringToSetting(argv[1]); ConfigSetting setting = CLIStringToSetting(argv[1]);
if(!ConfigUtils::IsVectorSetting(setting)) if (!ConfigUtils::IsVectorSetting(setting))
{ {
if(setting == ConfigSetting::Invalid) LOG_ERROR("Cannot remove setting which only supports one argument");
{ LOG_ERROR("use set instead.");
LOG_ERROR("No such setting: ", argv[1]);
}
else
{
LOG_ERROR("Cannot remove setting which only supports one argument");
LOG_ERROR("use set instead.");
}
return 1; return 1;
} }
for(int i = 2; i<argc;++i) for (int i = 2; i < argc; ++i)
{ {
config.RemoveSettingVectorString(setting, argv[i]); config.RemoveSettingVectorString(setting, argv[i]);
} }
@@ -264,29 +251,22 @@ int ConfigCLI::Remove(int argc, char** argv, ConfigFile& config)
int ConfigCLI::Set(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(); DisplaySetHelp();
return 0; return 0;
} }
if(argc != 3) if (argc != 3)
{ {
LOG_ERROR("set needs exactly two parameters"); LOG_ERROR("set needs exactly two parameters");
return 1; return 1;
} }
ConfigSetting setting = CLIStringToSetting(argv[1]); ConfigSetting setting = CLIStringToSetting(argv[1]);
if(!ConfigUtils::IsStringSetting(setting) && !ConfigUtils::IsBoolSetting(setting)) if (!ConfigUtils::IsStringSetting(setting) && !ConfigUtils::IsBoolSetting(setting))
{ {
if(setting == ConfigSetting::Invalid) LOG_ERROR("Cannot set setting which supports multiple arguments");
{ LOG_ERROR("use add or remove instead.");
LOG_ERROR("No such setting: ", argv[1]);
}
else
{
LOG_ERROR("Cannot set setting which supports multiple arguments");
LOG_ERROR("use add or remove instead.");
}
return 1; return 1;
} }
@@ -297,19 +277,19 @@ int ConfigCLI::Set(int argc, char** argv, ConfigFile& config)
int ConfigCLI::Get(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(); DisplayGetHelp();
return 0; return 0;
} }
if(argc != 2) if (argc != 2)
{ {
LOG_ERROR("get needs exactly one parameter"); LOG_ERROR("get needs exactly one parameter");
return 1; return 1;
} }
ConfigSetting setting = CLIStringToSetting(argv[1]); ConfigSetting setting = CLIStringToSetting(argv[1]);
std::vector<std::string> vector = config.GetSetting(setting); 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); LOG_INFO(*it);
} }
@@ -319,39 +299,53 @@ int ConfigCLI::Get(int argc, char** argv, ConfigFile& config)
int ConfigCLI::Main(int argc, char** argv) int ConfigCLI::Main(int argc, char** argv)
{ {
// Do nothing // Do nothing
if(argc < 2 || std::string(argv[1]) == "--help") if (argc < 2 || std::string(argv[1]) == "--help")
{ {
DisplayCLIHelp(); DisplayCLIHelp();
return 0; return 0;
} }
std::optional<ConfigFile> config = ConfigFile::GetConfigFile(); std::string target = "";
std::string command = argv[1]; int commandIndex = 1;
if(command == "gen") if (argc >= 1 && Utils::StartsWith(argv[1], "--target="))
{ {
if(config) std::string prefix("--target=");
std::string flag(argv[1]);
if (flag.size() < prefix.size() + 1)
{
LOG_ERROR("No target specified in --target=<target>");
return 1;
}
target = flag.substr(std::string("--target=").size());
commandIndex++;
}
std::optional<ConfigFile> config = ConfigFile::GetConfigFile("./", FlagData{target == "" ? 0 : FLAG_TARGET, target});
std::string command = argv[commandIndex];
if (command == "gen")
{
if (config)
{ {
LOG_ERROR("Config file already exist (", CONFIG_FILENAME, ")"); LOG_ERROR("Config file already exist (", CONFIG_FILENAME, ")");
return 1; return 1;
} }
return Gen(argc-1, &argv[1]); return Gen(argc - commandIndex, &argv[commandIndex]);
} }
else if(config) else if (config)
{ {
if(command == "add") if (command == "add")
return Add(argc-1, &argv[1], *config); return Add(argc - commandIndex, &argv[commandIndex], *config);
else if(command == "remove") else if (command == "remove")
return Remove(argc-1, &argv[1], *config); return Remove(argc - commandIndex, &argv[commandIndex], *config);
else if(command == "set") else if (command == "set")
return Set(argc-1, &argv[1], *config); return Set(argc - commandIndex, &argv[commandIndex], *config);
else if(command == "get") else if (command == "get")
return Get(argc-1, &argv[1], *config); return Get(argc - commandIndex, &argv[commandIndex], *config);
else else
{ {
LOG_ERROR("Unknown config command: ", command); LOG_ERROR("Unknown config command: ", command);
return 1; return 1;
} }
} }
else else
{ {
LOG_ERROR("There is no config file in the current directory"); LOG_ERROR("There is no config file in the current directory");
return 1; return 1;
+16 -16
View File
@@ -2,24 +2,24 @@
#include "ConfigFile.h" #include "ConfigFile.h"
struct ConfigCLI struct ConfigCLI
{ {
public: public:
static int Main(int argc, char** argv); 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();
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 ConfigSetting CLIStringToSetting(const std::string& s);
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 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
+679 -350
View File
File diff suppressed because it is too large Load Diff
Executable → Regular
+93 -38
View File
@@ -1,59 +1,114 @@
#pragma once #pragma once
#include "ConfigUtils.h"
#include "xml/XMLObject.h"
#include <map> #include <map>
#include <optional> #include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include "ConfigUtils.h"
#include "Dependency.h"
#include "FlagData.h"
#include "xml/XMLObject.h"
static const std::string CONFIG_FILENAME = "makegen.xml"; static const std::string CONFIG_FILENAME = "makegen.xml";
class ConfigFile class ConfigFile
{ {
private: public:
ConfigCache cache; // 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);
XMLObject config; void Save() const;
// Current configuration
std::string target;
std::string configPath; const std::string& GetOutputDir() const;
std::vector<ConfigFile> dependencyConfigs; const std::string& GetOutputName() const;
const std::string& GetProjectName() const;
const std::string& GetOutputType() const;
const std::string& GetCppVersion() const;
const std::optional<std::string>& GetSourceDir() const;
const std::optional<std::string>& GetHFileName() const;
const std::vector<std::string>& GetLibraryDirs() const;
const std::vector<std::string>& GetIncludeDirs() const;
const std::vector<std::string>& GetLibraries() const;
const std::vector<std::string>& GetDefines() const;
const std::vector<std::string>& GetCFlags() const;
const std::vector<std::string>& GetLFlags() const;
const std::vector<std::string>& GetExcludeHeaders() const;
const std::vector<std::string>& GetExcludeSources() const;
const std::vector<std::string>& GetSourceFiles() const;
const std::vector<std::string>& GetPreArguments() const;
const std::vector<std::string>& GetArguments() const;
const std::vector<std::string>& GetIncludeDirExclDeps() const;
const std::vector<Dependency>& GetDependencies() const;
bool IsGenerateHFile() const;
bool hasInitError = false; std::vector<std::string> GetSetting(ConfigSetting setting) const;
public: bool SetSettingString(ConfigSetting setting, std::string value);
// Generates a new default config file bool AddSettingVectorString(ConfigSetting setting, std::string value);
ConfigFile(const std::string& path, int); bool RemoveSettingVectorString(ConfigSetting setting, std::string value);
ConfigFile(const std::string& path);
ConfigFile(XMLObject& config, const std::string& path);
void Save() const; const std::filesystem::path& GetConfigPath() const;
ConfigFile& GetDependencyConfig(const std::string& path);
std::string& GetSettingString(ConfigSetting setting); static ConfigFile Gen(const FlagData& flagData);
bool GetSettingBool(ConfigSetting setting); static std::optional<ConfigFile> GetConfigFile(const std::string& filepath, const FlagData& flagData);
std::vector<std::string>& GetSettingVectorString(ConfigSetting setting);
std::vector<std::string> GetSetting(ConfigSetting setting);
bool SetSettingString(ConfigSetting setting, const std::string& value); private:
bool AddSettingVectorString(ConfigSetting setting, const std::string& value); XMLObject makegen;
bool RemoveSettingVectorString(ConfigSetting setting, const std::string& value); XMLObject config;
// Current configuration
std::string target;
XMLObject& GetConfiguration(); std::filesystem::path configPath;
const std::string& GetConfigPath() const; std::vector<ConfigFile> dependencyConfigs;
ConfigFile& GetDependencyConfig(size_t i);
private:
void Init();
public: std::vector<Dependency> dependencies;
static ConfigFile Gen(); std::string outputName;
static std::optional<ConfigFile> GetConfigFile(const std::string& filepath = "./"); std::string outputDir;
private: std::string projectName;
static std::optional<ConfigFile> GetConfigFile(const std::string& filepath, std::map<std::string, ConfigFile>& loadedConfigs); std::string outputType;
static std::optional<ConfigFile> Load(const std::string& filename); std::string cppVersion;
static void InputBoolean(const std::string& inputText, bool& b); std::optional<std::string> sourceDir;
static void InputMultiple(const std::string& inputText, std::vector<std::string>& vec, bool needEnding); std::optional<std::string> hFileName;
static void InputString(const std::string& inputText, std::string& vec, bool needEnding, bool allowEmpty); std::vector<std::string> libraryDirs;
std::vector<std::string> includeDirs;
std::vector<std::string> libraries;
std::vector<std::string> defines;
std::vector<std::string> cFlags;
std::vector<std::string> lFlags;
std::vector<std::string> excludeHeaders;
std::vector<std::string> excludeSources;
std::vector<std::string> sourceFiles;
std::vector<std::string> preArguments;
std::vector<std::string> arguments;
std::vector<std::string> includeDirExclDeps;
bool generateHFile{false};
private:
void Init(const FlagData& flagData);
void InitTarget(const FlagData& flagData);
void InitTargetConfig();
XMLObject& GetTargetConfig();
void InitDependencies();
void InitStringSetting(const std::string& name, std::string* output);
void InitStringSetting(const std::string& name, const std::string& defaultVal, std::string* output);
void InitOptionalStringSetting(const std::string& name, std::optional<std::string>* output);
void InitStringListSetting(const std::string& name, std::vector<std::string>* output);
void InitBoolSetting(const std::string& name, bool* output);
void InitDir(std::string& dir) const;
void InitOptionalDir(std::optional<std::string>& dir) const;
void InitDirs(std::vector<std::string>& dirs) const;
void RemoveFromVector(std::vector<std::string>& vector, const std::string& string);
void RemoveFromVector(std::vector<Dependency>& vector, const std::string& string);
static std::optional<ConfigFile> GetConfigFile(const std::string& filepath,
std::map<std::string, ConfigFile>& loadedConfigs,
const FlagData& flagData);
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);
}; };
+89 -99
View File
@@ -1,37 +1,46 @@
#pragma once #pragma once
#include "Common.h" #include <algorithm>
#include "FileUtils.h" #include <filesystem>
#include <assert.h>
#include <map> #include <map>
#include <vector>
#include <string> #include <string>
#include <vector>
struct ConfigCache #include "Common.h"
{
std::map<std::string, std::string> strings;
std::map<std::string, std::vector<std::string>> vecStrings;
std::map<std::string, bool> bools;
};
enum class ConfigSetting enum class ConfigSetting
{ {
// vectors // vectors
Library = 0, LibraryDir = 1, IncludeDir = 2, Define = 3, Dependency = 4, CFlag = 5, LFlag = 6, ExcludeSource = 7, ExcludeHeader = 8, ExecPreArgument = 9, ExecArgument = 10, Library,
LibraryDir,
IncludeDir,
Define,
Dependency,
CFlag,
LFlag,
ExcludeSource,
ExcludeHeader,
ExecPreArgument,
ExecArgument,
SourceFile,
IncludeDirExclDep,
// Strings // Strings
SourceDir = 32, OutputDir = 33, OutputName = 34, OutputType = 35, ProjectName = 36, HFileName = 37, SourceDir,
OutputDir,
OutputName,
OutputType,
ProjectName,
HFileName,
CppVersion,
// Bools // Bools
GenerateHFile = 64, GenerateHFile,
// Other
Invalid = 1024
}; };
struct ConfigUtils struct ConfigUtils
{ {
static std::string GetSettingName(ConfigSetting setting) static std::string GetSettingName(ConfigSetting setting)
{ {
switch(setting) switch (setting)
{ {
case ConfigSetting::SourceDir: case ConfigSetting::SourceDir:
return "srcdir"; return "srcdir";
@@ -69,20 +78,26 @@ struct ConfigUtils
return "argument"; return "argument";
case ConfigSetting::GenerateHFile: case ConfigSetting::GenerateHFile:
return "generatehfile"; return "generatehfile";
case ConfigSetting::Invalid: case ConfigSetting::SourceFile:
return "invalid"; return "sourcefile";
case ConfigSetting::IncludeDirExclDep:
return "includedirexcldep";
case ConfigSetting::CppVersion:
return "cppversion";
} }
return "";
} }
static bool IsDirectory(ConfigSetting setting) static bool IsDirectory(ConfigSetting setting)
{ {
switch(setting) switch (setting)
{ {
case ConfigSetting::SourceDir: case ConfigSetting::SourceDir:
case ConfigSetting::OutputDir: case ConfigSetting::OutputDir:
case ConfigSetting::LibraryDir: case ConfigSetting::LibraryDir:
case ConfigSetting::IncludeDir: case ConfigSetting::IncludeDir:
case ConfigSetting::Dependency: case ConfigSetting::Dependency:
case ConfigSetting::IncludeDirExclDep:
return true; return true;
case ConfigSetting::OutputName: case ConfigSetting::OutputName:
case ConfigSetting::OutputType: case ConfigSetting::OutputType:
@@ -97,16 +112,16 @@ struct ConfigUtils
case ConfigSetting::ExecPreArgument: case ConfigSetting::ExecPreArgument:
case ConfigSetting::ExecArgument: case ConfigSetting::ExecArgument:
case ConfigSetting::GenerateHFile: case ConfigSetting::GenerateHFile:
case ConfigSetting::SourceFile:
case ConfigSetting::CppVersion:
return false; return false;
default:
LOG_ERROR("INVALID ENUM: ", (int)setting);
assert(false);
} }
return false;
} }
static bool IsStringSetting(ConfigSetting setting) static bool IsStringSetting(ConfigSetting setting)
{ {
switch(setting) switch (setting)
{ {
case ConfigSetting::SourceDir: case ConfigSetting::SourceDir:
case ConfigSetting::OutputDir: case ConfigSetting::OutputDir:
@@ -114,6 +129,7 @@ struct ConfigUtils
case ConfigSetting::OutputType: case ConfigSetting::OutputType:
case ConfigSetting::ProjectName: case ConfigSetting::ProjectName:
case ConfigSetting::HFileName: case ConfigSetting::HFileName:
case ConfigSetting::CppVersion:
return true; return true;
case ConfigSetting::LibraryDir: case ConfigSetting::LibraryDir:
case ConfigSetting::IncludeDir: case ConfigSetting::IncludeDir:
@@ -127,14 +143,16 @@ struct ConfigUtils
case ConfigSetting::ExecPreArgument: case ConfigSetting::ExecPreArgument:
case ConfigSetting::ExecArgument: case ConfigSetting::ExecArgument:
case ConfigSetting::GenerateHFile: case ConfigSetting::GenerateHFile:
case ConfigSetting::Invalid: case ConfigSetting::SourceFile:
case ConfigSetting::IncludeDirExclDep:
return false; return false;
} }
return false;
} }
static bool IsVectorSetting(ConfigSetting setting) static bool IsVectorSetting(ConfigSetting setting)
{ {
switch(setting) switch (setting)
{ {
case ConfigSetting::LibraryDir: case ConfigSetting::LibraryDir:
case ConfigSetting::IncludeDir: case ConfigSetting::IncludeDir:
@@ -147,6 +165,8 @@ struct ConfigUtils
case ConfigSetting::ExcludeSource: case ConfigSetting::ExcludeSource:
case ConfigSetting::ExecPreArgument: case ConfigSetting::ExecPreArgument:
case ConfigSetting::ExecArgument: case ConfigSetting::ExecArgument:
case ConfigSetting::SourceFile:
case ConfigSetting::IncludeDirExclDep:
return true; return true;
case ConfigSetting::SourceDir: case ConfigSetting::SourceDir:
case ConfigSetting::OutputDir: case ConfigSetting::OutputDir:
@@ -155,100 +175,75 @@ struct ConfigUtils
case ConfigSetting::ProjectName: case ConfigSetting::ProjectName:
case ConfigSetting::HFileName: case ConfigSetting::HFileName:
case ConfigSetting::GenerateHFile: case ConfigSetting::GenerateHFile:
case ConfigSetting::Invalid: case ConfigSetting::CppVersion:
return false;
}
}
static bool IsBoolSetting(ConfigSetting setting)
{
switch(setting)
{
case ConfigSetting::GenerateHFile:
return true;
case ConfigSetting::SourceDir:
case ConfigSetting::OutputDir:
case ConfigSetting::OutputName:
case ConfigSetting::OutputType:
case ConfigSetting::ProjectName:
case ConfigSetting::HFileName:
case ConfigSetting::LibraryDir:
case ConfigSetting::IncludeDir:
case ConfigSetting::Dependency:
case ConfigSetting::Library:
case ConfigSetting::Define:
case ConfigSetting::CFlag:
case ConfigSetting::LFlag:
case ConfigSetting::ExcludeHeader:
case ConfigSetting::ExcludeSource:
case ConfigSetting::ExecPreArgument:
case ConfigSetting::ExecArgument:
case ConfigSetting::Invalid:
return false; return false;
} }
return false;
} }
static std::string GetDefaultSettingString(ConfigSetting setting, const std::string& path) static bool IsBoolSetting(ConfigSetting setting)
{ {
switch(setting) switch (setting)
{ {
case ConfigSetting::SourceDir:
return "src/";
case ConfigSetting::OutputDir:
return "bin/";
case ConfigSetting::OutputName:
return GetDefaultOutputName(path);
case ConfigSetting::OutputType:
return "executable";
case ConfigSetting::ProjectName:
return GetDefaultProjectName(path);
case ConfigSetting::HFileName:
return GetDefaultHFileName(path);
case ConfigSetting::GenerateHFile: case ConfigSetting::GenerateHFile:
return GetDefaultSettingBool(setting) ? "true" : "false"; return true;
default: case ConfigSetting::SourceDir:
LOG_ERROR("INVALID STRING ENUM: ", (int)setting); case ConfigSetting::OutputDir:
assert(false); case ConfigSetting::OutputName:
case ConfigSetting::OutputType:
case ConfigSetting::ProjectName:
case ConfigSetting::HFileName:
case ConfigSetting::LibraryDir:
case ConfigSetting::IncludeDir:
case ConfigSetting::Dependency:
case ConfigSetting::Library:
case ConfigSetting::Define:
case ConfigSetting::CFlag:
case ConfigSetting::LFlag:
case ConfigSetting::ExcludeHeader:
case ConfigSetting::ExcludeSource:
case ConfigSetting::ExecPreArgument:
case ConfigSetting::ExecArgument:
case ConfigSetting::SourceFile:
case ConfigSetting::IncludeDirExclDep:
case ConfigSetting::CppVersion:
return false;
} }
return false;
} }
static bool GetDefaultSettingBool(ConfigSetting setting) static bool GetDefaultSettingBool(ConfigSetting setting)
{ {
switch(setting) switch (setting)
{ {
case ConfigSetting::GenerateHFile: case ConfigSetting::GenerateHFile:
return false; return false;
default: default:
LOG_ERROR("NOT BOOLEAN VALUE: ", (int)setting); ASSERT(false, "NOT BOOLEAN VALUE: ", (int)setting);
assert(false);
} }
} }
static std::string GetDefaultProjectName(const std::string& path) static std::string GetDefaultProjectName(const std::string& path)
{ {
return FileUtils::GetTopDirectory(path); return std::filesystem::canonical(path).filename();
} }
static std::string GetDefaultOutputName(const std::string& path) static std::string GetDefaultOutputName(const std::string& path)
{ {
std::string projectname = GetDefaultProjectName(path); std::string projectname = GetDefaultProjectName(path);
std::string outputname; std::string outputname;
std::transform( std::transform(projectname.begin(),
projectname.begin(), projectname.end(),
projectname.end(), std::back_inserter(outputname),
std::back_inserter(outputname), [](unsigned char c)
[](unsigned char c) {
{ if (c == ' ')
if(c == ' ') return '_';
return '_'; return (char)std::tolower(c);
return (char)std::tolower(c); });
}); auto it = std::remove_if(outputname.begin(),
auto it = std::remove_if( outputname.end(),
outputname.begin(), [](unsigned char c) { return (c < '0' || c > '9') && (c < 'a' || c > 'z') && c != '_'; });
outputname.end(),
[](unsigned char c)
{
return (c < '0' || c > '9') && (c < 'a' || c > 'z') && c != '_';
});
outputname.erase(it, outputname.end()); outputname.erase(it, outputname.end());
outputname += ".out"; outputname += ".out";
return outputname; return outputname;
@@ -258,12 +253,7 @@ struct ConfigUtils
{ {
std::string hfile = GetDefaultProjectName(path); std::string hfile = GetDefaultProjectName(path);
auto it = std::remove_if( auto it = std::remove_if(
hfile.begin(), hfile.begin(), hfile.end(), [](unsigned char c) { return (c < 'a' || c > 'z') && (c < 'A' || c > 'Z'); });
hfile.end(),
[](unsigned char c)
{
return (c < 'a' || c > 'z') && (c < 'A' || c > 'Z');
});
hfile.erase(it, hfile.end()); hfile.erase(it, hfile.end());
hfile += ".h"; hfile += ".h";
return hfile; return hfile;
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <string>
struct Dependency
{
std::string path;
std::string target;
Dependency(const std::string& path, const std::string& target)
: path{path},
target{target}
{
}
};
+28 -131
View File
@@ -1,159 +1,56 @@
#pragma once #pragma once
#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 "Common.h"
#include "Utils.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 struct FileUtils
{ {
static bool HasPath(const std::string& path)
{
struct stat info;
if(stat(path.c_str(), &info) != 0)
return false;
else
return true;
}
static bool CreateDirectory(const std::string& path)
{
return mkdir(path.c_str(), 0777);
}
static std::string GetCurrentDirectory()
{
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)
{
LOG_ERROR("Cannot send empty string to FileUtils::GetTopDirectory()");
assert(false);
}
size_t dirEnd = std::string::npos;
if(dir[dir.size()-1] == '/')
dirEnd = dir.size()-2;
size_t pos = dir.find_last_of("/", dirEnd);
if(pos == std::string::npos)
{
LOG_ERROR("Couldn't find / (slash) in directory. This shouldn't occur.");
assert(false);
}
return dir.substr(pos + 1, dirEnd - pos);
}
static std::string GetRealPath(const std::string& filename) static std::string GetRealPath(const std::string& filename)
{ {
#if defined(__linux__) return std::filesystem::canonical(filename).string();
if(access(filename.c_str(), F_OK ) != -1)
{
char* path = realpath(filename.c_str(), NULL);
std::string sPath = path;
sPath+="/";
free(path);
return sPath;
}
else
{
LOG_ERROR("Directory doesn't exist: ", filename);
return "";
}
#endif
LOG_ERROR("GetRealPath not supported");
return "";
}
static std::string GetRelativePath(std::string from, std::string to)
{
std::string result;
if(to[to.size()-1] == '/')
to.pop_back();
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)
{
// Same directory
if(to.size() == from.size())
return "";
// Remove the 'from' path
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)
{
std::string sub = from.substr(to.size());
size_t n = std::count(sub.begin(), sub.end(), '/');
for(int i = 0;i<n;i++)
{
result+="..";
if(i != n-1)
result+="/";
}
return result;
}
// Otherwise it's a path in another directory
else
{
// Find the most common directory
std::string commonPath = Utils::CommonPrefix(from,to);
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++)
{
result+="..";
if(i != n-1)
result+="/";
}
// Add the path which diverges
result += to.substr(commonPath.size());
return result;
}
} }
static void GetAllFiles(const std::string& folder, std::vector<std::string>& files) static void GetAllFiles(const std::string& folder, std::vector<std::string>& files)
{ {
DIR* dp; DIR* dp;
struct dirent *dirp; struct dirent* dirp;
if((dp = opendir(folder.c_str())) == NULL){ if ((dp = opendir(folder.c_str())) == NULL)
LOG_ERROR(errno); {
LOG_ERROR("Failed to open directory: ", folder);
return; 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; continue;
if(strcmp(dirp->d_name,"..") == 0) if (strcmp(dirp->d_name, "..") == 0)
continue; continue;
GetAllFiles(folder+dirp->d_name+"/", files); GetAllFiles(folder + dirp->d_name + "/", files);
} }
else else
{ {
files.push_back(folder+dirp->d_name); files.push_back(folder + dirp->d_name);
} }
} }
closedir(dp); 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
};
+27 -11
View File
@@ -1,23 +1,35 @@
#include "HFileGen.h" #include "HFileGen.h"
#include "FileUtils.h"
#include <set> #include <set>
#include "FileUtils.h"
// TODO: Consider removing this functionality, since its not really used anyways
void HFileGen::Create(ConfigFile& conf) void HFileGen::Create(ConfigFile& conf)
{ {
const std::optional<std::string>& hFileName = conf.GetHFileName();
if (!hFileName.has_value())
{
LOG_ERROR("hfilename is not specified but generatehfile is true");
return;
}
std::set<std::string> hFiles; std::set<std::string> hFiles;
std::vector<std::string> files; std::vector<std::string> files;
std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir); const std::optional<std::string>& sourceDir = conf.GetSourceDir();
FileUtils::GetAllFiles(path,files); std::string path = conf.GetConfigPath();
if (sourceDir.has_value())
path += sourceDir.value();
FileUtils::GetAllFiles(path, files);
// include paramenter with the path of the file // include paramenter with the path of the file
// For example src/graphics/Window.h -> graphics/Window.h if src is a src folder // For example src/graphics/Window.h -> graphics/Window.h if src is a src folder
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("."); size_t extensionPos = it->find_last_of(".");
if(extensionPos != std::string::npos) if (extensionPos != std::string::npos)
{ {
std::string filename = it->substr(path.length()); std::string filename = it->substr(path.length());
if(Utils::IsHeaderFile(filename) && filename != conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::HFileName)) if (Utils::IsHeaderFile(filename) && filename != conf.GetConfigPath() / hFileName.value())
{ {
// Make files sorted in alphabetical order // Make files sorted in alphabetical order
hFiles.emplace(filename); hFiles.emplace(filename);
@@ -25,14 +37,18 @@ void HFileGen::Create(ConfigFile& conf)
} }
} }
const std::vector<std::string>& excludeHeaders = conf.GetSettingVectorString(ConfigSetting::ExcludeHeader); const std::vector<std::string>& excludeHeaders = conf.GetExcludeHeaders();
std::ofstream os(path + "/" + conf.GetSettingString(ConfigSetting::HFileName)); std::ofstream os(path + "/" + hFileName.value());
os << "#pragma once" << std::endl << std::endl; os << "#pragma once" << std::endl << std::endl;
for(auto&& hFile : hFiles) for (auto&& hFile : hFiles)
{ {
std::string headerFile = conf.GetSettingString(ConfigSetting::SourceDir) + hFile; const std::optional<std::string>& srcDir = conf.GetSourceDir();
std::string headerFile = hFile;
if (srcDir.has_value())
headerFile = srcDir.value() + headerFile;
auto it = std::find(excludeHeaders.begin(), excludeHeaders.end(), headerFile); auto it = std::find(excludeHeaders.begin(), excludeHeaders.end(), headerFile);
if(it == excludeHeaders.end()) if (it == excludeHeaders.end())
os << "#include <" << hFile << ">" << std::endl; os << "#include <" << hFile << ">" << std::endl;
} }
} }
+3 -3
View File
@@ -2,8 +2,8 @@
#include "ConfigFile.h" #include "ConfigFile.h"
class HFileGen class HFileGen
{ {
public: public:
static void Create(ConfigFile& conf); static void Create(ConfigFile& conf);
}; };
Executable → Regular
+64 -29
View File
@@ -1,64 +1,99 @@
#include "IncludeDeps.h" #include "IncludeDeps.h"
#include <sstream>
#include "Common.h" #include "Common.h"
std::set<std::string> IncludeDeps::printSet; std::set<std::string> IncludeDeps::printSet;
int IncludeDeps::printCounter = 0; 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::IncludeDeps(const std::string& filename,
: IncludeDeps{filename, dir, false, files, allDeps} const std::set<HFile>& files,
{} std::map<std::string, IncludeDeps*>& allDeps)
: IncludeDeps{filename, 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}
{ {
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); allDeps.emplace(filepath, this);
} }
std::ifstream file(filepath); std::ifstream file(filepath);
std::string line; std::string line;
while(std::getline(file,line)) while (std::getline(file, line))
{ {
size_t pos = line.find("#include"); std::string start;
if(pos != std::string::npos) std::stringstream ss{line};
ss >> start;
if (start == "#include")
{ {
std::string include = GetIncludeFile(line, pos, filename); std::string include = GetIncludeFile(line);
auto it = files.find({include, "", false});
if(it != files.end()) 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); auto itD = allDeps.find(includeFileRelativeToSource.string());
if(itD == allDeps.end()) 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); 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); size_t bracket = line.find('<');
if(bracket == std::string::npos) if (bracket == std::string::npos)
{ {
bracket = line.find('\"',pos); bracket = line.find('\"');
if(bracket == std::string::npos) if (bracket == std::string::npos)
{ {
return ""; return "";
} }
size_t slash = filename.find_last_of("/");
std::string include = line.substr(bracket+1, line.find('\"',bracket+1)-bracket-1); std::string include = line.substr(bracket + 1, line.find('\"', bracket + 1) - bracket - 1);
if(slash == std::string::npos) return include;
slash = -1;
return filename.substr(0,slash+1)+include;
} }
else 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 #pragma once
#include "ConfigFile.h" #include <filesystem>
#include "FileUtils.h"
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <set> #include <set>
#include <string> #include <string>
#include "ConfigFile.h"
#include "FileUtils.h"
struct CompareIncludeDeps; struct CompareIncludeDeps;
class IncludeDeps class IncludeDeps
{ {
public: public:
std::map<std::string, IncludeDeps*> dependencies; std::map<std::string, IncludeDeps*> dependencies;
std::string filepath; std::filesystem::path filepath;
bool projectHFile; bool projectHFile;
static std::set<std::string> printSet; static std::set<std::string> printSet;
static int printCounter; 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) std::ostream& Output(std::ostream& stream, const ConfigFile& conf)
{ {
if(printSet.find(filepath) != printSet.end()) std::string filePathInMakeFile = filepath;
return stream; if (!filepath.is_absolute())
printCounter++; filePathInMakeFile = std::filesystem::relative(conf.GetConfigPath() / filepath.string(), "./").string();
printSet.emplace(filepath);
if(!projectHFile) if (printSet.find(filePathInMakeFile) != printSet.end())
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();
return stream; 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 struct CompareIncludeDeps
{ {
using is_transparent = void; using is_transparent = void;
bool operator()(const IncludeDeps* d1, const IncludeDeps* d2) const bool operator()(const IncludeDeps* d1, const IncludeDeps* d2) const
{ {
return d1->filepath < d2->filepath; return d1->filepath < d2->filepath;
} }
bool operator()(const IncludeDeps* d, const std::string& filepath) const bool operator()(const IncludeDeps* d, const std::string& filepath) const
{ {
return d->filepath < filepath; return d->filepath < filepath;
} }
bool operator()(const std::string& filepath, const IncludeDeps* d) const bool operator()(const std::string& filepath, const IncludeDeps* d) const
{ {
return filepath < d->filepath; return filepath < d->filepath;
+115 -77
View File
@@ -1,29 +1,31 @@
#include "Makefile.h" #include "Makefile.h"
#include "IncludeDeps.h"
#include "Utils.h"
#include <fstream> #include <fstream>
#include <map> #include <map>
#include "Common.h"
#include "IncludeDeps.h"
#include "Utils.h"
void Makefile::Save(ConfigFile& conf, unsigned int flags) void Makefile::Save(ConfigFile& conf, unsigned int flags)
{ {
std::set<HFile> hFiles; // hFile, directory std::set<HFile> hFiles; // hFile, directory
std::set<std::string> cppFiles; std::set<std::string> cppFiles;
if(flags & FLAG_SIMPLE) if (flags & FLAG_SIMPLE)
Utils::GetCppFiles(conf, cppFiles); Utils::GetCppFiles(conf, cppFiles);
else else
Utils::GetCppAndHFiles(conf, hFiles, cppFiles); Utils::GetCppAndHFiles(conf, hFiles, cppFiles);
std::ofstream outputFile(conf.GetConfigPath()+ "Makefile"); std::ofstream outputFile(conf.GetConfigPath() / "Makefile");
outputFile << "# This Makefile was generated using MakeGen "<< MAKEGEN_VERSION << " made by Tim Håkansson" << std::endl; outputFile << "# This Makefile was generated using MakeGen " << MAKEGEN_VERSION << " made by Tim Håkansson"
<< std::endl;
outputFile << "# and is licensed under MIT. Full source of the project can be found at" << std::endl; outputFile << "# and is licensed under MIT. Full source of the project can be found at" << std::endl;
outputFile << "# https://github.com/Thraix/MakeGen" << std::endl; outputFile << "# https://gitea.timha.se/Thraix/MakeGen" << std::endl;
outputFile << "CC=@g++" << std::endl; outputFile << "CC=@g++" << std::endl;
std::string outputtype = conf.GetSettingString(ConfigSetting::OutputType); std::string outputtype = conf.GetOutputType();
if(outputtype != "executable") if (outputtype != "executable")
{ {
if(outputtype == "sharedlibrary") if (outputtype == "sharedlibrary")
outputFile << "CO=@g++ -shared -o" << std::endl; outputFile << "CO=@g++ -shared -o" << std::endl;
else else
outputFile << "CO=@g++ -o" << std::endl; outputFile << "CO=@g++ -o" << std::endl;
@@ -32,111 +34,127 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags)
outputFile << "CO=@g++ -o" << std::endl; outputFile << "CO=@g++ -o" << std::endl;
outputFile << "MKDIR_P=mkdir -p" << std::endl; outputFile << "MKDIR_P=mkdir -p" << std::endl;
outputFile << "BIN=" << conf.GetSettingString(ConfigSetting::OutputDir) << std::endl; outputFile << "BIN=" << conf.GetOutputDir() << std::endl;
outputFile << "OBJPATH=$(BIN)intermediates" << std::endl; outputFile << "OBJPATH=$(BIN)intermediates" << std::endl;
outputFile << "INCLUDES="; outputFile << "INCLUDES=";
std::vector<std::string>& includedirs = conf.GetSettingVectorString(ConfigSetting::IncludeDir); const std::vector<std::string>& includeDirs = conf.GetIncludeDirs();
for(auto it = includedirs.begin(); it != includedirs.end(); ++it) for (const auto& includeDir : includeDirs)
{ {
outputFile << "-I " << *it << " "; outputFile << "-I " << includeDir << " ";
}
const std::vector<std::string>& includeDirExclDeps = conf.GetIncludeDirExclDeps();
for (const auto& includeDirExclDep : includeDirExclDeps)
{
outputFile << "-I " << includeDirExclDep << " ";
} }
outputFile << std::endl; outputFile << std::endl;
outputFile << "OBJECTS="; 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("."); std::filesystem::path cppFile(*it);
size_t slash = it->find_last_of("/")+1; std::filesystem::path oFile = cppFile.replace_extension("o");
outputFile << "$(OBJPATH)/" << it->substr(slash, extensionPos - slash) << ".o "; std::string oFileStr = oFile.string();
Utils::Replace(oFileStr, "..", "dotdot");
outputFile << "$(OBJPATH)/" << oFileStr << " ";
} }
outputFile << std::endl; outputFile << std::endl;
if(outputtype == "executable" || outputtype != "sharedlibrary") if (outputtype == "executable" || outputtype != "sharedlibrary")
{ {
outputFile << "CFLAGS=$(INCLUDES) -std=c++17 -c "; outputFile << "CFLAGS=$(INCLUDES) -std=" + conf.GetCppVersion() + " -c ";
} }
else else
{ {
outputFile << "CFLAGS=$(INCLUDES) -fPIC -std=c++17 -c "; outputFile << "CFLAGS=$(INCLUDES) -fPIC -std=" + conf.GetCppVersion() + " -c ";
} }
std::vector<std::string>& defines = conf.GetSettingVectorString(ConfigSetting::Define); const std::vector<std::string>& defines = conf.GetDefines();
for(auto it = defines.begin(); it != defines.end(); ++it) for (const auto& define : defines)
{ {
outputFile << "-D" << *it << " "; outputFile << "-D" << define << " ";
} }
std::vector<std::string>& cflags = conf.GetSettingVectorString(ConfigSetting::CFlag); const std::vector<std::string>& cFlags = conf.GetCFlags();
for(auto it = cflags.begin(); it != cflags.end(); ++it) for (const auto& cFlag : cFlags)
{ {
outputFile << *it << " "; outputFile << cFlag << " ";
} }
outputFile << std::endl; outputFile << std::endl;
if(outputtype == "executable") if (outputtype == "executable")
{ {
std::vector<std::string>& libdirs= conf.GetSettingVectorString(ConfigSetting::LibraryDir); const std::vector<std::string>& libraryDirs = conf.GetLibraryDirs();
outputFile << "LIBDIR="; outputFile << "LIBDIR=";
for(auto it = libdirs.begin();it!=libdirs.end();++it) for (const auto& libraryDir : libraryDirs)
{ {
outputFile << "-L " << *it << " "; outputFile << "-L " << libraryDir << " ";
} }
outputFile << std::endl; outputFile << std::endl;
std::vector<std::string>& lflags = conf.GetSettingVectorString(ConfigSetting::LFlag); const std::vector<std::string>& lFlags = conf.GetLFlags();
outputFile << "LDFLAGS="; outputFile << "LDFLAGS=";
for(auto it = lflags.begin(); it != lflags.end(); ++it) for (const auto& lFlag : lFlags)
{ {
outputFile << *it << " "; outputFile << lFlag << " ";
} }
for(auto it = libdirs.begin(); it != libdirs.end(); ++it) for (const auto& libraryDir : libraryDirs)
{ {
outputFile << "-Wl,-rpath=" << *it << " "; outputFile << "-Wl,-rpath=" << libraryDir << " ";
} }
outputFile << std::endl; outputFile << std::endl;
std::vector<std::string>& libs = conf.GetSettingVectorString(ConfigSetting::Library); const std::vector<std::string>& libraries = conf.GetLibraries();
outputFile << "LIBS=$(LIBDIR) "; outputFile << "LIBS=$(LIBDIR) ";
for(auto it = libs.begin(); it != libs.end(); ++it) for (const auto& library : libraries)
{ {
outputFile << "-l" << *it << " "; outputFile << "-l" << library << " ";
} }
outputFile << std::endl; outputFile << std::endl;
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency); const std::vector<Dependency>& dependencies = conf.GetDependencies();
if(!dependencies.empty()) if (!dependencies.empty())
{ {
outputFile << "DEPENDENCIES="; outputFile << "DEPENDENCIES=";
for(auto it = dependencies.begin();it!=dependencies.end();++it) for (const auto& [path, target] : dependencies)
{ {
outputFile << *it << " "; outputFile << path << " ";
} }
outputFile << std::endl; outputFile << std::endl;
} }
} }
outputFile << "OUTPUT=$(BIN)" << conf.GetSettingString(ConfigSetting::OutputName) << std::endl; outputFile << "OUTPUT=$(BIN)" << conf.GetOutputName() << std::endl;
outputFile << ".PHONY: all directories rebuild clean run" << std::endl; outputFile << ".PHONY: all directories rebuild clean run" << std::endl;
// All // All
outputFile << "all: directories $(OUTPUT)" << std::endl; outputFile << "all: directories $(OUTPUT)" << std::endl;
// Directories // 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 // Intermediate directories
outputFile << "$(BIN):" << std::endl; for (const auto& intermediateDirectory : intermediateDirectories)
outputFile << "\t$(info Creating output directories)" << std::endl; {
outputFile << "\t@$(MKDIR_P) $(BIN)" << std::endl; outputFile << intermediateDirectory << ":" << std::endl;
outputFile << "\t@$(MKDIR_P) $@" << std::endl;
// Object path }
outputFile << "$(OBJPATH):" << std::endl;
outputFile << "\t@$(MKDIR_P) $(OBJPATH)" << std::endl;
// Run // Run
outputFile << "run: all" << std::endl; outputFile << "run: all" << std::endl;
if(outputtype == "executable") if (outputtype == "executable")
{ {
std::vector<std::string>& prearguments = conf.GetSettingVectorString(ConfigSetting::ExecPreArgument); const std::vector<std::string>& prearguments = conf.GetPreArguments();
std::vector<std::string>& arguments = conf.GetSettingVectorString(ConfigSetting::ExecArgument); const std::vector<std::string>& arguments = conf.GetArguments();
outputFile << "\t@"; outputFile << "\t@";
for(auto&& preargument : prearguments) for (const auto& preargument : prearguments)
{
outputFile << preargument << " "; outputFile << preargument << " ";
}
outputFile << "./$(OUTPUT)"; outputFile << "./$(OUTPUT)";
for(auto&& argument : arguments) for (const auto& argument : arguments)
{
outputFile << " " << argument; outputFile << " " << argument;
}
outputFile << std::endl; outputFile << std::endl;
} }
@@ -145,41 +163,61 @@ void Makefile::Save(ConfigFile& conf, unsigned int flags)
// Clean // Clean
outputFile << "clean:" << std::endl; outputFile << "clean:" << std::endl;
outputFile << "\t$(info Removing intermediates)" << std::endl; outputFile << "\t$(info Removing $(OBJPATH) and $(OUTPUT))" << std::endl;
outputFile << "\trm -rf $(OBJPATH)/*.o" << std::endl; outputFile << "\t@rm -rf $(OBJPATH)/ $(OUTPUT)" << std::endl;
// Output file // Output file
outputFile << "$(OUTPUT): $(OBJECTS)" << std::endl; outputFile << "$(OUTPUT): $(OBJECTS)" << std::endl;
outputFile << "\t$(info Generating output file)" << std::endl; outputFile << "\t$(info Generating output file $(OUTPUT))" << std::endl;
if(outputtype == "executable") if (outputtype == "executable")
outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS) $(LDFLAGS) $(LIBS)" << std::endl; outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS) $(LDFLAGS) $(LIBS)" << std::endl;
else else
outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS)" << std::endl; outputFile << "\t$(CO) $(OUTPUT) $(OBJECTS)" << std::endl;
// Install // Install
outputFile << "install: all" << std::endl; outputFile << "install: all" << std::endl;
outputFile << "\t$(info Installing " << conf.GetSettingString(ConfigSetting::ProjectName) <<" to /usr/bin/)" << std::endl; outputFile << "\t$(info Installing " << conf.GetProjectName() << " to /usr/bin/)" << std::endl;
outputFile << "\t@cp $(OUTPUT) /usr/bin/" << conf.GetSettingString(ConfigSetting::OutputName) << std::endl; outputFile << "\t@cp $(OUTPUT) /usr/bin/" << conf.GetOutputName() << std::endl;
std::map<std::string, IncludeDeps*> dependencies; std::map<std::string, IncludeDeps*> dependencies;
size_t i = 0; size_t i = 0;
for(auto it = cppFiles.begin(); it != cppFiles.end();++it) for (auto it = cppFiles.begin(); it != cppFiles.end(); ++it)
{ {
i++; i++;
std::string& srcdir = conf.GetSettingString(ConfigSetting::SourceDir); auto itD = dependencies.find(*it);
auto itD = dependencies.find(srcdir + *it); if (itD == dependencies.end())
if(itD == dependencies.end())
{ {
IncludeDeps* deps = new IncludeDeps(*it, conf.GetConfigPath() + srcdir,hFiles,dependencies); std::filesystem::path cppFile(*it);
size_t extensionPos = it->find_last_of("."); std::filesystem::path oFile = cppFile.replace_extension("o");
size_t slash = it->find_last_of("/")+1; std::string oFileStr = oFile.string();
std::string oFile = it->substr(slash, extensionPos - slash)+".o "; Utils::Replace(oFileStr, "..", "dotdot");
outputFile << "$(OBJPATH)/" << oFileStr << ":";
outputFile << "$(OBJPATH)/" << oFile << ": "; if (flags & FLAG_SIMPLE)
deps->Output(outputFile, conf); {
outputFile << std::endl; outputFile << " " << *it << " makegen.xml" << std::endl;
}
else
{
IncludeDeps* deps = new IncludeDeps(*it, hFiles, dependencies);
deps->Output(outputFile, conf);
outputFile << " makegen.xml" << std::endl;
}
outputFile << "\t$(info -[" << (int)(i / (float)cppFiles.size() * 100) << "%]- $<)" << std::endl; outputFile << "\t$(info -[" << (int)(i / (float)cppFiles.size() * 100) << "%]- $<)" << std::endl;
outputFile << "\t$(CC) $(CFLAGS) -o $@ $<" << 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 class Makefile
{ {
public: public:
static void Save(ConfigFile& conf, unsigned int flags); 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 class Timer
{ {
private: private:
std::chrono::time_point<std::chrono::high_resolution_clock> m_start; std::chrono::time_point<std::chrono::high_resolution_clock> m_start;
public:
Timer(){
Reset();
}
void Reset() public:
{ Timer()
m_start = std::chrono::high_resolution_clock::now(); {
} Reset();
}
float Elapsed() void Reset()
{ {
return std::chrono::duration_cast<std::chrono::duration<float,std::milli>>(std::chrono::high_resolution_clock::now() - m_start).count() / 1000.0f; 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;
}
}; };
+127 -50
View File
@@ -1,5 +1,7 @@
#include "Utils.h" #include "Utils.h"
#include <filesystem>
#include "ConfigFile.h" #include "ConfigFile.h"
#include "FileUtils.h" #include "FileUtils.h"
@@ -8,7 +10,7 @@ bool Utils::IsSourceFile(const std::string& filepath)
std::string_view extension(filepath); std::string_view extension(filepath);
size_t pSlash = filepath.find_last_of('/'); size_t pSlash = filepath.find_last_of('/');
size_t pDot = 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); LOG_ERROR("No file extension for file: ", filepath);
return false; return false;
@@ -22,21 +24,41 @@ bool Utils::IsHeaderFile(const std::string& filepath)
std::string_view extension(filepath); std::string_view extension(filepath);
size_t pSlash = filepath.find_last_of('/'); size_t pSlash = filepath.find_last_of('/');
size_t pDot = 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; return false;
} }
extension.remove_prefix(pDot + 1); extension.remove_prefix(pDot + 1);
return extension == "hpp" || extension == "h" || extension == "hxx"; 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) std::string Utils::CommonPrefix(const std::string& s1, const std::string& s2)
{ {
size_t n = 0; 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; n = i;
break; break;
@@ -48,20 +70,30 @@ std::string Utils::CommonPrefix(const std::string& s1, const std::string& s2)
void Utils::GetCppFiles(ConfigFile& conf, std::set<std::string>& cppFiles) void Utils::GetCppFiles(ConfigFile& conf, std::set<std::string>& cppFiles)
{ {
std::vector<std::string> files; std::vector<std::string> files;
std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir); const std::optional<std::string>& sourceDir = conf.GetSourceDir();
FileUtils::GetAllFiles(path, files); if (sourceDir.has_value())
const std::vector<std::string>& excludeSources = conf.GetSettingVectorString(ConfigSetting::ExcludeSource);
for(auto it = files.begin(); it!=files.end();++it)
{ {
std::string filename = it->substr(path.length()); FileUtils::GetAllFiles(conf.GetConfigPath() / sourceDir.value(), files);
if(IsSourceFile(filename)) }
const std::vector<std::string>& excludeSources = conf.GetExcludeSources();
for (const auto& sourceFile : conf.GetSourceFiles())
{
if (FileUtils::FileExists(conf.GetConfigPath() / sourceFile))
cppFiles.emplace(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(), filename);
auto it = std::find(excludeSources.begin(), excludeSources.end(), sourceFile); if (it == excludeSources.end())
if(it == excludeSources.end())
{ {
cppFiles.emplace(filename); cppFiles.emplace(filepath.string());
} }
} }
} }
@@ -69,60 +101,105 @@ void Utils::GetCppFiles(ConfigFile& conf, std::set<std::string>& cppFiles)
void Utils::GetCppAndHFiles(ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles) void Utils::GetCppAndHFiles(ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles)
{ {
std::vector<std::string> files; const std::vector<std::string>& excludeSources = conf.GetExcludeSources();
std::string path = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::SourceDir); for (const auto& sourceFile : conf.GetSourceFiles())
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 filename = it->substr(path.length()); if (FileUtils::FileExists(conf.GetConfigPath() / sourceFile))
if(IsSourceFile(filename)) cppFiles.emplace(sourceFile);
{ else
std::string sourceFile =conf.GetSettingString(ConfigSetting::SourceDir) + filename; LOG_WARNING("Source file doesn't exist: ", sourceFile);
auto it = std::find(excludeSources.begin(), excludeSources.end(), sourceFile);
if(it == excludeSources.end())
{
cppFiles.emplace(filename);
}
}
else if(IsHeaderFile(filename))
{
hFiles.emplace(HFile{filename,path,false});
}
} }
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency); const std::optional<std::string>& sourceDir = conf.GetSourceDir();
for(size_t i = 0; i < dependencies.size(); ++i) if (sourceDir.has_value())
{ {
GetHFiles(dependencies[i], conf.GetDependencyConfig(i), hFiles); std::vector<std::string> files;
FileUtils::GetAllFiles(conf.GetConfigPath() / sourceDir.value(), files);
for (const auto& filename : files)
{
if (IsSourceFile(filename))
{
std::filesystem::path filepath = std::filesystem::relative(filename, "./");
auto it = std::find(excludeSources.begin(), excludeSources.end(), filepath.string());
if (it == excludeSources.end())
{
cppFiles.emplace(filepath.string());
}
}
else if (IsHeaderFile(filename))
{
std::filesystem::path path = std::filesystem::relative(filename, sourceDir.value());
hFiles.emplace(HFile{path.string(), sourceDir.value(), false});
}
}
for (const auto& includePath : conf.GetIncludeDirs())
{
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});
}
}
}
}
const std::vector<Dependency>& dependencies = conf.GetDependencies();
for (size_t i = 0; i < dependencies.size(); ++i)
{
GetHFiles(conf.GetDependencyConfig(dependencies[i].path), hFiles);
} }
} }
void Utils::GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::set<HFile>& hFiles) void Utils::GetHFiles(ConfigFile& conf, std::set<HFile>& hFiles)
{ {
// TODO: Fix so that cyclic dependencies doesn't crash the tool. // TODO: Fix so that cyclic dependencies doesn't crash the tool.
// Cyclic dependencies probably shouldn't exist. // Cyclic dependencies probably shouldn't exist.
// so just warn the user that it does and terminate. // so just warn the user that it does and terminate.
std::vector<std::string>& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency); const std::vector<Dependency>& dependencies = conf.GetDependencies();
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); std::filesystem::path dependencyConfigPath =
std::filesystem::canonical(conf.GetConfigPath() / dependencies[i].path);
GetHFiles(conf.GetDependencyConfig(dependencyConfigPath), hFiles);
}
const std::optional<std::string>& sourceDir = conf.GetSourceDir();
if (!sourceDir.has_value())
{
return;
} }
std::vector<std::string> files; std::vector<std::string> files;
std::string depSrcDir = dependencyDir + conf.GetSettingString(ConfigSetting::SourceDir); std::string depSrcDir = conf.GetConfigPath() / sourceDir.value();
FileUtils::GetAllFiles(depSrcDir, files); FileUtils::GetAllFiles(depSrcDir, files);
for(auto it = files.begin(); it!=files.end();++it) for (auto it = files.begin(); it != files.end(); ++it)
{ {
if(IsHeaderFile(*it)) if (IsHeaderFile(*it))
{ {
std::string filename = it->substr(depSrcDir.length()); 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.GetHFileName() && !it->isProjectHFile)
{
HFile hfile = *it;
hfile.isProjectHFile = true;
hFiles.erase(it);
hFiles.emplace(hfile);
}
}
else
{
hFiles.emplace(HFile{filename, depSrcDir, conf.IsGenerateHFile() && filename == conf.GetHFileName()});
}
} }
} }
} }
bool Utils::IsWhiteSpace(char c) bool Utils::IsWhiteSpace(char c)
{ {
return c == '\n' || c == '\t' || c == '\r' || c == ' ' || c == '\t'; return c == '\n' || c == '\t' || c == '\r' || c == ' ' || c == '\t';
@@ -135,9 +212,9 @@ bool Utils::IsLetter(char c)
bool Utils::IsWord(const std::string& string) 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 false;
} }
return true; return true;
+18 -6
View File
@@ -1,25 +1,33 @@
#pragma once #pragma once
#include <filesystem>
#include <iostream>
#include <set> #include <set>
#include <string> #include <string>
struct HFile struct HFile
{ {
std::string filename; std::string filename;
std::string directory;
bool isProjectHFile; bool isProjectHFile;
std::string filepath; std::filesystem::path filepath;
HFile(const std::string& filename, const std::string& directory, bool isProjectHFile) 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) friend bool operator<(const HFile& h1, const HFile& h2)
{ {
return h1.filename < h2.filename; 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; class ConfigFile;
@@ -28,10 +36,14 @@ struct Utils
{ {
static bool IsSourceFile(const std::string& filepath); static bool IsSourceFile(const std::string& filepath);
static bool IsHeaderFile(const std::string& filepath); static bool IsHeaderFile(const std::string& filepath);
static std::string CommonPrefix(const std::string& s1, const std::string& s2); static std::string CommonPrefix(const std::string& s1, const std::string& s2);
static 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 GetCppFiles(ConfigFile& conf, std::set<std::string>& cppFiles);
static void GetCppAndHFiles(ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles); static void GetCppAndHFiles(ConfigFile& conf, std::set<HFile>& hFiles, std::set<std::string>& cppFiles);
static void GetHFiles(const std::string& dependencyDir, ConfigFile& conf, std::set<HFile>& hFiles); static void GetHFiles(ConfigFile& conf, std::set<HFile>& hFiles);
// Used for parsing xml // Used for parsing xml
static bool IsWhiteSpace(char c); static bool IsWhiteSpace(char c);
+59 -58
View File
@@ -2,41 +2,43 @@
const std::string CONFIG_FILENAME_CONF = "makegen.conf"; const std::string CONFIG_FILENAME_CONF = "makegen.conf";
#include "../ConfigFile.h"
#include "../FileUtils.h"
#include <algorithm> #include <algorithm>
#include <filesystem>
#include <fstream> #include <fstream>
#include "../Common.h"
#include "../xml/XMLObject.h"
#define FLAG_NONE 0 #define FLAG_NONE 0
#define FLAG_VECTOR 1 #define FLAG_VECTOR 1
#define FLAG_STRING 2 #define FLAG_STRING 2
#define FLAG_BOOL 3 #define FLAG_BOOL 3
ConfigFileConf::ConfigFileConf() ConfigFileConf::ConfigFileConf()
: outputdir("bin/"), srcdir("src/"), outputname(""), projectname(FileUtils::GetCurrentDirectory()), hFile(""), executable(true), shared(true), generateHFile(false) : outputdir("bin/Release"),
srcdir("src/"),
outputname(""),
projectname(std::filesystem::current_path().filename()),
hFile(""),
executable(true),
shared(true),
generateHFile(false)
{ {
// Converts project name (current directory) to lowercase // Converts project name (current directory) to lowercase
// and replace whitespace with underscore // and replace whitespace with underscore
std::transform( std::transform(projectname.begin(),
projectname.begin(), projectname.end(),
projectname.end(), std::back_inserter(outputname),
std::back_inserter(outputname), [](unsigned char c)
[](unsigned char c) {
{ if (c == ' ')
if(c == ' ') return '_';
return '_'; return (char)std::tolower(c);
return (char)std::tolower(c); });
});
// Removes all other characters // Removes all other characters
std::remove_if( outputdir.erase(std::remove_if(
outputdir.begin(), outputdir.begin(), outputdir.end(), [](unsigned char c) { return (c < 'a' || c > 'z') && c != '_'; }));
outputdir.end(),
[](unsigned char c)
{
return (c < 'a' || c > 'z') && c != '_';
});
// Add suffix // Add suffix
outputname += ".out"; outputname += ".out";
@@ -57,11 +59,10 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
std::ifstream file(filepath + CONFIG_FILENAME_CONF); std::ifstream file(filepath + CONFIG_FILENAME_CONF);
std::string line; std::string line;
if(file.is_open()) if (file.is_open())
{ {
// config name, { pointer to memory, isDirectory} // 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}}, {"#srcdir", {&conf.srcdir, true}},
{"#outputdir", {&conf.outputdir, true}}, {"#outputdir", {&conf.outputdir, true}},
{"#outputname", {&conf.outputname, false}}, {"#outputname", {&conf.outputname, false}},
@@ -70,33 +71,32 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
}; };
// config name, { pointer to memory, isDirectory} // 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}}, {"#libs", {&conf.libs, false}},
{"#libdirs", {&conf.libdirs, true}}, {"#libdirs", {&conf.libdirs, true}},
{"#includedirs", {&conf.includedirs, true}}, {"#includedirs", {&conf.includedirs, true}},
{"#compileflags", {&conf.flags, false}}, {"#compileflags", {&conf.flags, false}},
{"#defines", {&conf.defines, false}}, {"#defines", {&conf.defines, false}},
{"#dependencies", {&conf.dependencies, true}}, {"#dependencies", {&conf.dependencies, true}},
{"#sourcefiles", {&conf.sourceFiles, false}},
}; };
std::map<std::string, bool*> booleans = std::map<std::string, bool*> booleans = {
{
{"#executable", &conf.executable}, {"#executable", &conf.executable},
{"#shared", &conf.shared}, {"#shared", &conf.shared},
{"#generatehfile", &conf.generateHFile}, {"#generatehfile", &conf.generateHFile},
}; };
while(std::getline(file,line)) while (std::getline(file, line))
{ {
if(line == "") if (line == "")
continue; continue;
if(line[0]=='#') if (line[0] == '#')
{ {
// The format is a bit wacky, but it is this way since we do not want // 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. // to use map::find for all maps. This way we gain some optimization.
auto&& itStr{strings.find(line)}; auto&& itStr{strings.find(line)};
if(itStr != strings.end()) if (itStr != strings.end())
{ {
s = itStr->second.first; s = itStr->second.first;
isDirectory = itStr->second.second; isDirectory = itStr->second.second;
@@ -105,7 +105,7 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
else else
{ {
auto&& itVec{vectors.find(line)}; auto&& itVec{vectors.find(line)};
if(itVec != vectors.end()) if (itVec != vectors.end())
{ {
vec = itVec->second.first; vec = itVec->second.first;
isDirectory = itVec->second.second; isDirectory = itVec->second.second;
@@ -114,7 +114,7 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
else else
{ {
auto&& itBool{booleans.find(line)}; auto&& itBool{booleans.find(line)};
if(itBool != booleans.end()) if (itBool != booleans.end())
{ {
b = itBool->second; b = itBool->second;
loadFlag = FLAG_BOOL; loadFlag = FLAG_BOOL;
@@ -129,23 +129,24 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
} }
else else
{ {
if(loadFlag == FLAG_STRING) if (loadFlag == FLAG_STRING)
{ {
if(isDirectory && line[line.size()-1] != '/') if (isDirectory && line[line.size() - 1] != '/')
line += '/'; line += '/';
*s = 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 += '/'; line += '/';
} }
vec->push_back(line); vec->push_back(line);
} }
else if(loadFlag == FLAG_BOOL) else if (loadFlag == FLAG_BOOL)
{ {
if(line == "true") if (line == "true")
*b = true; *b = true;
else else
*b = false; *b = false;
@@ -155,13 +156,13 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
LOG_INFO("------ COULDN\'T FIND makegen.xml. BUT FOUND OLD makegen.conf."); LOG_INFO("------ COULDN\'T FIND makegen.xml. BUT FOUND OLD makegen.conf.");
LOG_INFO("------ GENERATING NEW CONFIGURATION FILE"); LOG_INFO("------ GENERATING NEW CONFIGURATION FILE");
if(conf.hFile == "") if (conf.hFile == "")
conf.hFile = conf.projectname+".h"; conf.hFile = conf.projectname + ".h";
XMLObject makegen("makegen", {}, std::map<std::string, std::vector<XMLObject>>{}); XMLObject makegen("makegen", {}, std::map<std::string, std::vector<XMLObject>>{});
// Version, target and configuration is probably going to be used in the future // Version, target and configuration is probably going to be used in the future
makegen.AddXMLObject(XMLObject("version", {}, "v1.3.0")); makegen.AddXMLObject(XMLObject("version", {}, MAKEGEN_VERSION));
makegen.AddXMLObject(XMLObject("target", {}, "Release")); makegen.AddXMLObject(XMLObject("target", {}, "Release"));
XMLObject configuration("configuration", {{"name", "Release"}}, std::map<std::string, std::vector<XMLObject>>{}); XMLObject configuration("configuration", {{"name", "Release"}}, std::map<std::string, std::vector<XMLObject>>{});
@@ -170,22 +171,22 @@ void ConfigFileConf::CreateXMLFile(const std::string& filepath)
configuration.AddXMLObject(XMLObject("srcdir", {}, conf.srcdir)); configuration.AddXMLObject(XMLObject("srcdir", {}, conf.srcdir));
configuration.AddXMLObject(XMLObject("outputdir", {}, conf.outputdir)); configuration.AddXMLObject(XMLObject("outputdir", {}, conf.outputdir));
configuration.AddXMLObject(XMLObject("hfilename", {}, conf.hFile)); configuration.AddXMLObject(XMLObject("hfilename", {}, conf.hFile));
configuration.AddXMLObject(XMLObject("outputtype", {}, configuration.AddXMLObject(
conf.executable ? "executable" : (conf.shared ? "sharedlibrary" : "staticlibrary"))); XMLObject("outputtype", {}, conf.executable ? "executable" : (conf.shared ? "sharedlibrary" : "staticlibrary")));
configuration.AddXMLObject(XMLObject("generatehfile", {}, conf.generateHFile ? "true" : "false")); configuration.AddXMLObject(XMLObject("generatehfile", {}, conf.generateHFile ? "true" : "false"));
for(auto it = conf.libs.begin();it != conf.libs.end(); ++it) for (auto it = conf.libs.begin(); it != conf.libs.end(); ++it) configuration.AddXMLObject({"library", {}, *it});
configuration.AddXMLObject({"library",{},*it}); for (auto it = conf.libdirs.begin(); it != conf.libdirs.end(); ++it)
for(auto it = conf.libdirs.begin();it != conf.libdirs.end(); ++it) configuration.AddXMLObject({"librarydir", {}, *it});
configuration.AddXMLObject({"librarydir",{},*it}); for (auto it = conf.includedirs.begin(); it != conf.includedirs.end(); ++it)
for(auto it = conf.includedirs.begin();it != conf.includedirs.end(); ++it) configuration.AddXMLObject({"includedir", {}, *it});
configuration.AddXMLObject({"includedir",{},*it}); for (auto it = conf.defines.begin(); it != conf.defines.end(); ++it)
for(auto it = conf.defines.begin();it != conf.defines.end(); ++it) configuration.AddXMLObject({"define", {}, *it});
configuration.AddXMLObject({"define",{},*it}); for (auto it = conf.flags.begin(); it != conf.flags.end(); ++it) configuration.AddXMLObject({"cflag", {}, *it});
for(auto it = conf.flags.begin();it != conf.flags.end(); ++it) for (auto it = conf.dependencies.begin(); it != conf.dependencies.end(); ++it)
configuration.AddXMLObject({"cflag",{},*it}); configuration.AddXMLObject({"dependency", {}, *it});
for(auto it = conf.dependencies.begin();it != conf.dependencies.end(); ++it) for (auto it = conf.sourceFiles.begin(); it != conf.sourceFiles.end(); ++it)
configuration.AddXMLObject({"dependency",{},*it}); configuration.AddXMLObject({"sourcefile", {}, *it});
makegen.AddXMLObject(configuration); makegen.AddXMLObject(configuration);
std::ofstream xmlFile(conf.configPath + "makegen.xml"); std::ofstream xmlFile(conf.configPath + "makegen.xml");
+23 -20
View File
@@ -9,26 +9,29 @@ class ConfigFile;
class ConfigFileConf class ConfigFileConf
{ {
public: public:
std::string configPath; std::string configPath;
std::vector<std::string> libs; std::vector<std::string> libs;
std::vector<std::string> libdirs; std::vector<std::string> libdirs;
std::vector<std::string> includedirs; std::vector<std::string> includedirs;
std::vector<std::string> defines; std::vector<std::string> defines;
std::vector<std::string> flags; std::vector<std::string> flags;
std::vector<std::string> dependencies; std::vector<std::string> dependencies;
std::vector<std::string> sourceFiles;
std::string outputdir; std::string outputdir;
std::string srcdir; std::string srcdir;
std::string outputname; std::string outputname;
std::string projectname; std::string projectname;
std::string hFile; std::string hFile;
bool executable; bool executable;
bool shared; bool shared;
bool generateHFile; bool generateHFile;
public:
ConfigFileConf();
static void CreateXMLFile(const std::string& filename); public:
private: ConfigFileConf();
static void CreateXMLFile(const std::string& filename);
private:
}; };
Executable → Regular
+138 -94
View File
@@ -1,22 +1,27 @@
#include <string.h>
#include <cmath>
#include <filesystem>
#include <thread>
#include "Common.h" #include "Common.h"
#include "CompileFlags.h"
#include "ConfigCLI.h" #include "ConfigCLI.h"
#include "ConfigFile.h" #include "ConfigFile.h"
#include "FileUtils.h" #include "FlagData.h"
#include "HFileGen.h" #include "HFileGen.h"
#include "Makefile.h" #include "Makefile.h"
#include "Timer.h" #include "Timer.h"
#include "Utils.h"
#include <cmath>
#include <thread>
#define RETURN_IF(x, b) \ #define RETURN_IF(x, b) \
if(x)\ if (x) \
return b; return b;
void PrintHelp() void PrintHelp()
{ {
LOG_INFO("MakeGen ", MAKEGEN_VERSION); 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. MakeGen is a utility tool to generate and run Makefiles in a simple manner.
By default it always compiles code with parallell jobs. By default it always compiles code with parallell jobs.
@@ -24,175 +29,214 @@ By default it always compiles code with parallell jobs.
Usage: makegen [options] Usage: makegen [options]
Options: Options:
-h, --help Displays this information -h, --help Displays this information
-v, --version Displays the version of this program -v, --version Displays the version of this program
-m,-a, make, all Generates a Makefile and runs -m,-a, make, all Generates a Makefile and runs
make all make all
-i, install Generates a Makefile and runs -i, install Generates a Makefile and runs
make all && make install make all && make install
-c, clean Generates a Makefile and runs -c, clean Generates a Makefile and runs
make clean make clean
-r, rebuild Generates a Makefile and runs -r, rebuild Generates a Makefile and runs
make clean && make all make clean && make all
-e, run, execute Generates a Makefile and runs -e, run, execute Generates a Makefile and runs
make all && make run make all && make run
-s, single Runs additional makegen options as single thread -s, single Runs additional makegen options as single thread
(no --jobs=X flag) (no --jobs=X flag)
--simple Creates a simple Makefile without include dependencies --simple Creates a simple Makefile without include dependencies
(no --jobs=X flag) --target=<target> Run the makegen.xml file with the specified target
gcf, generate-compile-flags
Generates a Makefile and runs
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: 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) void GenMakefile(ConfigFile& conf, unsigned int flags)
{ {
if(conf.GetSettingBool(ConfigSetting::GenerateHFile)) if (conf.IsGenerateHFile())
HFileGen::Create(conf); HFileGen::Create(conf);
Makefile::Save(conf, flags); 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") if (argc >= 2 && std::string(argv[1]) == "conf")
return FLAG_CONFIG; return FlagData{FLAG_CONFIG};
unsigned int flags = 0; FlagData flagData{};
bool make = true; 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]); 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; 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; flagData.flags |= FLAG_CLEAN;
flags |= FLAG_MAKE; 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 == "gcf" || flag == "generate-compile-flags")
{ {
flags |= FLAG_SIMPLE; flagData.flags |= FLAG_GEN_COMP_FLAGS;
} }
else if(flag != "") else if (flag == "--simple")
{
flagData.flags |= FLAG_SIMPLE;
}
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); LOG_ERROR("Unknown argument ", flag);
return FLAG_HELP; return FlagData{FLAG_HELP};
} }
} }
} }
if(make) if (make)
flags |= FLAG_MAKE; flagData.flags |= FLAG_MAKE;
return flags; return flagData;
} }
bool RunMake(const std::string& filepath, unsigned int flags, ConfigFile& conf) bool RunMake(const std::string& filepath, unsigned int flags, ConfigFile& conf)
{ {
std::string make = "make --no-print-directory -C " + filepath; std::string make = "make --no-print-directory -C " + filepath;
if(!(flags & FLAG_SINGLE_THREAD)) if (!(flags & FLAG_SINGLE_THREAD))
make += " -j" + std::to_string(std::thread::hardware_concurrency()) + " "; 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); 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); 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); RETURN_IF(system(std::string(make + " install").c_str()) != 0, false);
} }
if(flags & FLAG_RUN && conf.GetSettingString(ConfigSetting::OutputType) == "executable") if (flags & FLAG_RUN && conf.GetOutputType() == "executable")
{ {
RETURN_IF(system(std::string(make + " run").c_str()) != 0, false); RETURN_IF(system(std::string(make + " run").c_str()) != 0, false);
} }
return true; 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); const std::vector<Dependency>& dependencies = conf.GetDependencies();
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)); std::filesystem::path currentPath = std::filesystem::current_path();
if(!success) std::filesystem::current_path(dependencies[i].path);
return success; FlagData dependencyFlagData = flagData;
dependencyFlagData.target = dependencies[i].target;
std::optional<ConfigFile> conf = ConfigFile::GetConfigFile("./", dependencyFlagData);
if (conf)
{
bool success = MakeGen("./", dependencyFlagData, conf.value());
if (!success)
{
std::filesystem::current_path(currentPath);
return success;
}
}
std::filesystem::current_path(currentPath);
} }
LOG_INFO("-----------------------------------"); LOG_INFO("-----------------------------------");
LOG_INFO("Building ", conf.GetSettingString(ConfigSetting::ProjectName)); LOG_INFO("Building ", conf.GetProjectName());
LOG_INFO("Generating Makefile..."); LOG_INFO("Generating Makefile...");
Timer timer; Timer timer;
GenMakefile(conf, flags); GenMakefile(conf, flagData.flags);
LOG_INFO("Took ", round(timer.Elapsed()*1000.0)/1000.0,"s"); LOG_INFO("Took ", round(timer.Elapsed() * 1000.0) / 1000.0, "s");
LOG_INFO("Running Makefile..."); LOG_INFO("Running Makefile...");
std::string outputPath = conf.GetConfigPath() + conf.GetSettingString(ConfigSetting::OutputDir); return RunMake(filepath, flagData.flags, conf);
if(!FileUtils::HasPath(outputPath))
{
FileUtils::CreateDirectory(outputPath);
std::string intermediatePath = outputPath + "intermediates";
if(!FileUtils::HasPath(intermediatePath ))
FileUtils::CreateDirectory(intermediatePath );
}
return RunMake(filepath, flags, conf);
} }
int main(int argc, char** argv) int Run(int argc, char** argv)
{ {
unsigned int flags = ReadFlags(argc,argv); FlagData flagData = ReadFlags(argc, argv);
if(flags & FLAG_HELP) if (flagData.flags & FLAG_HELP)
{ {
PrintHelp(); PrintHelp();
return 0; return 0;
} }
if(flags & FLAG_VERSION) if (flagData.flags & FLAG_VERSION)
{ {
LOG_INFO("MakeGen ",MAKEGEN_VERSION); LOG_INFO("MakeGen ", MAKEGEN_VERSION);
return 0; 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(); auto conf = ConfigFile::GetConfigFile("./", flagData);
if(conf) if (!conf.has_value())
{
bool success = MakeGen("./", flags, *conf);
return success ? 0 : 1;
}
else
{ {
LOG_ERROR("Couldn\'t load config file"); LOG_ERROR("Couldn\'t load config file");
return 1;
}
if (flagData.flags & FLAG_GEN_COMP_FLAGS)
{
CompileFlags::Save(conf.value());
return 0;
}
bool success = MakeGen("./", flagData, conf.value());
return success ? 0 : 1;
}
int main(int argc, char** argv)
{
try
{
return Run(argc, argv);
}
catch (const AssertException& exception)
{
return 1;
} }
} }
+9 -9
View File
@@ -1,28 +1,28 @@
#include "XML.h" #include "XML.h"
#include <algorithm>
#include <fstream>
#include "XMLException.h" #include "XMLException.h"
#include <fstream> XMLObject XML::FromString(const std::string& string, const std::string& filename = "")
#include <algorithm>
XMLObject XML::FromString(const std::string& string, const std::string& filename="")
{ {
int startLine = 1; int startLine = 1;
int startPos = 0; int startPos = 0;
// Remove version tag. // Remove version tag.
if(string.find("<?") != std::string::npos) if (string.find("<?") != std::string::npos)
{ {
startPos = string.find("?>") + 3; 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) XMLObject XML::FromFile(const std::string& filename)
{ {
std::ifstream file(filename, std::ios::binary | std::ios::ate); std::ifstream file(filename, std::ios::binary | std::ios::ate);
if(!file) if (!file)
throw XMLException("Could not read file \""+filename+"\""); throw XMLException("Could not read file \"" + filename + "\"");
std::streamsize size = file.tellg(); std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
std::string buffer; std::string buffer;
+19 -13
View File
@@ -1,22 +1,28 @@
#pragma once #pragma once
#include "XMLObject.h"
#include <exception> #include <exception>
#include <string> #include <string>
#include "XMLObject.h"
class XMLException : public std::exception class XMLException : public std::exception
{ {
private: private:
std::string m_message; 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)
{}
virtual const char* what() const throw() public:
{ explicit XMLException(const std::string& message)
return m_message.c_str(); : 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();
}
}; };
+84 -60
View File
@@ -1,9 +1,9 @@
#include "XMLObject.h" #include "XMLObject.h"
#include <cstring>
#include "../Common.h" #include "../Common.h"
#include "../Utils.h" #include "../Utils.h"
#include <cstring>
#include "XMLException.h" #include "XMLException.h"
XMLObject::XMLObject(const std::string& string) XMLObject::XMLObject(const std::string& string)
@@ -11,7 +11,7 @@ XMLObject::XMLObject(const std::string& string)
int pos = 0; int pos = 0;
int line = 1; int line = 1;
XMLLoadData data{pos, line, ""}; XMLLoadData data{pos, line, ""};
if(!ReadHead(string, data)) if (!ReadHead(string, data))
ReadBodyTail(string, data); ReadBodyTail(string, data);
} }
@@ -28,16 +28,22 @@ XMLObject::XMLObject(const std::string& string, XMLLoadData& data)
ReadBodyTail(string, data); ReadBodyTail(string, data);
} }
XMLObject::XMLObject(const std::string& name, const std::map<std::string, std::string>& attributes, const std::string& text) XMLObject::XMLObject(const std::string& name,
:name(name), attributes(attributes), text(text) 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) XMLObject::XMLObject(const std::string& name,
: name(name), attributes(attributes), objects(objects) 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 bool XMLObject::HasAttribute(const std::string& property) const
@@ -53,7 +59,7 @@ const std::string& XMLObject::GetAttribute(const std::string& property) const
return it->second; return it->second;
} }
const std::string& XMLObject::GetAttribute(const std::string& property, const std::string& defaultValue) const std::string XMLObject::GetAttribute(const std::string& property, const std::string& defaultValue) const
{ {
auto it = attributes.find(property); auto it = attributes.find(property);
if (it == attributes.end()) if (it == attributes.end())
@@ -69,12 +75,32 @@ unsigned int XMLObject::GetObjectCount() const
std::vector<XMLObject>* XMLObject::GetObjectPtr(const std::string& name) std::vector<XMLObject>* XMLObject::GetObjectPtr(const std::string& name)
{ {
auto it = objects.find(name); auto it = objects.find(name);
if(it == objects.end()) if (it == objects.end())
return nullptr; return nullptr;
return &it->second; return &it->second;
} }
std::vector<XMLObject>& XMLObject::GetObjects(const std::string& name)
{
static std::vector<XMLObject> empty{};
auto it = objects.find(name);
if (it == objects.end())
return empty;
return it->second;
}
const std::vector<XMLObject>& XMLObject::GetObjects(const std::string& name) const
{
static std::vector<XMLObject> empty{};
auto it = objects.find(name);
if (it == objects.end())
return empty;
return it->second;
}
const std::map<std::string, std::vector<XMLObject>>& XMLObject::GetObjects() const const std::map<std::string, std::vector<XMLObject>>& XMLObject::GetObjects() const
{ {
return objects; return objects;
@@ -92,7 +118,7 @@ const std::string& XMLObject::GetText() const
void XMLObject::SetName(const std::string& name) void XMLObject::SetName(const std::string& name)
{ {
if(Utils::IsWord(name)) if (Utils::IsWord(name))
this->name = name; this->name = name;
else else
LOG_ERROR("XML Head can only be made up of letters"); LOG_ERROR("XML Head can only be made up of letters");
@@ -105,7 +131,7 @@ void XMLObject::SetText(const std::string& text)
void XMLObject::AddAttribute(const std::string& property, const std::string& value) void XMLObject::AddAttribute(const std::string& property, const std::string& value)
{ {
if(Utils::IsWord(property)) if (Utils::IsWord(property))
attributes.emplace(property, value); attributes.emplace(property, value);
else else
LOG_ERROR("XML property name can only be made up of letters"); LOG_ERROR("XML property name can only be made up of letters");
@@ -114,7 +140,7 @@ void XMLObject::AddAttribute(const std::string& property, const std::string& val
void XMLObject::AddXMLObject(const XMLObject& object) void XMLObject::AddXMLObject(const XMLObject& object)
{ {
auto it = objects.find(object.name); auto it = objects.find(object.name);
if(it == objects.end()) if (it == objects.end())
objects.emplace(object.name, std::vector<XMLObject>{object}); objects.emplace(object.name, std::vector<XMLObject>{object});
else else
it->second.push_back(object); it->second.push_back(object);
@@ -123,18 +149,18 @@ void XMLObject::AddXMLObject(const XMLObject& object)
bool XMLObject::RemoveXMLObject(const XMLObject& object) bool XMLObject::RemoveXMLObject(const XMLObject& object)
{ {
auto it = objects.find(object.name); auto it = objects.find(object.name);
if(it == objects.end()) if (it == objects.end())
return false; return false;
bool removed = 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); it2 = it->second.erase(it2);
removed = true; removed = true;
} }
else else
++it2; ++it2;
} }
return removed; return removed;
@@ -142,7 +168,7 @@ bool XMLObject::RemoveXMLObject(const XMLObject& object)
XMLObject XMLObject::GetStrippedXMLObject() const XMLObject XMLObject::GetStrippedXMLObject() const
{ {
if(text == "") if (text == "")
return XMLObject(name, attributes, objects); return XMLObject(name, attributes, objects);
else else
return XMLObject(name, attributes, text); return XMLObject(name, attributes, text);
@@ -154,7 +180,6 @@ XMLObject XMLObject::GetStrippedXMLObject() const
// // // //
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool XMLObject::ReadHead(const std::string& string, XMLLoadData& data) bool XMLObject::ReadHead(const std::string& string, XMLLoadData& data)
{ {
// Check if the first character is the start of and xml tag. // Check if the first character is the start of and xml tag.
@@ -179,7 +204,8 @@ bool XMLObject::ReadHead(const std::string& string, XMLLoadData& data)
data.pos++; data.pos++;
ReadWhiteSpace(string, data); ReadWhiteSpace(string, data);
if (string[data.pos] != '>') 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++; data.pos++;
// nothing more to read. // nothing more to read.
return true; return true;
@@ -187,7 +213,9 @@ bool XMLObject::ReadHead(const std::string& string, XMLLoadData& data)
ReadWhiteSpace(string, data); ReadWhiteSpace(string, data);
if (string[data.pos] != '>') 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)++; (data.pos)++;
return false; return false;
} }
@@ -203,7 +231,8 @@ void XMLObject::ReadName(const std::string& string, XMLLoadData& data)
ReadWhiteSpace(string, data); ReadWhiteSpace(string, data);
if (string[data.pos] != '/' && string[data.pos] != '>' && Utils::IsWhiteSpace(string[data.pos])) 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 +259,9 @@ void XMLObject::ReadAttribute(const std::string& string, XMLLoadData& data)
// Read = // Read =
if (string[data.pos] != '=') 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)++; (data.pos)++;
ReadWhiteSpace(string, data); ReadWhiteSpace(string, data);
@@ -256,7 +287,10 @@ void XMLObject::ReadBodyTail(const std::string& string, XMLLoadData& data)
ReadWhiteSpace(string, data); ReadWhiteSpace(string, data);
std::string closeTag = GetClosingTag(string, data); std::string closeTag = GetClosingTag(string, data);
if (closeTag.length() == 0) 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; return;
} }
// Check if we can read the closing tag. // Check if we can read the closing tag.
@@ -279,14 +313,14 @@ void XMLObject::ReadText(const std::string& string, XMLLoadData& data)
void XMLObject::ReadWhiteSpace(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') if (string[data.pos] == '\n')
(data.line)++; (data.line)++;
(data.pos)++; (data.pos)++;
} }
} }
std::string XMLObject::GetClosingTag(const std::string& string, XMLLoadData& data) std::string XMLObject::GetClosingTag(const std::string& string, XMLLoadData& data)
{ {
int startPos = data.pos; int startPos = data.pos;
@@ -307,7 +341,8 @@ std::string XMLObject::GetClosingTag(const std::string& string, XMLLoadData& dat
ReadWhiteSpace(string, data); ReadWhiteSpace(string, data);
std::string tag = Utils::GetWord(string, data.pos); std::string tag = Utils::GetWord(string, data.pos);
if (tag != name) 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(); data.pos += tag.length();
ReadWhiteSpace(string, data); ReadWhiteSpace(string, data);
if (string[data.pos] != '>') if (string[data.pos] != '>')
@@ -318,82 +353,72 @@ std::string XMLObject::GetClosingTag(const std::string& string, XMLLoadData& dat
void XMLObject::ReplacePredefinedEntities(std::string& string, XMLLoadData& data) void XMLObject::ReplacePredefinedEntities(std::string& string, XMLLoadData& data)
{ {
std::vector<std::pair<std::string, std::string>> entities std::vector<std::pair<std::string, std::string>> entities{
{ {"&quot;", "\""}, {"&apos;", "\'"}, {"&lt;", "<"}, {"&gt;", ">"}, {"&amp;", "&"}};
{"&quot;","\""},
{"&apos;", "\'"},
{"&lt;", "<"},
{"&gt;",">"},
{"&amp;", "&"}
};
size_t pos = string.find('&'); size_t pos = string.find('&');
while(pos != std::string::npos) while (pos != std::string::npos)
{ {
bool found = false; 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); string.replace(pos, entity.first.length(), entity.second);
found = true; found = true;
} }
} }
if(!found) if (!found)
LOG_ERROR("(" + data.file + ":" + std::to_string(data.line) + "): ""Ampersand found in xml but isn't a predefined entity."); LOG_ERROR("(" + data.file + ":" + std::to_string(data.line) +
pos = string.find('&', pos+1); "): "
"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) std::string XMLObject::ReadXMLName(const std::string& string, XMLLoadData& data)
{ {
if(!(Utils::IsLetter(string[data.pos]) || if (!(Utils::IsLetter(string[data.pos]) || string[data.pos] == '_' || string[data.pos] == ':'))
string[data.pos] == '_' ||
string[data.pos] == ':'))
throw XMLException(std::string("Name doesn't start with a letter."), data); throw XMLException(std::string("Name doesn't start with a letter."), data);
int endPos = data.pos + 1; int endPos = data.pos + 1;
while (endPos < string.length() && ( while (endPos < string.length() && (Utils::IsLetter(string[endPos]) || string[endPos] == '_' ||
Utils::IsLetter(string[endPos]) || string[endPos] == '-' || string[endPos] == ':' || string[endPos] == '.'))
string[endPos] == '_' ||
string[endPos] == '-' ||
string[endPos] == ':' ||
string[endPos] == '.'))
endPos++; endPos++;
return string.substr(data.pos, endPos - data.pos); return string.substr(data.pos, endPos - data.pos);
} }
std::ostream& XMLObject::WriteToStream(std::ostream& stream, int indent) const 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 << " ";
} }
stream << "<" << name; 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 << " " << it->first << "=\"" << it->second << "\"";
} }
stream << ">"; stream << ">";
if(text != "") if (text != "")
{ {
stream << text; stream << text;
} }
else else
{ {
bool hasChild = false; 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"; stream << "\n";
it2->WriteToStream(stream, indent+1); it2->WriteToStream(stream, indent + 1);
hasChild = true; hasChild = true;
} }
} }
if(hasChild) if (hasChild)
{ {
stream << "\n"; stream << "\n";
for(int i = 0;i<indent;i++) for (int i = 0; i < indent; i++)
{ {
stream << " "; stream << " ";
} }
@@ -403,4 +428,3 @@ std::ostream& XMLObject::WriteToStream(std::ostream& stream, int indent) const
return stream; return stream;
} }
+107 -96
View File
@@ -1,110 +1,121 @@
#pragma once #pragma once
#include <string>
#include <map> #include <map>
#include <set> #include <set>
#include <string>
#include <vector> #include <vector>
class XMLObject class XMLObject
{ {
public: public:
friend class XMLexception; friend class XMLexception;
struct XMLLoadData
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;
std::string GetAttribute(const std::string& property, const std::string& defaultValue) const;
unsigned int GetObjectCount() const;
std::vector<XMLObject>* GetObjectPtr(const std::string& name);
std::vector<XMLObject>& GetObjects(const std::string& name);
const std::vector<XMLObject>& GetObjects(const std::string& name) const;
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; auto it1 = object1.attributes.begin();
int line; auto it2 = object2.attributes.begin();
const std::string& file; while (it1 != object1.attributes.end())
};
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(); if (it1->first != it2->first || it1->second != it1->second)
auto it2 = object2.attributes.begin(); return false;
while(it1 != object1.attributes.end()) ++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); auto it1 = object1.objects.begin();
// Returns true if the head contained closing tag. auto it2 = object2.objects.begin();
bool ReadHead(const std::string& string, XMLLoadData& data); while (it1 != object1.objects.end())
void ReadName(const std::string& string, XMLLoadData& data); {
void ReadAttribute(const std::string& string, XMLLoadData& data); if (it1->second != it2->second)
void ReadAttributes(const std::string& string, XMLLoadData& data); return false;
void ReadBodyTail(const std::string& string, XMLLoadData& data); ++it1;
void ReadText(const std::string& string, XMLLoadData& data); ++it2;
void ReadWhiteSpace(const std::string& string, XMLLoadData& data); }
void ReplacePredefinedEntities(std::string& string, XMLLoadData& data); }
std::string ReadXMLName(const std::string& string, XMLLoadData& data); 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);
}; };