From 568064068ef204db3648cef8f593f04407289494 Mon Sep 17 00:00:00 2001 From: modeco80 Date: Sun, 30 Jul 2023 06:57:31 -0400 Subject: [PATCH] projgen: Initial commit This commit adds `projgen`, a very simplistic project generator. Some knobs to the build system were added to ensure that only the needed parts will build with each end (building the GMod module won't build projgen since that isn't needed on the host) The fun part will be figuring out how to jail things properly --- .gitignore | 4 - .gitmodules | 3 + build_module.sh | 5 +- native/CMakeLists.txt | 15 ++- native/projects/projgen/CMakeLists.txt | 17 ++++ native/projects/projgen/src/BaseConfig.hpp | 8 ++ native/projects/projgen/src/FsUtils.hpp | 30 ++++++ native/projects/projgen/src/Project.hpp | 49 ++++++++++ native/projects/projgen/src/main.cpp | 94 +++++++++++++++++++ .../projgen/third_party/daw_json_link | 1 + test-gmod/{Makefile => Makefile.Hand} | 0 test-gmod/project.json | 35 ++++--- 12 files changed, 232 insertions(+), 29 deletions(-) create mode 100644 native/projects/projgen/CMakeLists.txt create mode 100644 native/projects/projgen/src/BaseConfig.hpp create mode 100644 native/projects/projgen/src/FsUtils.hpp create mode 100644 native/projects/projgen/src/Project.hpp create mode 100644 native/projects/projgen/src/main.cpp create mode 160000 native/projects/projgen/third_party/daw_json_link rename test-gmod/{Makefile => Makefile.Hand} (100%) diff --git a/.gitignore b/.gitignore index 678b4b1..5c97147 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,6 @@ build/ # this one is created by the build script module_build/ -native/projects/riscv/ref - -# for now -native/projects/projgen .cache/ .vscode/ diff --git a/.gitmodules b/.gitmodules index 5f832f3..5bd49a3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ path = native/projects/lcpu/third_party/gmod_headers url = https://github.com/Facepunch/gmod-module-base branch = development +[submodule "native/projects/projgen/third_party/daw_json_link"] + path = native/projects/projgen/third_party/daw_json_link + url = https://github.com/beached/daw_json_link diff --git a/build_module.sh b/build_module.sh index 4d122d3..225fd6d 100755 --- a/build_module.sh +++ b/build_module.sh @@ -28,8 +28,9 @@ cmake_build() { } build_and_place() { - cmake_gen linux32 --toolchain $PWD/native/cmake/linux32-toolchain.cmake - cmake_gen linux64 + # don't build utilities; they're only needed by the oci image + cmake_gen linux32 --toolchain $PWD/native/cmake/linux32-toolchain.cmake -DLCPU_BUILD_UTILITIES=OFF + cmake_gen linux64 -DLCPU_BUILD_UTILITIES=OFF cmake_build linux32 cmake_build linux64 diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index a934e74..ee73bee 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -3,12 +3,17 @@ project(lcpu-native DESCRIPTION "Superproject for LCPU GMOD Native Module" ) +option(LCPU_BUILD_UTILITIES "Build LCPU utiltiies" ON) +option(LCPU_BUILD_MODULE "Build GMod module" ON) + # Lucore (lily utilities core) add_subdirectory(projects/lucore) -# RISC-V emulator library -add_subdirectory(projects/riscv) +if(LCPU_BUILD_MODULE) + add_subdirectory(projects/riscv) + add_subdirectory(projects/lcpu) +endif() -# Garry's Mod native bindings to RISC-V emulator -# Also lua device stuff -add_subdirectory(projects/lcpu) +if(LCPU_BUILD_UTILITIES) + add_subdirectory(projects/projgen) +endif() diff --git a/native/projects/projgen/CMakeLists.txt b/native/projects/projgen/CMakeLists.txt new file mode 100644 index 0000000..5c12f78 --- /dev/null +++ b/native/projects/projgen/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.15) +project(lcpu-projgen + DESCRIPTION "LCPU Project Generator - generates a Makefile from project.json" +) + +set(DAW_USE_CPP17_NAMES OFF) +add_subdirectory(third_party/daw_json_link) + +add_executable(lcpu_projgen + # driver + src/main.cpp +) + +target_link_libraries(lcpu_projgen + lucore::lucore + daw::json_link +) diff --git a/native/projects/projgen/src/BaseConfig.hpp b/native/projects/projgen/src/BaseConfig.hpp new file mode 100644 index 0000000..8918258 --- /dev/null +++ b/native/projects/projgen/src/BaseConfig.hpp @@ -0,0 +1,8 @@ +#pragma once + +/// These are the hardcoded defaults +#define PROJGEN_CC "riscv32-unknown-elf-gcc" +#define PROJGEN_CXX "riscv32-unknown-elf-g++" +#define PROJGEN_BASE_C_FLAGS "-ffreestanding -fno-stack-protector -fdata-sections -ffunction-sections -march=rv32ima -mabi=ilp32" +#define PROJGEN_BASE_CC_FLAGS "-ffreestanding -fno-stack-protector -fdata-sections -ffunction-sections -march=rv32ima -mabi=ilp32" +#define PROJGEN_BASE_LD_FLAGS "-nostdlib" diff --git a/native/projects/projgen/src/FsUtils.hpp b/native/projects/projgen/src/FsUtils.hpp new file mode 100644 index 0000000..0ddbb8d --- /dev/null +++ b/native/projects/projgen/src/FsUtils.hpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +namespace fs = std::filesystem; + +namespace projgen::util { + + using unique_file_ptr = std::unique_ptr; + + unique_file_ptr UniqueFopen(std::string_view path, std::string_view mode) { + return unique_file_ptr(std::fopen(path.data(), mode.data()), &std::fclose); + } + + std::string ReadFileAsString(const fs::path& path) { + auto file = UniqueFopen(path.string(), "r"); + std::string data; + if(file) { + std::fseek(file.get(), 0, SEEK_END); + auto len = std::ftell(file.get()); + std::fseek(file.get(), 0, SEEK_SET); + + data.resize(len); + std::fread(data.data(), 1, len, file.get()); + } + return data; + } + +} // namespace projgen::util diff --git a/native/projects/projgen/src/Project.hpp b/native/projects/projgen/src/Project.hpp new file mode 100644 index 0000000..ebf5939 --- /dev/null +++ b/native/projects/projgen/src/Project.hpp @@ -0,0 +1,49 @@ +#include + +#include +#include +#include +#include + +namespace projgen { + struct Project { + struct Configuration { + /// The C/C++/linker flags for this configuration. + /// These append to the defaults. + std::string cCompileFlags; + std::string cppCompileFlags; + std::optional linkerFlags; + }; + + std::string name; + std::unordered_map configurations; + std::vector sourceFileNames; + }; + +} // namespace projgen + +/// DAW JSON Link bindings +namespace daw::json { + + template <> + struct json_data_contract { + using type = json_member_list, json_string<"CppCompileFlags">, json_string_null<"LinkerFlags"> >; + + static inline auto to_json_data(const projgen::Project::Configuration& value) { + return std::forward_as_tuple(value.cCompileFlags, value.cppCompileFlags, value.linkerFlags); + } + }; + + template <> + struct json_data_contract { + using type = + json_member_list, + json_key_value<"Configurations", std::unordered_map, projgen::Project::Configuration>, + json_array<"Sources", std::string> >; + + static inline auto to_json_data(const projgen::Project& value) { + return std::forward_as_tuple(value.name, value.configurations, value.sourceFileNames); + } + }; + +} // namespace daw::json diff --git a/native/projects/projgen/src/main.cpp b/native/projects/projgen/src/main.cpp new file mode 100644 index 0000000..27aa1ee --- /dev/null +++ b/native/projects/projgen/src/main.cpp @@ -0,0 +1,94 @@ +//! Main for the LCPU project generator + +#include +#include +#include + +#include "BaseConfig.hpp" +#include "FsUtils.hpp" +#include "Project.hpp" + +template +T ParseJsonFromFile(const fs::path& path) { + auto data = projgen::util::ReadFileAsString(path); + return daw::json::from_json(data); +} + +// this describes a source file +struct SourceFile { + enum class Type { + Invalid, // invalid file + AsmSourceFile, // Assembly source file + CSourceFile, // C source code + CppSourceFile, // C++ source code + LinkerScript, // prepended to linker flags with a -T (only one can exist in a project) + }; + + static constexpr Type TypeFromExtension(std::string_view extension) { + if(extension == "s" || extension == "S") + return Type::AsmSourceFile; + + if(extension == "c") + return Type::CSourceFile; + if(extension == "cpp" || extension == "cc") + return Type::CppSourceFile; + if(extension == "ld") + return Type::LinkerScript; + + return Type::Invalid; + } + + explicit SourceFile(const std::string& filename) : filename(filename) { + if(auto pos = filename.rfind('.'); pos != std::string::npos) { + type = TypeFromExtension(filename.substr(pos + 1)); + } else { + type = Type::Invalid; + } + } + + static std::vector MakeArray(const std::vector& filenames) { + auto vec = std::vector(); + vec.reserve(filenames.size()); + + for(auto& filename : filenames) + vec.emplace_back(filename); + + return vec; + } + + Type type; + std::string filename; +}; + +int main(int argc, char** argv) { + lucore::LoggerAttachStdout(); + + lucore::LogInfo("LCPU project generator!"); + + auto project_json_path = (fs::current_path() / "project.json"); + + if(!fs::exists(project_json_path)) { + lucore::LogFatal("The directory \"{}\" does not seem like it's a project to me", fs::current_path().string()); + return 1; + } + + try { + auto project = ParseJsonFromFile(project_json_path); + + for(auto& pair : project.configurations) { + std::printf("%s: %s %s %s\n", pair.first.c_str(), pair.second.cCompileFlags.c_str(), pair.second.cppCompileFlags.c_str(), + pair.second.linkerFlags.value_or(PROJGEN_BASE_LD_FLAGS).c_str()); + } + + auto sourceFiles = SourceFile::MakeArray(project.sourceFileNames); + + for(auto& source : sourceFiles) { + std::printf("%s -> %d\n", source.filename.c_str(), source.type); + } + + } catch(daw::json::json_exception& ex) { + lucore::LogFatal("Exception while trying to parse JSON data: {} {}", ex.what(), ex.reason()); + } + + return 0; +} diff --git a/native/projects/projgen/third_party/daw_json_link b/native/projects/projgen/third_party/daw_json_link new file mode 160000 index 0000000..730a54f --- /dev/null +++ b/native/projects/projgen/third_party/daw_json_link @@ -0,0 +1 @@ +Subproject commit 730a54f2780c771df6263a43087fa8621e871052 diff --git a/test-gmod/Makefile b/test-gmod/Makefile.Hand similarity index 100% rename from test-gmod/Makefile rename to test-gmod/Makefile.Hand diff --git a/test-gmod/project.json b/test-gmod/project.json index 365f713..9b22e17 100644 --- a/test-gmod/project.json +++ b/test-gmod/project.json @@ -1,23 +1,22 @@ { - "Project": { - "Name": "test", + "Name": "test", - "Configurations": { - "Debug": { - "CCompileFlags": "-O0 ${BaseCCompileFlags}", - "CppCompileFlags": "-O0 ${BaseCppCompileFlags}" - }, - "Release": { - "CCompileFlags": "-O2 ${BaseCCompileFlags}", - "CppCompileFlags": "-O2 ${BaseCppCompileFlags}", - "LinkerFlags": "-Wl,--gc-sections ${BaseLinkerFlags}" - } + "Configurations": { + "Debug": { + "CCompileFlags": "-O0", + "CppCompileFlags": "-O0", + "LinkerFlags": "" }, + "Release": { + "CCompileFlags": "-O2", + "CppCompileFlags": "-O2", + "LinkerFlags": "-Wl,--gc-sections" + } + }, - "Sources": [ - "binary.ld", - "start.S", - "main.c" - ] - } + "Sources": [ + "binary.ld", + "start.S", + "main.c" + ] }