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" + ] }