feat(autogen): better integration into cmake and replaced caching
This commit is contained in:
parent
a2e2210998
commit
0c3c6f43fc
5 changed files with 38 additions and 166 deletions
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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());
|
||||
// }
|
||||
// }
|
||||
|
||||
// First-pass: Analyze type hierarchy
|
||||
for (std::string path : headerFiles) {
|
||||
fs::path relpath = fs::relative(path, argv[1]);
|
||||
fs::path relpath = fs::relative(srcPath, srcRoot);
|
||||
printf("[AUTOGEN] Processing file %s...\n", relpath.c_str());
|
||||
analyzeClasses(path, argv[1], &state);
|
||||
}
|
||||
analyzeClasses(srcPath, srcRoot, &state);
|
||||
|
||||
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");
|
||||
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);
|
||||
|
||||
for (auto& [_, clazz] : state.classes) {
|
||||
writeCodeForClass(outStream, clazz);
|
||||
}
|
||||
|
||||
outStream.close();
|
||||
}
|
||||
|
||||
// // Write __all__.cpp file
|
||||
// fs::path outPath = fs::path(argv[3]) / "__all__.cpp";
|
||||
// std::ofstream outStream(outPath);
|
||||
|
||||
// // 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;
|
||||
}
|
|
@ -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}"
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h" "${CMAKE_BINARY_DIR}/generated/__all__.cpp")
|
||||
list(APPEND AUTOGEN_OUTS "${OUT_PATH}")
|
||||
endforeach()
|
||||
|
||||
add_custom_target(autogen_build ALL
|
||||
DEPENDS ${AUTOGEN_OUTS}
|
||||
)
|
||||
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue