diff --git a/include.xml b/include.xml
index 557ade113..005dea3f6 100644
--- a/include.xml
+++ b/include.xml
@@ -68,6 +68,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lime/project/HXProject.hx b/lime/project/HXProject.hx
index fef6a4b88..3d1172013 100644
--- a/lime/project/HXProject.hx
+++ b/lime/project/HXProject.hx
@@ -49,6 +49,7 @@ class HXProject {
public var libraries:Array ;
public var libraryHandlers:Map ;
public var meta:MetaData;
+ public var modules:Map;
public var ndlls:Array ;
public var platformType:PlatformType;
public var postBuildCallbacks:Array ;
@@ -234,6 +235,7 @@ class HXProject {
javaPaths = new Array ();
libraries = new Array ();
libraryHandlers = new Map ();
+ modules = new Map ();
ndlls = new Array ();
postBuildCallbacks = new Array ();
preBuildCallbacks = new Array ();
@@ -325,6 +327,12 @@ class HXProject {
ObjectHelper.copyFields (meta, project.meta);
+ for (key in modules.keys ()) {
+
+ project.modules.set (key, modules.get (key).clone ());
+
+ }
+
for (ndll in ndlls) {
project.ndlls.push (ndll.clone ());
@@ -370,7 +378,7 @@ class HXProject {
}
- private function filter (text:String, include:Array = null, exclude:Array = null):Bool {
+ private function filter (text:String, include:Array = null, exclude:Array = null):Bool {
if (include == null) {
@@ -744,6 +752,21 @@ class HXProject {
icons = ArrayHelper.concatUnique (icons, project.icons);
javaPaths = ArrayHelper.concatUnique (javaPaths, project.javaPaths, true);
libraries = ArrayHelper.concatUnique (libraries, project.libraries, true);
+
+ for (key in project.modules.keys ()) {
+
+ if (modules.exists (key)) {
+
+ modules.get (key).merge (project.modules.get (key));
+
+ } else {
+
+ modules.set (key, project.modules.get (key));
+
+ }
+
+ }
+
ndlls = ArrayHelper.concatUnique (ndlls, project.ndlls);
postBuildCallbacks = postBuildCallbacks.concat (project.postBuildCallbacks);
preBuildCallbacks = preBuildCallbacks.concat (project.preBuildCallbacks);
diff --git a/lime/project/ModuleData.hx b/lime/project/ModuleData.hx
new file mode 100644
index 000000000..2802efdd7
--- /dev/null
+++ b/lime/project/ModuleData.hx
@@ -0,0 +1,57 @@
+package lime.project;
+
+
+import lime.tools.helpers.ArrayHelper;
+
+
+class ModuleData {
+
+
+ public var classNames:Array;
+ public var excludeTypes:Array;
+ public var haxeflags:Array;
+ public var includeTypes:Array;
+ public var name:String;
+
+
+ public function new (name:String) {
+
+ this.name = name;
+ classNames = [];
+ excludeTypes = [];
+ haxeflags = [];
+ includeTypes = [];
+
+ }
+
+
+ public function clone ():ModuleData {
+
+ var copy = new ModuleData (name);
+ copy.classNames = classNames.copy ();
+ copy.excludeTypes = excludeTypes.copy ();
+ copy.haxeflags = haxeflags.copy ();
+ copy.includeTypes = includeTypes.copy ();
+ return copy;
+
+ }
+
+
+ public function merge (other:ModuleData):Bool {
+
+ if (other.name == name) {
+
+ classNames = ArrayHelper.concatUnique (classNames, other.classNames);
+ excludeTypes = ArrayHelper.concatUnique (excludeTypes, other.excludeTypes);
+ haxeflags = ArrayHelper.concatUnique (haxeflags, other.haxeflags);
+ includeTypes = ArrayHelper.concatUnique (includeTypes, other.includeTypes);
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/lime/project/ProjectXMLParser.hx b/lime/project/ProjectXMLParser.hx
index dd1f2360f..44fe35e35 100644
--- a/lime/project/ProjectXMLParser.hx
+++ b/lime/project/ProjectXMLParser.hx
@@ -133,6 +133,10 @@ class ProjectXMLParser extends HXProject {
defines.set ("debug", "1");
+ } else if (targetFlags.exists ("final")) {
+
+ defines.set ("final", "1");
+
} else {
defines.set ("release", "1");
@@ -754,6 +758,191 @@ class ProjectXMLParser extends HXProject {
}
+ private function parseModuleElement (element:Fast, basePath:String = "", moduleData:ModuleData = null):Void {
+
+ var topLevel = (moduleData == null);
+
+ var exclude = "";
+ var include = "*";
+
+ if (element.has.include) {
+
+ include = substitute (element.att.include);
+
+ }
+
+ if (element.has.exclude) {
+
+ exclude = substitute (element.att.exclude);
+
+ }
+
+ if (moduleData == null) {
+
+ var name = substitute (element.att.name);
+
+ if (modules.exists (name)) {
+
+ moduleData = modules.get (name);
+
+ } else {
+
+ moduleData = new ModuleData (name);
+ modules.set (name, moduleData);
+
+ }
+
+ }
+
+ switch (element.name) {
+
+ case "module":
+
+ if (element.has.source) {
+
+ var source = PathHelper.combine (basePath, substitute (element.att.source));
+
+ if (!FileSystem.exists (source)) {
+
+ LogHelper.error ("Could not find module source \"" + source + "\"");
+ return;
+
+ }
+
+ moduleData.haxeflags.push ("-cp " + source);
+
+ var path = source;
+
+ if (element.has.resolve ("package")) {
+
+ path = PathHelper.combine (source, StringTools.replace (substitute (element.att.resolve ("package")), ".", "/"));
+
+ }
+
+ parseModuleElementSource (source, moduleData, include.split ("|"), exclude.split ("|"), path);
+
+ }
+
+ case "source":
+
+ if (element.has.path) {
+
+ var source = PathHelper.combine (basePath, substitute (element.att.path));
+
+ if (!FileSystem.exists (source)) {
+
+ LogHelper.error ("Could not find module source \"" + source + "\"");
+ return;
+
+ }
+
+ moduleData.haxeflags.push ("-cp " + source);
+
+ var path = source;
+
+ if (element.has.resolve ("package")) {
+
+ path = PathHelper.combine (source, StringTools.replace (substitute (element.att.resolve ("package")), ".", "/"));
+
+ }
+
+ parseModuleElementSource (source, moduleData, include.split ("|"), exclude.split ("|"), path);
+
+ }
+
+ case "class":
+
+ moduleData.classNames.push (substitute (element.att.name));
+
+ case "haxedef":
+
+ var value = substitute (element.att.name);
+
+ if (element.has.value) {
+
+ value += "=" + substitute (element.att.value);
+
+ }
+
+ moduleData.haxeflags.push ("-D " + value);
+
+ case "haxeflag":
+
+ var flag = substitute (element.att.name);
+
+ if (element.has.value) {
+
+ flag += " " + substitute (element.att.value);
+
+ }
+
+ moduleData.haxeflags.push (substitute (flag));
+
+ case "include":
+
+ moduleData.includeTypes.push (substitute (element.att.type));
+
+ case "exclude":
+
+ moduleData.excludeTypes.push (substitute (element.att.type));
+
+ }
+
+ if (topLevel) {
+
+ for (childElement in element.elements) {
+
+ if (isValidElement (childElement, "")) {
+
+ parseModuleElement (childElement, basePath, moduleData);
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ private function parseModuleElementSource (source:String, moduleData:ModuleData, include:Array, exclude:Array, currentPath:String):Void {
+
+ var files = FileSystem.readDirectory (currentPath);
+ var filePath, className;
+
+ for (file in files) {
+
+ filePath = PathHelper.combine (currentPath, file);
+
+ if (FileSystem.isDirectory (filePath)) {
+
+ parseModuleElementSource (source, moduleData, include, exclude, filePath);
+
+ } else {
+
+ if (Path.extension (file) != "hx") continue;
+
+ className = StringTools.replace (filePath, source, "");
+ className = StringTools.replace (className, "\\", "/");
+
+ while (StringTools.startsWith (className, "/")) className = className.substr (1);
+
+ className = StringTools.replace (className, "/", ".");
+ className = StringTools.replace (className, ".hx", "");
+
+ if (filter (className, include, exclude)) {
+
+ moduleData.classNames.push (className);
+
+ }
+
+ }
+
+ }
+
+ }
+
+
private function parseOutputElement (element:Fast):Void {
if (element.has.name) {
@@ -1367,6 +1556,10 @@ class ProjectXMLParser extends HXProject {
}
+ case "module":
+
+ parseModuleElement (element, extensionPath);
+
case "ssl":
//if (wantSslCertificate())
diff --git a/lime/tools/helpers/ArrayHelper.hx b/lime/tools/helpers/ArrayHelper.hx
index 9d4077589..35470d516 100644
--- a/lime/tools/helpers/ArrayHelper.hx
+++ b/lime/tools/helpers/ArrayHelper.hx
@@ -111,4 +111,53 @@ class ArrayHelper {
}
+ public static function getUnique (a:Array, b:Array, key:String = null):Array {
+
+ if (a == null && b == null) {
+
+ return new Array ();
+
+ } else if (a == null && b != null) {
+
+ return b;
+
+ }
+
+ var concat = [];
+
+ for (bValue in b) {
+
+ var hasValue = false;
+
+ for (aValue in a) {
+
+ if (key != null) {
+
+ if (Reflect.field (aValue, key) == Reflect.field (bValue, key)) {
+
+ hasValue = true;
+
+ }
+
+ } else if (aValue == bValue) {
+
+ hasValue = true;
+
+ }
+
+ }
+
+ if (!hasValue) {
+
+ concat.push (bValue);
+
+ }
+
+ }
+
+ return concat;
+
+ }
+
+
}
diff --git a/lime/tools/helpers/ModuleHelper.hx b/lime/tools/helpers/ModuleHelper.hx
new file mode 100644
index 000000000..2261b3ba1
--- /dev/null
+++ b/lime/tools/helpers/ModuleHelper.hx
@@ -0,0 +1,179 @@
+package lime.tools.helpers; #if !macro
+
+
+import lime.project.Dependency;
+import lime.project.Haxelib;
+import lime.project.HXProject;
+import sys.io.File;
+
+
+class ModuleHelper {
+
+
+ public static function buildModules (project:HXProject, tempDirectory:String, outputDirectory:String):Void {
+
+ tempDirectory = PathHelper.combine (tempDirectory, "lib");
+ outputDirectory = PathHelper.combine (outputDirectory, "lib");
+
+ PathHelper.mkdir (tempDirectory);
+ PathHelper.mkdir (outputDirectory);
+
+ var importName, hxmlPath, importPath, outputPath, moduleImport, hxml;
+
+ for (module in project.modules) {
+
+ if (module.classNames.length > 0) {
+
+ importName = "Module" + module.name.charAt (0).toUpperCase () + module.name.substr (1);
+
+ hxmlPath = PathHelper.combine (tempDirectory, module.name + ".hxml");
+ importPath = PathHelper.combine (tempDirectory, importName + ".hx");
+
+ if (project.targetFlags.exists ("final")) {
+
+ outputPath = PathHelper.combine (outputDirectory, module.name + ".min.js");
+
+ } else {
+
+ outputPath = PathHelper.combine (outputDirectory, module.name + ".js");
+
+ }
+
+ moduleImport = "package;\n\nimport " + module.classNames.join (";\nimport ") + ";";
+
+ hxml = "-cp " + tempDirectory;
+
+ hxml += "\n" + module.haxeflags.join ("\n");
+ hxml += "\n-cp " + PathHelper.getHaxelib (new Haxelib ("lime"));
+
+ for (key in project.haxedefs.keys ()) {
+
+ if (key != "no-compilation") {
+
+ var value = project.haxedefs.get (key);
+
+ if (value == null || value == "") {
+
+ hxml += "\n-D " + key;
+
+ } else {
+
+ hxml += "\n-D " + key + "=" + value;
+
+ }
+
+ }
+
+ }
+
+ hxml += "\n-D html5";
+ hxml += "\n-D html";
+ hxml += "\n--no-inline";
+ hxml += "\n-dce no";
+ hxml += "\n-js " + outputPath;
+
+ var includeTypes = module.classNames.concat (module.includeTypes);
+ var excludeTypes = module.excludeTypes;
+
+ for (otherModule in project.modules) {
+
+ if (otherModule != module) {
+
+ excludeTypes = excludeTypes.concat (ArrayHelper.getUnique (includeTypes, otherModule.classNames));
+ excludeTypes = excludeTypes.concat (ArrayHelper.getUnique (includeTypes, otherModule.includeTypes));
+
+ }
+
+ }
+
+ if (excludeTypes.length > 0) {
+
+ hxml += "\n--macro lime.tools.helpers.ModuleHelper.exclude(['" + excludeTypes.join ("','") + "'])";
+
+ }
+
+ hxml += "\n--macro lime.tools.helpers.ModuleHelper.expose(['" + includeTypes.join ("','") + "'])";
+
+ hxml += "\n" + importName;
+
+ File.saveContent (importPath, moduleImport);
+ File.saveContent (hxmlPath, hxml);
+
+ ProcessHelper.runCommand ("", "haxe", [ hxmlPath ]);
+
+ if (project.targetFlags.exists ("final")) {
+
+ HTML5Helper.minify (project, outputPath);
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ public static function updateProject (project:HXProject):Void {
+
+ var excludeTypes = [];
+ var suffix = (project.targetFlags.exists ("final") ? ".min" : "") + ".js";
+
+ for (module in project.modules) {
+
+ project.dependencies.push (new Dependency ("./lib/" + module.name + suffix, null));
+
+ excludeTypes = ArrayHelper.concatUnique (excludeTypes, module.classNames);
+ excludeTypes = ArrayHelper.concatUnique (excludeTypes, module.excludeTypes);
+ excludeTypes = ArrayHelper.concatUnique (excludeTypes, module.includeTypes);
+
+ }
+
+ if (excludeTypes.length > 0) {
+
+ project.haxeflags.push ("--macro lime.tools.helpers.ModuleHelper.exclude(['" + excludeTypes.join ("','") + "'])");
+
+ }
+
+ }
+
+
+}
+
+
+#else
+
+
+import haxe.macro.Compiler;
+
+
+class ModuleHelper {
+
+
+ public static function exclude (types:Array):Void {
+
+ for (type in types) {
+
+ Compiler.exclude (type);
+ Compiler.addMetadata ("@:native(\"$hx_exports." + type + "\")", type);
+
+ }
+
+ }
+
+
+ public static function expose (classNames:Array):Void {
+
+ for (className in classNames) {
+
+ Compiler.addMetadata ("@:expose('" + className + "')", className);
+
+ }
+
+ }
+
+
+}
+
+
+#end
\ No newline at end of file
diff --git a/lime/tools/platforms/HTML5Platform.hx b/lime/tools/platforms/HTML5Platform.hx
index 22647d68f..94229fd0f 100644
--- a/lime/tools/platforms/HTML5Platform.hx
+++ b/lime/tools/platforms/HTML5Platform.hx
@@ -9,6 +9,7 @@ import lime.tools.helpers.FileHelper;
import lime.tools.helpers.HTML5Helper;
import lime.tools.helpers.IconHelper;
import lime.tools.helpers.LogHelper;
+import lime.tools.helpers.ModuleHelper;
import lime.tools.helpers.PathHelper;
import lime.tools.helpers.ProcessHelper;
import lime.project.AssetType;
@@ -36,6 +37,8 @@ class HTML5Platform extends PlatformTarget {
public override function build ():Void {
+ ModuleHelper.buildModules (project, targetDirectory + "/obj", targetDirectory + "/bin");
+
if (project.app.main != null) {
var type = "release";
@@ -169,6 +172,8 @@ class HTML5Platform extends PlatformTarget {
}
+ ModuleHelper.updateProject (project);
+
var context = project.templateContext;
context.WIN_FLASHBACKGROUND = project.window.background != null ? StringTools.hex (project.window.background, 6) : "";
diff --git a/tools/CommandLineTools.hx b/tools/CommandLineTools.hx
index 10a7e09ec..04ce4aad2 100644
--- a/tools/CommandLineTools.hx
+++ b/tools/CommandLineTools.hx
@@ -1395,6 +1395,26 @@ class CommandLineTools {
}
+ if (Sys.getEnv ("HAXEPATH") == null) {
+
+ if (PlatformHelper.hostPlatform == Platform.WINDOWS) {
+
+ Sys.putEnv ("HAXEPATH", "C:\\HaxeToolkit\\haxe\\");
+
+ } else {
+
+ Sys.putEnv ("HAXEPATH", "/usr/lib/haxe");
+
+ }
+
+ }
+
+ if (Sys.getEnv ("HAXE_STD_PATH") == null) {
+
+ Sys.putEnv ("HAXE_STD_PATH", PathHelper.combine (Sys.getEnv ("HAXEPATH"), "std"));
+
+ }
+
if (project == null) {
HXProject._command = command;