Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[hlc] automatic compilation with Ninja generator #726

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
13 changes: 8 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ jobs:
libturbojpeg-dev \
libuv1-dev \
libvorbis-dev \
libsqlite3-dev
libsqlite3-dev \
ninja-build
;;

darwin*)
Expand Down Expand Up @@ -155,7 +156,7 @@ jobs:
set -eux

haxelib setup ~/haxelib
haxelib install hashlink
haxelib dev hashlink other/haxelib
haxelib list


Expand Down Expand Up @@ -233,9 +234,11 @@ jobs:
popd
fi

haxe -hl src/_main.c -cp other/tests -main HelloWorld
make hlc
./hlc
haxe -hl out/helloworld/main.c -cp other/tests -main HelloWorld -D hlgen.makefile=ninja
out/helloworld/main

haxe -hl out/fmtsample/main.c -cp other/fmtsample -main FmtSample -D hlgen.makefile=ninja
out/fmtsample/main
;;
esac

Expand Down
1 change: 1 addition & 0 deletions Brewfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ brew "mbedtls"
brew "libuv"
brew "openssl"
brew "sqlite"
brew "ninja"
10 changes: 10 additions & 0 deletions other/fmtsample/FmtSample.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function main() {
var out = haxe.io.Bytes.alloc(16);
var src = haxe.io.Bytes.ofString("Hello World!");
hl.Format.digest(out.getData(), src.getData(), src.length, 0 /* md5 */);
final expected = "ed076287532e86365e841e92bfc50d8c";
final got = out.toHex();
if (got != expected) {
throw 'expected $expected, got $got';
}
}
172 changes: 161 additions & 11 deletions other/haxelib/Run.hx
Original file line number Diff line number Diff line change
@@ -1,15 +1,161 @@
import sys.io.File;
import haxe.io.Path;
using StringTools;

class NinjaGenerator {
var buf:StringBuf;

public function new() {
buf = new StringBuf();
}

function comment(value:String, empty_line = false) {
buf.add('# $value \n');
if (empty_line) buf.add('\n');
}

function bind(name:String, value:String) {
buf.add('$name = $value\n\n');
}

function rule(name:String, args:Map<String, String>) {
buf.add('rule $name\n');
for (key => value in args) {
buf.add(' $key = $value\n');
}
buf.add('\n');
}

function build(out:Array<String>, rule:String, input:Array<String>, ?args:Map<String, String>) {
if(args == null) args = [];
buf.add('build ${out.join(' ')}: $rule ${input.join(' ')}\n');
for (key => value in args) {
buf.add(' $key = $value\n');
}
buf.add('\n');
}

function save(path:String) {
var str = this.buf.toString();
File.saveContent(path, str);
}

public static function gen(config: HlcConfig, output: String) {
var gen = new NinjaGenerator();
gen.comment('Automatically generated file, do not edit', true);
gen.bind('ninja_required_version', '1.2');

var compiler_flavor: CCFlavor = switch Sys.systemName() {
case "Windows": MSVC;
case _: GCC;
}

switch compiler_flavor {
case GCC:
var opt_flag = config.defines.exists("debug") ? "-g" : '-O2';
var rpath = switch Sys.systemName() {
case "Mac": "-rpath @executable_path -rpath /usr/local/lib";
case _: "-Wl,-rpath,$$ORIGIN:/usr/local/lib";
};
gen.bind('cflags', '$opt_flag -std=c11 -DHL_MAKE -Wall -I. -pthread');
final libflags = config.libs.map((lib) -> switch lib {
case "std": "-lhl";
case "uv": '/usr/local/lib/$lib.hdll -luv';
case var lib: '/usr/local/lib/$lib.hdll';
}).join(' ');
gen.bind('ldflags', '-pthread -lm -L/usr/local/lib $libflags $rpath');
gen.rule('cc', [
"command" => "cc -MD -MF $out.d $cflags -c $in -o $out",
"deps" => "gcc",
"depfile" => "$out.d",
]);
gen.rule('ld', [
"command" => "cc $in -o $out $ldflags"
]);
case MSVC:
gen.bind('hashlink', Sys.getEnv('HASHLINK'));
gen.bind('cflags', "/DHL_MAKE /std:c11 /I. /I$hashlink\\include");
gen.bind('ldflags', "/LIBPATH:$hashlink libhl.lib");
gen.rule('cc', [
"command" => "cl.exe /nologo /showIncludes $cflags /c $in /Fo$out",
"deps" => "msvc",
]);
gen.rule('ld', [
"command" => "link.exe /nologo /OUT:$out $ldflags @$out.rsp",
"rspfile" => "$out.rsp",
"rspfile_content" => "$in"
]);
}

final objects = [];

for (file in config.files) {
final out_path = haxe.io.Path.withExtension(file, 'o');
objects.push(out_path);
gen.build([out_path.toString()], "cc", [file], []);
}

final exe_path = Path.withExtension(Path.withoutDirectory(output), switch compiler_flavor {
case MSVC: "exe";
case GCC: null;
});
gen.build([exe_path], 'ld', objects, []);

gen.save(Path.join([Path.directory(output), 'build.ninja']));
}

public static function run(dir:String) {
switch Sys.systemName() {
case "Windows":
var devcmd = findVsDevCmdScript();
Sys.command("cmd.exe", ["/C", devcmd, "-arch=x64", '&&', 'ninja', '-C', dir]);
case _:
Sys.command("ninja", ["-C", dir]);
}
}

private static function findVsDevCmdScript(): Null<String> {
var proc = new sys.io.Process('C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe', [
"-latest",
"-products", "*",
"-requires",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"-property",
"installationPath"
]);
proc.stdin.close();
var stdout = proc.stdout.readAll();
if (proc.exitCode(true) == 0) {
var instPath = stdout.toString().trim();
return '$instPath\\Common7\\Tools\\vsdevcmd.bat';
} else {
return null;
}
}
}

enum abstract CCFlavor(String) {
var MSVC = "msvc";
/**
* GCC, Clang, etc
**/
var GCC = "gcc";
}

typedef HlcConfig = {
var version:Int;
var libs:Array<String>;
var defines:haxe.DynamicAccess<String>;
var files:Array<String>;
};

class Build {

var output : String;
var name : String;
var targetDir : String;
var dataPath : String;
var config : {
var version : Int;
var libs : Array<String>;
var defines : haxe.DynamicAccess<String>;
var files : Array<String>;
};
var config : HlcConfig;

public function new(dataPath,output,config) {
this.output = output;
Expand All @@ -21,11 +167,15 @@ class Build {
}

public function run() {
var tpl = config.defines.get("hlgen.makefile");
if( tpl != null )
generateTemplates(tpl);
if( config.defines.get("hlgen.silent") == null )
Sys.println("Code generated in "+output+" automatic native compilation not yet implemented");
switch config.defines.get("hlgen.makefile") {
case "ninja":
NinjaGenerator.gen(config, output);
NinjaGenerator.run(Path.directory(output));
case var tpl:
generateTemplates(tpl);
if( config.defines.get("hlgen.silent") == null )
Sys.println("Code generated in "+output+" automatic native compilation not yet implemented");
}
}

function isAscii( bytes : haxe.io.Bytes ) {
Expand Down