Last active
May 3, 2025 11:45
-
-
Save tritao/1817eebcf2a2a13b3831df9d85d1ec95 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.IO; | |
using System.Linq; | |
using System.Runtime.CompilerServices; | |
using CppSharp; | |
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Cors.Infrastructure; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Logging; | |
var builder = WebApplication.CreateBuilder(args); | |
// Configure logging | |
builder.Logging.ClearProviders(); | |
builder.Logging.AddConsole(); | |
builder.Logging.SetMinimumLevel(LogLevel.Information); | |
// Enable CORS | |
builder.Services.AddCors(options => | |
{ | |
options.AddPolicy("AllowAll", policy => | |
policy.AllowAnyOrigin() | |
.AllowAnyMethod() | |
.AllowAnyHeader()); | |
}); | |
var app = builder.Build(); | |
app.UseCors("AllowAll"); | |
// POST /generate endpoint | |
app.MapPost("/generate", async (CodeGenerationRequest request, ILogger<Program> logger) => | |
{ | |
if (string.IsNullOrWhiteSpace(request.Code) || | |
string.IsNullOrWhiteSpace(request.GenerationOptions.Generator)) | |
{ | |
return Results.BadRequest("Invalid input data"); | |
} | |
var stopwatch = Stopwatch.StartNew(); | |
try | |
{ | |
// Create temp dirs for headers and output | |
using var headersDir = new TempDirectory(); | |
using var outputDir = new TempDirectory(); | |
// Write input header | |
var headerPath = Path.Combine(headersDir.Path, "Code.h"); | |
await File.WriteAllTextAsync(headerPath, request.Code); | |
// Set up diagnostics and options | |
Diagnostics.Implementation = new BufferDiagnostics(); | |
var options = new Options | |
{ | |
Architecture = TargetArchitecture.x64, | |
Platform = TargetPlatform.Linux, | |
Compile = false, | |
Debug = true, | |
OutputDir = outputDir.Path | |
}; | |
options.HeaderFiles.Add("Code.h"); | |
options.IncludeDirs.Add(headersDir.Path); | |
// Determine generator kind | |
var errors = new List<string>(); | |
CLI.GetGeneratorKind(options, request.GenerationOptions.Generator, errors); | |
var generator = new Generator(options); | |
if (errors.Any() || !generator.ValidateOptions(errors)) | |
{ | |
return Results.Problem(string.Join("\n", errors)); | |
} | |
// Run generation | |
generator.Run(); | |
stopwatch.Stop(); | |
// Collect generated files | |
var files = Directory.GetFiles(outputDir.Path); | |
var generated = files.Select(file => new GeneratedFile | |
{ | |
Filename = Path.GetRelativePath(outputDir.Path, file), | |
Content = File.ReadAllText(file) | |
}).ToList(); | |
// Build response | |
var response = new CodeGenerationResponse | |
{ | |
GeneratedFiles = generated, | |
ProgramOutputs = ((BufferDiagnostics)Diagnostics.Implementation).Outputs, | |
GenerationTime = stopwatch.ElapsedMilliseconds.ToString() | |
}; | |
return Results.Ok(response); | |
} | |
catch (Exception ex) | |
{ | |
logger.LogError(ex, "Code generation failed"); | |
return Results.Problem(detail: ex.ToString()); | |
} | |
}); | |
app.Run(); | |
/// <summary> | |
/// Helper for creating and auto‑deleting temp directories. | |
/// </summary> | |
public class TempDirectory : IDisposable | |
{ | |
public string Path { get; } | |
private readonly DirectoryInfo _dirInfo; | |
public TempDirectory() | |
{ | |
_dirInfo = Directory.CreateTempSubdirectory("cppsharp"); | |
Path = _dirInfo.FullName; | |
} | |
public void Dispose() | |
{ | |
try | |
{ | |
_dirInfo.Delete(true); | |
} | |
catch | |
{ | |
// ignore cleanup errors | |
} | |
} | |
} | |
/// <summary> | |
/// Collects diagnostic messages in memory with optional indentation. | |
/// </summary> | |
public class BufferDiagnostics : IDiagnostics | |
{ | |
/// <summary> | |
/// All the diagnostic messages collected so far. | |
/// </summary> | |
public IList<string> Outputs { get; } = new List<string>(); | |
private readonly Stack<int> _indents = new(); | |
/// <summary> | |
/// The minimum DiagnosticKind to emit. | |
/// </summary> | |
public DiagnosticKind Level { get; set; } = DiagnosticKind.Message; | |
public void Emit(DiagnosticInfo info) | |
{ | |
if (info.Kind < Level) | |
return; | |
int totalIndent = _indents.Sum(); | |
string formatted = new string(' ', totalIndent) + info.Message; | |
Outputs.Add(formatted); | |
} | |
/// <summary> | |
/// Increase indentation by the given number of spaces (default 2). | |
/// </summary> | |
public void PushIndent(int spaces = 2) => _indents.Push(spaces); | |
/// <summary> | |
/// Remove the most recently added indent level, if any. | |
/// </summary> | |
public void PopIndent() | |
{ | |
if (_indents.Count > 0) | |
_indents.Pop(); | |
} | |
} | |
/// <summary> | |
/// Options specifying how code generation should be performed. | |
/// </summary> | |
public class GenerationOptions | |
{ | |
/// <summary> | |
/// The generator to use (e.g., "C#", "Java", "Python"). | |
/// </summary> | |
public string Generator { get; set; } = string.Empty; | |
} | |
/// <summary> | |
/// The request payload for the code generation endpoint. | |
/// </summary> | |
public class CodeGenerationRequest | |
{ | |
/// <summary> | |
/// The C/C++ source code to generate bindings for. | |
/// </summary> | |
public string Code { get; set; } = string.Empty; | |
/// <summary> | |
/// Options controlling how code generation should proceed. | |
/// </summary> | |
public GenerationOptions GenerationOptions { get; set; } = new GenerationOptions(); | |
} | |
/// <summary> | |
/// A single file generated by the code generator. | |
/// </summary> | |
public class GeneratedFile | |
{ | |
/// <summary> | |
/// Relative path or name of the generated file. | |
/// </summary> | |
public string Filename { get; set; } = string.Empty; | |
/// <summary> | |
/// Contents of the generated file. | |
/// </summary> | |
public string Content { get; set; } = string.Empty; | |
} | |
/// <summary> | |
/// The response payload from the code generation endpoint. | |
/// </summary> | |
public class CodeGenerationResponse | |
{ | |
/// <summary> | |
/// Files generated by the code generator. | |
/// </summary> | |
public List<GeneratedFile> GeneratedFiles { get; set; } = new List<GeneratedFile>(); | |
/// <summary> | |
/// Any textual outputs or diagnostics produced during generation. | |
/// </summary> | |
public List<string> ProgramOutputs { get; set; } = new List<string>(); | |
/// <summary> | |
/// How long generation took, in milliseconds. | |
/// </summary> | |
public string GenerationTime { get; set; } = string.Empty; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment