diff --git a/content/runtime/_index.md b/content/runtime/_index.md new file mode 100644 index 0000000..926dfdc --- /dev/null +++ b/content/runtime/_index.md @@ -0,0 +1,8 @@ ++++ +title = 'Runtime' +date = 2025-10-22T20:22:26-05:00 +weight = 3 ++++ + +- [Create A Runtime Plugin](plugin.md) + diff --git a/content/runtime/plugin.md b/content/runtime/plugin.md new file mode 100644 index 0000000..7ed8be4 --- /dev/null +++ b/content/runtime/plugin.md @@ -0,0 +1,233 @@ ++++ +title = 'Create A Runtime Plugin' +date = 2025-10-22T20:23:48-05:00 +weight = 1 ++++ + +There are a couple ways of doing this + +- Creating a shared library (only works if using shared libs) +- Embeding the runtime +- Forking crosslang and adding functionality (I don't support pull requests at this time) + +### Shared Library + +This assumes you are on linux, if on windows use MyPlugin.dll on mac libMyPlugin.dylib in crosslang project (it would be a good idea to check Env.Platform) + +CMakeLists.txt: +```cmake +cmake_minimum_required(VERSION 3.16) + +project(MyPlugin) + +find_package(TessesCrossLang REQUIRED) + +add_library(MyPlugin SHARED lib.cpp) + +target_link_libraries(MyPlugin PUBLIC TessesCrossLang::crosslang_shared) +``` + +lib.cpp: +```c++ +#include + +using namespace Tesses::CrossLang; + +void MyPlugin(GC* gc, TRootEnvironment* env) +{ + GCList ls(gc); + TDictionary* dict = TDictionary::Create(ls,{ + TDItem("MyFunction", TExternalMethod::Create(ls, "A description for function",{"myLong","$optionalList"},[](GCList& ls, std::vector args)->TObject { + int64_t n; + if(GetArgument(args,0,n)) + { + TList* myLs; + if(GetArgumentHeap(args,1,myLs)) + { + //do something with the list + myLs->Add(n); + return TList::Create(ls, {n,myLs}); + } + + + return TList::Create(ls, {n}); + } + + return nullptr; + })) + }); + + gc->BarrierBegin(); + env->SetVariable("MyPlugin",dict); + gc->BarrierEnd(); +} + +CROSSLANG_PLUGIN(MyPlugin); + +``` + +main.tcross: +```go +func main(args) +{ + Reflection.LoadNativePlugin(FS.MakeFull("libMyPlugin.so")); + + var res = MyPlugin.MyFunction(42); + if(TypeOf(res) == "List") + { + Console.WriteLine(res); + } + + var res = MyPlugin.MyFunction(42,["Hello","John"]); + if(TypeOf(res) == "List") + { + Console.WriteLine(res); + } +} +``` + + +### Embeding the runtime + +CMakeLists.txt: +```cmake +cmake_minimum_required(VERSION 3.16) + +project(MyCrossLangBinary) + +find_package(TessesCrossLang REQUIRED) + +add_executable(MyCrossLangBinary SHARED app.cpp) + +target_link_libraries(MyCrossLangBinary PUBLIC TessesCrossLang::crosslang_shared) # or crosslang_static for static linking + + +``` + +app.cpp: +```c++ +#include + +using namespace Tesses::CrossLang; +using namespace Tesses::Framework; + +void MyPlugin(GC* gc, TRootEnvironment* env) +{ + GCList ls(gc); + TDictionary* dict = TDictionary::Create(ls,{ + TDItem("MyFunction", TExternalMethod::Create(ls, "A description for function",{"myLong","$optionalList"},[](GCList& ls, std::vector args)->TObject { + int64_t n; + if(GetArgument(args,0,n)) + { + TList* myLs; + if(GetArgumentHeap(args,1,myLs)) + { + //do something with the list + myLs->Add(n); + return TList::Create(ls, {n,myLs}); + } + + + return TList::Create(ls, {n}); + } + + return nullptr; + })) + }); + + gc->BarrierBegin(); + env->SetVariable("MyPlugin",dict); + gc->BarrierEnd(); +} + +int main(int argc, char** argv) +{ + TF_Init(); + if(argc < 2) + { + printf("USAGE: %s \n",argv[0]); + return 1; + } + GC gc; + gc.RegisterEverythingCallback(MyPlugin); + gc.Start(); + GCList ls(gc); + TRootEnvironment* env = TRootEnvironment::Create(ls,TDictionary::Create(ls)); + Tesses::Framework::Filesystem::LocalFilesystem fs; + TStd::RegisterStd(&gc,env); + env->LoadFileWithDependencies(&gc, &fs, fs.SystemToVFSPath(argv[1])); + + TList* args = TList::Create(ls); + for(int arg=1;argAdd(std::string(argv[arg])); + + auto res = env->CallFunction(ls,"main",{args}); + int64_t iresult; + if(GetObject(res,iresult)) + return (int)iresult; + return 0; +} +``` + +main.tcross (needs to be compiled with crossc): +```go +func main(args) +{ + //no reflection necessary + + var res = MyPlugin.MyFunction(42); + if(TypeOf(res) == "List") + { + Console.WriteLine(res); + } + + var res = MyPlugin.MyFunction(42,["Hello","John"]); + if(TypeOf(res) == "List") + { + Console.WriteLine(res); + } +} +``` + +### Forking (implementing it in runtime library itself) +- edit include/CrossLang.hpp +- in TStd class insert, static void RegisterMyPlugin(GC* gc, TRootEnvironment* env); where MyPlugin is whatever you want +- edit src/runtime_methods/std.cpp +- in TStd::RegisterStd before register everything call TStd::RegisterMyPlugin(gc, env); +- in CMakeLists.txt within list(APPEND CROSSLANG_SOURCE **Many Source Files**) you must add src/runtime_methods/myplugin.cpp + +src/runtime_methods/myplugin.cpp: +```c++ +#include +namespace Tesses::CrossLang +{ + void TStd::RegisterMyPlugin(GC* gc, TRootEnvironment* env) + { + GCList ls(gc); + TDictionary* dict = TDictionary::Create(ls,{ + TDItem("MyFunction", TExternalMethod::Create(ls, "A description for function",{"myLong","$optionalList"},[](GCList& ls, std::vector args)->TObject { + int64_t n; + if(GetArgument(args,0,n)) + { + TList* myLs; + if(GetArgumentHeap(args,1,myLs)) + { + //do something with the list + myLs->Add(n); + return TList::Create(ls, {n,myLs}); + } + + + return TList::Create(ls, {n}); + } + + return nullptr; + })) + }); + + gc->BarrierBegin(); + env->SetVariable("MyPlugin",dict); + gc->BarrierEnd(); + } +} +``` \ No newline at end of file