aboutsummaryrefslogtreecommitdiff
path: root/buildtools
diff options
context:
space:
mode:
Diffstat (limited to 'buildtools')
-rw-r--r--buildtools/codegen/CodegenOutput.inl19
-rw-r--r--buildtools/codegen/CodegenUtils.inl73
-rw-r--r--buildtools/codegen/main.cpp154
3 files changed, 134 insertions, 112 deletions
diff --git a/buildtools/codegen/CodegenOutput.inl b/buildtools/codegen/CodegenOutput.inl
index edd9abc..ff7b912 100644
--- a/buildtools/codegen/CodegenOutput.inl
+++ b/buildtools/codegen/CodegenOutput.inl
@@ -3,6 +3,9 @@
#include "CodegenDecl.hpp"
#include "CodegenMacros.hpp"
+#include <Utils.hpp>
+
+#include <robin_hood.h>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
@@ -16,6 +19,7 @@ struct CodegenOutputThing {
class CodegenOutput {
private:
+ robin_hood::unordered_set<std::string, StringHash, StringEqual> mRequestIncludes;
std::vector<CodegenOutputThing> mOutThings;
std::vector<DeclStruct> mOutStructs;
std::vector<DeclEnum> mOutEnums;
@@ -27,6 +31,12 @@ public:
bool optionAutoAddPrefix : 1 = false;
public:
+ void AddRequestInclude(std::string_view include) {
+ if (!mRequestIncludes.contains(include)) {
+ mRequestIncludes.insert(std::string(include));
+ }
+ }
+
void AddOutputThing(CodegenOutputThing thing) {
mOutThings.push_back(std::move(thing));
}
@@ -39,15 +49,20 @@ public:
}
void Write(FILE* file) const {
+ for (auto& include : mRequestIncludes) {
+ // TODO how to resolve to the correct include paths?
+ WRITE_FMT_LN(file, "#include <%s>", include.c_str());
+ }
+
for (auto& thing : mOutThings) {
fwrite(thing.text.c_str(), sizeof(char), thing.text.size(), file);
WRITE_LIT(file, "\n");
}
for (auto& declStruct : mOutStructs) {
- WRITE_FMT(file, "struct %s {\n", declStruct.name.c_str());
+ WRITE_FMT_LN(file, "struct %s {", declStruct.name.c_str());
// TODO
- WRITE_LIT(file, "}\n");
+ WRITE_LIT_LN(file, "};");
}
for (auto& declEnum : mOutEnums) {
diff --git a/buildtools/codegen/CodegenUtils.inl b/buildtools/codegen/CodegenUtils.inl
new file mode 100644
index 0000000..ea46ac1
--- /dev/null
+++ b/buildtools/codegen/CodegenUtils.inl
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "CodegenConfig.hpp"
+#include "CodegenMacros.hpp"
+
+#include "CodegenOutput.inl"
+
+#include <Macros.hpp>
+#include <ScopeGuard.hpp>
+
+#include <cstdio>
+#include <cstdlib>
+#include <filesystem>
+
+namespace Utils {
+
+std::string ReadFileAsString(const std::filesystem::path& path) {
+ auto file = Utils::OpenCstdioFile(path, Utils::Read);
+ if (!file) throw std::runtime_error("Failed to open source file.");
+ DEFER { fclose(file); };
+
+ fseek(file, 0, SEEK_END);
+ auto fileSize = ftell(file);
+ rewind(file);
+
+ std::string result(fileSize, '\0');
+ fread(result.data(), fileSize, 1, file);
+
+ return result;
+}
+
+bool WriteOutputFile(const CodegenOutput& output, std::string_view dir, std::string_view filename, std::string_view additionalSuffix = {}) {
+ char path[2048];
+ snprintf(path, sizeof(path), "%.*s/%.*s%.*s", PRINTF_STRING_VIEW(dir), PRINTF_STRING_VIEW(filename), PRINTF_STRING_VIEW(additionalSuffix));
+
+ auto outputFile = Utils::OpenCstdioFile(path, Utils::WriteTruncate);
+ if (!outputFile) {
+ printf("[ERROR] unable to open output file %s\n", path);
+ return false;
+ }
+ DEFER { fclose(outputFile); };
+
+ DEBUG_PRINTF("Writing output %s\n", path);
+ output.Write(outputFile);
+
+ return true;
+}
+
+void ProduceGeneratedHeaderFileHeader(CodegenOutput& output) {
+ output.AddOutputThing(CodegenOutputThing{
+ .text = &R"""(
+// This file is generated. Any changes will be overidden when building.
+#pragma once
+
+#include <MetadataBase.hpp>
+)"""[1],
+ });
+}
+
+void ProduceGeneratedSourceFileHeader(CodegenOutput& output) {
+ output.AddOutputThing(CodegenOutputThing{
+ .text = &R"""(
+// This file is generated. Any changes will be overidden when building.
+#include "GeneratedCode.hpp"
+
+#include <frozen/string.h>
+#include <frozen/unordered_map.h>
+using namespace std::literals;
+ )"""[1],
+ });
+}
+
+} // namespace Utils
diff --git a/buildtools/codegen/main.cpp b/buildtools/codegen/main.cpp
index 298f19e..3a3e443 100644
--- a/buildtools/codegen/main.cpp
+++ b/buildtools/codegen/main.cpp
@@ -4,6 +4,7 @@
#include "CodegenInput.inl"
#include "CodegenOutput.inl"
+#include "CodegenUtils.inl"
#include <Enum.hpp>
#include <LookupTable.hpp>
@@ -27,10 +28,12 @@ using namespace std::literals;
namespace fs = std::filesystem;
// TODO handle namespace
+// TODO support codegen target in .cpp files
struct AppState {
- CodegenOutput headerOutput;
- CodegenOutput sourceOutput;
+ std::string_view outputDir;
+ CodegenOutput mainHeaderOutput;
+ CodegenOutput mainSourceOutput;
};
enum {
@@ -113,7 +116,7 @@ bool StbTokenIsMultiChar(int lexerToken) {
void CheckBraceDepth(int braceDpeth) {
if (braceDpeth < 0) {
- printf("[WARNING] unbalanced brace");
+ printf("[WARNING] unbalanced brace\n");
}
}
@@ -197,7 +200,7 @@ std::vector<StbLexerToken> RecordTokens(std::string_view source) {
}
if (lexer.token == CLEX_parse_error) {
- printf("[ERROR] stb_c_lexer countered a parse error.");
+ printf("[ERROR] stb_c_lexer countered a parse error.\n");
// TODO how to handle?
continue;
}
@@ -292,11 +295,6 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
maxVal = decl.elements[decl.elements.size() - 2].value;
}
- CodegenOutputThing lookupFunctionDecl;
- auto& o1 = lookupFunctionDecl.text;
- APPEND_LIT_LN(o1, "template <>");
- APPEND_FMT_LN(o1, "std::string_view Metadata::EnumToString<%s>(%s);", decl.name.c_str(), decl.name.c_str());
-
CodegenOutputThing lookupFunctionDef;
auto& o2 = lookupFunctionDef.text;
APPEND_LIT_LN(o2, "template <>");
@@ -305,7 +303,6 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
APPEND_FMT_LN(o2, " return %s[value - %d];", arrayName.c_str(), minVal);
APPEND_LIT_LN(o2, "}");
- headerOut.AddOutputThing(std::move(lookupFunctionDecl));
sourceOut.AddOutputThing(std::move(lookupFunctionDef));
} break;
@@ -337,11 +334,6 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
APPEND_LIT_LN(o1, "};");
// Generate lookup function
- CodegenOutputThing lookupFunctionDecl;
- auto& o2 = lookupFunctionDecl.text;
- APPEND_LIT_LN(o2, "template <>");
- APPEND_FMT_LN(o2, "std::optional<%s> Metadata::EnumFromString<%s>(std::string_view);", decl.name.c_str(), decl.name.c_str());
-
CodegenOutputThing lookupFunctionDef;
auto& o3 = lookupFunctionDef.text;
APPEND_LIT_LN(o3, "template <>");
@@ -355,12 +347,11 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
APPEND_LIT_LN(o3, "}");
sourceOut.AddOutputThing(std::move(lookupTable));
- headerOut.AddOutputThing(std::move(lookupFunctionDecl));
sourceOut.AddOutputThing(std::move(lookupFunctionDef));
}
}
-void HandleInputFile(AppState& state, std::string_view source) {
+void HandleInputFile(AppState& state, std::string_view filenameStem, std::string_view source) {
auto tokens = RecordTokens(source);
size_t idx = 0;
@@ -373,8 +364,10 @@ void HandleInputFile(AppState& state, std::string_view source) {
#endif
CodegenInput cgInput;
- auto& cgHeaderOutput = state.headerOutput;
- auto& cgSourceOutput = state.sourceOutput;
+ CodegenOutput cgHeaderOutput;
+ Utils::ProduceGeneratedHeaderFileHeader(cgHeaderOutput);
+ CodegenOutput cgSourceOutput;
+ Utils::ProduceGeneratedSourceFileHeader(cgSourceOutput);
int bracePairDepth = 0;
while (idx < tokens.size()) {
@@ -545,21 +538,9 @@ void HandleInputFile(AppState& state, std::string_view source) {
if (bracePairDepth != 0) {
printf("[WARNING] unbalanced brace at end of file.");
}
-}
-
-std::string ReadFileAtOnce(const fs::path& path) {
- auto file = Utils::OpenCstdioFile(path, Utils::Read);
- if (!file) throw std::runtime_error("Failed to open source file.");
- DEFER { fclose(file); };
- fseek(file, 0, SEEK_END);
- auto fileSize = ftell(file);
- rewind(file);
-
- std::string result(fileSize, '\0');
- fread(result.data(), fileSize, 1, file);
-
- return result;
+ Utils::WriteOutputFile(cgHeaderOutput, state.outputDir, filenameStem, ".gh.inl"sv);
+ Utils::WriteOutputFile(cgSourceOutput, state.outputDir, filenameStem, ".gs.inl"sv);
}
enum InputOpcode {
@@ -571,12 +552,17 @@ enum InputOpcode {
void HandleArgument(AppState& state, InputOpcode opcode, std::string_view operand) {
switch (opcode) {
case IOP_ProcessSingleFile: {
- fs::path filePath(operand);
- auto source = ReadFileAtOnce(filePath);
- HandleInputFile(state, source);
+ DEBUG_PRINTF("Processing single file %.*s\n", PRINTF_STRING_VIEW(operand));
+
+ fs::path path(operand);
+ auto filenameStem = path.stem().string();
+ auto source = Utils::ReadFileAsString(path);
+ HandleInputFile(state, filenameStem, source);
} break;
case IOP_ProcessRecursively: {
+ DEBUG_PRINTF("Recursively processing folder %.*s\n", PRINTF_STRING_VIEW(operand));
+
fs::path startPath(operand);
for (auto& item : fs::recursive_directory_iterator(startPath)) {
if (!item.is_regular_file()) {
@@ -584,15 +570,19 @@ void HandleArgument(AppState& state, InputOpcode opcode, std::string_view operan
}
auto& path = item.path();
- auto filename = path.filename().string();
- if (filename != ".c" ||
- filename != ".cpp")
+ auto pathExt = path.extension();
+ auto pathStem = path.stem();
+ if (pathExt != ".h" &&
+ pathExt != ".hpp")
{
continue;
}
- auto source = ReadFileAtOnce(path);
- HandleInputFile(state, source);
+ DEBUG_PRINTF("Processing subfile %s\n", path.string().c_str());
+
+ auto filenameStem = pathStem.string();
+ auto source = Utils::ReadFileAsString(path);
+ HandleInputFile(state, filenameStem, source);
}
} break;
@@ -605,25 +595,10 @@ InputOpcode ParseInputOpcode(std::string_view text) {
return IOP_ProcessSingleFile;
} else if (text == "rec"sv) {
return IOP_ProcessRecursively;
+ } else {
+ DEBUG_PRINTF("Unknown input opcode %s\n", text.data());
+ throw std::runtime_error("Unknown input opcode");
}
- return IOP_COUNT;
-}
-
-bool WriteOutputFile(const CodegenOutput& output, const char* dirPath, const char* fileName) {
- char path[2048];
- snprintf(path, sizeof(path), "%s/%s", dirPath, fileName);
-
- auto outputFile = Utils::OpenCstdioFile(path, Utils::WriteTruncate);
- if (!outputFile) {
- printf("[ERROR] unable to open output file %s", path);
- return false;
- }
- DEFER { fclose(outputFile); };
-
- DEBUG_PRINTF("Writing output %s", path);
- output.Write(outputFile);
-
- return true;
}
int main(int argc, char* argv[]) {
@@ -639,25 +614,8 @@ int main(int argc, char* argv[]) {
AppState state;
- state.headerOutput.AddOutputThing(CodegenOutputThing{
- .text = &R"""(
-// This file is generated. Any changes will be overidden when building.
-#pragma once
-
-#include <MetadataBase.hpp>
-)"""[1],
- });
-
- state.sourceOutput.AddOutputThing(CodegenOutputThing{
- .text = &R"""(
-// This file is generated. Any changes will be overidden when building.
-#include "MetadataImpl.hpp"
-
-#include <frozen/string.h>
-#include <frozen/unordered_map.h>
-using namespace std::literals;
- )"""[1],
- });
+ Utils::ProduceGeneratedHeaderFileHeader(state.mainHeaderOutput);
+ Utils::ProduceGeneratedSourceFileHeader(state.mainSourceOutput);
// If no cli is provided (argv[0] conventionally but not mandatorily the cli), this will do thing
// Otherwise, start with the 2nd element in the array, which is the 1st actual argument
@@ -668,55 +626,31 @@ USAGE: codegen.exe <output path> [<opcode>:<input path>]...
where <output path>: the directory to write generated contents to. This will NOT automatically create the directory.
<opcode> is one of:
"single" process this <input path> file only
- "rec" starting at the given directory <input path>, recursively process all .h .c .hpp .cpp files
+ "rec" starting at the given directory <input path>, recursively process all .h .hpp files
)"""[1]);
return -1;
}
- const char* outputDir = argv[1];
+ state.outputDir = std::string_view(argv[1]);
DEBUG_PRINTF("Outputting to directory %s.\n", outputDir);
- {
- char path[2048];
- snprintf(path, sizeof(path), "%s/%s", outputDir, "Metadata.hpp");
-
- auto fileContent = R"""(
-// This file is generated. Any changes will be overidden when building.
-// This file is an umbrella header for all generated metadata. End users simply include this file to get access to everything.
-#pragma once
-
-#include <MetadataBase.hpp>
-
-#include <generated/MetadataImpl.hpp>
-)"""sv.substr(1); // Get rid of the \n at the beginning
-
- auto file = Utils::OpenCstdioFile(path, Utils::WriteTruncate);
- if (!file) {
- printf("[ERROR] unable to open output file %s", path);
- return -1;
- }
- DEFER { fclose(file); };
-
- DEBUG_PRINTF("Writing output file %s", path);
- fwrite(fileContent.data(), sizeof(decltype(fileContent)::value_type), fileContent.size(), file);
- }
-
for (int i = 2; i < argc; ++i) {
- std::string_view arg(argv[i]);
+ const char* argRaw = argv[i];
+ std::string_view arg(argRaw);
+ DEBUG_PRINTF("Processing input command %s\n", argRaw);
+
auto separatorLoc = arg.find(':');
if (separatorLoc != std::string_view::npos) {
auto opcodeString = arg.substr(0, separatorLoc);
auto opcode = ParseInputOpcode(opcodeString);
auto operand = arg.substr(separatorLoc + 1);
- DEBUG_PRINTF("Processing input command %.*s at path %.*s\n", (int)opcodeString.size(), opcodeString.data(), (int)operand.size(), operand.data());
-
HandleArgument(state, opcode, operand);
}
}
- WriteOutputFile(state.headerOutput, outputDir, "MetadataImpl.hpp");
- WriteOutputFile(state.sourceOutput, outputDir, "MetadataImpl.cpp");
+ Utils::WriteOutputFile(state.mainHeaderOutput, state.outputDir, "GeneratedCode.hpp"sv);
+ Utils::WriteOutputFile(state.mainSourceOutput, state.outputDir, "GeneratedCode.cpp"sv);
return 0;
}