Browse Source

[hlc] Implement automatic compilation with make and Build.xml templates (#706)

* Add Makefile hlc template

* Add hxcpp Build.xml hlc template

* Automate Makefile and Build.xml template builds

* Fix header file check when hlgen.makefilepath is set

* Avoid duplicate slashes in paths in hlc templates

* Avoid passing -std=c11 on MSVC in build.xml

* Add HASHLINK variable based paths in Build.xml

* Support debug builds with Build.xml template

* Improve makefile template

Use LDLIBS for passing libraries to the linker:
https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html#index-LDLIBS

Compile .c files into separate .o files to avoid recompiling the entire
project every time. Use .d files to keep track of .c files that
depend on .h files. For reference:
https://stackoverflow.com/a/52036564

* Add warning about auto generated makefile

* Add mingw support for makefile template

* Fix include path in generated makefile for mingw

For some reason, mingw doesn't like `-I./`, this causes it to be unable
to find the includes

* Keep makefile tmp files within hlgen.makefilepath

Previously it would always generate them next to the .c files,
regardless of whether hlgen.makefilepath had been set. Now it ensures
that it doesn't write outside of the Makefile directory.

This means that it first has to create the directories, otherwise the
compiler complains about directories not existing when it tries to
write the output files.

".SUFFIXES" also has to be set as an empty target, otherwise the built-
in rules mess up the rule dependencies.

* Allow HASHLINK for makefile template on linux/mac

* Simplify mingw flags for makefile template

* Let vs2019, vs2022 template build with makefile provided

* Makefile: generate separate linking flags for mac

* Add hlgen.makefile suggestion based on systemName

---------

Co-authored-by: Yuxiao Mao <[email protected]>
tobil4sk 4 months ago
parent
commit
0f3bc3908f
3 changed files with 120 additions and 21 deletions
  1. 39 21
      other/haxelib/Run.hx
  2. 39 0
      other/haxelib/templates/hxcpp/Build.xml
  3. 42 0
      other/haxelib/templates/make/Makefile

+ 39 - 21
other/haxelib/Run.hx

@@ -2,6 +2,7 @@ class Build {
 
 	var output : String;
 	var name : String;
+	var sourcesDir : String;
 	var targetDir : String;
 	var dataPath : String;
 	var config : {
@@ -17,17 +18,36 @@ class Build {
 		this.dataPath = dataPath;
 		var path = new haxe.io.Path(output);
 		this.name = path.file;
-		this.targetDir = path.dir+"/";
+		this.sourcesDir = path.dir+"/";
+		this.targetDir = this.sourcesDir;
 	}
 
+	function log(message:String) {
+		if( config.defines.get("hlgen.silent") == null )
+			Sys.println(message);
+	}
+
+
 	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");
+		log('Code generated in $output');
+		switch tpl {
+			case "make":
+				Sys.command("make", ["-C", targetDir]);
+			case "hxcpp":
+				Sys.command("haxelib", ["--cwd", targetDir, "run", "hxcpp", "Build.xml"].concat(config.defines.exists("debug") ? ["-Ddebug"] : []));
+			case "vs2019", "vs2022":
+				Sys.command("make", ["-C", targetDir]);
+			case null:
+				var suggestion = (Sys.systemName() == "Windows") ? "vs2019" : "make";
+				log('Set -D hlgen.makefile=${suggestion} for automatic native compilation');
+			case unimplemented:
+				log('Automatic native compilation not yet implemented for $unimplemented');
+		}
 	}
-	
+
 	function isAscii( bytes : haxe.io.Bytes ) {
 		// BOM CHECK
 		if( bytes.length > 3 && bytes.get(0) == 0xEF && bytes.get(1) == 0xBB && bytes.get(2) == 0xBF )
@@ -36,7 +56,7 @@ class Build {
 		var len = bytes.length;
 		while( i < len ) {
 			var c = bytes.get(i++);
-			if( c == 0 || c >= 0x80 ) return false;			
+			if( c == 0 || c >= 0x80 ) return false;
 		}
 		return true;
 	}
@@ -45,22 +65,20 @@ class Build {
 		if( tpl == null || tpl == "1" )
 			tpl = "vs2015";
 		var srcDir = tpl;
-		var targetDir = config.defines.get("hlgen.makefilepath");
 		var jumboBuild = config.defines.get("hlgen.makefile.jumbo");
 		var relDir = "";
-		if( targetDir == null )
-			targetDir = this.targetDir;
-		else {
+		if( config.defines["hlgen.makefilepath"] != null ) {
+			targetDir = config.defines.get("hlgen.makefilepath");
 			if( !StringTools.endsWith(targetDir,"/") && !StringTools.endsWith(targetDir,"\\") )
 				targetDir += "/";
+			var sourcesAbs = sys.FileSystem.absolutePath(sourcesDir);
 			var targetAbs = sys.FileSystem.absolutePath(targetDir);
-			var currentAbs = sys.FileSystem.absolutePath(this.targetDir);
-			if( !StringTools.startsWith(currentAbs, targetAbs+"/") )
-				relDir = currentAbs+"/"; // absolute
-			else 
-				relDir = currentAbs.substr(targetAbs.length+1);
+			if( !StringTools.startsWith(sourcesAbs, targetAbs+"/") )
+				relDir = sourcesAbs+"/"; // absolute
+			else
+				relDir = sourcesAbs.substr(targetAbs.length+1);
 			relDir = relDir.split("\\").join("/");
-			if( relDir != "" )
+			if( !(relDir == "" || StringTools.endsWith(relDir, "/")) )
 				relDir += "/";
 		}
 		if( !sys.FileSystem.exists(srcDir) ) {
@@ -76,7 +94,7 @@ class Build {
 		for( f in config.files )
 			if( StringTools.endsWith(f,".c") ) {
 				var h = f.substr(0,-2) + ".h";
-				if( sys.FileSystem.exists(targetDir+h) )
+				if( sys.FileSystem.exists(sourcesDir+h) )
 					allFiles.push(h);
 			}
 		allFiles.sort(Reflect.compare);
@@ -98,7 +116,7 @@ class Build {
 
 		var directories = [for( k in directories.keys() ) { path : k }];
 		directories.sort(function(a,b) return Reflect.compare(a.path,b.path));
-		
+
 		function genRec( path : String ) {
 			var dir = srcDir + "/" + path;
 			for( f in sys.FileSystem.readDirectory(dir) ) {
@@ -143,7 +161,7 @@ class Build {
 						return sha1.substr(0,8)+"-"+sha1.substr(8,4)+"-"+sha1.substr(12,4)+"-"+sha1.substr(16,4)+"-"+sha1.substr(20,12);
 					},
 					makePath : function(_,dir:String) {
-						return dir == "" ? "./" : (StringTools.endsWith(dir,"/") || StringTools.endsWith(dir,"\\")) ? dir : dir + "/";
+						return dir == "" ? "." : (StringTools.endsWith(dir,"/") || StringTools.endsWith(dir,"\\")) ? dir : dir + "/";
 					},
 					upper : function(_,s:String) {
 						return s.charAt(0).toUpperCase() + s.substr(1);
@@ -172,7 +190,7 @@ class Run {
 		var originalPath = args.pop();
 		var haxelibPath = Sys.getCwd()+"/";
 		Sys.setCwd(originalPath);
-		
+
 		switch( args.shift() ) {
 		case "build":
 			var output = args.shift();
@@ -183,11 +201,11 @@ class Run {
 			new Build(haxelibPath,output,config).run();
 		case "run":
 			var output = args.shift();
-			if( StringTools.endsWith(output,".c") ) return;			
+			if( StringTools.endsWith(output,".c") ) return;
 			Sys.command("hl "+output);
 		case cmd:
 			Sys.println("Unknown command "+cmd);
 			Sys.exit(1);
 		}
 	}
-}
+}

+ 39 - 0
other/haxelib/templates/hxcpp/Build.xml

@@ -0,0 +1,39 @@
+<xml>
+	<files id="::name::">
+		<compilerflag value="-std=c11" unless="MSVC_VER" />
+		<compilerflag value="-DHL_MAKE" />
+		<compilerflag value="-I$$makePath(::relDir::)" />
+		<compilerflag value="-I${HASHLINK}/src" if="HASHLINK" />
+		<compilerflag value="-I${HASHLINK}/include" if="HASHLINK" />
+::foreach hfiles::
+		<depend name="::relDir::::path::" />::end::
+::foreach cfiles::
+		<file name="::relDir::::path::" />::end::
+	</files>
+
+	<set name="ARCH_DIR" value="/x64" if="HXCPP_M64" />
+
+	<target id="default" output="::name::" tool="linker" toolid="exe">
+		<files id="::name::" />
+
+		<libpath name="${HASHLINK}" if="HASHLINK" />
+		<libpath name="${HASHLINK}/lib" if="HASHLINK" />
+
+		<section unless="windows">
+			<lib name="-lhl" />
+			<lib name="-lm" />
+			<lib name="-luv" />
+::foreach libraries::
+			<lib name="-l:::name::.hdll" />::end::
+		</section>
+
+		<section if="windows">
+			<libpath name="${HASHLINK}${ARCH_DIR}/Debug" if="debug HASHLINK" />
+			<libpath name="${HASHLINK}${ARCH_DIR}/Release" if="HASHLINK" unless="debug" />
+
+			<lib name="libhl.lib" />
+::foreach libraries::
+			<lib name="::name::.lib" />::end::
+		</section>
+	</target>
+</xml>

+ 42 - 0
other/haxelib/templates/make/Makefile

@@ -0,0 +1,42 @@
+# Auto-generated from hashlink's Makefile template; do not edit
+
+UNAME := $(shell uname)
+CFLAGS=-O3 -std=c11 -DHL_MAKE -I$$makePath(::relDir::)
+ifeq ($(UNAME),Darwin)
+LDLIBS=-lhl -lm -luv::foreach libraries:: /usr/local/lib/::name::.hdll::end::
+else
+LDLIBS=-lhl -lm -luv::foreach libraries:: -l:::name::.hdll::end::
+endif
+
+ifdef HASHLINK
+CFLAGS+=-I$(HASHLINK)/include -I$(HASHLINK)/src
+LDFLAGS+=-L$(HASHLINK)/lib -L$(HASHLINK)
+endif
+
+ifeq ($(OS),Windows_NT)
+LDFLAGS+=-municode
+LDLIBS+=-ldbghelp
+EXE_SUFFIX=.exe
+endif
+
+SRC_FILES=::foreach cfiles:: \
+	::path::::end::
+
+OBJ_FILES=$(patsubst %.c,%.o,$(SRC_FILES))
+
+DEP_FILES=$(patsubst %.c,%.d,$(SRC_FILES))
+
+::name::$(EXE_SUFFIX): $(OBJ_FILES)
+	$(CC) $(OBJ_FILES) -o $@ $(LDFLAGS) $(LDLIBS)
+
+-include $(DEP_FILES)
+
+%.o:
+	@mkdir -p $(dir $@)
+	$(CC) $(CFLAGS) -MMD -MP -c ::relDir::$*.c -o $@
+
+clean:
+	find . \( -name '*.o' -o -name '*.d' \) -delete
+	rm ::name::$(EXE_SUFFIX)
+
+.SUFFIXES: