support module system

This commit is contained in:
ouczbs 2024-07-31 10:48:28 +08:00
parent b17f3ef1d3
commit 7e2712848c
43 changed files with 685 additions and 168 deletions

21
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "emmylua_new",
"request": "launch",
"name": "EmmyLua New Debug",
"host": "localhost",
"port": 9966,
"ext": [
".lua",
".lua.txt",
".lua.bytes"
],
"ideConnectDebugger": true
}
]
}

View File

@ -1 +1 @@
add_requires("spdlog")
add_requires("spdlog", "lemon")

View File

@ -27,6 +27,17 @@ namespace gen {
return obj;
}
};
template<typename T>
struct JsonSerde<T, std::enable_if_t<refl::is_container_v<T>>> {
inline static bool Read(yyjson_val* val, const void* ptr) {
return true;
}
inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, const void* ptr) {
T& v = *(T*)ptr;
yyjson_mut_val* obj = yyjson_mut_obj(doc);
return obj;
}
};
}
namespace api {
namespace detail {

View File

@ -2,7 +2,7 @@
#include "serde.h"
namespace api {
// 定义 yyjson_alc 适配器类
inline yyjson_alc JsonAllocatorAdapter(std::pmr::memory_resource* mr = &FramePool) {
inline yyjson_alc JsonAllocatorAdapter(std::pmr::memory_resource* mr = FramePool) {
// 初始化 yyjson_alc 结构体
yyjson_alc alc;
alc.malloc = [](void* ctx, size_t size) -> void* {
@ -29,7 +29,7 @@ namespace api {
}
inline JsonFuncTable JsonArchive::BuildFuncTable()
{
JsonFuncTable funcTable{ &MemPool };
JsonFuncTable funcTable{ MemPool };
using std::string_view;
#define RegisterAny(T) funcTable.emplace(&TypeInfo<T>::StaticClass,JsonVTable::Make<T>())
#include "../register.inl"

View File

@ -9,6 +9,14 @@ namespace api {
Reload = 1,
};
ENABLE_BITMASK_OPERATORS(EModuleFlag);
struct ModuleDependency {
UPROPERTY()
Name name;
UPROPERTY()
Name version;
UPROPERTY()
Name kind;
};
struct ModuleInfo {
UPROPERTY()
EModuleFlag flag{0};
@ -28,6 +36,9 @@ namespace api {
Name url; //!< url of the plugin
UPROPERTY()
Name copyright; //!< copyright of the plugin
UPROPERTY()
pmr::vector<ModuleDependency> dependencies;
ModuleInfo(pmr::memory_resource* mr = MemPool) : dependencies(mr){};
public:
bool IsReload() {
return !!(flag & EModuleFlag::Reload);
@ -43,8 +54,8 @@ namespace api {
virtual void EndLoad() {}
};
struct IModule {
friend class ModuleManagerImpl;
public:
friend class ModuleManager;
using CreatePFN = IModule * (*)();
IModule() = default;
IModule(const IModule& rhs) = delete;
@ -53,7 +64,7 @@ namespace api {
virtual void OnLoad(int argc, char** argv) = 0;
virtual void OnUnload() = 0;
virtual const char* MetaData(void) = 0;
virtual void InitMetaData(void) = 0;
virtual int Main(int argc, char** argv) { return 0; }
virtual const ModuleInfo* GetModuleInfo()
@ -62,7 +73,7 @@ namespace api {
}
protected:
ModuleInfo mInfo;
std::vector<IModuleSubsystem*> mSubSystems;
pmr::vector<IModuleSubsystem*> mSubSystems;
};
}
#include "module.inl"

View File

@ -5,8 +5,13 @@ namespace api {
}
SharedLibrary mSharedLib;
};
struct IStaticModule : public IModule {
struct DefaultDynamicModule : public IDynamicModule {
DefaultDynamicModule(Name name) : IDynamicModule() {};
void OnLoad(int argc, char** argv) override {};
void OnUnload() override {};
void InitMetaData(void) override {};
};
using IStaticModule = IModule;
struct IHotfixModule : public IDynamicModule {
void* state = nullptr;
//IHotfixModule(){ mInfo.flag |= EModuleFlag::Reload; }
@ -15,11 +20,11 @@ namespace api {
};
}
#define IMPLEMENT_STATIC_MODULE(ModuleImplClass, ModuleName) \
inline static const api::ModuleRegistrantImpl<ModuleImplClass> __RegisterModule##ModuleName((const char*)#ModuleName);
inline const api::ModuleRegistrantImpl<ModuleImplClass> __RegisterModule__##ModuleName(#ModuleName);
#define IMPLEMENT_DYNAMIC_MODULE(ModuleImplClass, ModuleName) \
extern "C" api::IModule* __newDynamicModule##ModuleName() \
{ \
return new ModuleImplClass(); \
#define IMPLEMENT_DYNAMIC_MODULE(DLL_APL, ModuleImplClass, ModuleName) \
using __##ModuleName##__module = ModuleImplClass; \
extern "C" DLL_APL api::IModule* __newDynamicModule__##ModuleName() \
{ \
return new(MemPool) ModuleImplClass(); \
}
#define MODULE_DEPENDENCY(...)

View File

@ -1,31 +1,54 @@
#pragma once
#include "module.h"
namespace api {
template<typename T1, typename T2, typename Hasher = std::hash<T1>>
using table = std::pmr::unordered_map<T1, T2, Hasher>;
class ModuleManager
{
friend struct IModule;
private:
struct ModuleBlock {
bool isActive;
};
struct ExecuteInfo {
Name name;
int argc;
char** argv;
bool isActive;
};
ExecuteInfo mInfo;
SharedLibrary mProcessLib;
table<Name, IModule*> mModuleTable;
pmr::table<Name, ModuleBlock> mModuleBlocks{ GetMemPool() };
pmr::table<Name, IModule*> mModuleTable{GetMemPool()};
pmr::table<Name, IModule::CreatePFN> mInitializeTable{ GetMemPool() };
public:
ModuleManager() = default;
IModule* GetModule(Name name);
bool RegisterModule(Name name, IModule::CreatePFN fn);
static ModuleManager* Ptr();
public:
ModuleManager();
~ModuleManager();
IModule* GetModule(Name name);
void RegisterModule(Name name, IModule::CreatePFN fn) { mInitializeTable[name] = fn; }
void CreateModule(Name name, bool shared);
void DestroyModule(Name name);
void MakeGraph(Name name, bool shared, int argc, char** argv);
void DestroyGraph();
protected:
IModule* spawnDynamicModule(Name name, bool hotfix);
IModule* spawnStaticModule(Name name);
};
struct empty {
};
static empty e;
template <typename ModuleClass>
struct ModuleRegistrantImpl {
ModuleRegistrantImpl(const char* InModuleName)
{
ModuleManager::Ptr()->RegisterModule(InModuleName, []() {
ModuleManager::Ptr()->RegisterModule(InModuleName, []()->IModule* {
return new ModuleClass();
});
}
};
class CoreModule : public IStaticModule
{
public:
void OnLoad(int argc, char** argv) override;
void OnUnload() override;
void InitMetaData(void) override;
};
IMPLEMENT_STATIC_MODULE(CoreModule, core)
}

View File

@ -0,0 +1,69 @@
#pragma once
#include "singleton.h"
#include "package_path.h"
namespace api
{
class FileManager : public Singleton<FileManager>
{
public:
FileManager();
~FileManager();
public:
void Mount(Name name, const string& path) {
MountMap.emplace(name, std::make_pair(name, path));
}
std::pair<string, string> FindMount(Name id) {
auto it = MountMap.find(id);
if (it != MountMap.end()) {
return it->second;
}
return {};
}
string_view FindMountName(Name id) {
auto pair = FindMount(id);
return pair.first;
}
string_view FindMountPath(Name id) {
auto pair = FindMount(id);
return pair.second;
}
string_view FindPathView(Name name) {
auto it = FileMap.find(name);
if (it != FileMap.end()) {
return it->second.path;
}
return "";
}
string_view FindOrPathView(Name name) {
auto it = FileMap.find(name);
if (it != FileMap.end()) {
return it->second.path;
}
auto res = FileMap.emplace(name, FileBlock{ FileFlag::File_Default, name.ToString()});
return res.first->second.path;
}
uint32_t FindPathFlag(const PackagePath& pack_path) {
auto it = FileMap.find(pack_path());
if (it == FileMap.end()) {
return FileFlag::File_Not_Exist;
}
return it->second.flag;
}
FileBlock* FindPathBlock(const PackagePath& pack_path) {
auto it = FileMap.find(pack_path());
if (it == FileMap.end()) {
return nullptr;
}
return &it->second;
}
void SaveMountMap();
void LoadFileMap();
void SaveFileMap();
private:
pmr::table<Name, std::pair<string, string>> MountMap{GetMemPool()};
pmr::table<Name, FileBlock> FileMap{GetMemPool()};
public:
//外界不应该使用绝对路径
pmr::string RealPath(const PackagePath& pack_path);
};
}

View File

@ -0,0 +1,72 @@
#pragma once
#include <string>
#include "pmr/name.h"
namespace api
{
using std::string;
using std::string_view;
using pmr::Name;
enum FileFlag : uint32_t {
File_Default = 0,
File_Success = 1 << 0,
File_Binary = 1 << 1,
File_Compress = 1 << 2,
File_Http = 1 << 3,
File_Not_Exist = 1 << 4,
File_Error = 1 << 5,
};
//占位符浪费了四个字节
struct FileBlock {
uint32_t flag{ 0 };
string path;
string addr;
operator bool() {
return !(flag & FileFlag::File_Not_Exist);
}
};
struct PackagePath {
string_view path;
PackagePath() {};
PackagePath(const char* path) : path(path) {}
PackagePath(string_view path) : path(path) {}
PackagePath(const string& path) : path(path) {}
PackagePath(const pmr::string& path) : path(path) {}
operator bool() {
return path != "";
}
string_view operator()() const {
return path;
}
size_t size() const {
return path.size();
}
pmr::string operator+(const char* suffix) const {
return pmr::string(path, FramePool) + suffix;
}
string_view ParsePackage()const {
string_view name;
if (path[0] == '/') {
size_t pos = path.find('/', 1);
if (pos != string::npos) {
return path.substr(1, pos - 1);
}
}
return name;
}
string_view GetFileName()const {
size_t pos = path.rfind('/');
if (pos != std::string::npos)
return path.substr(pos + 1);
return "";
}
Name GetExtension() const {
size_t pos = path.rfind('.');
if (pos != std::string::npos)
return path.substr(pos);
return "";
}
PackagePath ToSuffixPath(string_view suffix)const;
PackagePath SafePath()const;
pmr::string RealPath()const;
};
}

View File

@ -1,9 +1,13 @@
#pragma once
#include "os/package_path.h"
namespace api {
using NativeLibHandle = void*;
class SharedLibrary {
NativeLibHandle mHandle;
public:
bool Load(const char* path = nullptr);
bool Load(PackagePath path = "");
void* GetSymbol(const char* name);
static string_view GetExtensionName();
};
}

View File

@ -0,0 +1,16 @@
#include "module/module_manager.h"
#include "os/file_manager.h"
namespace api {
void CoreModule::OnLoad(int argc, char** argv)
{
}
void CoreModule::OnUnload()
{
}
void CoreModule::InitMetaData(void)
{
}
}

View File

@ -1,14 +1,103 @@
#include "module/module_manager.h"
#include "os/file_manager.h"
namespace api {
ModuleManager* ModuleManager::Ptr()
{
static ModuleManager* ptr;
if (ptr) {
return ptr;
static ModuleManager ptr;
return &ptr;
}
ModuleManager::ModuleManager()
{
GetMemPool();
GetFramePool();
mProcessLib.Load();
new FileManager();
}
ModuleManager::~ModuleManager()
{
DestroyGraph();
delete FileManager::Ptr();
delete GetFramePool();
delete GetMemPool();
}
void ModuleManager::CreateModule(Name name, bool shared)
{
bool hotfix = true;
IModule* module = shared ?
spawnDynamicModule(name, hotfix) :
spawnStaticModule(name);
if (!module) { return; }
mModuleBlocks[name] = ModuleBlock{false};
ModuleBlock& block = mModuleBlocks[name];
auto& moduleInfo = module->mInfo;
for (auto& dep : moduleInfo.dependencies) {
if(auto it = mModuleBlocks.find(name); it != mModuleBlocks.end())
CreateModule(dep.name, dep.kind == pmr::FName("shared"));
}
ptr = new ModuleManager();
ptr->mProcessLib.Load();
return ptr;
module->OnLoad(mInfo.argc, mInfo.argv);
block.isActive = true;
}
void ModuleManager::DestroyModule(Name name)
{
auto it = mModuleBlocks.find(name);
if (it == mModuleBlocks.end() || !it->second.isActive) {
return;
}
IModule* module = mModuleTable[name];
auto& moduleInfo = module->mInfo;
for (auto& dep : moduleInfo.dependencies) {
DestroyModule(dep.name);
}
it->second.isActive = false;
}
void ModuleManager::MakeGraph(Name name, bool shared, int argc, char** argv)
{
mInfo = { name, argc, argv , true};
CreateModule(name, shared);
}
void ModuleManager::DestroyGraph()
{
if(mInfo.isActive)
DestroyModule(mInfo.name);
}
IModule* ModuleManager::spawnDynamicModule(Name name, bool hotfix)
{
if (auto it = mModuleTable.find(name); it != mModuleTable.end()) {
return it->second;
}
SharedLibrary sharedLib;
string_view name_view = name.ToStringView();
pmr::string newFuncName("__newDynamicModule__", FramePool);
newFuncName.append(name_view);
void* newFuncAddr = mProcessLib.GetSymbol(newFuncName.data());
if (!newFuncAddr) {
pmr::string libPath("/exe/", FramePool);
libPath.reserve(10 + name_view.size());
libPath.append(name_view);
libPath.append(SharedLibrary::GetExtensionName());
if (sharedLib.Load(libPath)) {
newFuncAddr = sharedLib.GetSymbol(newFuncName.data());
}
}
IDynamicModule* module = newFuncAddr ? (IDynamicModule*)((IModule::CreatePFN)newFuncAddr)() : new(MemPool) DefaultDynamicModule(name);
mModuleTable[name] = module;
module->mSharedLib = sharedLib;
module->InitMetaData();
return module;
}
IModule* ModuleManager::spawnStaticModule(Name name)
{
if (auto it = mModuleTable.find(name); it != mModuleTable.end()) {
return it->second;
}
auto it = mInitializeTable.find(name);
if (it == mInitializeTable.end()) {
return nullptr;
}
IModule* module = it->second();
module->InitMetaData();
mModuleTable[name] = module;
return module;
}
IModule* ModuleManager::GetModule(Name name)
{
@ -18,8 +107,4 @@ namespace api {
}
return it->second;
}
bool ModuleManager::RegisterModule(Name name, IModule::CreatePFN fn)
{
return false;
}
}

View File

@ -0,0 +1,43 @@
#include "os/file_manager.h"
#include "os/file_system.h"
#include <fstream>
#include "zlog.h"
namespace api {
FileManager::FileManager()
{
Mount("exe", fs::GetExecutablePath());
Mount("engine", fs::GetWorkPath());
LoadFileMap();
}
FileManager::~FileManager()
{
SaveMountMap();
SaveFileMap();
}
void FileManager::SaveMountMap()
{
}
void FileManager::LoadFileMap()
{
}
void FileManager::SaveFileMap()
{
}
pmr::string FileManager::RealPath(const PackagePath& pack_path)
{
string_view name = pack_path.ParsePackage();
string_view pre_path = FindMountPath(name);
if (name.empty() || pre_path.empty()) {
return pmr::string(pack_path(), FramePool);
}
pmr::string path{FramePool};
path.reserve(pre_path.size() + pack_path.size() - name.size() - 1);
path.append(pre_path);
path.append(pack_path().substr(name.size() + 1));
return path;
}
}

View File

@ -0,0 +1,25 @@
#include "os/package_path.h"
#include "os/file_manager.h"
namespace api {
PackagePath PackagePath::ToSuffixPath(string_view suffix)const
{
string_view name = ParsePackage();
if (name.empty() || suffix.empty())
return *this;
string suffixPath;
suffixPath.reserve(path.size() + suffix.size());
suffixPath.append(name);
suffixPath.append(suffix);
suffixPath.append(path.substr(name.size()));
return PackagePath{ FileManager::Ptr()->FindPathView(suffixPath) };
}
PackagePath PackagePath::SafePath()const
{
return PackagePath{ FileManager::Ptr()->FindPathView(path) };
}
pmr::string PackagePath::RealPath() const
{
return FileManager::Ptr()->RealPath(*this);
}
}

View File

@ -1,21 +1,35 @@
#include "os/shared_library.h"
#include <Windows.h>
namespace api {
bool SharedLibrary::Load(const char* path)
bool SharedLibrary::Load(PackagePath path)
{
if (path == nullptr)
if (path)
{
mHandle = GetModuleHandle(nullptr);
auto rpath = path.RealPath();
mHandle = GetModuleHandle(rpath.c_str());
if (mHandle == NULL)
{
mHandle = LoadLibrary(rpath.c_str());
}
}
else
{
mHandle = GetModuleHandle(path);
if (mHandle == NULL)
{
mHandle = LoadLibrary(path);
}
mHandle = GetModuleHandle(nullptr);
}
return mHandle;
}
void* SharedLibrary::GetSymbol(const char* name)
{
void* addr = (void*)GetProcAddress((HMODULE)mHandle, name);
return addr;
}
string_view SharedLibrary::GetExtensionName()
{
#ifdef _WIN32
return string_view(".dll");
#elif __linux__
return string_view(".so");
#endif
}
}

View File

@ -7,4 +7,3 @@ static_component("core","engine")
add_files("src/**.cpp")
add_deps("zlib", {public = true})
add_packages("spdlog", {public = true})
--add_syslinks("Kernel32")

View File

@ -2,7 +2,9 @@
#include <vector>
#include <memory_resource>
namespace pmr {
class FrameAllocator : public std::pmr::memory_resource {
using std::pmr::memory_resource;
using std::pmr::vector;
class FrameAllocator : public memory_resource {
private:
char* buffer;
size_t capacity;
@ -23,9 +25,9 @@ namespace pmr {
void move_clear() { buffer = nullptr; capacity = 0; offset = 0; };
void* do_allocate(size_t bytes, size_t alignment) override;
void do_deallocate(void* p, size_t bytes, size_t alignment) override {};
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; };
bool do_is_equal(const memory_resource& other) const noexcept override { return this == &other; };
};
class FrameAllocatorPool : public std::pmr::memory_resource {
class FrameAllocatorPool : public memory_resource {
public:
FrameAllocatorPool(size_t allocatorSize = 1024 * 1024) noexcept : allocatorSize(allocatorSize) {}
@ -33,17 +35,30 @@ namespace pmr {
void reset();
void* do_allocate(size_t bytes, size_t alignment) override { return allocate(bytes, alignment); }
void do_deallocate(void* p, size_t bytes, size_t alignment) override {};
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; };
bool do_is_equal(const memory_resource& other) const noexcept override { return this == &other; };
private:
size_t allocatorSize;
std::vector<FrameAllocator> allocators{};
vector<FrameAllocator> allocators{};
};
};
// 自定义的new操作符
inline void* operator new(size_t size, pmr::FrameAllocatorPool& pool, size_t alignment = alignof(std::max_align_t)) {
inline void* operator new(size_t size, pmr::FrameAllocatorPool* pool, size_t alignment = alignof(std::max_align_t)) {
size = (size + alignment - 1) & ~(alignment - 1);
return pool.allocate(size, alignment);
return pool->allocate(size, alignment);
}
#include "frame_allocator.inl"
inline static pmr::FrameAllocatorPool MemPool{};
inline static pmr::FrameAllocatorPool FramePool{};
inline pmr::FrameAllocatorPool* MemPool{};
inline pmr::FrameAllocatorPool* FramePool{};
inline pmr::FrameAllocatorPool* GetMemPool(){
if(!MemPool){
MemPool = new pmr::FrameAllocatorPool();
}
return MemPool;
}
inline pmr::FrameAllocatorPool* GetFramePool(){
if(!FramePool){
FramePool = new(GetMemPool()) pmr::FrameAllocatorPool();
}
return FramePool;
}

View File

@ -3,6 +3,9 @@
#include <unordered_map>
namespace pmr
{
template<typename T1, typename T2, typename Hasher = std::hash<T1>>
using table = std::pmr::unordered_map<T1, T2, Hasher>;
using std::pmr::string;
static consteval inline size_t InvalidValue() noexcept { return static_cast<size_t>(-1); }
constexpr inline size_t string_hash(std::string_view str) noexcept;
struct Name {
@ -17,6 +20,7 @@ namespace pmr
Name(const char(&str)[N]) noexcept;
Name(const char* str)noexcept;
Name(const std::string& str)noexcept;
Name(const string& str)noexcept;
Name(std::string_view str)noexcept;
auto operator<=>(const Name& other) const noexcept { return hash <=> other.hash; };
bool operator==(const Name& other) const {return hash == other.hash;}
@ -32,6 +36,7 @@ namespace pmr
std::string_view value;
public:
constexpr CName() noexcept : hash{ InvalidValue() } {}
constexpr CName(string str) noexcept : hash{ string_hash(str) }, value(str) {}
constexpr CName(std::string_view str) noexcept : hash{ string_hash(str) } ,value(str) {}
template<size_t N>
constexpr CName(const char(&str)[N]) noexcept : hash{ string_hash(str) }, value(str) {}
@ -47,7 +52,7 @@ namespace pmr
std::string ToString() const { return std::string(value); };
operator std::string() const { return ToString(); }
};
bool operator==(const CName& cname, const Name& name) {
inline bool operator==(const CName& cname, const Name& name) {
return cname.Hash() == name.Hash();
}
constexpr inline size_t string_hash(std::string_view str) noexcept

View File

@ -1,21 +1,22 @@
#include "name.h"
namespace pmr {
using NameTable_t = std::pmr::unordered_map<size_t,const std::pmr::string>;
using NameTable_t = table<size_t,const string>;
struct NameTable {
static const std::pmr::string& Find(size_t id);
static const string& Find(size_t id);
template<typename T>
static std::string_view MakePair(size_t id, T&& str);
static NameTable_t BuildNameTable() {
static FrameAllocatorPool MemPool;
return NameTable_t(&MemPool);
static NameTable_t& TableRef() {
static NameTable_t Table{GetMemPool()};
return Table;
}
inline static NameTable_t Table = BuildNameTable();
};
template<typename T>
inline std::string_view NameTable::MakePair(size_t id, T&& str)
{
auto& Table = TableRef();
auto it = Table.find(id);
if (it == Table.end()) {
auto it2 = Table.emplace(std::make_pair(id, std::pmr::string(str, Table.get_allocator())));
auto it2 = Table.emplace(std::make_pair(id, string(str, Table.get_allocator())));
if (it2.second) {
return it2.first->second;
}
@ -23,11 +24,12 @@ namespace pmr {
}
return it->second;
}
inline const std::pmr::string& NameTable::Find(size_t id)
inline const string& NameTable::Find(size_t id)
{
auto& Table = TableRef();
auto it = Table.find(id);
if (it == Table.end()) {
static std::pmr::string empty("", Table.get_allocator());
static string empty("", Table.get_allocator());
return empty;
}
return it->second;
@ -64,6 +66,10 @@ namespace pmr {
{
MAKE_NAME_PAIR(hash, str);
}
inline Name::Name(const string& str)noexcept : hash(string_hash(str))
{
MAKE_NAME_PAIR(hash, str);
}
#undef MAKE_NAME_PAIR
#undef NAME_TO_STRING
}

View File

@ -1,11 +1,12 @@
#pragma once
#include "module/module.h"
#include "asset/asset.h"
class VulkanModule : public api::IDynamicModule
class VULKAN_API VulkanModule : public api::IDynamicModule
{
public:
void OnLoad(int argc, char** argv) override;
void OnUnload() override;
const char* MetaData(void) override;
void InitMetaData(void) override;
};
MODULE_DEPENDENCY(core, asset, {public = true})
IMPLEMENT_DYNAMIC_MODULE(VulkanModule, vulkan)
IMPLEMENT_DYNAMIC_MODULE(VULKAN_API, VulkanModule, vulkan)
#include "vulkan.plugin.inl"

View File

@ -8,8 +8,3 @@ void VulkanModule::OnLoad(int argc, char** argv)
void VulkanModule::OnUnload()
{
}
const char* VulkanModule::MetaData(void)
{
return nullptr;
}

View File

@ -1 +0,0 @@
{"flag":0,"name":"vulkan"}

View File

@ -1,5 +1,5 @@
shared_component("vulkan","engine")
shared_module("vulkan","engine")
add_includedirs("include/vulkan")
add_headerfiles("include/**.h")
add_files("src/**.cpp")
add_rules("engine.plugin", {file = "include/vulkan/module.h"})
add_dependency("core", "asset", {public = true})

View File

@ -16,13 +16,36 @@ function static_component(name, owner, opt)
set_group("Engine/"..owner.."__comp")
add_includedirs("include", {public = true})
end
function shared_component(name, owner, opt)
target(owner)
add_deps(name, { public = opt and opt.public or true })
target_end()
function shared_module(name, owner, opt)
target(name)
set_kind("shared")
set_group("Engine/"..owner.."__comp")
set_group("Engine/"..owner.."__dyn")
add_rules("engine.api")
add_includedirs("include", {public = true})
add_rules("engine.plugin", {file = opt and opt.file or "include/" .. name .. "/module.h"})
end
function add_dependency(...)
add_deps(...)
local args = {...}
local opt = args[#args]
if type(opt) ~= "table" or not opt.public then
return
end
for _,v in ipairs(args) do
if v ~= opt then
add_values("module.public_dependencies", v)
end
end
end
function game_instance(name, opt)
target(name)
set_kind("shared")
set_group("Games")
add_rules("engine.api")
add_rules("engine.plugin", {file = opt and opt.file or "src/" .. name .. ".h"})
target(name .. "-editor")
set_kind("binary")
set_group("Games")
add_deps(name)
end
includes("**/xmake.lua")

View File

@ -4,7 +4,7 @@
#include <optional>
#include <iostream>
#include <fstream>
std::string_view module_macro[] = { MODULE_DEPENDENCY , IMPLEMENT_DYNAMIC_MODULE , IMPLEMENT_STATIC_MODULE };
std::string_view module_macro[] = { PUBLIC_MODULE_DEPENDENCY, PRIVATE_MODULE_DEPENDENCY , IMPLEMENT_DYNAMIC_MODULE, EXPORT_MODULE };
pmr::vector<pmr::string> parseArgs(std::string_view& str) {
pmr::vector<pmr::string> args(&pool);
std::stack<char> stack;
@ -75,20 +75,25 @@ std::optional<MacroData> parseLine(std::string_view line) {
return std::optional<MacroData>{};
}
// 读取文件并返回每一行内容
pmr::vector<MacroData> readMacroFile(const char* file_path) {
pmr::vector<MacroData> lines(&pool);
void readMacroFile(const char* file_path, ParseData& pd) {
std::ifstream file(file_path);
if (!file.is_open()) {
//std::cerr << "Failed to open file: " << file_path << std::endl;
return lines;
return;
}
std::string line;
while (std::getline(file, line)) {
std::string_view line_view(line);
if (auto md = parseLine(line_view)) {
lines.push_back(md.value());
const char* macro = md.value().macro;
if (macro == EXPORT_MODULE) {
std::string_view text = md.value().args[0];
text = text.substr(3, text.size() - 5);//R(" + )" = 3 + 2 = 5;
pd.exportText = text;
}
else
pd.mdList.push_back(md.value());
}
}
file.close();
return lines;
}

View File

@ -5,13 +5,20 @@ namespace pmr {
using std::pmr::string;
}
inline pmr::monotonic_buffer_resource pool;
inline const char* MODULE_DEPENDENCY = "MODULE_DEPENDENCY";
inline const char* PUBLIC_MODULE_DEPENDENCY = "PUBLIC_MODULE_DEPENDENCY";
inline const char* PRIVATE_MODULE_DEPENDENCY = "PRIVATE_MODULE_DEPENDENCY";
inline const char* IMPLEMENT_DYNAMIC_MODULE = "IMPLEMENT_DYNAMIC_MODULE";
inline const char* IMPLEMENT_STATIC_MODULE = "IMPLEMENT_STATIC_MODULE";
inline const char* EXPORT_MODULE = "EXPORT_MODULE";
struct MacroData {
const char* macro{ nullptr };
pmr::vector<pmr::string> args;
MacroData() :args(&pool) {}
MacroData(const pmr::vector<pmr::string>& args) :args(args) {}
operator bool() const { return macro; }
};
pmr::vector<MacroData> readMacroFile(const char* file_path);
struct ParseData {
pmr::string moduleFile;
pmr::string exportText;
pmr::vector<MacroData> mdList;
};
void readMacroFile(const char* file_path, ParseData& pd);

View File

@ -4,6 +4,7 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
std::string_view readFile(const char* file_path) {
std::ifstream file(file_path, std::ios::ate);
if (!file.is_open()) {
@ -24,47 +25,46 @@ void genLua(const char* file_path, const pmr::vector<MacroData>& mdList) {
std::ostringstream oss;
oss << "{\n";
for (auto& md : mdList) {
if (md.macro == MODULE_DEPENDENCY) {
if (md.macro == PUBLIC_MODULE_DEPENDENCY || md.macro == PRIVATE_MODULE_DEPENDENCY) {
oss << "\t{";
for (auto& args : md.args) {
if (args[0] != '{') {
oss << '"' << args << "\", ";
}
else {
oss << args;
}
oss << '"' << args << "\", ";
}
oss << "},\n";
oss << (md.macro == PUBLIC_MODULE_DEPENDENCY ? "{public = true}},\n" : "{public = false}},\n");
}
}
oss << '}';
writeFile(file_path, oss.str());
}
void genPlugin(const char* file_path, const pmr::vector<MacroData>& mdList) {
std::string_view text = readFile(file_path);
void genPlugin(const char* file_path, ParseData& pd) {
readMacroFile(file_path, pd);
api::ModuleInfo info;
std::string_view text = pd.exportText;
api::JsonDeserialize<api::ModuleInfo>(text, &info);
bool bchange = false;
for (auto& md : mdList) {
if (md.macro == IMPLEMENT_DYNAMIC_MODULE || md.macro == IMPLEMENT_STATIC_MODULE) {
api::Name name = md.args[1].c_str();
bchange = info.name != name;
info.name = name;
info.dependencies.clear();
for (auto& md : pd.mdList) {
if (md.macro == IMPLEMENT_DYNAMIC_MODULE) {
info.name = md.args[1];
}
else if (md.macro == MODULE_DEPENDENCY) {
else if (md.macro == PUBLIC_MODULE_DEPENDENCY) {
for (auto& args : md.args) {
if (args[0] != '{') {
}
std::pmr::string upname{ args, FramePool};
std::transform(upname.begin(), upname.end(), upname.begin(), std::toupper);
info.dependencies.push_back({args, upname + "_VERSION", upname + "_KIND"});
}
}
}
if (bchange) {
writeFile(file_path, api::JsonSerialize(info));
}
std::ostringstream oss;
std::string name = info.name.ToString();
std::transform(name.begin(), name.end(), name.begin(), std::toupper);
oss << "#include \"" << pd.moduleFile << "\"\n";
oss << "#define EXPORT_MODULE(json)" << name << "_API const char* __module_meta_" << info.name.data() << "__ = json\n";
oss << "EXPORT_MODULE(R\"(" << api::JsonSerialize(info) << ")\");\n";
writeFile(file_path, oss.str());
}
//已废弃
int main(int argc, char* argv[]) {
if (argc < 6) {
if (argc < 100) {
return -1;
}
std::string project_dir = argv[1];
@ -72,8 +72,10 @@ int main(int argc, char* argv[]) {
std::string script_dir = argv[3];
std::string module_file = script_dir + "\\" + argv[4];
std::string plugin_file = script_dir + "\\" + argv[5];
auto mdList = readMacroFile(module_file.c_str());
genLua(lua_file.c_str(), mdList);
genPlugin(plugin_file.c_str(), mdList);
ParseData pd;
pd.moduleFile = argv[4];
readMacroFile(module_file.c_str(), pd);
genLua(lua_file.c_str(), pd.mdList);
genPlugin(plugin_file.c_str(), pd);
return 0;
}

View File

@ -1,8 +1,7 @@
tool_target("make_plugin")
add_includedirs("src")
add_files("src/*.cpp")
add_headerfiles("src/*.h")
add_rules("engine.tool")
add_deps("core")
set_runargs([[F:\engine\zengine]], [[build\.gens\vulkan\windows\xmake.lua]],
[[F:\engine\zengine\engine\modules\render\vulkan]], [[include/vulkan/module.h]], [[vulkan.plugin]])
-- tool_target("make_plugin", "shared")
-- add_includedirs("src")
-- add_files("src/*.cpp")
-- add_headerfiles("src/*.h")
-- add_deps("core")
-- set_runargs(os.projectdir(), [[build\.gens\vulkan\windows\xmake.lua]],
-- os.projectdir() .. [[\engine\modules\render\vulkan]], [[include\vulkan\module.h]], "vulkan" .. ".plugin.cpp")

View File

@ -1,6 +1,7 @@
function tool_target(name)
function tool_target(name, kind)
target(name)
set_kind("binary")
set_kind(kind or "binary")
set_group("Tools")
add_rules("engine.tool")
end
includes("*/xmake.lua")

View File

@ -1,9 +1,5 @@
import("core.project.depend")
local genList = {}
function cmd_compile(genfile, sourcefile, template, macro, define)
if genList[genfile] then
return
end
import("find_sdk")
local meta = find_sdk.find_my_program("refl")
template = template or path.join(meta.sdkdir, "template")
@ -18,7 +14,6 @@ function cmd_compile(genfile, sourcefile, template, macro, define)
table.insert(argv, "-d")
table.insert(argv, define)
end
genList[genfile] = true
print("cmd_meta_compile", genfile)
os.execv(meta.program, argv)
return argv
@ -26,6 +21,7 @@ end
function _listen_gen_file(target, batch, template, macro, define)
genfile, sourcefile = batch[1], batch[2]
sourcefile = string.lower(sourcefile)
local dependfile = target:dependfile(genfile)
depend.on_changed(
function()

View File

@ -1,30 +1,43 @@
import("core.project.depend")
local loadTable = {}
function cmd_compile(target, genfile, file)
if is_mode("release") then return end
import("find_sdk")
local plugin = find_sdk.find_my_program("make_plugin")
if not plugin then return end
print("cmd_compile plugin", genfile, file)
argv = { os.projectdir() , genfile, target:scriptdir(), file, target:name() .. ".plugin"}
os.execv(plugin.program, argv)
local name = target:name()
if loadTable[name] then
return
end
loadTable[name] = true
import("core.project.project")
target:data_set("compile", true)
local pub_deps = target:values("module.public_dependencies")
local cpp_content = "inline void __" .. name .. "__module::InitMetaData(void){\n"
cpp_content = cpp_content.."\tmInfo.name = \"" .. name.."\";\n"
cpp_content = cpp_content.."\tmInfo.dependencies = {\n "
for k,dep in ipairs(pub_deps) do
local deptarget = project.target(dep)
if deptarget then
local kind = deptarget:kind()
local version = deptarget:version() or "0.0"
cpp_content = cpp_content.."\t\t{\"" .. dep .. "\", \""..version.."\", \""..kind.."\" },\n"
end
end
cpp_content = cpp_content.sub(cpp_content, 1, -3)
cpp_content = cpp_content.."\n\t};\n};"
print("cmd_compile plugin ", genfile)
io.writefile(genfile, cpp_content)
end
function main(target, file)
local sourcedir = path.join(target:autogendir({root = true}), target:plat())
local sourcedir = path.join(target:autogendir({root = true}), target:plat(), "inl")
if not os.isdir(sourcedir) then
os.mkdir(sourcedir)
end
local genfile = path.join(sourcedir,"xmake.lua")
target:add("includedirs", sourcedir, {public = true})
local genfile = path.join(sourcedir, target:name() .. ".plugin.inl")
local dependfile = target:dependfile(genfile)
local sourcefile = string.lower(path.join(target:scriptdir(), file))
depend.on_changed(
function()
cmd_compile(target, genfile, file)
end,
{dependfile = dependfile, files = {path.join(target:scriptdir(), file)}}
{dependfile = dependfile, files = sourcefile}
)
if os.exists(genfile) then
local dependency = io.load(genfile)
for k,v in ipairs(dependency) do
target:add("deps", v[1], v[2])
end
end
end

View File

@ -5,3 +5,4 @@ rule("engine.plugin")
local file = target:extraconf("rules", "engine.plugin", "file")
make_plugin(target, file or "module.h")
end)

View File

@ -7,3 +7,9 @@ rule("engine.tool")
local exefile = target:targetfile()
os.cp(exefile, path.join(tooldir, path.filename(exefile)))
end)
rule("engine.api")
on_load(function (target)
local api = string.upper(target:name()) .. "_API"
target:add("defines", api.."=__declspec(dllimport)", {interface=true})
target:add("defines", api.."=__declspec(dllexport)", {public=false})
end)

View File

@ -8,8 +8,8 @@
void test(std::string_view str = "") {
std::cout << "test " << str << std::endl;
}
int main() {
api::ModuleManager::Ptr();
int main(int argc, char** argv) {
api::ModuleManager::Ptr()->MakeGraph("zworld", true, argc, argv);
test("sss");
using namespace refl;
constexpr TStr str1{ "Hello" };
@ -36,14 +36,14 @@ int main() {
std::string s1 = name.ToString();
std::string s2 = name2.ToString();
if (s1.c_str() == s2.c_str()) {
new(pool)int(1);
new(&pool)int(1);
}
if (s1 == s2) {
new(pool)int(1);
new(&pool)int(1);
}
}
int* a = new(pool)int(1);
int* b = new(pool)int(2);
int* c = new(pool)int(3);
int* a = new(&pool)int(1);
int* b = new(&pool)int(2);
int* c = new(&pool)int(3);
std::cout << "hello engine\n";
}

View File

@ -1,5 +1,9 @@
#include "zworld.h"
void hello() {
void ZWorldModule::OnLoad(int argc, char** argv)
{
}
void ZWorldModule::OnUnload()
{
}

View File

@ -1 +1,11 @@
void hello();
#pragma once
#include "module/module.h"
class ZWORLD_API ZWorldModule : public api::IDynamicModule
{
public:
void OnLoad(int argc, char** argv) override;
void OnUnload() override;
void InitMetaData(void) override;
};
IMPLEMENT_DYNAMIC_MODULE(ZWORLD_API, ZWorldModule, zworld)
#include "zworld.plugin.inl"

View File

@ -1,11 +1,7 @@
game_instance("zworld", "src/zworld.h")
target("zworld")
set_kind("shared")
set_group("Games")
add_deps("engine", "editor", "vulkan", {public = true})
add_files("src/*.cpp")
add_headerfiles("src/*.h")
add_dependency("engine", "editor", "vulkan", {public = true})
target("zworld-editor")
set_kind("binary")
set_group("Games")
add_deps("zworld")
add_files("editor/main.cpp")

View File

@ -0,0 +1,9 @@
#include "src/zworld.h"
void __zworld__module::InitMetaData(void){
mInfo.name = "zworld";
mInfo.dependencies = {
{"engine", "1.0.1", "static" },
{"editor", "1.0.1", "static" },
{"vulkan", "1.0.1", "shared" }
};
};

7
module.plugin.inl Normal file
View File

@ -0,0 +1,7 @@
inline void __vulkan__module::InitMetaData(void){
mInfo.name = "vulkan";
mInfo.dependencies = {
{"core", "1.0.1", "static" },
{"asset", "1.0.1", "static" }
};
};

8
nil.plugin.inl Normal file
View File

@ -0,0 +1,8 @@
inline void __zworld__module::InitMetaData(void){
mInfo.name = "zworld";
mInfo.dependencies = {
{"engine", "1.0.1", "static" },
{"editor", "1.0.1", "static" },
{"vulkan", "1.0.1", "shared" }
};
};

View File

@ -1,4 +1,5 @@
add_rules("mode.debug", "mode.release")
set_version("1.0.1", {soname = true})
set_arch("x64")
set_languages("cxx20")
set_project("zengine")
@ -8,3 +9,5 @@ includes("engine")
includes("game/*/xmake.lua")
--xmake project -k vsxmake2022 -a x64
--xmake project -k vsxmake2022 -m "debug;release"
--xmake build -vD -y -P . "zworld-editor"
--xrepo env -b emmylua_debugger -- xmake project -k vsxmake2022 -m "debug;release"

8
zworld.plugin.inl Normal file
View File

@ -0,0 +1,8 @@
inline void __zworld__module::InitMetaData(void){
mInfo.name = "zworld";
mInfo.dependencies = {
{"engine", "1.0.1", "static" },
{"editor", "1.0.1", "static" },
{"vulkan", "1.0.1", "shared" }
};
};