feat(autogen): better integration into cmake and replaced caching

This commit is contained in:
maelstrom 2025-04-26 13:46:51 +02:00
parent a2e2210998
commit 0c3c6f43fc
5 changed files with 38 additions and 166 deletions

View file

@ -1,85 +0,0 @@
#include "cache.h"
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <map>
#include <string>
#include <vector>
namespace fs = std::filesystem;
extern std::map<std::string, std::vector<std::string>> SUBCLASSES;
extern std::map<std::string, std::string> SUPERCLASS;
std::map<std::string, uint64_t> LAST_MODIFIED_TIMES;
void loadModTimes(std::string path);
void writeModTimes(std::string path);
void loadCaches(std::string outDir) {
fs::path cacheDir = fs::path(outDir) / ".cache";
if (!fs::exists(cacheDir)) return;
fs::path modtimesFile = cacheDir / "modified.txt";
if (fs::exists(modtimesFile))
loadModTimes(modtimesFile);
}
void flushCaches(std::string outDir) {
fs::path cacheDir = fs::path(outDir) / ".cache";
fs::create_directories(cacheDir);
fs::path modtimesFile = cacheDir / "modified.txt";
writeModTimes(modtimesFile);
}
void loadModTimes(std::string path) {
std::ifstream stream(path);
std::string line;
while (std::getline(stream, line)) {
int pos = line.find(":");
std::string filename = line.substr(0, pos);
std::string timestr = line.substr(pos+1);
uint64_t time = std::stoull(timestr);
LAST_MODIFIED_TIMES[filename] = time;
}
stream.close();
}
void writeModTimes(std::string path) {
std::ofstream stream(path);
for (auto& [key, time] : LAST_MODIFIED_TIMES) {
stream << key.c_str() << ":" << time << "\n";
}
stream.close();
}
bool hasFileBeenUpdated(std::string path) {
path = fs::canonical(path);
if (LAST_MODIFIED_TIMES.count(path) == 0) return true;
// https://stackoverflow.com/a/31258680/16255372
auto rawtime = fs::last_write_time(path);
auto rawtime_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(rawtime);
uint64_t time = std::chrono::duration_cast<std::chrono::milliseconds>(rawtime_ms.time_since_epoch()).count();
uint64_t cachedTime = LAST_MODIFIED_TIMES[path];
return time > cachedTime;
}
void markFileCached(std::string path) {
path = fs::canonical(path);
// https://stackoverflow.com/a/31258680/16255372
auto rawtime = fs::last_write_time(path);
auto rawtime_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(rawtime);
uint64_t time = std::chrono::duration_cast<std::chrono::milliseconds>(rawtime_ms.time_since_epoch()).count();
LAST_MODIFIED_TIMES[path] = time;
}

View file

@ -1,10 +0,0 @@
#pragma once
#include <filesystem>
#include <string>
void loadCaches(std::string outDir);
void flushCaches(std::string outDir);
bool hasFileBeenUpdated(std::string path);
void markFileCached(std::string path);

View file

@ -16,84 +16,33 @@ namespace fs = std::filesystem;
int main(int argc, char** argv) {
if (argc < 4) {
fprintf(stderr, "Usage: autogen <src-root> <parse-dir> <out-dir>\n");
fprintf(stderr, "Usage: autogen <src-root> <src-file> <out-dir>\n");
return 1;
}
loadCaches(argv[3]);
std::vector<std::string> headerFiles;
// Scrape directory for header files
for (const fs::directory_entry& file : fs::recursive_directory_iterator(argv[2])) {
if (!file.is_regular_file()) continue; // Not a file, skip
if (file.path().extension() != ".h") continue; // Not a header file, skip
if (!hasFileBeenUpdated(file.path())) {
fs::path relpath = fs::relative(file.path(), argv[1]);
printf("[AUTOGEN] Skipping file %s...\n", relpath.c_str());
continue;
}
markFileCached(file.path());
headerFiles.push_back(file.path());
}
AnalysisState state;
// analyzeClasses("../core/src/objects/part.h", argv[1], &state);
// for (auto& [_, clazz] : state.classes) {
// printf("Class: %s\n", clazz.name.c_str());
// if (clazz.baseClass != "")
// printf("==> Base class: %s\n", clazz.baseClass.c_str());
// if (clazz.explorerIcon != "")
// printf("==> Explorer icon: %s\n", clazz.explorerIcon.c_str());
// printf("==> Flags (%x): ", clazz.flags);
// if (clazz.flags & ClassFlag_Service)
// printf("INSTANCE_SERVICE ");
// if (clazz.flags & ClassFlag_NotCreatable)
// printf("INSTANCE_NOT_CREATABLE ");
// if (clazz.flags & ClassFlag_Hidden)
// printf("INSTANCE_HIDDEN");
// printf("\n");
fs::path srcRoot = argv[1];
fs::path srcPath = argv[2];
fs::path outPath = argv[3];
// if (!clazz.properties.empty())
// printf("==> Properties:\n");
// for (auto prop : clazz.properties) {
// printf("====> %s (%s) (%s)\n", prop.name.c_str(), prop.fieldName.c_str(), prop.backingFieldType.c_str());
// }
// }
fs::path relpath = fs::relative(srcPath, srcRoot);
printf("[AUTOGEN] Processing file %s...\n", relpath.c_str());
analyzeClasses(srcPath, srcRoot, &state);
// First-pass: Analyze type hierarchy
for (std::string path : headerFiles) {
fs::path relpath = fs::relative(path, argv[1]);
printf("[AUTOGEN] Processing file %s...\n", relpath.c_str());
analyzeClasses(path, argv[1], &state);
}
fs::create_directories(outPath.parent_path()); // Make sure generated dir exists before we try writing to it
if (state.classes.empty())
return 0;
printf("[AUTOGEN] Generating file %s...\n", relpath.c_str());
std::ofstream outStream(outPath);
printf("[AUTOGEN] Generating cpp files...\n");
fs::create_directories(argv[3]); // Make sure generated dir exists before we try writing to it
for (auto& [_, clazz] : state.classes) {
fs::path outPath = fs::path(argv[3]) / ("class_" + clazz.name + ".cpp");
std::ofstream outStream(outPath);
writeCodeForClass(outStream, clazz);
outStream.close();
}
// // Write __all__.cpp file
// fs::path outPath = fs::path(argv[3]) / "__all__.cpp";
// std::ofstream outStream(outPath);
outStream.close();
// // TODO: replace these with just direct filenames that can be converted by
// // CMake itself
// for (auto& [_, clazz] : state.classes) {
// std::string includeName = "class_" + clazz.name + ".cpp";
// outStream << "#include \"" << includeName << "\"\n";
// }
// outStream.close();
flushCaches(argv[3]);
return 0;
}

View file

@ -16,11 +16,29 @@ find_package(PkgConfig REQUIRED)
pkg_check_modules(LUAJIT REQUIRED luajit)
# Run autogen
add_custom_target(build_autogen ALL
COMMAND "${CMAKE_BINARY_DIR}/autogen/autogen" "${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_CURRENT_SOURCE_DIR}/src/objects" "${CMAKE_BINARY_DIR}/generated"
file(GLOB_RECURSE AUTOGEN_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src/objects" "src/objects/*.h")
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Custom%20Commands.html
foreach (SRC ${AUTOGEN_SOURCES})
string(REGEX REPLACE "[.]h$" ".cpp" OUT_SRC_NAME ${SRC})
set(SRC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src/objects/${SRC}")
set(OUT_PATH "${CMAKE_BINARY_DIR}/generated/${OUT_SRC_NAME}")
add_custom_command(
OUTPUT "${OUT_PATH}"
DEPENDS "${SRC_PATH}"
COMMAND "${CMAKE_BINARY_DIR}/autogen/autogen" "${CMAKE_CURRENT_SOURCE_DIR}/src" "${SRC_PATH}" "${OUT_PATH}"
)
list(APPEND AUTOGEN_OUTS "${OUT_PATH}")
endforeach()
add_custom_target(autogen_build ALL
DEPENDS ${AUTOGEN_OUTS}
)
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h" "${CMAKE_BINARY_DIR}/generated/__all__.cpp")
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
list(APPEND SOURCES ${AUTOGEN_OUTS})
add_library(openblocks STATIC ${SOURCES})
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
target_link_libraries(openblocks ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml)

View file

@ -8,7 +8,7 @@
class Part;
class Workspace;
class INSTANCE_SERVICE() JointInstance : public Instance {
class INSTANCE_WITH(abstract) JointInstance : public Instance {
AUTOGEN_PREAMBLE
std::weak_ptr<Part> oldPart0;