diff --git a/package.json b/package.json index 03411e81..872b619e 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "@types/pako": "^2.0.4", "@types/papaparse": "^5.5.2", "@types/three": "^0.182.0", + "@yowasp/clang": "^22.0.0-git20542-10", "bson": "^7.2.0", "celaria-formats": "^1.0.2", "chess.js": "^1.4.0", diff --git a/src/handlers/clang-wasi.ts b/src/handlers/clang-wasi.ts new file mode 100644 index 00000000..6d3e7ab1 --- /dev/null +++ b/src/handlers/clang-wasi.ts @@ -0,0 +1,100 @@ +// file: clang-wasi.ts + +import type { FileData, FileFormat, FormatHandler } from "../FormatHandler.ts"; +import CommonFormats, { Category } from "src/CommonFormats.ts"; +import { commands } from '@yowasp/clang'; + +class clangWasiHandler implements FormatHandler { + + public name: string = "clang-wasi"; + public supportedFormats: FileFormat[] = [ + { + name: "C Source File", + format: "c", + extension: "c", + mime: "text/x-c", + from: true, + to: false, + internal: "c", + category: Category.CODE, + lossless: false, + }, + { + name: "C++ Source File", + format: "cpp", + extension: "cpp", + mime: "text/x-c++src", + from: true, + to: false, + internal: "cpp", + category: Category.CODE, + lossless: false, + }, + { + name: "Assembly Source File", + format: "asm", + extension: "s", + mime: "text/x-asm", + from: true, + to: false, + internal: "asm", + category: Category.CODE, + lossless: false, + }, + { + name: "WebAssembly Binary (Wasm)", + format: "wasm", + extension: "wasm", + mime: "application/wasm", + from: false, + to: true, + internal: "wasm", + category: Category.CODE, + lossless: true, + }, + ]; + public ready: boolean = false; + + async init () { + this.ready = true; + } + + async doConvert ( + inputFiles: FileData[], + inputFormat: FileFormat, + outputFormat: FileFormat + ): Promise { + const outputFiles: FileData[] = []; + for (const inputFile of inputFiles) { + const output = await commands + [inputFormat.internal === "cpp" ? "clang++" : "clang"] + ( + [inputFile.name, "-o", "out.wasm", "-O3", "-fno-exceptions"], + // this build specifically excludes exceptions for some reason + { + [inputFile.name]: inputFile.bytes + } + ); + if (!output) throw new Error("clang did not return any files?"); + + const data = output["out.wasm"]; + let bytes; + if (data instanceof Uint8Array) { // js wtf is this ?? + bytes = data; + } else if (typeof data === "string") { + bytes = new TextEncoder().encode(data); + } else { + throw new Error("clang output was not a file"); + } + + outputFiles.push({ + name: inputFile.name.replace(/\.[^.]+$/, "") + `.wasm`, + bytes, + }); + } + return outputFiles; + } + +} + +export default clangWasiHandler; diff --git a/src/handlers/index.ts b/src/handlers/index.ts index 0c6fae4b..1978e624 100644 --- a/src/handlers/index.ts +++ b/src/handlers/index.ts @@ -72,6 +72,7 @@ import xcursorHandler from "./xcursor.ts"; import shToElfHandler from "./shToElf.ts"; import cssHandler from "./css.ts"; import TypstHandler from "./typst.ts"; +import clangWasiHandler from "./clang-wasi.ts"; const handlers: FormatHandler[] = []; try { handlers.push(new svgTraceHandler()) } catch (_) { }; @@ -150,5 +151,6 @@ try { handlers.push(new xcursorHandler()) } catch (_) { }; try { handlers.push(new shToElfHandler()) } catch (_) { }; try { handlers.push(new cssHandler()) } catch (_) { }; try { handlers.push(new TypstHandler()) } catch (_) { }; +try { handlers.push(new clangWasiHandler()) } catch (_) { }; export default handlers; diff --git a/vite.config.js b/vite.config.js index 2eea43aa..2c6bb3f5 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,7 +7,8 @@ export default defineConfig({ exclude: [ "@ffmpeg/ffmpeg", "@sqlite.org/sqlite-wasm", - "@bokuweb/zstd-wasm" + "@bokuweb/zstd-wasm", + "@yowasp/clang", ] }, base: "/convert/",