Add publish to crosslang and add plugin_host support for packages

This commit is contained in:
2025-09-30 22:22:14 -05:00
parent cac59c863c
commit 0b51a04bfa
12 changed files with 500 additions and 22 deletions

View File

@@ -0,0 +1,46 @@
cmake_minimum_required(VERSION 3.16)
project(@<<short_name>>@)
option(@<<caps_version>>@_FETCHCONTENT "Whether to use fetchcontent" ON)
option(@<<caps_version>>@_SHARED_CROSSLANG "Whether to use shared crosslang" ON)
add_executable(@<<short_name>>@ src/main.cpp)
if(@<<caps_version>>@_FETCHCONTENT)
set(TESSESFRAMEWORK_ENABLE_EXAMPLES OFF CACHE INTERNAL "For TessesFramework" FORCE)
set(TESSESFRAMEWORK_ENABLE_APPS OFF CACHE INTERNAL "For TessesFramework" FORCE)
set(TESSESFRAMEWORK_FETCHCONTENT ON CACHE INTERNAL "For TessesFramework" FORCE)
set(CROSSLANG_ENABLE_BINARIES OFF CACHE INTERNAL "For CrossLang" FORCE)
if(@<<caps_version>>@_SHARED_CROSSLANG)
set(TESSESFRAMEWORK_ENABLE_STATIC OFF CACHE INTERNAL "For TessesFramework" FORCE)
set(TESSESFRAMEWORK_ENABLE_SHARED ON CACHE INTERNAL "For TessesFramework" FORCE)
else()
set(TESSESFRAMEWORK_ENABLE_STATIC ON CACHE INTERNAL "For TessesFramework" FORCE)
set(TESSESFRAMEWORK_ENABLE_SHARED OFF CACHE INTERNAL "For TessesFramework" FORCE)
endif()
include(FetchContent)
FetchContent_Declare(
TessesCrossLang
GIT_REPOSITORY https://onedev.site.tesses.net/crosslang.git
)
FetchContent_MakeAvailable(TessesCrossLang)
if(@<<caps_version>>@_SHARED_CROSSLANG)
target_link_libraries(@<<short_name>>@ PUBLIC crosslang_shared)
else()
target_link_libraries(@<<short_name>>@ PUBLIC crosslang_static)
endif()
else()
find_package(TessesCrossLang REQUIRED)
if(@<<caps_version>>@_SHARED_CROSSLANG)
target_link_libraries(@<<short_name>>@ PUBLIC TessesCrossLang::crosslang_shared)
else()
target_link_libraries(@<<short_name>>@ PUBLIC TessesCrossLang::crosslang_static)
endif()
endif()
install(TARGETS @<<short_name>>@ DESTINATION "${CMAKE_INSTALL_BINDIR}")

View File

@@ -0,0 +1,76 @@
#include <CrossLang.hpp>
#include "@<<HEADER>>@.h"
using namespace Tesses::Framework;
using namespace Tesses::CrossLang;
int main(int argc, char** argv)
{
std::string name = argv[0];
Tesses::Framework::Filesystem::LocalFilesystem fs;
Tesses::Framework::Filesystem::VFSPath exePath=fs.SystemToVFSPath(name);
exePath.MakeAbsolute();
TF_InitWithConsole();
GC gc;
gc.Start();
GCList ls(gc);
TRootEnvironment* env = TRootEnvironment::Create(ls, TDictionary::Create(ls));
TStd::RegisterStd(&gc,env);
{
auto ms = std::shared_ptr<Tesses::Framework::Streams::MemoryStream>(false);
auto& buff = ms->GetBuffer();
buff.resize(@<<CAPS_VERSION>>@_length);
memcpy(buff.data(),@<<CAPS_VERSION>>@_data,@<<CAPS_VERSION>>@_length);
auto file = TFile::Create(ls);
file->Load(&gc, &ms);
env->LoadFile(&gc,file);
}
if(env->HasVariable("WebAppMain"))
{
Args args(argc, argv);
int port = 4206;
for(auto& item : args.options)
{
if(item.first == "port")
{
port = std::stoi(item.second);
}
}
TList* args2 = TList::Create(ls);
args2->Add(exePath.ToString());
for(auto& item : args.positional)
{
args2->Add(item);
}
auto res = env->CallFunction(ls, "WebAppMain", {args2});
TObjectHttpServer http(&gc, res);
Tesses::Framework::Http::HttpServer svr(port,http,false);
svr.StartAccepting();
TF_RunEventLoop();
TDictionary* _dict;
if(GetObjectHeap(res,_dict))
{
_dict->CallMethod(ls,"Close",{});
}
TF_Quit();
}
else {
TList* args = TList::Create(ls);
args->Add(exePath.ToString());
for(int arg=1;arg<argc;arg++)
args->Add(argv[arg]);
auto res = env->CallFunction(ls,"main",{args});
int64_t iresult;
if(GetObject(res,iresult))
return (int)iresult;
}
return 0;
}

View File

@@ -10,9 +10,9 @@ class Tesses.CrossLang.PackageManager
public PackageManager()
{
this.configRoot = Env.CrossLangConfig;
this.packageCache = configRoot / "PackageCache";
this.packageCache = this.configRoot / "PackageCache";
FS.Local.CreateDirectory(packageCache);
FS.Local.CreateDirectory(this.packageCache);
}
/^ Parse package filename ^/
public ParseFileName(name)
@@ -60,6 +60,7 @@ class Tesses.CrossLang.PackageManager
var v = Version.Parse(version);
var useCache = v.Stage != "dev";
var pkgFile = packageCache / name / v.ToString();
if(useCache && FS.Local.RegularFileExists(pkgFile))
{
return FS.ReadAllBytes(FS.Local,pkgFile);

View File

@@ -0,0 +1,248 @@
class Tesses.CrossLang.Publisher
{
public Publisher(builder,project_dir)
{
this.ProjectBuilder = builder;
this.ProjectDirectory = project_dir;
this.ProjectInfo = Json.Decode(FS.ReadAllText(FS.Local, project_dir / "cross.json"));
}
/^
The project directory to publish
^/
public ProjectDirectory;
/^
The project builder
^/
public ProjectBuilder;
/^
The project cross.json contents
^/
public ProjectInfo;
/^
Where we output the published files
If null (which is default) we output at ProjectDirectory / "publish" / RuntimeIdentifier
^/
public OutputDirectory = null;
/^
The runtime identifier
builtins:
"crvm" (merge to one crvm)
"header" (merge to one crvm and generate C header)
"cmake" (merge to one crvm and generate C header and create a cmake project)
actual runtimes can be found here: https://cpkg.tesseslanguage.com/packages?q=Tesses.CrossLang.Runtime. (you need to strip the Tesses.CrossLang.Runtime. from the names)
^/
public RuntimeIdentifier="crvm";
/^
The prefix of the package (to prepend onto runtime identifier, we put the trailing period for you)
^/
public PackagePrefix = "Tesses.CrossLang.Runtime";
/^
Merge for runtimes (one crvm file)
^/
public MergeForRuntimes = false;
private Build()
{
var out = this.ProjectBuilder.BuildProject(this.ProjectDirectory).Output;
return FS.MakeFull(out);
}
private Merge()
{
var path = this.Build();
var objDir = "obj";
if(TypeOf(ProjectInfo.obj_directory) == "String")
objDir = ProjectInfo.obj_directory;
var packPath = this.ProjectDirectory / objDir / "merge";
if(packPath.Count > 0 && FS.Local.DirectoryExists(packPath))
{
FS.Local.DeleteDirectoryRecurse(packPath);
}
FS.Local.CreateDirectory(packPath);
var pack_dir = new SubdirFilesystem(FS.Local, packPath);
return packPath / VM.Merge(FS.Local,path,pack_dir);
}
private CopyBuild(destPath)
{
func CopyCRVM(src,dest)
{
func copyFile(src,dest)
{
var _src = FS.Local.OpenFile(src,"rb");
var _dest = FS.Local.OpenFile(dest, "wb");
_src.CopyTo(_dest);
_src.Close();
_dest.Close();
Console.WriteLine($"{src} -> {dest}");
}
if(FS.Local.FileExists(dest)) return;
copyFile(src,dest);
var srcStrm = FS.Local.OpenFile(src,"rb");
var crvm = VM.LoadExecutable(srcStrm);
srcStrm.Close();
each(var dep : crvm.Dependencies)
{
var name = $"{dep.Name}-{dep.Version.ToString()}.crvm";
CopyCRVM(src.GetParent()/name, dest.GetParent()/name);
}
}
CopyCRVM(this.Build(), destPath);
}
private CreateCMake(dir, short_name)
{
FS.Local.CreateDirectory(dir / "src");
var path = this.Merge();
var bytes = FS.ReadAllBytes(FS.Local, path);
var caps_version = this.FixCHeaderName(short_name);
FS.WriteAllText(FS.Local, dir / "src" / $"{short_name}.h", bytes.ToCHeaderFile(caps_version));
if(!FS.Local.RegularFileExists(dir / "CMakeLists.txt"))
{
var cmake_file = embed("cml.txt").ToString().Replace("@<<caps_version>>@",caps_version).Replace("@<<short_name>>@",short_name);
FS.WriteAllText(FS.Local,dir / "CMakeLists.txt", cmake_file);
}
if(!FS.Local.RegularFileExists(dir / "src"/"main.cpp"))
{
var cppFile = embed("cppfiletemplate.cpp").ToString().Replace("@<<CAPS_VERSION>>@", caps_version).Replace("@<<HEADER>>@",short_name);
FS.WriteAllText(FS.Local,dir / "src"/"main.cpp", cppFile);
}
}
private CopyFile(src,dest)
{
var srcStrm = FS.Local.OpenFile(src,"rb");
var destStrm = FS.Local.OpenFile(dest, "wb");
srcStrm.CopyTo(destStrm);
srcStrm.Close();
destStrm.Close();
}
private FixCHeaderName(name)
{
var myStr = name.ToUpper();
name = "";
each(var item : myStr)
{
if((item >= 'A' && item <= 'Z') || (item >= '0' && item <= '9') || item == '_')
name += item;
}
if(name.Length == 0) return "NONAME";
else if(name[0] >= '0' && name[0] <= '9')
return $"_{name}";
return name;
}
/^ Start the publishing process ^/
public Publish()
{
var outDir = TypeOf(this.OutputDirectory) == "Null" ? (this.ProjectDirectory / "publish" / this.RuntimeIdentifier) : this.OutputDirectory;
var short_name = TypeOf(this.ProjectInfo.info.short_name) == "String" ? this.ProjectInfo.info.short_name : this.ProjectInfo.name;
FS.Local.CreateDirectory(outDir);
switch(this.RuntimeIdentifier)
{
case "crvm":
{
var path = this.Merge();
FS.Local.MoveFile(path, outDir / $"{short_name}.crvm");
}
break;
case "header":
{
var path = this.Merge();
var bytes = FS.ReadAllBytes(FS.Local, path);
FS.WriteAllText(FS.Local, outDir / $"{short_name}.h", bytes.ToCHeaderFile(this.FixCHeaderName(short_name)));
}
break;
case "cmake":
{
this.CreateCMake(outDir, short_name);
}
break;
default:
{
var runtimePackageName = this.PackagePrefix;
if(runtimePackageName.Count > 0 && !runtimePackageName.EndsWith('.'))
runtimePackageName += ".";
runtimePackageName += this.RuntimeIdentifier;
var version = this.ProjectBuilder.PackageManager.GetLatest(runtimePackageName);
if(TypeOf(version) != "String")
{
throw {
Type="PackageNotFoundException",
Message=$"Could not find package {runtimePackageName}.",
ToString=(this)=>$"{this.Type} on line: {this.Line} {this.Message}"
};
}
var pkgObj = this.ProjectBuilder.PackageManager.GetPackage(runtimePackageName, version);
var strm = new MemoryStream(true);
strm.WriteBlock(pkgObj,0,pkgObj.Length);
strm.Seek(0,0);
var sdfs = new SubdirFilesystem(FS.Local, outDir);
var archiveResponse = FS.ExtractArchive(strm,sdfs);
sdfs.Close();
var archiveInfo = Json.Decode(archiveResponse.Info);
if(archiveInfo.executable_can_be_renamed)
{
var executable_name_path = /archiveInfo.executable_name;
var executable_extension = executable_name_path.GetExtension();
var newName = outDir/short_name;
if(executable_extension.Length > 0) newName += executable_extension;
FS.Local.MoveFile(outDir/archiveInfo.executable_name,newName);
FS.Local.Chmod(newName, 0755);
if(this.MergeForRuntimes)
{
FS.Local.MoveFile(this.Merge(), outDir / short_name + ".crvm");
}
else {
this.CopyBuild(outDir / short_name + ".crvm");
}
}
else {
var executable_name_path = /archiveInfo.executable_name;
FS.Local.Chmod(outDir/archiveInfo.executable_name, 0755);
var executable_name_no_ext = executable_name_path.ChangeExtension(null).GetFileName();
if(this.MergeForRuntimes)
{
FS.Local.MoveFile(this.Merge(), outDir / executable_name_no_ext + ".crvm");
}
else {
this.CopyBuild(outDir / executable_name_no_ext + ".crvm");
}
}
}
break;
}
}
}

View File

@@ -4,16 +4,16 @@ class Tesses.CrossLang.BuildTool
/^ Construct the build tool with Package Manager ^/
public BuildTool(pm)
{
this.PacakgeManager = pm;
this.PackageManager = pm;
}
private copyFile(src,dest)
{
var src = FS.Local.OpenFile(src,"rb");
var dest = FS.Local.OpenFile(dest, "wb");
src.CopyTo(dest);
src.Close();
dest.Close();
var srcStrm = FS.Local.OpenFile(src,"rb");
var destStrm = FS.Local.OpenFile(dest, "wb");
srcStrm.CopyTo(destStrm);
srcStrm.Close();
destStrm.Close();
}
/^ Package Manager Object ^/
public PackageManager;
@@ -22,8 +22,9 @@ class Tesses.CrossLang.BuildTool
/^ Get the dependencies (don't use this directly unless you know what you are doing) ^/
public GetPackageDependencies(name, version, dir)
{
var dep = PackageManager.GetPackage(name,version);
var dep = this.PackageManager.GetPackage(name,version);
if(TypeOf(dep) == "Null") throw $"Package {name} with version {version} does not exist";
var pkgPath = dir / $"{name}-{version}.crvm";
@@ -102,7 +103,7 @@ class Tesses.CrossLang.BuildTool
outputDir = configData.bin_directory;
if(TypeOf(configData.obj_directory) != "Undefined")
outputDir = configData.obj_directory;
objDir = configData.obj_directory;
if(TypeOf(configData.source_directory) != "Undefined")
srcDir = configData.source_directory;
if(TypeOf(configData.resource_directory) != "Undefined")
@@ -185,7 +186,7 @@ class Tesses.CrossLang.BuildTool
FS.Local.CreateDirectory(newDir);
var newFile = newDir / $"{item.Name}-{item.Version}.crvm";
copyFile(item.Output, newFile);
this.copyFile(item.Output, newFile);
each(var item2 : item.Dependencies)
{
walk_for_compiling(item2, newDir);
@@ -205,7 +206,7 @@ class Tesses.CrossLang.BuildTool
}
else
{
copyFile(item.Output, dir2 / $"{item.Name}-{item.Version}.crvm");
this.copyFile(item.Output, dir2 / $"{item.Name}-{item.Version}.crvm");
each(var item2 : item.Dependencies)
{
walk_for_compiling(item2, dir2);