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
This commit is contained in:
Lily Tsuru 2023-07-30 06:57:31 -04:00
parent 5f7f36296f
commit 568064068e
12 changed files with 232 additions and 29 deletions

4
.gitignore vendored
View File

@ -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/

3
.gitmodules vendored
View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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
)

View File

@ -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"

View File

@ -0,0 +1,30 @@
#include <cstdio>
#include <filesystem>
#include <memory>
#include <string>
namespace fs = std::filesystem;
namespace projgen::util {
using unique_file_ptr = std::unique_ptr<std::FILE, decltype(&std::fclose)>;
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

View File

@ -0,0 +1,49 @@
#include <daw/json/daw_json_link.h>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
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<std::string> linkerFlags;
};
std::string name;
std::unordered_map<std::string, Project::Configuration> configurations;
std::vector<std::string> sourceFileNames;
};
} // namespace projgen
/// DAW JSON Link bindings
namespace daw::json {
template <>
struct json_data_contract<projgen::Project::Configuration> {
using type = json_member_list<json_string<"CCompileFlags">, 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<projgen::Project> {
using type =
json_member_list<json_string<"Name">,
json_key_value<"Configurations", std::unordered_map<std::string, projgen::Project::Configuration>, 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

View File

@ -0,0 +1,94 @@
//! Main for the LCPU project generator
#include <lucore/Logger.hpp>
#include <lucore/StdoutSink.hpp>
#include <unordered_map>
#include "BaseConfig.hpp"
#include "FsUtils.hpp"
#include "Project.hpp"
template <class T>
T ParseJsonFromFile(const fs::path& path) {
auto data = projgen::util::ReadFileAsString(path);
return daw::json::from_json<T>(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<SourceFile> MakeArray(const std::vector<std::string>& filenames) {
auto vec = std::vector<SourceFile>();
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<projgen::Project>(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;
}

@ -0,0 +1 @@
Subproject commit 730a54f2780c771df6263a43087fa8621e871052

View File

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