Skip to content

Commit 5d0bdbe

Browse files
Add ninja generator.
1 parent 4a42e9e commit 5d0bdbe

File tree

4 files changed

+184
-13
lines changed

4 files changed

+184
-13
lines changed

.github/workflows/build.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ jobs:
128128
libturbojpeg-dev \
129129
libuv1-dev \
130130
libvorbis-dev \
131-
libsqlite3-dev
131+
libsqlite3-dev \
132+
ninja-build
132133
;;
133134
134135
darwin*)
@@ -156,7 +157,7 @@ jobs:
156157
set -eux
157158
158159
haxelib setup ~/haxelib
159-
haxelib install hashlink
160+
haxelib dev hashlink other/haxelib
160161
haxelib list
161162
162163
@@ -237,6 +238,11 @@ jobs:
237238
haxe -hl src/_main.c -cp other/tests -main HelloWorld
238239
make hlc
239240
./hlc
241+
haxe -hl out/helloworld/main.c -cp other/tests -main HelloWorld -D hlgen.makefile=ninja
242+
out/helloworld/main
243+
244+
haxe -hl out/fmtsample/main.c -cp other/fmtsample -main FmtSample -D hlgen.makefile=ninja
245+
out/fmtsample/main
240246
;;
241247
esac
242248

Brewfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ brew "mbedtls"
1111
brew "libuv"
1212
brew "openssl"
1313
brew "sqlite"
14+
brew "ninja"

other/fmtsample/FmtSample.hx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
function main() {
2+
var out = haxe.io.Bytes.alloc(16);
3+
var src = haxe.io.Bytes.ofString("Hello World!");
4+
hl.Format.digest(out.getData(), src.getData(), src.length, 0 /* md5 */);
5+
final expected = "ed076287532e86365e841e92bfc50d8c";
6+
final got = out.toHex();
7+
if (got != expected) {
8+
throw 'expected $expected, got $got';
9+
}
10+
}

other/haxelib/Run.hx

Lines changed: 165 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,165 @@
1+
import sys.io.File;
2+
import haxe.io.Path;
3+
using StringTools;
4+
5+
class NinjaGenerator {
6+
var buf:StringBuf;
7+
8+
public function new() {
9+
buf = new StringBuf();
10+
}
11+
12+
function comment(value:String, empty_line = false) {
13+
buf.add('# $value \n');
14+
if (empty_line) buf.add('\n');
15+
}
16+
17+
function bind(name:String, value:String) {
18+
buf.add('$name = $value\n\n');
19+
}
20+
21+
function rule(name:String, args:Map<String, String>) {
22+
buf.add('rule $name\n');
23+
for (key => value in args) {
24+
buf.add(' $key = $value\n');
25+
}
26+
buf.add('\n');
27+
}
28+
29+
function build(out:Array<String>, rule:String, input:Array<String>, ?args:Map<String, String>) {
30+
if(args == null) args = [];
31+
buf.add('build ${out.join(' ')}: $rule ${input.join(' ')}\n');
32+
for (key => value in args) {
33+
buf.add(' $key = $value\n');
34+
}
35+
buf.add('\n');
36+
}
37+
38+
function save(path:String) {
39+
var str = this.buf.toString();
40+
File.saveContent(path, str);
41+
}
42+
43+
public static function gen(config: HlcConfig, output: String) {
44+
var gen = new NinjaGenerator();
45+
gen.comment('Automatically generated file, do not edit', true);
46+
gen.bind('ninja_required_version', '1.2');
47+
48+
var compiler_flavor: CCFlavor = switch Sys.systemName() {
49+
case "Windows": MSVC;
50+
case _: GCC;
51+
}
52+
53+
switch compiler_flavor {
54+
case GCC:
55+
var opt_flag = config.defines.exists("debug") ? "-g" : '-O2';
56+
var rpath = switch Sys.systemName() {
57+
case "Mac": "-rpath @executable_path -rpath /usr/local/lib";
58+
case _: "-Wl,-rpath,$$ORIGIN:/usr/local/lib";
59+
};
60+
gen.bind('cflags', '$opt_flag -std=c11 -DHL_MAKE -Wall -I. -pthread');
61+
final libflags = config.libs.map((lib) -> switch lib {
62+
case "std": "-lhl";
63+
case "uv": '/usr/local/lib/$lib.hdll -luv';
64+
case var lib: '/usr/local/lib/$lib.hdll';
65+
}).join(' ');
66+
gen.bind('ldflags', '-pthread -lm -L/usr/local/lib $libflags $rpath');
67+
gen.rule('cc', [
68+
"command" => "cc -MD -MF $out.d $cflags -c $in -o $out",
69+
"deps" => "gcc",
70+
"depfile" => "$out.d",
71+
]);
72+
gen.rule('ld', [
73+
"command" => "cc $in -o $out $ldflags"
74+
]);
75+
case MSVC:
76+
gen.bind('hashlink', Sys.getEnv('HASHLINK'));
77+
gen.bind('cflags', "/DHL_MAKE /std:c11 /I. /I$hashlink\\include");
78+
final libflags = config.libs.map((lib) -> switch lib {
79+
case "std": "libhl.lib";
80+
case var lib: '$lib.lib';
81+
});
82+
gen.bind('ldflags', "/LIBPATH:$hashlink " + libflags);
83+
gen.rule('cc', [
84+
"command" => "cl.exe /nologo /showIncludes $cflags /c $in /Fo$out",
85+
"deps" => "msvc",
86+
]);
87+
gen.rule('ld', [
88+
"command" => "link.exe /nologo /OUT:$out $ldflags @$out.rsp",
89+
"rspfile" => "$out.rsp",
90+
"rspfile_content" => "$in"
91+
]);
92+
}
93+
94+
final objects = [];
95+
96+
for (file in config.files) {
97+
final out_path = haxe.io.Path.withExtension(file, 'o');
98+
objects.push(out_path);
99+
gen.build([out_path.toString()], "cc", [file], []);
100+
}
101+
102+
final exe_path = Path.withExtension(Path.withoutDirectory(output), switch compiler_flavor {
103+
case MSVC: "exe";
104+
case GCC: null;
105+
});
106+
gen.build([exe_path], 'ld', objects, []);
107+
108+
gen.save(Path.join([Path.directory(output), 'build.ninja']));
109+
}
110+
111+
public static function run(dir:String) {
112+
switch Sys.systemName() {
113+
case "Windows":
114+
var devcmd = findVsDevCmdScript();
115+
Sys.command("cmd.exe", ["/C", devcmd, "-arch=x64", '&&', 'ninja', '-C', dir]);
116+
case _:
117+
Sys.command("ninja", ["-C", dir]);
118+
}
119+
}
120+
121+
private static function findVsDevCmdScript(): Null<String> {
122+
var proc = new sys.io.Process('C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe', [
123+
"-latest",
124+
"-products", "*",
125+
"-requires",
126+
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
127+
"-property",
128+
"installationPath"
129+
]);
130+
proc.stdin.close();
131+
var stdout = proc.stdout.readAll();
132+
if (proc.exitCode(true) == 0) {
133+
var instPath = stdout.toString().trim();
134+
return '$instPath\\Common7\\Tools\\vsdevcmd.bat';
135+
} else {
136+
return null;
137+
}
138+
}
139+
}
140+
141+
enum abstract CCFlavor(String) {
142+
var MSVC = "msvc";
143+
/**
144+
* GCC, Clang, etc
145+
**/
146+
var GCC = "gcc";
147+
}
148+
149+
typedef HlcConfig = {
150+
var version:Int;
151+
var libs:Array<String>;
152+
var defines:haxe.DynamicAccess<String>;
153+
var files:Array<String>;
154+
};
155+
1156
class Build {
2157

3158
var output : String;
4159
var name : String;
5160
var targetDir : String;
6161
var dataPath : String;
7-
var config : {
8-
var version : Int;
9-
var libs : Array<String>;
10-
var defines : haxe.DynamicAccess<String>;
11-
var files : Array<String>;
12-
};
162+
var config : HlcConfig;
13163

14164
public function new(dataPath,output,config) {
15165
this.output = output;
@@ -21,11 +171,15 @@ class Build {
21171
}
22172

23173
public function run() {
24-
var tpl = config.defines.get("hlgen.makefile");
25-
if( tpl != null )
26-
generateTemplates(tpl);
27-
if( config.defines.get("hlgen.silent") == null )
28-
Sys.println("Code generated in "+output+" automatic native compilation not yet implemented");
174+
switch config.defines.get("hlgen.makefile") {
175+
case "ninja":
176+
NinjaGenerator.gen(config, output);
177+
NinjaGenerator.run(Path.directory(output));
178+
case var tpl:
179+
generateTemplates(tpl);
180+
if( config.defines.get("hlgen.silent") == null )
181+
Sys.println("Code generated in "+output+" automatic native compilation not yet implemented");
182+
}
29183
}
30184

31185
function isAscii( bytes : haxe.io.Bytes ) {

0 commit comments

Comments
 (0)