diff options
author | rtk0c <[email protected]> | 2022-05-30 13:09:26 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2022-05-30 13:09:26 -0700 |
commit | ce9559e8c2b69d46cff064241bd9a04c014af44f (patch) | |
tree | 370c793d4fde63f4bd4d988d73a3c4d9353ede56 | |
parent | cdd84f25ab1d2a57ee5c7b4c954e35a8d7e2dca3 (diff) |
Changeset: 51 Add integration into the main game
-rw-r--r-- | CMakeLists.txt | 24 | ||||
-rw-r--r-- | buildtools/codegen/CodegenOutput.inl | 19 | ||||
-rw-r--r-- | buildtools/codegen/CodegenUtils.inl | 73 | ||||
-rw-r--r-- | buildtools/codegen/main.cpp | 154 | ||||
-rw-r--r-- | source-codegen-base/MacrosCodegen.hpp (renamed from source-common/MacrosCodegen.hpp) | 0 | ||||
-rw-r--r-- | source-codegen-base/Metadata.cpp | 1 | ||||
-rw-r--r-- | source-codegen-base/Metadata.hpp | 4 | ||||
-rw-r--r-- | source-codegen-base/MetadataBase.hpp | 4 | ||||
-rw-r--r-- | source-common/Macros.hpp | 2 | ||||
-rw-r--r-- | source/GraphicsTags.cpp | 2 | ||||
-rw-r--r-- | source/GraphicsTags.hpp | 12 | ||||
-rw-r--r-- | source/main.cpp | 5 |
12 files changed, 184 insertions, 116 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 55db14b..4800935 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,8 +62,6 @@ if(BRUSSEL_CODEGEN_DEBUG_PRINT) target_compile_definitions(codegen PRIVATE CODEGEN_DEBUG_PRINT=1) endif() -# ============================================================================== - file(GLOB_RECURSE things_codegen_base_SOURCES source-codegen-base/*.c source-codegen-base/*.cpp) add_library(things_codegen_base OBJECT ${things_codegen_base_SOURCES}) @@ -82,6 +80,25 @@ target_link_libraries(things_codegen_base PUBLIC things_common ) +# TODO support reading all files from the target, instead of manually supplying a search dir +function(target_gen_metadata TARGET_NAME SEARCH_DIR) + get_target_property(TARGET_SOURCES ${TARGET_NAME} SOURCES) + + set(OUTPUT_DIR ${CMAKE_BINARY_DIR}/generated/${TARGET_NAME}) + set(OUTPUT_FILES + ${OUTPUT_DIR}/generated/GeneratedCode.hpp + ${OUTPUT_DIR}/generated/GeneratedCode.cpp + ) + add_custom_command( + OUTPUT ${OUTPUT_FILES} + COMMAND codegen ${OUTPUT_DIR}/generated rec:${SEARCH_DIR} + DEPENDS ${TARGET_SOURCES} + ) + + target_include_directories(${TARGET_NAME} PRIVATE ${OUTPUT_DIR}) + target_sources(${TARGET_NAME} PRIVATE ${OUTPUT_FILES}) +endfunction() + # ============================================================================== # add_executable requires at least one source file @@ -153,3 +170,6 @@ if(BRUSSEL_ENABLE_ASAN) -fno-omit-frame-pointer ) endif() + +get_filename_component(METADATA_INP_DIR "source" ABSOLUTE) +target_gen_metadata(${PROJECT_NAME} ${METADATA_INP_DIR}) 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; } diff --git a/source-common/MacrosCodegen.hpp b/source-codegen-base/MacrosCodegen.hpp index 6803023..6803023 100644 --- a/source-common/MacrosCodegen.hpp +++ b/source-codegen-base/MacrosCodegen.hpp diff --git a/source-codegen-base/Metadata.cpp b/source-codegen-base/Metadata.cpp new file mode 100644 index 0000000..ee32054 --- /dev/null +++ b/source-codegen-base/Metadata.cpp @@ -0,0 +1 @@ +#include "Metadata.hpp" diff --git a/source-codegen-base/Metadata.hpp b/source-codegen-base/Metadata.hpp new file mode 100644 index 0000000..a038c15 --- /dev/null +++ b/source-codegen-base/Metadata.hpp @@ -0,0 +1,4 @@ +#pragma once + +#include "MacrosCodegen.hpp" +#include "MetadataBase.hpp" diff --git a/source-codegen-base/MetadataBase.hpp b/source-codegen-base/MetadataBase.hpp index 59c61da..8be668d 100644 --- a/source-codegen-base/MetadataBase.hpp +++ b/source-codegen-base/MetadataBase.hpp @@ -6,9 +6,9 @@ namespace Metadata { template <class TEnum> -std::string_view EnumToString(TEnum value) = delete; +std::string_view EnumToString(TEnum value); template <class TEnum> -std::optional<TEnum> EnumFromString(std::string_view str) = delete; +std::optional<TEnum> EnumFromString(std::string_view str); } // namespace Metadata diff --git a/source-common/Macros.hpp b/source-common/Macros.hpp index b5d05fa..a255ada 100644 --- a/source-common/Macros.hpp +++ b/source-common/Macros.hpp @@ -14,6 +14,8 @@ #define UNUSED(x) (void)x; +#define PRINTF_STRING_VIEW(s) (int)s.size(), s.data() + #if defined(_MSC_VER) # define UNREACHABLE __assume(0) #elif defined(__GNUC__) || defined(__clang__) diff --git a/source/GraphicsTags.cpp b/source/GraphicsTags.cpp index b389acf..522a58f 100644 --- a/source/GraphicsTags.cpp +++ b/source/GraphicsTags.cpp @@ -306,3 +306,5 @@ GLenum Tags::FindGLType(std::string_view name) { return GL_NONE; } } + +#include <generated/GraphicsTags.gs.inl> diff --git a/source/GraphicsTags.hpp b/source/GraphicsTags.hpp index 34c0885..09e62bf 100644 --- a/source/GraphicsTags.hpp +++ b/source/GraphicsTags.hpp @@ -5,6 +5,16 @@ #include <string> #include <string_view> +#include <MacrosCodegen.hpp> + +enum TestEnum { + TE_Position, + TE_Color, + TE_TexCoord, + TE_COUNT, +}; +BRUSSEL_ENUM(TestEnum, ToString FromString ExcludeHeuristics); + namespace Tags { /// Vertex element semantics, used to identify the meaning of vertex buffer contents enum VertexElementSemantic { @@ -96,3 +106,5 @@ GLenum FindGLType(std::string_view name); constexpr GLuint kInvalidLocation = std::numeric_limits<GLuint>::max(); } // namespace Tags + +#include <generated/GraphicsTags.gh.inl> diff --git a/source/main.cpp b/source/main.cpp index c49fc0b..353746b 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -3,9 +3,11 @@ #include "AppConfig.hpp" #include "CommonVertexIndex.hpp" #include "EditorGuizmo.hpp" +#include "GraphicsTags.hpp" #include "Ires.hpp" #include "Level.hpp" #include "Material.hpp" +#include "Metadata.hpp" #include "Shader.hpp" #define GLFW_INCLUDE_NONE @@ -102,6 +104,9 @@ fs::path GetEnvVar(const char* name, const char* backup) { int main(int argc, char* argv[]) { using namespace Tags; + auto str = Metadata::EnumToString(TE_Color); + printf("%.*s", PRINTF_STRING_VIEW(str)); + constexpr auto kImGuiBackend = "imgui-backend"; constexpr auto kGameDataDir = "game-data-directory"; constexpr auto kGameAssetDir = "game-asset-directory"; |