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