Skip to content

Commit

Permalink
Use the MakeExporter for emscripten
Browse files Browse the repository at this point in the history
  • Loading branch information
RobDangerous committed Mar 14, 2024
1 parent 7fcc7d9 commit c34087e
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 399 deletions.
229 changes: 38 additions & 191 deletions kmake/src/Exporters/EmscriptenExporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,225 +5,72 @@ import { GraphicsApi } from 'kmake/GraphicsApi';
import * as fs from 'kmake/fsextra';
import * as path from 'path';
import { CompilerCommandsExporter } from 'kmake/Exporters/CompileCommandsExporter';
import { MakeExporter } from 'kmake/Exporters/MakeExporter';

export class EmscriptenExporter extends Exporter {
compileCommands: CompilerCommandsExporter;
make: MakeExporter;

constructor(options: any) {
constructor(project: Project, options: any) {
super(options);
this.compileCommands = new CompilerCommandsExporter(options);
}

exportMakefile(project: Project, from: string, to: string, platform: string, vrApi: any, options: any) {
const cCompiler = 'emcc';
const cppCompiler = 'emcc';

let objects: any = {};
let ofiles: any = {};
let outputPath = path.resolve(to, options.buildPath);
fs.ensureDirSync(outputPath);

let debugDirName = project.getDebugDir();
debugDirName = debugDirName.replace(/\\/g, '/');
if (debugDirName.endsWith('/')) debugDirName = debugDirName.substr(0, debugDirName.length - 1);
if (debugDirName.lastIndexOf('/') >= 0) debugDirName = debugDirName.substr(debugDirName.lastIndexOf('/') + 1);

fs.copyDirSync(path.resolve(from, debugDirName), path.resolve(outputPath, debugDirName));

for (let fileobject of project.getFiles()) {
let file = fileobject.file;
if (file.endsWith('.cpp') || file.endsWith('.c') || file.endsWith('.cc') || file.endsWith('.s') || file.endsWith('.S')) {
let name = file.toLowerCase();
if (name.indexOf('/') >= 0) name = name.substr(name.lastIndexOf('/') + 1);
name = name.substr(0, name.lastIndexOf('.'));
if (!objects[name]) {
objects[name] = true;
ofiles[file] = name;
}
else {
while (objects[name]) {
name = name + '_';
}
objects[name] = true;
ofiles[file] = name;
}
}
let linkerFlags = '-static-libgcc -static-libstdc++';
if (project.targetOptions.emscripten.threads) {
linkerFlags += ' -pthread';
}

let gchfilelist = '';
let precompiledHeaders: string[] = [];
for (let file of project.getFiles()) {
if (file.options && file.options.pch && precompiledHeaders.indexOf(file.options.pch) < 0) {
precompiledHeaders.push(file.options.pch);
}
if (project.targetOptions.emscripten.threads) {
linkerFlags += ' -pthread';
}
for (let file of project.getFiles()) {
let precompiledHeader: string = null;
for (let header of precompiledHeaders) {
if (file.file.endsWith(header)) {
precompiledHeader = header;
break;
}
}
if (precompiledHeader !== null) {
// let realfile = path.relative(outputPath, path.resolve(from, file.file));
gchfilelist += path.basename(file.file) + '.gch ';
}

linkerFlags += ' -s TOTAL_MEMORY=134217728 ';
if (Options.graphicsApi === GraphicsApi.WebGPU) {
linkerFlags += '-s USE_WEBGPU=1 ';
}

let ofilelist = '';
for (let o in objects) {
ofilelist += o + '.o ';
let executableName = project.getSafeName();
if (project.getExecutableName()) {
executableName = project.getExecutableName();
}

this.writeFile(path.resolve(outputPath, 'makefile'));
linkerFlags += ' -o ' + executableName + '.html --preload-file ' + this.debugDirName(project);

let incline = '-I./ '; // local directory to pick up the precompiled header hxcpp.h.gch
for (let inc of project.getIncludeDirs()) {
inc = path.relative(outputPath, path.resolve(from, inc));
incline += '-I' + inc + ' ';
}
this.p('INC=' + incline);
this.make = new MakeExporter(options, 'emcc', 'emcc', '', '', '', '.html', this.libsMakeLine);
}

let libsline = '-static-libgcc -static-libstdc++';
if (project.targetOptions.emscripten.threads) {
libsline += ' -pthread';
}
/*if (project.cmd) {
libsline += ' -static';
}*/
libsMakeLine(project: Project): string {
let libs = '';
for (let lib of project.getLibs()) {
if (lib.startsWith('USE_')) {
libsline += ' -s' + lib;
libs += ' -s' + lib;
}
else {
libsline += ' -l' + lib;
}
}
this.p('LIB=' + libsline);

let defline = '';

if (!options.debug) {
defline += '-DNDEBUG ';
}

for (const def of project.getDefines()) {
if (def.config && def.config.toLowerCase() === 'debug' && !options.debug) {
continue;
}

if (def.config && def.config.toLowerCase() === 'release' && options.debug) {
continue;
libs += ' -l' + lib;
}

defline += '-D' + def.value.replace(/\"/g, '\\"') + ' ';
}
defline += '-D KORE_DEBUGDIR="\\"' + debugDirName + '\\""' + ' ';
this.p('DEF=' + defline);
this.p();

let cline = '-std=c99 ';
if (project.cStd !== '') {
cline = '-std=' + project.cStd + ' ';
}
if (options.dynlib) {
cline += '-fPIC ';
}
for (let flag of project.cFlags) {
cline += flag + ' ';
}
this.p('CFLAGS=' + cline);

let cppline = '';
if (options.dynlib) {
cppline += '-fPIC ';
}
for (let flag of project.cppFlags) {
cppline += flag + ' ';
}
this.p('CPPFLAGS=' + cppline);

let optimization = '';
if (!options.debug) optimization = '-O2';
else optimization = '-g';

if (options.lib) {
this.p(project.getSafeName() + '.a: ' + gchfilelist + ofilelist);
}
else if (options.dynlib) {
this.p(project.getSafeName() + '.so: ' + gchfilelist + ofilelist);
}
else {
this.p('index.html' + ': ' + gchfilelist + ofilelist);
}

let cpp = '';
// cpp = '-std=c++11';
if (project.targetOptions.emscripten.threads) {
cpp += ' -pthread';
}

let linkerFlags = '-s TOTAL_MEMORY=134217728 ';
if (Options.graphicsApi === GraphicsApi.WebGPU) {
linkerFlags += '-s USE_WEBGPU=1 ';
}

let output = ' ' + linkerFlags + '-o index.html --preload-file ' + debugDirName;
if (options.lib) {
output = '-o "' + project.getSafeName() + '.a"';
}
else if (options.dynlib) {
output = '-shared -o "' + project.getSafeName() + '.so"';
}
this.p('\t' + (options.lib ? 'ar rcs' : cppCompiler) + ' ' + output + ' ' + cpp + ' ' + optimization + ' ' + ofilelist + ' $(LIB)');
return libs;
}

for (let file of project.getFiles()) {
let precompiledHeader: string = null;
for (let header of precompiledHeaders) {
if (file.file.endsWith(header)) {
precompiledHeader = header;
break;
}
}
if (precompiledHeader !== null) {
let realfile = path.relative(outputPath, path.resolve(from, file.file));
this.p(path.basename(realfile) + '.gch: ' + realfile);
this.p('\t' + cppCompiler + ' ' + cpp + ' ' + optimization + ' $(INC) $(DEF) -c ' + realfile + ' -o ' + path.basename(file.file) + '.gch');
}
debugDirName(project: Project): string {
let name = project.getDebugDir();
name = name.replace(/\\/g, '/');
if (name.endsWith('/')) {
name = name.substr(0, name.length - 1);
}

for (let fileobject of project.getFiles()) {
let file = fileobject.file;
if (file.endsWith('.c') || file.endsWith('.cpp') || file.endsWith('.cc') || file.endsWith('.s') || file.endsWith('.S')) {
this.p();
let name = ofiles[file];
let realfile = path.relative(outputPath, path.resolve(from, file));
this.p(name + '.o: ' + realfile);

let compiler = cppCompiler;
let flags = '$(CPPFLAGS)';
if (file.endsWith('.c')) {
compiler = cCompiler;
flags = '$(CFLAGS)';
}
else if (file.endsWith('.s') || file.endsWith('.S')) {
compiler = cCompiler;
flags = '';
}

this.p('\t' + compiler + ' ' + cpp + ' ' + optimization + ' $(INC) $(DEF) ' + flags + ' -c ' + realfile + ' -o ' + name + '.o');
}
if (name.lastIndexOf('/') >= 0) {
name = name.substr(name.lastIndexOf('/') + 1);
}

// project.getDefines()
// project.getIncludeDirs()

this.closeFile();
return name;
}

async exportSolution(project: Project, from: string, to: string, platform: string, vrApi: any, options: any) {
this.exportMakefile(project, from, to, platform, vrApi, options);
let outputPath = path.resolve(to, options.buildPath);
fs.ensureDirSync(outputPath);

fs.copyDirSync(path.resolve(from, this.debugDirName(project)), path.resolve(outputPath, this.debugDirName(project)));

this.make.exportSolution(project, from, to, platform, vrApi, options);
this.compileCommands.exportSolution(project, from, to, platform, vrApi, options);
}
}
32 changes: 17 additions & 15 deletions kmake/src/Exporters/MakeExporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,25 @@ export class MakeExporter extends Exporter {
linkerFlags: string;
outputExtension: string;

constructor(options: any, cCompiler: string, cppCompiler: string, cFlags: string, cppFlags: string, linkerFlags: string, outputExtension: string) {
constructor(options: any, cCompiler: string, cppCompiler: string, cFlags: string, cppFlags: string, linkerFlags: string, outputExtension: string, libsLine: (p: Project) => string = null) {
super(options);
this.cCompiler = cCompiler;
this.cppCompiler = cppCompiler;
this.cFlags = cFlags;
this.cppFlags = cppFlags;
this.linkerFlags = linkerFlags;
this.outputExtension = outputExtension;
if (libsLine != null) {
this.libsLine = libsLine;
}
}

libsLine(project: Project): string {
let libs = '';
for (let lib of project.getLibs()) {
libs += ' -l' + lib;
}
return libs;
}

async exportSolution(project: Project, from: string, to: string, platform: string, vrApi: any, options: any) {
Expand Down Expand Up @@ -78,18 +89,14 @@ export class MakeExporter extends Exporter {

this.writeFile(path.resolve(outputPath, 'makefile'));

let incline = '-I./ '; // local directory to pick up the precompiled header hxcpp.h.gch
let incline = '-I./ '; // local directory to pick up the precompiled headers
for (let inc of project.getIncludeDirs()) {
inc = path.relative(outputPath, path.resolve(from, inc));
incline += '-I' + inc + ' ';
}
this.p('INC=' + incline);

let libsline = this.linkerFlags;
for (let lib of project.getLibs()) {
libsline += ' -l' + lib;
}
this.p('LIB=' + libsline);
this.p('LIB=' + this.linkerFlags + this.libsLine(project));

let defline = '';
for (const def of project.getDefines()) {
Expand Down Expand Up @@ -146,8 +153,6 @@ export class MakeExporter extends Exporter {

this.p(executableName + this.outputExtension + ': ' + gchfilelist + ofilelist);

let cpp = '';

let output = '-o "' + executableName + this.outputExtension + '"';
if (options.dynlib) {
output = '-shared -o "' + executableName + '.so"';
Expand All @@ -157,7 +162,7 @@ export class MakeExporter extends Exporter {
this.p('\t' + 'ar rcs ' + output + ' ' + ofilelist);
}
else {
this.p('\t' + this.cppCompiler + ' ' + output + ' ' + cpp + ' ' + optimization + ' ' + ofilelist + ' $(LIB)');
this.p('\t' + this.cppCompiler + ' ' + output + ' ' + optimization + ' ' + ofilelist + ' $(LIB)');
}

for (let file of project.getFiles()) {
Expand All @@ -172,7 +177,7 @@ export class MakeExporter extends Exporter {
let realfile = path.relative(outputPath, path.resolve(from, file.file));
this.p('-include ' + path.basename(file.file) + '.d');
this.p(path.basename(realfile) + '.gch: ' + realfile);
this.p('\t' + this.cppCompiler + ' ' + cpp + ' ' + optimization + ' $(INC) $(DEF) -MD -c ' + realfile + ' -o ' + path.basename(file.file) + '.gch');
this.p('\t' + this.cppCompiler + ' ' + optimization + ' $(INC) $(DEF) -MD -c ' + realfile + ' -o ' + path.basename(file.file) + '.gch');
}
}

Expand All @@ -198,13 +203,10 @@ export class MakeExporter extends Exporter {
flags = '';
}

this.p('\t' + compiler + ' ' + cpp + ' ' + optimization + ' $(INC) $(DEF) -MD ' + flags + ' -c ' + realfile + ' -o ' + name + '.o');
this.p('\t' + compiler + ' ' + optimization + ' $(INC) $(DEF) -MD ' + flags + ' -c ' + realfile + ' -o ' + name + '.o');
}
}

// project.getDefines()
// project.getIncludeDirs()

this.closeFile();
}
}
2 changes: 1 addition & 1 deletion kmake/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ async function exportKoremakeProject(from: string, to: string, platform: string,
}
else if (platform === Platform.iOS || platform === Platform.OSX || platform === Platform.tvOS) exporter = new XCodeExporter(options);
else if (platform === Platform.Android) exporter = new AndroidExporter(options);
else if (platform === Platform.Emscripten) exporter = new EmscriptenExporter(options);
else if (platform === Platform.Emscripten) exporter = new EmscriptenExporter(project, options);
else if (platform === Platform.Wasm) exporter = new WasmExporter(options);
else if (platform === Platform.Linux || platform === Platform.Pi) exporter = new LinuxExporter(options);
else if (platform === Platform.FreeBSD) exporter = new FreeBSDExporter(options);
Expand Down
Loading

0 comments on commit c34087e

Please sign in to comment.