From ecd7876c4b38853022e368415288ec2b93509ed1 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 21 Jun 2018 16:33:33 -0700 Subject: [PATCH] Add external platform code for use with HXP --- include.xml | 15 + tools/platforms/AIRPlatform.hx | 353 +++++++++++ tools/platforms/AndroidPlatform.hx | 481 ++++++++++++++ tools/platforms/EmscriptenPlatform.hx | 374 +++++++++++ tools/platforms/FlashPlatform.hx | 295 +++++++++ tools/platforms/HTML5Platform.hx | 496 +++++++++++++++ tools/platforms/IOSPlatform.hx | 775 +++++++++++++++++++++++ tools/platforms/LinuxPlatform.hx | 457 ++++++++++++++ tools/platforms/MacPlatform.hx | 425 +++++++++++++ tools/platforms/TVOSPlatform.hx | 649 +++++++++++++++++++ tools/platforms/TizenPlatform.hx | 232 +++++++ tools/platforms/WindowsPlatform.hx | 870 ++++++++++++++++++++++++++ 12 files changed, 5422 insertions(+) create mode 100644 tools/platforms/AIRPlatform.hx create mode 100644 tools/platforms/AndroidPlatform.hx create mode 100644 tools/platforms/EmscriptenPlatform.hx create mode 100644 tools/platforms/FlashPlatform.hx create mode 100644 tools/platforms/HTML5Platform.hx create mode 100644 tools/platforms/IOSPlatform.hx create mode 100644 tools/platforms/LinuxPlatform.hx create mode 100644 tools/platforms/MacPlatform.hx create mode 100644 tools/platforms/TVOSPlatform.hx create mode 100644 tools/platforms/TizenPlatform.hx create mode 100644 tools/platforms/WindowsPlatform.hx diff --git a/include.xml b/include.xml index 843899872..848526af6 100644 --- a/include.xml +++ b/include.xml @@ -44,6 +44,21 @@ +
+ + + + + + + + + + + + +
+
diff --git a/tools/platforms/AIRPlatform.hx b/tools/platforms/AIRPlatform.hx new file mode 100644 index 000000000..bd3935dad --- /dev/null +++ b/tools/platforms/AIRPlatform.hx @@ -0,0 +1,353 @@ +package; + + +import haxe.io.Path; +import hxp.project.AssetType; +import hxp.project.HXProject; +import hxp.project.Icon; +import hxp.project.Platform; +import hxp.project.PlatformType; +import hxp.helpers.AIRHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.FlashHelper; +import hxp.helpers.IconHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.PlatformHelper; +import hxp.helpers.LogHelper; +import hxp.helpers.ZipHelper; +import sys.io.File; +import sys.FileSystem; + + +class AIRPlatform extends FlashPlatform { + + + private var iconData:Array; + private var targetPlatform:Platform; + private var targetPlatformType:PlatformType; + + + public function new (command:String, _project:HXProject, targetFlags:Map) { + + super (command, _project, targetFlags); + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("air.output-directory", "air")); + + if (targetFlags.exists ("android")) { + + targetPlatform = Platform.ANDROID; + targetPlatformType = MOBILE; + + } else if (targetFlags.exists ("ios")) { + + targetPlatform = Platform.IOS; + targetPlatformType = MOBILE; + + } else if (targetFlags.exists ("windows")) { + + targetPlatform = Platform.WINDOWS; + targetPlatformType = DESKTOP; + + } else if (targetFlags.exists ("mac")) { + + targetPlatform = Platform.MAC; + targetPlatformType = DESKTOP; + + } else { + + targetPlatform = PlatformHelper.hostPlatform; + targetPlatformType = DESKTOP; + + } + + } + + + public override function build ():Void { + + super.build (); + + if (!project.defines.exists ("AIR_SDK")) { + + LogHelper.error ("You must define AIR_SDK with the path to your AIR SDK"); + + } + + // TODO: Should we package on desktop in "deploy" command instead? + + if (targetPlatformType != DESKTOP) { + + var files = [ project.app.file + ".swf" ]; + for (asset in project.assets) { + + if (asset.embed == false && asset.type != TEMPLATE) { + + files.push (asset.targetPath); + + } + + } + + for (icon in iconData) { + + files.push (icon.path); + + } + + var targetPath = switch (targetPlatform) { + + case ANDROID: "bin/" + project.app.file + ".apk"; + case IOS: "bin/" + project.app.file + ".ipa"; + default: "bin/" + project.app.file + ".air"; + + } + + AIRHelper.build (project, targetDirectory, targetPlatform, targetPath, "application.xml", files, "bin"); + + } + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + if (targetFlags.exists ("gdrive") || targetFlags.exists ("zip")) { + + DeploymentHelper.deploy (project, targetFlags, targetDirectory, "AIR"); + + } else { + + var rootDirectory = targetDirectory + "/bin"; + var paths = PathHelper.readDirectory (rootDirectory, [ project.app.file + ".apk", project.app.file + ".ipa", project.app.file + ".air" ]); + var files = []; + + for (path in paths) { + + files.push (path.substr (rootDirectory.length + 1)); + + } + + var name = project.meta.title + " (" + project.meta.version + " build " + project.meta.buildNumber + ")"; + + switch (targetPlatform) { + + case WINDOWS: + + name += " (Windows)"; + + case MAC: + + name += " (macOS)"; + + case IOS: + + name += " (iOS).ipa"; + + case ANDROID: + + name += " (Android).apk"; + + default: + + } + + var outputPath = "dist/" + name; + + PathHelper.mkdir (targetDirectory + "/dist"); + + outputPath = AIRHelper.build (project, targetDirectory, targetPlatform, outputPath, "application.xml", files, "bin"); + + if (targetPlatformType == DESKTOP) { + + ZipHelper.compress (PathHelper.combine (targetDirectory, outputPath), PathHelper.combine (targetDirectory, "dist/" + name + ".zip")); + + } + + } + + } + + + public override function install ():Void { + + // TODO: Make separate install step + + } + + + public override function run ():Void { + + AIRHelper.run (project, targetDirectory, targetPlatform, "application.xml", "bin"); + + } + + + public override function trace ():Void { + + AIRHelper.trace (project, targetDirectory, targetPlatform, "application.xml", "bin"); + + } + + + public override function uninstall ():Void { + + AIRHelper.uninstall (project, targetDirectory, targetPlatform, "application.xml", "bin"); + + } + + + public override function update ():Void { + + var destination = targetDirectory + "/bin/"; + PathHelper.mkdir (destination); + + // project = project.clone (); + + embedded = FlashHelper.embedAssets (project, targetDirectory); + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + context.AIR_SDK_VERSION = project.config.getString ("air.sdk-version", "28.0"); + + var buildNumber = Std.string (context.APP_BUILD_NUMBER); + + if (buildNumber.length <= 3) { + + context.APP_BUILD_NUMBER_SPLIT = buildNumber; + + } else { + + var major = null; + + var patch = buildNumber.substr (-3); + buildNumber = buildNumber.substr (0, -3); + + var minor = buildNumber.substr (-Std.int (Math.min (buildNumber.length, 3))); + buildNumber = buildNumber.substr (0, -minor.length); + + if (buildNumber.length > 0) { + + major = buildNumber.substr (-Std.int (Math.min (buildNumber.length, 3))); + buildNumber = buildNumber.substr (0, -major.length); + + } + + var buildNumberSplit = minor + "." + patch; + if (major != null) buildNumberSplit = major + "." + buildNumberSplit; + + context.APP_BUILD_NUMBER_SPLIT = buildNumberSplit; + + if (buildNumber.length > 0) { + + LogHelper.warn ("Application build number " + buildNumber + buildNumberSplit + " exceeds 9 digits"); + + } + + } + + var iconSizes = [ 16, 29, 32, 36, 40, 48, 50, 57, 58, 60, 72, 75, 76, 80, 87, 96, 100, 114, 120, 128, 144, 152, 167, 180, 192, 512, 1024 ]; + var icons = project.icons; + iconData = []; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + for (size in iconSizes) { + + if (IconHelper.createIcon (icons, size, size, targetDirectory + "/bin/_res/icon-" + size + ".png")) { + + iconData.push ({ size: size, path: "_res/icon-" + size + ".png" }); + + } + + } + + if (iconData.length > 0) context.icons = iconData; + + context.extensions = new Array(); + + for (dependency in project.dependencies) { + + if (StringTools.endsWith(dependency.path, ".ane")) { + + var extension:Dynamic = { name: dependency.name }; + context.extensions.push(extension); + context.HAXE_FLAGS += "\n-swf-lib " + dependency.path; + + } + + } + + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "air/hxml", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "air/template", targetDirectory, context); + + if (embedded) { + + var files = [ "debug.hxml", "release.hxml", "final.hxml" ]; + var path, hxml, lines, output; + + for (file in files) { + + path = targetDirectory + "/haxe/" + file; + hxml = File.getContent (path); + + if (hxml.indexOf ("-swf-header") > -1) { + + lines = ~/[\r\n]+/g.split (hxml); + output = []; + + for (line in lines) { + + if (line.indexOf ("-swf-header") > -1) continue; + output.push (line); + + } + + if (output.length < lines.length) { + + File.saveContent (path, output.join ("\n")); + + } + + } + + } + + } + + for (asset in project.assets) { + + if (asset.type == AssetType.TEMPLATE || asset.embed == false /*|| !usesLime*/) { + + var path = PathHelper.combine (destination, asset.targetPath); + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path, context); + + } + + } + + } + + + @ignore public override function rebuild ():Void {} + + +} \ No newline at end of file diff --git a/tools/platforms/AndroidPlatform.hx b/tools/platforms/AndroidPlatform.hx new file mode 100644 index 000000000..29a070571 --- /dev/null +++ b/tools/platforms/AndroidPlatform.hx @@ -0,0 +1,481 @@ +package; + + +import haxe.io.Path; +import haxe.Template; +import hxp.helpers.AndroidHelper; +import hxp.helpers.ArrayHelper; +import hxp.helpers.CPPHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.IconHelper; +import hxp.helpers.LogHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.ProcessHelper; +import hxp.helpers.WatchHelper; +import hxp.project.Architecture; +import hxp.project.AssetType; +import hxp.project.Haxelib; +import hxp.project.HXProject; +import hxp.project.Icon; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.FileSystem; + + +class AndroidPlatform extends PlatformTarget { + + + private var deviceID:String; + + + public function new (command:String, _project:HXProject, targetFlags:Map) { + + super (command, _project, targetFlags); + + if (command != "display" && command != "clean") { + + // project = project.clone (); + + if (!project.environment.exists ("ANDROID_SETUP")) { + + LogHelper.error ("You need to run \"lime setup android\" before you can use the Android target"); + + } + + AndroidHelper.initialize (project); + + if (deviceID == null && project.targetFlags.exists ("device")) { + + deviceID = project.targetFlags.get ("device") + ":5555"; + + } + + } + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("android.output-directory", "android")); + + } + + + public override function build ():Void { + + var destination = targetDirectory + "/bin"; + var hxml = targetDirectory + "/haxe/" + buildType + ".hxml"; + var sourceSet = destination + "/app/src/main"; + + var hasARMV5 = (ArrayHelper.containsValue (project.architectures, Architecture.ARMV5) || ArrayHelper.containsValue (project.architectures, Architecture.ARMV6)); + var hasARMV7 = ArrayHelper.containsValue (project.architectures, Architecture.ARMV7); + var hasX86 = ArrayHelper.containsValue (project.architectures, Architecture.X86); + + var architectures = []; + + if (hasARMV5) architectures.push (Architecture.ARMV5); + if (hasARMV7 || (!hasARMV5 && !hasX86)) architectures.push (Architecture.ARMV7); + if (hasX86) architectures.push (Architecture.X86); + + for (architecture in architectures) { + + var haxeParams = [ hxml, "-D", "android", "-D", "PLATFORM=android-14" ]; + var cppParams = [ "-Dandroid", "-DPLATFORM=android-14" ]; + var path = sourceSet + "/jniLibs/armeabi"; + var suffix = ".so"; + + if (architecture == Architecture.ARMV7) { + + haxeParams.push ("-D"); + haxeParams.push ("HXCPP_ARMV7"); + cppParams.push ("-DHXCPP_ARMV7"); + + if (hasARMV5) { + + path = sourceSet + "/jniLibs/armeabi-v7a"; + + } + + suffix = "-v7.so"; + + } else if (architecture == Architecture.X86) { + + haxeParams.push ("-D"); + haxeParams.push ("HXCPP_X86"); + cppParams.push ("-DHXCPP_X86"); + path = sourceSet + "/jniLibs/x86"; + suffix = "-x86.so"; + + } + + for (ndll in project.ndlls) { + + FileHelper.copyLibrary (project, ndll, "Android", "lib", suffix, path, project.debug, ".so"); + + } + + ProcessHelper.runCommand ("", "haxe", haxeParams); + + if (noOutput) return; + + CPPHelper.compile (project, targetDirectory + "/obj", cppParams); + + FileHelper.copyIfNewer (targetDirectory + "/obj/libApplicationMain" + (project.debug ? "-debug" : "") + suffix, path + "/libApplicationMain.so"); + + } + + if (!ArrayHelper.containsValue (project.architectures, Architecture.ARMV7) || !hasARMV5) { + + if (FileSystem.exists (sourceSet + "/jniLibs/armeabi-v7a")) { + + PathHelper.removeDirectory (sourceSet + "/jniLibs/armeabi-v7a"); + + } + + } + + if (!hasX86) { + + if (FileSystem.exists (sourceSet + "/jniLibs/x86")) { + + PathHelper.removeDirectory (sourceSet + "/jniLibs/x86"); + + } + + } + + if (noOutput) return; + + AndroidHelper.build (project, destination); + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + DeploymentHelper.deploy (project, targetFlags, targetDirectory, "Android"); + + } + + + public override function display ():Void { + + Sys.println (getDisplayHXML ()); + + } + + + private function getDisplayHXML ():String { + + var hxml = PathHelper.findTemplate (project.templatePaths, "android/hxml/" + buildType + ".hxml"); + + var context = project.templateContext; + context.CPP_DIR = targetDirectory + "/obj"; + context.OUTPUT_DIR = targetDirectory; + + var template = new Template (File.getContent (hxml)); + + return template.execute (context) + "\n-D display"; + + } + + + public override function install ():Void { + + var build = "-debug"; + + if (project.keystore != null) { + + build = "-release"; + + } + + var outputDirectory = null; + + if (project.config.exists ("android.gradle-build-directory")) { + + outputDirectory = PathHelper.combine (project.config.getString ("android.gradle-build-directory"), project.app.file + "/app/outputs/apk"); + + } else { + + outputDirectory = PathHelper.combine (FileSystem.fullPath (targetDirectory), "bin/app/build/outputs/apk"); + + } + + var apkPath = PathHelper.combine (outputDirectory, project.app.file + build + ".apk"); + + deviceID = AndroidHelper.install (project, apkPath, deviceID); + + } + + + public override function rebuild ():Void { + + var armv5 = (command == "rebuild" || ArrayHelper.containsValue (project.architectures, Architecture.ARMV5) || ArrayHelper.containsValue (project.architectures, Architecture.ARMV6)); + var armv7 = (command == "rebuild" || ArrayHelper.containsValue (project.architectures, Architecture.ARMV7)); + var x86 = (command == "rebuild" || ArrayHelper.containsValue (project.architectures, Architecture.X86)); + + var commands = []; + + if (armv5) commands.push ([ "-Dandroid", "-DPLATFORM=android-14" ]); + if (armv7) commands.push ([ "-Dandroid", "-DHXCPP_ARMV7", "-DHXCPP_ARM7", "-DPLATFORM=android-14" ]); + if (x86) commands.push ([ "-Dandroid", "-DHXCPP_X86", "-DPLATFORM=android-14" ]); + + CPPHelper.rebuild (project, commands); + + } + + + public override function run ():Void { + + AndroidHelper.run (project.meta.packageName + "/" + project.meta.packageName + ".MainActivity", deviceID); + + } + + + public override function trace ():Void { + + AndroidHelper.trace (project, project.debug, deviceID); + + } + + + public override function uninstall ():Void { + + AndroidHelper.uninstall (project.meta.packageName, deviceID); + + } + + + public override function update ():Void { + + // project = project.clone (); + + for (asset in project.assets) { + + if (asset.embed && asset.sourcePath == "") { + + var path = PathHelper.combine (targetDirectory + "/obj/tmp", asset.targetPath); + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path); + asset.sourcePath = path; + + } + + } + + //initialize (project); + + var destination = targetDirectory + "/bin"; + var sourceSet = destination + "/app/src/main"; + PathHelper.mkdir (sourceSet); + PathHelper.mkdir (sourceSet + "/res/drawable-ldpi/"); + PathHelper.mkdir (sourceSet + "/res/drawable-mdpi/"); + PathHelper.mkdir (sourceSet + "/res/drawable-hdpi/"); + PathHelper.mkdir (sourceSet + "/res/drawable-xhdpi/"); + + for (asset in project.assets) { + + if (asset.type != AssetType.TEMPLATE) { + + var targetPath = ""; + + switch (asset.type) { + + default: + //case SOUND, MUSIC: + + //var extension = Path.extension (asset.sourcePath); + //asset.flatName += ((extension != "") ? "." + extension : ""); + + //asset.resourceName = asset.flatName; + targetPath = PathHelper.combine (sourceSet + "/assets/", asset.resourceName); + + //asset.resourceName = asset.id; + //targetPath = sourceSet + "/res/raw/" + asset.flatName + "." + Path.extension (asset.targetPath); + + //default: + + //asset.resourceName = asset.flatName; + //targetPath = sourceSet + "/assets/" + asset.resourceName; + + } + + FileHelper.copyAssetIfNewer (asset, targetPath); + + } + + } + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + var context = project.templateContext; + + context.CPP_DIR = targetDirectory + "/obj"; + context.OUTPUT_DIR = targetDirectory; + context.ANDROID_INSTALL_LOCATION = project.config.getString ("android.install-location", "auto"); + context.ANDROID_MINIMUM_SDK_VERSION = project.config.getInt ("android.minimum-sdk-version", 9); + context.ANDROID_TARGET_SDK_VERSION = project.config.getInt ("android.target-sdk-version", 19); + context.ANDROID_EXTENSIONS = project.config.getArrayString ("android.extension"); + context.ANDROID_PERMISSIONS = project.config.getArrayString ("android.permission", [ "android.permission.WAKE_LOCK", "android.permission.INTERNET", "android.permission.VIBRATE", "android.permission.ACCESS_NETWORK_STATE" ]); + context.ANDROID_GRADLE_VERSION = project.config.getString ("android.gradle-version", "2.10"); + context.ANDROID_GRADLE_PLUGIN = project.config.getString ("android.gradle-plugin", "2.1.0"); + context.ANDROID_LIBRARY_PROJECTS = []; + + if (!project.environment.exists ("ANDROID_SDK") || !project.environment.exists ("ANDROID_NDK_ROOT")) { + + var command = "lime"; + var toolsBase = Type.resolveClass ("CommandLineTools"); + if (toolsBase != null) + command = Reflect.field (toolsBase, "commandName"); + + LogHelper.error ("You must define ANDROID_SDK and ANDROID_NDK_ROOT to target Android, please run '" + command + " setup android' first"); + Sys.exit (1); + + } + + if (project.config.exists ("android.gradle-build-directory")) { + + context.ANDROID_GRADLE_BUILD_DIRECTORY = project.config.getString ("android.gradle-build-directory"); + + } + + if (project.config.exists ("android.build-tools-version")) { + + context.ANDROID_BUILD_TOOLS_VERSION = project.config.getString ("android.build-tools-version"); + + } else { + + context.ANDROID_BUILD_TOOLS_VERSION = AndroidHelper.getBuildToolsVersion (project); + + } + + var escaped = ~/([ #!=\\:])/g; + context.ANDROID_SDK_ESCAPED = escaped.replace(context.ENV_ANDROID_SDK, "\\$1"); + context.ANDROID_NDK_ROOT_ESCAPED = escaped.replace(context.ENV_ANDROID_NDK_ROOT, "\\$1"); + + if (Reflect.hasField (context, "KEY_STORE")) context.KEY_STORE = StringTools.replace (context.KEY_STORE, "\\", "\\\\"); + if (Reflect.hasField (context, "KEY_STORE_ALIAS")) context.KEY_STORE_ALIAS = StringTools.replace (context.KEY_STORE_ALIAS, "\\", "\\\\"); + if (Reflect.hasField (context, "KEY_STORE_PASSWORD")) context.KEY_STORE_PASSWORD = StringTools.replace (context.KEY_STORE_PASSWORD, "\\", "\\\\"); + if (Reflect.hasField (context, "KEY_STORE_ALIAS_PASSWORD")) context.KEY_STORE_ALIAS_PASSWORD = StringTools.replace (context.KEY_STORE_ALIAS_PASSWORD, "\\", "\\\\"); + + var index = 1; + + for (dependency in project.dependencies) { + + if (dependency.path != "" && FileSystem.exists (dependency.path) && FileSystem.isDirectory (dependency.path) && (FileSystem.exists (PathHelper.combine (dependency.path, "project.properties")) || FileSystem.exists (PathHelper.combine (dependency.path, "build.gradle")))) { + + var name = dependency.name; + if (name == "") name = "project" + index; + + context.ANDROID_LIBRARY_PROJECTS.push ({ name: name, index: index, path: "deps/" + name, source: dependency.path }); + index++; + + } + + } + + var iconTypes = [ "ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi" ]; + var iconSizes = [ 36, 48, 72, 96, 144, 192 ]; + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + for (i in 0...iconTypes.length) { + + if (IconHelper.createIcon (icons, iconSizes[i], iconSizes[i], sourceSet + "/res/drawable-" + iconTypes[i] + "/icon.png")) { + + context.HAS_ICON = true; + + } + + } + + IconHelper.createIcon (icons, 732, 412, sourceSet + "/res/drawable-xhdpi/ouya_icon.png"); + + var packageDirectory = project.meta.packageName; + packageDirectory = sourceSet + "/java/" + packageDirectory.split (".").join ("/"); + PathHelper.mkdir (packageDirectory); + + for (javaPath in project.javaPaths) { + + try { + + if (FileSystem.isDirectory (javaPath)) { + + FileHelper.recursiveCopy (javaPath, sourceSet + "/java", context, true); + + } else { + + if (Path.extension (javaPath) == "jar") { + + FileHelper.copyIfNewer (javaPath, destination + "/app/libs/" + Path.withoutDirectory (javaPath)); + + } else { + + FileHelper.copyIfNewer (javaPath, sourceSet + "/java/" + Path.withoutDirectory (javaPath)); + + } + + } + + } catch (e:Dynamic) {} + + // throw"Could not find javaPath " + javaPath +" required by extension."; + + //} + + } + + for (library in context.ANDROID_LIBRARY_PROJECTS) { + + FileHelper.recursiveCopy (library.source, destination + "/deps/" + library.name, context, true); + + } + + FileHelper.recursiveSmartCopyTemplate (project, "android/template", destination, context); + FileHelper.copyFileTemplate (project.templatePaths, "android/MainActivity.java", packageDirectory + "/MainActivity.java", context); + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "android/hxml", targetDirectory + "/haxe", context); + + for (asset in project.assets) { + + if (asset.type == AssetType.TEMPLATE) { + + var targetPath = PathHelper.combine (destination, asset.targetPath); + PathHelper.mkdir (Path.directory (targetPath)); + FileHelper.copyAsset (asset, targetPath, context); + + } + + } + + } + + + public override function watch ():Void { + + var dirs = WatchHelper.processHXML (project, getDisplayHXML ()); + var command = WatchHelper.getCurrentCommand (); + WatchHelper.watch (project, command, dirs); + + } + + +} \ No newline at end of file diff --git a/tools/platforms/EmscriptenPlatform.hx b/tools/platforms/EmscriptenPlatform.hx new file mode 100644 index 000000000..fe2ff167e --- /dev/null +++ b/tools/platforms/EmscriptenPlatform.hx @@ -0,0 +1,374 @@ +package; + + +import haxe.io.Path; +import haxe.Json; +import haxe.Template; +import hxp.helpers.CPPHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.HTML5Helper; +import hxp.helpers.LogHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.ProcessHelper; +import hxp.project.AssetType; +import hxp.project.Haxelib; +import hxp.project.HXProject; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.FileSystem; + + +class EmscriptenPlatform extends PlatformTarget { + + + private var outputFile:String; + + + public function new (command:String, _project:HXProject, targetFlags:Map) { + + super (command, _project, targetFlags); + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("emscripten.output-directory", "emscripten")); + outputFile = targetDirectory + "/bin/" + project.app.file + ".js"; + + } + + + public override function build ():Void { + + var sdkPath = null; + + if (project.defines.exists ("EMSCRIPTEN_SDK")) { + + sdkPath = project.defines.get ("EMSCRIPTEN_SDK"); + + } else if (project.environment.exists ("EMSCRIPTEN_SDK")) { + + sdkPath = project.environment.get ("EMSCRIPTEN_SDK"); + + } + + if (sdkPath == null) { + + LogHelper.error ("You must define EMSCRIPTEN_SDK with the path to your Emscripten SDK"); + + } + + var hxml = targetDirectory + "/haxe/" + buildType + ".hxml"; + var args = [ hxml, "-D", "emscripten", "-D", "webgl", "-D", "static_link"]; + + if (LogHelper.verbose) { + + args.push ("-D"); + args.push ("verbose"); + + } + + ProcessHelper.runCommand ("", "haxe", args); + + if (noOutput) return; + + CPPHelper.compile (project, targetDirectory + "/obj", [ "-Demscripten", "-Dwebgl", "-Dstatic_link" ]); + + project.path (sdkPath); + + ProcessHelper.runCommand ("", "emcc", [ targetDirectory + "/obj/Main.cpp", "-o", targetDirectory + "/obj/Main.o" ], true, false, true); + + args = [ "Main.o" ]; + + for (ndll in project.ndlls) { + + var path = PathHelper.getLibraryPath (ndll, "Emscripten", "lib", ".a", project.debug); + args.push (path); + + } + + var json = Json.parse (File.getContent (PathHelper.getHaxelib (new Haxelib ("hxcpp"), true) + "/haxelib.json")); + var prefix = ""; + + if (Std.parseFloat (json.version) > 3.1) { + + prefix = "lib"; + + } + + args = args.concat ([ prefix + "ApplicationMain" + (project.debug ? "-debug" : "") + ".a", "-o", "ApplicationMain.o" ]); + ProcessHelper.runCommand (targetDirectory + "/obj", "emcc", args, true, false, true); + + args = [ "ApplicationMain.o" ]; + + if (project.targetFlags.exists ("webassembly") || project.targetFlags.exists ("wasm")) { + + args.push ("-s"); + args.push ("WASM=1"); + + } else { + + args.push ("-s"); + args.push ("ASM_JS=1"); + + } + + args.push ("-s"); + args.push ("NO_EXIT_RUNTIME=1"); + + args.push ("-s"); + args.push ("USE_SDL=2"); + + for (dependency in project.dependencies) { + + if (dependency.name != "") { + + args.push ("-l" + dependency.name); + + } + + } + + if (project.targetFlags.exists ("final")) { + + args.push ("-s"); + args.push ("DISABLE_EXCEPTION_CATCHING=0"); + args.push ("-O3"); + + } else if (!project.debug) { + + args.push ("-s"); + args.push ("DISABLE_EXCEPTION_CATCHING=0"); + //args.push ("-s"); + //args.push ("OUTLINING_LIMIT=70000"); + args.push ("-O2"); + + } else { + + args.push ("-s"); + args.push ("DISABLE_EXCEPTION_CATCHING=2"); + args.push ("-s"); + args.push ("ASSERTIONS=1"); + args.push ("-O1"); + + } + + args.push ("-s"); + args.push ("ALLOW_MEMORY_GROWTH=1"); + + if (project.targetFlags.exists ("minify")) { + + // 02 enables minification + + //args.push ("--minify"); + //args.push ("1"); + //args.push ("--closure"); + //args.push ("1"); + + } + + //args.push ("--memory-init-file"); + //args.push ("1"); + //args.push ("--jcache"); + //args.push ("-g"); + + if (FileSystem.exists (targetDirectory + "/obj/assets")) { + + args.push ("--preload-file"); + args.push ("assets"); + + } + + if (LogHelper.verbose) { + + args.push ("-v"); + + } + + //if (project.targetFlags.exists ("compress")) { + // + //args.push ("--compression"); + //args.push (PathHelper.findTemplate (project.templatePaths, "bin/utils/lzma/compress.exe") + "," + PathHelper.findTemplate (project.templatePaths, "resources/lzma-decoder.js") + ",LZMA.decompress"); + //args.push ("haxelib run openfl compress," + PathHelper.findTemplate (project.templatePaths, "resources/lzma-decoder.js") + ",LZMA.decompress"); + //args.push ("-o"); + //args.push ("../bin/index.html"); + // + //} else { + + args.push ("-o"); + args.push ("../bin/" + project.app.file + ".js"); + + //} + + //args.push ("../bin/index.html"); + + ProcessHelper.runCommand (targetDirectory + "/obj", "emcc", args, true, false, true); + + if (project.targetFlags.exists ("minify")) { + + HTML5Helper.minify (project, targetDirectory + "/bin/" + project.app.file + ".js"); + + } + + if (project.targetFlags.exists ("compress")) { + + if (FileSystem.exists (targetDirectory + "/bin/" + project.app.file + ".data")) { + + //var byteArray = ByteArray.readFile (targetDirectory + "/bin/" + project.app.file + ".data"); + //byteArray.compress (CompressionAlgorithm.GZIP); + //File.saveBytes (targetDirectory + "/bin/" + project.app.file + ".data.compress", byteArray); + + } + + //var byteArray = ByteArray.readFile (targetDirectory + "/bin/" + project.app.file + ".js"); + //byteArray.compress (CompressionAlgorithm.GZIP); + //File.saveBytes (targetDirectory + "/bin/" + project.app.file + ".js.compress", byteArray); + + } else { + + File.saveContent (targetDirectory + "/bin/.htaccess", "SetOutputFilter DEFLATE"); + + } + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + DeploymentHelper.deploy (project, targetFlags, targetDirectory, "Emscripten"); + + } + + + public override function display ():Void { + + var hxml = PathHelper.findTemplate (project.templatePaths, "emscripten/hxml/" + buildType + ".hxml"); + + var context = project.templateContext; + context.OUTPUT_DIR = targetDirectory; + context.OUTPUT_FILE = outputFile; + + var template = new Template (File.getContent (hxml)); + + Sys.println (template.execute (context)); + Sys.println ("-D display"); + + } + + + public override function rebuild ():Void { + + CPPHelper.rebuild (project, [[ "-Demscripten", "-Dstatic_link" ]]); + + } + + + public override function run ():Void { + + HTML5Helper.launch (project, targetDirectory + "/bin"); + + } + + + public override function update ():Void { + + // project = project.clone (); + + for (asset in project.assets) { + + if (asset.embed && asset.sourcePath == "") { + + var path = PathHelper.combine (targetDirectory + "/obj/tmp", asset.targetPath); + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path); + asset.sourcePath = path; + + } + + } + + for (asset in project.assets) { + + asset.resourceName = "assets/" + asset.resourceName; + + } + + var destination = targetDirectory + "/bin/"; + PathHelper.mkdir (destination); + + //for (asset in project.assets) { + // + //if (asset.type == AssetType.FONT) { + // + //project.haxeflags.push (HTML5Helper.generateFontData (project, asset)); + // + //} + // + //} + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + var context = project.templateContext; + + context.WIN_FLASHBACKGROUND = StringTools.hex (project.window.background, 6); + context.OUTPUT_DIR = targetDirectory; + context.OUTPUT_FILE = outputFile; + context.CPP_DIR = targetDirectory + "/obj"; + context.USE_COMPRESSION = project.targetFlags.exists ("compress"); + + for (asset in project.assets) { + + var path = PathHelper.combine (targetDirectory + "/obj/assets", asset.targetPath); + + if (asset.type != AssetType.TEMPLATE) { + + //if (asset.type != AssetType.FONT) { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAssetIfNewer (asset, path); + + //} + + } + + } + + FileHelper.recursiveSmartCopyTemplate (project, "emscripten/template", destination, context); + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "emscripten/hxml", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "emscripten/cpp", targetDirectory + "/obj", context); + + for (asset in project.assets) { + + var path = PathHelper.combine (destination, asset.targetPath); + + if (asset.type == AssetType.TEMPLATE) { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path, context); + + } + + } + + } + + + @ignore public override function install ():Void {} + @ignore public override function trace ():Void {} + @ignore public override function uninstall ():Void {} + + +} diff --git a/tools/platforms/FlashPlatform.hx b/tools/platforms/FlashPlatform.hx new file mode 100644 index 000000000..069bf9304 --- /dev/null +++ b/tools/platforms/FlashPlatform.hx @@ -0,0 +1,295 @@ +package; + + +import haxe.io.Path; +import haxe.Json; +import haxe.Template; +import hxp.helpers.CompatibilityHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.FlashHelper; +import hxp.helpers.HTML5Helper; +import hxp.helpers.LogHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.PlatformHelper; +import hxp.helpers.ProcessHelper; +import hxp.helpers.WatchHelper; +import hxp.project.AssetType; +import hxp.project.Haxelib; +import hxp.project.HXProject; +import hxp.project.Platform; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.FileSystem; + +#if neko +import neko.vm.Thread; +#end + + +class FlashPlatform extends PlatformTarget { + + + private var embedded:Bool; + private var logLength:Int = 0; + + + public function new (command:String, _project:HXProject, targetFlags:Map) { + + super (command, _project, targetFlags); + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("flash.output-directory", "flash")); + + } + + + public override function build ():Void { + + ProcessHelper.runCommand ("", "haxe", [ targetDirectory + "/haxe/" + buildType + ".hxml" ]); + + } + + + public override function clean ():Void { + + var targetPath = targetDirectory + ""; + + if (FileSystem.exists (targetPath)) { + + PathHelper.removeDirectory (targetPath); + + } + + } + + + public override function deploy ():Void { + + DeploymentHelper.deploy (project, targetFlags, targetDirectory, "Flash"); + + } + + + public override function display ():Void { + + Sys.println (getDisplayHXML ()); + + } + + + private function generateContext ():Dynamic { + + // project = project.clone (); + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + if (LogHelper.verbose) { + + project.haxedefs.set ("verbose", 1); + + } + + var context = project.templateContext; + context.WIN_FLASHBACKGROUND = project.window.background != null ? StringTools.hex (project.window.background, 6) : "0xFFFFFF"; + var assets:Array = cast context.assets; + + for (asset in assets) { + + var assetType:AssetType = Reflect.field (AssetType, asset.type.toUpperCase ()); + + switch (assetType) { + + case MUSIC : asset.flashClass = "flash.media.Sound"; + case SOUND : asset.flashClass = "flash.media.Sound"; + case IMAGE : asset.flashClass = "flash.display.BitmapData"; + case FONT : asset.flashClass = "flash.text.Font"; + default: asset.flashClass = "flash.utils.ByteArray"; + + } + + } + + return context; + + } + + + private function getDisplayHXML ():String { + + var hxml = PathHelper.findTemplate (project.templatePaths, "flash/hxml/" + buildType + ".hxml"); + + var context = project.templateContext; + context.WIN_FLASHBACKGROUND = StringTools.hex (project.window.background, 6); + context.OUTPUT_DIR = targetDirectory; + + var template = new Template (File.getContent (hxml)); + + return template.execute (context) + "\n-D display"; + + } + + + public override function run ():Void { + + if (traceEnabled) { + + FlashHelper.enableLogging (); + logLength = FlashHelper.getLogLength (); + + } + + if (project.app.url != null && project.app.url != "") { + + ProcessHelper.openURL (project.app.url); + + } else { + + var destination = targetDirectory + "/bin"; + var targetPath = project.app.file + ".swf"; + + if (project.targetFlags.exists ("web")) { + + HTML5Helper.launch (project, targetDirectory + "/bin"); + + } else { + + if (traceEnabled) { + + #if neko Thread.create (function () { #end + + FlashHelper.run (project, destination, targetPath); + //Sys.exit (0); + + #if neko }); #end + + Sys.sleep (0.1); + + } else { + + FlashHelper.run (project, destination, targetPath); + + } + + } + + } + + } + + + public override function trace ():Void { + + FlashHelper.enableLogging (); + FlashHelper.tailLog (logLength); + + } + + + public override function update ():Void { + + var destination = targetDirectory + "/bin/"; + PathHelper.mkdir (destination); + + // project = project.clone (); + + embedded = FlashHelper.embedAssets (project, targetDirectory); + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "flash/hxml", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "flash/haxe", targetDirectory + "/haxe", context, true, false); + + if (project.targetFlags.exists ("web") || project.app.url != "") { + + PathHelper.mkdir (destination); + FileHelper.recursiveSmartCopyTemplate (project, "flash/templates/web", destination, generateContext ()); + + } + + if (embedded) { + + var files = [ "debug.hxml", "release.hxml", "final.hxml" ]; + var path, hxml, lines, output; + + for (file in files) { + + path = targetDirectory + "/haxe/" + file; + hxml = File.getContent (path); + + if (hxml.indexOf ("-swf-header") > -1) { + + lines = ~/[\r\n]+/g.split (hxml); + output = []; + + for (line in lines) { + + if (line.indexOf ("-swf-header") > -1) continue; + output.push (line); + + } + + if (output.length < lines.length) { + + File.saveContent (path, output.join ("\n")); + + } + + } + + } + + } + + for (asset in project.assets) { + + if (asset.type == AssetType.TEMPLATE || asset.embed == false /*|| !usesLime*/) { + + var path = PathHelper.combine (destination, asset.targetPath); + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path, context); + + } + + } + + } + + + /*private function getIcon (size:Int, targetPath:String):Void { + + var icon = icons.findIcon (size, size); + + if (icon != "") { + + FileHelper.copyIfNewer (icon, targetPath); + + } else { + + icons.updateIcon (size, size, targetPath); + + } + + }*/ + + + public override function watch ():Void { + + var dirs = WatchHelper.processHXML (project, getDisplayHXML ()); + var command = WatchHelper.getCurrentCommand (); + WatchHelper.watch (project, command, dirs); + + } + + + @ignore public override function install ():Void {} + @ignore public override function rebuild ():Void {} + @ignore public override function uninstall ():Void {} + +} \ No newline at end of file diff --git a/tools/platforms/HTML5Platform.hx b/tools/platforms/HTML5Platform.hx new file mode 100644 index 000000000..ade6f0894 --- /dev/null +++ b/tools/platforms/HTML5Platform.hx @@ -0,0 +1,496 @@ +package; + + +import haxe.io.Path; +import haxe.Template; +// import lime.text.Font; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.ElectronHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.HTML5Helper; +import hxp.helpers.IconHelper; +import hxp.helpers.LogHelper; +import hxp.helpers.ModuleHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.ProcessHelper; +import hxp.helpers.WatchHelper; +import hxp.project.AssetType; +import hxp.project.HXProject; +import hxp.project.Icon; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.FileSystem; + + +class HTML5Platform extends PlatformTarget { + + + private var dependencyPath:String; + private var outputFile:String; + + + public function new (command:String, _project:HXProject, targetFlags:Map ) { + + super (command, _project, targetFlags); + + initialize (command, _project); + + } + + + public override function build ():Void { + + ModuleHelper.buildModules (project, targetDirectory + "/obj", targetDirectory + "/bin"); + + if (project.app.main != null) { + + var type = "release"; + + if (project.debug) { + + type = "debug"; + + } else if (project.targetFlags.exists ("final")) { + + type = "final"; + + } + + var hxml = targetDirectory + "/haxe/" + type + ".hxml"; + ProcessHelper.runCommand ("", "haxe", [ hxml ] ); + + if (noOutput) return; + + HTML5Helper.encodeSourceMappingURL (targetDirectory + "/bin/" + project.app.file + ".js"); + + if (project.targetFlags.exists ("webgl")) { + + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain.js", outputFile); + + } + + if (project.modules.iterator ().hasNext ()) { + + ModuleHelper.patchFile (outputFile); + + } + + if (project.targetFlags.exists ("minify") || type == "final") { + + HTML5Helper.minify (project, targetDirectory + "/bin/" + project.app.file + ".js"); + + } + + } + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + var name = "HTML5"; + + if (targetFlags.exists ("electron")) { + + name = "Electron"; + + } + + DeploymentHelper.deploy (project, targetFlags, targetDirectory, name); + + } + + + public override function display ():Void { + + Sys.println (getDisplayHXML ()); + + } + + + private function getDisplayHXML ():String { + + var type = "html5"; + + if (targetFlags.exists ("electron")) { + + type = "electron"; + + } + + var hxml = PathHelper.findTemplate (project.templatePaths, type + "/hxml/" + buildType + ".hxml"); + + var context = project.templateContext; + context.OUTPUT_DIR = targetDirectory; + context.OUTPUT_FILE = outputFile; + + var template = new Template (File.getContent (hxml)); + + return template.execute (context) + "\n-D display"; + + } + + + private function initialize (command:String, project:HXProject):Void { + + if (targetFlags.exists ("electron")) { + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("electron.output-directory", "electron")); + + } else { + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("html5.output-directory", "html5")); + + } + + dependencyPath = project.config.getString ("html5.dependency-path", "lib"); + + if (targetFlags.exists ("electron")) { + + dependencyPath = project.config.getString ("html5.dependency-path", dependencyPath); + + } + + outputFile = targetDirectory + "/bin/" + project.app.file + ".js"; + + } + + + public override function run ():Void { + + if (targetFlags.exists ("electron")) { + + ElectronHelper.launch (project, targetDirectory + "/bin"); + + } else { + + HTML5Helper.launch (project, targetDirectory + "/bin"); + + } + + } + + + public override function update ():Void { + + // project = project.clone (); + + var destination = targetDirectory + "/bin/"; + PathHelper.mkdir (destination); + + var webfontDirectory = targetDirectory + "/obj/webfont"; + var useWebfonts = true; + + for (haxelib in project.haxelibs) { + + if (haxelib.name == "openfl-html5-dom" || haxelib.name == "openfl-bitfive") { + + useWebfonts = false; + + } + + } + + var fontPath; + + for (asset in project.assets) { + + if (asset.type == AssetType.FONT && asset.targetPath != null) { + + if (useWebfonts) { + + fontPath = PathHelper.combine (webfontDirectory, Path.withoutDirectory (asset.targetPath)); + + if (!FileSystem.exists (fontPath)) { + + PathHelper.mkdir (webfontDirectory); + FileHelper.copyFile (asset.sourcePath, fontPath); + + var originalPath = asset.sourcePath; + asset.sourcePath = fontPath; + + HTML5Helper.generateWebfonts (project, asset); + + var ext = "." + Path.extension (asset.sourcePath); + var source = Path.withoutExtension (asset.sourcePath); + var extensions = [ ext, ".eot", ".woff", ".svg" ]; + + for (extension in extensions) { + + if (!FileSystem.exists (source + extension)) { + + if (extension != ".eot" && extension != ".svg") { + + LogHelper.warn ("Could not generate *" + extension + " web font for \"" + originalPath + "\""); + + } + + } + + } + + } + + asset.sourcePath = fontPath; + asset.targetPath = Path.withoutExtension (asset.targetPath); + + } else { + + project.haxeflags.push (HTML5Helper.generateFontData (project, asset)); + + } + + } + + } + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + if (LogHelper.verbose) { + + project.haxedefs.set ("verbose", 1); + + } + + ModuleHelper.updateProject (project); + + var libraryNames = new Map (); + + for (asset in project.assets) { + + if (asset.library != null && !libraryNames.exists (asset.library)) { + + libraryNames[asset.library] = true; + + } + + } + + //for (library in libraryNames.keys ()) { + // + //project.haxeflags.push ("-resource " + targetDirectory + "/obj/manifest/" + library + ".json@__ASSET_MANIFEST__" + library); + // + //} + + //project.haxeflags.push ("-resource " + targetDirectory + "/obj/manifest/default.json@__ASSET_MANIFEST__default"); + + var context = project.templateContext; + + context.WIN_FLASHBACKGROUND = project.window.background != null ? StringTools.hex (project.window.background, 6) : ""; + context.OUTPUT_DIR = targetDirectory; + context.OUTPUT_FILE = outputFile; + + if (project.targetFlags.exists ("webgl")) { + + context.CPP_DIR = targetDirectory + "/obj"; + + } + + context.favicons = []; + + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + //if (IconHelper.createWindowsIcon (icons, PathHelper.combine (destination, "favicon.ico"))) { + // + //context.favicons.push ({ rel: "icon", type: "image/x-icon", href: "./favicon.ico" }); + // + //} + + if (IconHelper.createIcon (icons, 192, 192, PathHelper.combine (destination, "favicon.png"))) { + + context.favicons.push ({ rel: "shortcut icon", type: "image/png", href: "./favicon.png" }); + + } + + context.linkedLibraries = []; + + for (dependency in project.dependencies) { + + if (StringTools.endsWith (dependency.name, ".js")) { + + context.linkedLibraries.push (dependency.name); + + } else if (StringTools.endsWith (dependency.path, ".js") && FileSystem.exists (dependency.path)) { + + var name = Path.withoutDirectory (dependency.path); + + context.linkedLibraries.push ("./" + dependencyPath + "/" + name); + FileHelper.copyIfNewer (dependency.path, PathHelper.combine (destination, PathHelper.combine (dependencyPath, name))); + + } + + } + + for (asset in project.assets) { + + var path = PathHelper.combine (destination, asset.targetPath); + + if (asset.type != AssetType.TEMPLATE) { + + if (/*asset.embed != true &&*/ asset.type != AssetType.FONT) { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAssetIfNewer (asset, path); + + } else if (asset.type == AssetType.FONT && useWebfonts) { + + PathHelper.mkdir (Path.directory (path)); + var ext = "." + Path.extension (asset.sourcePath); + var source = Path.withoutExtension (asset.sourcePath); + + var hasFormat = [ false, false, false, false ]; + var extensions = [ ext, ".eot", ".svg", ".woff" ]; + var extension; + + for (i in 0...extensions.length) { + + extension = extensions[i]; + + if (FileSystem.exists (source + extension)) { + + FileHelper.copyIfNewer (source + extension, path + extension); + hasFormat[i] = true; + + } + + } + + var shouldEmbedFont = false; + + for (embedded in hasFormat) { + if (embedded) shouldEmbedFont = true; + } + + var embeddedAssets:Array = cast context.assets; + for (embeddedAsset in embeddedAssets) { + + if (embeddedAsset.type == "font" && embeddedAsset.sourcePath == asset.sourcePath) { + + // var font = Font.fromFile (asset.sourcePath); + + // embeddedAsset.ascender = font.ascender; + // embeddedAsset.descender = font.descender; + // embeddedAsset.height = font.height; + // embeddedAsset.numGlyphs = font.numGlyphs; + // embeddedAsset.underlinePosition = font.underlinePosition; + // embeddedAsset.underlineThickness = font.underlineThickness; + // embeddedAsset.unitsPerEM = font.unitsPerEM; + + embeddedAsset.ascender = 0; + embeddedAsset.descender = 0; + embeddedAsset.height = 0; + embeddedAsset.numGlyphs = 0; + embeddedAsset.underlinePosition = 0; + embeddedAsset.underlineThickness = 0; + embeddedAsset.unitsPerEM = 0; + embeddedAsset.fontName = "sans"; + + if (shouldEmbedFont) { + + var urls = []; + if (hasFormat[1]) urls.push ("url('" + embeddedAsset.targetPath + ".eot?#iefix') format('embedded-opentype')"); + if (hasFormat[3]) urls.push ("url('" + embeddedAsset.targetPath + ".woff') format('woff')"); + urls.push ("url('" + embeddedAsset.targetPath + ext + "') format('truetype')"); + if (hasFormat[2]) urls.push ("url('" + embeddedAsset.targetPath + ".svg#" + StringTools.urlEncode (embeddedAsset.fontName) + "') format('svg')"); + + var fontFace = "\t\t@font-face {\n"; + fontFace += "\t\t\tfont-family: '" + embeddedAsset.fontName + "';\n"; + // if (hasFormat[1]) fontFace += "\t\t\tsrc: url('" + embeddedAsset.targetPath + ".eot');\n"; + fontFace += "\t\t\tsrc: " + urls.join (",\n\t\t\t") + ";\n"; + fontFace += "\t\t\tfont-weight: normal;\n"; + fontFace += "\t\t\tfont-style: normal;\n"; + fontFace += "\t\t}\n"; + + embeddedAsset.cssFontFace = fontFace; + + } + break; + + } + + } + + } + + } + + } + + FileHelper.recursiveSmartCopyTemplate (project, "html5/template", destination, context); + + if (project.app.main != null) { + + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "html5/haxe", targetDirectory + "/haxe", context, true, false); + FileHelper.recursiveSmartCopyTemplate (project, "html5/hxml", targetDirectory + "/haxe", context); + + } + + if (targetFlags.exists ("electron")) { + + FileHelper.recursiveSmartCopyTemplate (project, "electron/template", destination, context); + + if (project.app.main != null) { + + FileHelper.recursiveSmartCopyTemplate (project, "electron/haxe", targetDirectory + "/haxe", context, true, false); + FileHelper.recursiveSmartCopyTemplate (project, "electron/hxml", targetDirectory + "/haxe", context); + + } + + } + + for (asset in project.assets) { + + var path = PathHelper.combine (destination, asset.targetPath); + + if (asset.type == AssetType.TEMPLATE) { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path, context); + + } + + } + + } + + + public override function watch ():Void { + + // TODO: Use a custom live reload HTTP server for test/run instead + + var dirs = WatchHelper.processHXML (project, getDisplayHXML ()); + var command = WatchHelper.getCurrentCommand (); + WatchHelper.watch (project, command, dirs); + + } + + + @ignore public override function install ():Void {} + @ignore public override function rebuild ():Void {} + @ignore public override function trace ():Void {} + @ignore public override function uninstall ():Void {} + + +} \ No newline at end of file diff --git a/tools/platforms/IOSPlatform.hx b/tools/platforms/IOSPlatform.hx new file mode 100644 index 000000000..70f5e64a6 --- /dev/null +++ b/tools/platforms/IOSPlatform.hx @@ -0,0 +1,775 @@ +package; + + +//import openfl.display.BitmapData; +import haxe.io.Path; +import haxe.Json; +import haxe.Template; +import hxp.helpers.ArrayHelper; +import hxp.helpers.CPPHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.IconHelper; +import hxp.helpers.IOSHelper; +import hxp.helpers.LogHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.PlatformHelper; +import hxp.helpers.ProcessHelper; +import hxp.helpers.StringHelper; +import hxp.helpers.WatchHelper; +import lime.graphics.Image; +import hxp.project.Architecture; +import hxp.project.Asset; +import hxp.project.AssetType; +import hxp.project.Haxelib; +import hxp.project.HXProject; +import hxp.project.Icon; +import hxp.project.Keystore; +import hxp.project.NDLL; +import hxp.project.Platform; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.FileSystem; + + +class IOSPlatform extends PlatformTarget { + + + public function new (command:String, _project:HXProject, targetFlags:Map ) { + + super (command, _project, targetFlags); + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("ios.output-directory", "ios")); + + } + + + public override function build ():Void { + + if (project.targetFlags.exists ("xcode") && PlatformHelper.hostPlatform == Platform.MAC) { + + ProcessHelper.runCommand ("", "open", [ targetDirectory + "/" + project.app.file + ".xcodeproj" ] ); + + } else { + + IOSHelper.build (project, targetDirectory); + + if (noOutput) return; + + if (!project.targetFlags.exists ("simulator")) { + + IOSHelper.sign (project, targetDirectory + "/bin"); + + } + + } + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + IOSHelper.deploy (project, targetDirectory); + + } + + + public override function display ():Void { + + Sys.println (getDisplayHXML ()); + + } + + + private function generateContext ():Dynamic { + + //project = project.clone (); + + project.sources.unshift (""); + project.sources = PathHelper.relocatePaths (project.sources, PathHelper.combine (targetDirectory, project.app.file + "/haxe")); + //project.dependencies.push ("stdc++"); + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + if (project.targetFlags.exists ("final")) { + + project.haxedefs.set ("final", ""); + + } + + if (!project.config.exists ("ios.identity")) { + + project.config.set ("ios.identity", "iPhone Developer"); + + } + + IOSHelper.getIOSVersion (project); + project.haxedefs.set ("IPHONE_VER", project.environment.get ("IPHONE_VER")); + + project.haxedefs.set ("HXCPP_CPP11", "1"); + + if (project.config.getString ("ios.compiler") == "llvm" || project.config.getString ("ios.compiler", "clang") == "clang") { + + project.haxedefs.set ("HXCPP_CLANG", "1"); + project.haxedefs.set ("OBJC_ARC", "1"); + + } + + var context = project.templateContext; + + context.HAS_ICON = false; + context.HAS_LAUNCH_IMAGE = false; + context.OBJC_ARC = false; + context.KEY_STORE_IDENTITY = project.config.getString ("ios.identity"); + + if (project.config.exists ("ios.provisioning-profile")) { + + context.IOS_PROVISIONING_PROFILE = PathHelper.tryFullPath (project.config.getString ("ios.provisioning-profile")); + + } + + if (project.config.exists ("ios.team-id")) { + + context.DEVELOPMENT_TEAM_ID = project.config.getString ("ios.team-id"); + + } + + context.linkedLibraries = []; + + for (dependency in project.dependencies) { + + if (!StringTools.endsWith (dependency.name, ".framework") && !StringTools.endsWith (dependency.name, ".tbd") && !StringTools.endsWith (dependency.path, ".framework")) { + + if (dependency.path != "") { + + var name = Path.withoutDirectory (Path.withoutExtension (dependency.path)); + + if (dependency.forceLoad) { + + project.config.push ("ios.linker-flags", "-force_load $SRCROOT/$PRODUCT_NAME/lib/$CURRENT_ARCH/" + Path.withoutDirectory (dependency.path)); + + } + + if (StringTools.startsWith (name, "lib")) { + + name = name.substring (3, name.length); + + } + + context.linkedLibraries.push (name); + + } else if (dependency.name != "") { + + context.linkedLibraries.push (dependency.name); + + } + + } + + } + + var valid_archs = new Array (); + var armv6 = false; + var armv7 = false; + var armv7s = false; + var arm64 = false; + var architectures = project.architectures; + + if (architectures == null || architectures.length == 0) { + + architectures = [ Architecture.ARMV7, Architecture.ARM64 ]; + + } + + if (project.config.getString ("ios.device", "universal") == "universal" || project.config.getString ("ios.device") == "iphone") { + + if (project.config.getFloat ("ios.deployment", 8) < 5) { + + ArrayHelper.addUnique (architectures, Architecture.ARMV6); + + } + + } + + for (architecture in project.architectures) { + + switch (architecture) { + + case ARMV6: valid_archs.push ("armv6"); armv6 = true; + case ARMV7: valid_archs.push ("armv7"); armv7 = true; + case ARMV7S: valid_archs.push ("armv7s"); armv7s = true; + case ARM64: valid_archs.push ("arm64"); arm64 = true; + default: + + } + + } + + context.CURRENT_ARCHS = "( " + valid_archs.join(",") + ") "; + + valid_archs.push ("x86_64"); + valid_archs.push ("i386"); + + context.VALID_ARCHS = valid_archs.join(" "); + context.THUMB_SUPPORT = armv6 ? "GCC_THUMB_SUPPORT = NO;" : ""; + + var requiredCapabilities = []; + + if (!armv6 && armv7) { + + requiredCapabilities.push ({ name: "armv7", value: true }); + + } else if (!armv6 && !armv7 && armv7s) { + + requiredCapabilities.push ({ name: "armv7s", value: true }); + + } else if (!armv6 && !armv7 && !armv7s && arm64) { + + requiredCapabilities.push ({ name: "arm64", value: true }); + + } + + context.REQUIRED_CAPABILITY = requiredCapabilities; + context.ARMV6 = armv6; + context.ARMV7 = armv7; + context.ARMV7S = armv7s; + context.ARM64 = arm64; + context.TARGET_DEVICES = switch (project.config.getString ("ios.device", "universal")) { case "iphone": "1"; case "ipad": "2"; default: "1,2"; } + context.DEPLOYMENT = project.config.getString ("ios.deployment", "8.0"); + + if (project.config.getString ("ios.compiler") == "llvm" || project.config.getString ("ios.compiler", "clang") == "clang") { + + context.OBJC_ARC = true; + + } + + //context.ENABLE_BITCODE = (project.config.getFloat ("ios.deployment", 8) >= 6); + context.ENABLE_BITCODE = project.config.getBool ("ios.enable-bitcode", false); + context.IOS_COMPILER = project.config.getString ("ios.compiler", "clang"); + context.CPP_BUILD_LIBRARY = project.config.getString ("cpp.buildLibrary", "hxcpp"); + + var json = Json.parse (File.getContent (PathHelper.getHaxelib (new Haxelib ("hxcpp"), true) + "/haxelib.json")); + + if (Std.parseFloat (json.version) > 3.1) { + + context.CPP_LIBPREFIX = "lib"; + + } else { + + context.CPP_LIBPREFIX = ""; + + } + + context.IOS_LINKER_FLAGS = ["-stdlib=libc++"].concat (project.config.getArrayString ("ios.linker-flags")); + context.IOS_NON_EXEMPT_ENCRYPTION = project.config.getBool ("ios.non-exempt-encryption", true); + + switch (project.window.orientation) { + + case PORTRAIT: + context.IOS_APP_ORIENTATION = "UIInterfaceOrientationPortraitUIInterfaceOrientationPortraitUpsideDown"; + case LANDSCAPE: + context.IOS_APP_ORIENTATION = "UIInterfaceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRight"; + case ALL: + context.IOS_APP_ORIENTATION = "UIInterfaceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRightUIInterfaceOrientationPortraitUIInterfaceOrientationPortraitUpsideDown"; + //case "allButUpsideDown": + //context.IOS_APP_ORIENTATION = "UIInterfaceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRightUIInterfaceOrientationPortrait"; + default: + context.IOS_APP_ORIENTATION = "UIInterfaceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRightUIInterfaceOrientationPortraitUIInterfaceOrientationPortraitUpsideDown"; + + } + + context.ADDL_PBX_BUILD_FILE = ""; + context.ADDL_PBX_FILE_REFERENCE = ""; + context.ADDL_PBX_FRAMEWORKS_BUILD_PHASE = ""; + context.ADDL_PBX_FRAMEWORK_GROUP = ""; + + context.frameworkSearchPaths = []; + + for (dependency in project.dependencies) { + + var name = null; + var path = null; + var fileType = null; + + if (Path.extension (dependency.name) == "framework") { + + name = dependency.name; + path = "/System/Library/Frameworks/" + dependency.name; + fileType = "wrapper.framework"; + + } else if (Path.extension (dependency.name) == "tbd") { + + name = dependency.name; + path = "/usr/lib/" + dependency.name; + fileType = "sourcecode.text-based-dylib-definition"; + + } else if (Path.extension (dependency.path) == "framework") { + + name = Path.withoutDirectory (dependency.path); + path = PathHelper.tryFullPath (dependency.path); + fileType = "wrapper.framework"; + + } + + if (name != null) { + + var frameworkID = "11C0000000000018" + StringHelper.getUniqueID (); + var fileID = "11C0000000000018" + StringHelper.getUniqueID (); + + ArrayHelper.addUnique (context.frameworkSearchPaths, Path.directory (path)); + + context.ADDL_PBX_BUILD_FILE += " " + frameworkID + " /* " + name + " in Frameworks */ = {isa = PBXBuildFile; fileRef = " + fileID + " /* " + name + " */; };\n"; + context.ADDL_PBX_FILE_REFERENCE += " " + fileID + " /* " + name + " */ = {isa = PBXFileReference; lastKnownFileType = \"" + fileType + "\"; name = \"" + name + "\"; path = \"" + path + "\"; sourceTree = SDKROOT; };\n"; + context.ADDL_PBX_FRAMEWORKS_BUILD_PHASE += " " + frameworkID + " /* " + name + " in Frameworks */,\n"; + context.ADDL_PBX_FRAMEWORK_GROUP += " " + fileID + " /* " + name + " */,\n"; + + } + + } + + context.HXML_PATH = PathHelper.findTemplate (project.templatePaths, "iphone/PROJ/haxe/Build.hxml", false); + if (context.HXML_PATH == null) context.HXML_PATH = PathHelper.findTemplate (project.templatePaths, "ios/template/{{app.file}}/haxe/Build.hxml"); + context.PRERENDERED_ICON = project.config.getBool ("ios.prerenderedIcon", false); + + var allowInsecureHTTP = project.config.getString ("ios.allow-insecure-http", "*"); + + if (allowInsecureHTTP != "*" && allowInsecureHTTP != "true") { + + var sites = []; + + if (allowInsecureHTTP != "false") { + + var domains = project.config.getArrayString ("ios.allow-insecure-http"); + + for (domain in domains) { + + sites.push ({ domain: domain }); + + } + + } + + context.IOS_ALLOW_INSECURE_HTTP = sites; + + } + + var haxelibPath = project.environment.get ("HAXELIB_PATH"); + + if (haxelibPath != null) { + + context.HAXELIB_PATH = 'export HAXELIB_PATH="$haxelibPath";'; + + } else { + + context.HAXELIB_PATH = ''; + + } + + return context; + + } + + + private function getDisplayHXML ():String { + + var hxml = PathHelper.findTemplate (project.templatePaths, "iphone/PROJ/haxe/Build.hxml", false); + if (hxml == null) hxml = PathHelper.findTemplate (project.templatePaths, "iphone/template/{{app.file}}/Build.hxml", true); + var template = new Template (File.getContent (hxml)); + + // project = project.clone (); + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + return template.execute (context) + "\n-D display"; + + } + + + public override function rebuild ():Void { + + var armv6 = (project.architectures.indexOf (Architecture.ARMV6) > -1 && !project.targetFlags.exists ("simulator")); + var armv7 = (command == "rebuild" || (project.architectures.indexOf (Architecture.ARMV7) > -1 && !project.targetFlags.exists ("simulator"))); + var armv7s = (project.architectures.indexOf (Architecture.ARMV7S) > -1 && !project.targetFlags.exists ("simulator")); + var arm64 = (command == "rebuild" || (project.architectures.indexOf (Architecture.ARM64) > -1 && !project.targetFlags.exists ("simulator"))); + var i386 = (command == "rebuild" || project.targetFlags.exists ("simulator")); + var x86_64 = (command == "rebuild" || project.targetFlags.exists ("simulator")); + + var arc = (project.targetFlags.exists ("arc")); + + var commands = []; + + if (armv6) commands.push ([ "-Dios", "-DHXCPP_CPP11" ]); + if (armv7) commands.push ([ "-Dios", "-DHXCPP_CPP11", "-DHXCPP_ARMV7" ]); + if (armv7s) commands.push ([ "-Dios", "-DHXCPP_CPP11", "-DHXCPP_ARMV7S" ]); + if (arm64) commands.push ([ "-Dios", "-DHXCPP_CPP11", "-DHXCPP_ARM64" ]); + if (i386) commands.push ([ "-Dios", "-Dsimulator", "-DHXCPP_CPP11" ]); + if (x86_64) commands.push ([ "-Dios", "-Dsimulator", "-DHXCPP_M64", "-DHXCPP_CPP11" ]); + + if (arc) { + + for (command in commands) { + + command.push ("-DOBJC_ARC"); + + } + + } + + IOSHelper.getIOSVersion (project); + var iphoneVer = project.environment.get ("IPHONE_VER"); + + for (command in commands) { + + command.push ("-DIPHONE_VER=" + iphoneVer); + + } + + CPPHelper.rebuild (project, commands); + + } + + + public override function run ():Void { + + if (project.targetFlags.exists ("xcode")) return; + + IOSHelper.launch (project, targetDirectory); + + } + + + public override function update ():Void { + + // project = project.clone (); + + for (asset in project.assets) { + + if (asset.embed && asset.sourcePath == "") { + + var path = PathHelper.combine (targetDirectory + "/" + project.app.file + "/obj/tmp", asset.targetPath); + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path); + asset.sourcePath = path; + + } + + } + + //var manifest = new Asset (); + //manifest.id = "__manifest__"; + //manifest.data = AssetHelper.createManifest (project).serialize (); + //manifest.resourceName = manifest.flatName = manifest.targetPath = "manifest"; + //manifest.type = AssetType.TEXT; + //project.assets.push (manifest); + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + var projectDirectory = targetDirectory + "/" + project.app.file + "/"; + + PathHelper.mkdir (targetDirectory); + PathHelper.mkdir (projectDirectory); + PathHelper.mkdir (projectDirectory + "/haxe"); + PathHelper.mkdir (projectDirectory + "/haxe/lime/installer"); + + var iconSizes:Array = [ + { name: "Icon-20.png", size: 20 }, + { name: "Icon-Small.png", size: 29 }, + { name: "Icon-Small-40.png", size: 40 }, + { name: "Icon-20@2x.png", size: 40 }, + { name: "Icon-Small-50.png", size: 50 }, + { name: "Icon.png", size: 57 }, + { name: "Icon-Small@2x.png", size: 58 }, + { name: "Icon-20@3x.png", size: 60 }, + { name: "Icon-72.png", size: 72 }, + { name: "Icon-76.png", size: 76 }, + { name: "Icon-Small-40@2x.png", size: 80 }, + { name: "Icon-Small@3x.png", size: 87 }, + { name: "Icon-Small-50@2x.png", size: 100 }, + { name: "Icon@2x.png", size: 114 }, + { name: "Icon-60@2x.png", size: 120 }, + { name: "Icon-Small-40@3x.png", size: 120 }, + { name: "Icon-72@2x.png", size: 144 }, + { name: "Icon-76@2x.png", size: 152 }, + { name: "Icon-83.5@2x.png", size: 167 }, + { name: "Icon-60@3x.png", size: 180 }, + { name: "Icon-Marketing.png", size: 1024 } + ]; + + context.HAS_ICON = true; + + var iconPath = PathHelper.combine (projectDirectory, "Images.xcassets/AppIcon.appiconset"); + PathHelper.mkdir (iconPath); + + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + for (iconSize in iconSizes) { + + if (!IconHelper.createIcon (icons, iconSize.size, iconSize.size, PathHelper.combine (iconPath, iconSize.name))) { + + context.HAS_ICON = false; + + } + + } + + var splashSizes:Array = [ + { name: "Default.png", w: 320, h: 480 }, // iPhone, portrait + { name: "Default@2x.png", w: 640, h: 960 }, // iPhone Retina, portrait + { name: "Default-568h@2x.png", w: 640, h: 1136 }, // iPhone 5, portrait + { name: "Default-667h@2x.png", w: 750, h: 1334 }, // iPhone 6, portrait + { name: "Default-736h@3x.png", w: 1242, h: 2208 }, // iPhone 6 Plus, portrait + { name: "Default-Landscape.png", w: 1024, h: 768 }, // iPad, landscape + { name: "Default-Landscape@2x.png", w: 2048, h: 1536 }, // iPad Retina, landscape + { name: "Default-736h-Landscape@3x.png", w: 2208, h: 1242 }, // iPhone 6 Plus, landscape + { name: "Default-Portrait.png", w: 768, h: 1024 }, // iPad, portrait + { name: "Default-Portrait@2x.png", w: 1536, h: 2048 }, // iPad Retina, portrait + { name: "Default-812h@3x.png", w: 1125, h: 2436 }, // iPhone X, portrait + { name: "Default-Landscape-812h@3x.png", w: 2436, h: 1125 } // iPhone X, landscape + ]; + + var splashScreenPath = PathHelper.combine (projectDirectory, "Images.xcassets/LaunchImage.launchimage"); + PathHelper.mkdir (splashScreenPath); + + for (size in splashSizes) { + + var match = false; + + for (splashScreen in project.splashScreens) { + + if (splashScreen.width == size.w && splashScreen.height == size.h && Path.extension (splashScreen.path) == "png") { + + FileHelper.copyFile (splashScreen.path, PathHelper.combine (splashScreenPath, size.name)); + match = true; + + } + + } + + if (!match) { + + var imagePath = PathHelper.combine (splashScreenPath, size.name); + + if (!FileSystem.exists (imagePath)) { + + LogHelper.info ("", " - \x1b[1mGenerating image:\x1b[0m " + imagePath); + + var image = new Image (null, 0, 0, size.w, size.h, (0xFF << 24) | (project.window.background & 0xFFFFFF)); + var bytes = image.encode ("png"); + + File.saveBytes (imagePath, bytes); + + } + + } + + } + + context.HAS_LAUNCH_IMAGE = true; + + PathHelper.mkdir (projectDirectory + "/resources"); + PathHelper.mkdir (projectDirectory + "/haxe/build"); + + // Long deprecated template path + + FileHelper.recursiveSmartCopyTemplate (project, "iphone/resources", projectDirectory + "/resources", context, true, false); + + // New template path + + FileHelper.recursiveSmartCopyTemplate (project, "ios/template", targetDirectory, context); + + // Recently deprecated template paths + + FileHelper.recursiveSmartCopyTemplate (project, "iphone/PROJ/haxe", projectDirectory + "/haxe", context, true, false); + FileHelper.recursiveSmartCopyTemplate (project, "haxe", projectDirectory + "/haxe", context, true, false); + FileHelper.recursiveSmartCopyTemplate (project, "iphone/PROJ/Classes", projectDirectory + "/Classes", context, true, false); + FileHelper.recursiveSmartCopyTemplate (project, "iphone/PROJ/Images.xcassets", projectDirectory + "/Images.xcassets", context, true, false); + FileHelper.copyFileTemplate (project.templatePaths, "iphone/PROJ/PROJ-Info.plist", projectDirectory + "/" + project.app.file + "-Info.plist", context, true, false); + FileHelper.copyFileTemplate (project.templatePaths, "iphone/PROJ/PROJ-Prefix.pch", projectDirectory + "/" + project.app.file + "-Prefix.pch", context, true, false); + FileHelper.recursiveSmartCopyTemplate (project, "iphone/PROJ.xcodeproj", targetDirectory + "/" + project.app.file + ".xcodeproj", context, true, false); + + PathHelper.mkdir (projectDirectory + "/lib"); + + for (archID in 0...6) { + + var arch = [ "armv6", "armv7", "armv7s", "arm64", "i386", "x86_64" ][archID]; + + if (arch == "armv6" && !context.ARMV6) + continue; + + if (arch == "armv7" && !context.ARMV7) + continue; + + if (arch == "armv7s" && !context.ARMV7S) + continue; + + if (arch == "arm64" && !context.ARM64) + continue; + + var libExt = [ ".iphoneos.a", ".iphoneos-v7.a", ".iphoneos-v7s.a", ".iphoneos-64.a", ".iphonesim.a", ".iphonesim-64.a" ][archID]; + + PathHelper.mkdir (projectDirectory + "/lib/" + arch); + PathHelper.mkdir (projectDirectory + "/lib/" + arch + "-debug"); + + for (ndll in project.ndlls) { + + //if (ndll.haxelib != null) { + + var releaseLib = PathHelper.getLibraryPath (ndll, "iPhone", "lib", libExt); + var debugLib = PathHelper.getLibraryPath (ndll, "iPhone", "lib", libExt, true); + var releaseDest = projectDirectory + "/lib/" + arch + "/lib" + ndll.name + ".a"; + var debugDest = projectDirectory + "/lib/" + arch + "-debug/lib" + ndll.name + ".a"; + + if (!FileSystem.exists (releaseLib)) { + + releaseLib = PathHelper.getLibraryPath (ndll, "iPhone", "lib", ".iphoneos.a"); + debugLib = PathHelper.getLibraryPath (ndll, "iPhone", "lib", ".iphoneos.a", true); + + } + + FileHelper.copyIfNewer (releaseLib, releaseDest); + + if (FileSystem.exists (debugLib) && debugLib != releaseLib) { + + FileHelper.copyIfNewer (debugLib, debugDest); + + } else if (FileSystem.exists (debugDest)) { + + FileSystem.deleteFile (debugDest); + + } + + //} + + } + + for (dependency in project.dependencies) { + + if (StringTools.endsWith (dependency.path, ".a")) { + + var fileName = Path.withoutDirectory (dependency.path); + + if (!StringTools.startsWith (fileName, "lib")) { + + fileName = "lib" + fileName; + + } + + FileHelper.copyIfNewer (dependency.path, projectDirectory + "/lib/" + arch + "/" + fileName); + + } + + } + + } + + PathHelper.mkdir (projectDirectory + "/assets"); + + for (asset in project.assets) { + + if (asset.type != AssetType.TEMPLATE) { + + var targetPath = PathHelper.combine (projectDirectory + "/assets/", asset.resourceName); + + //var sourceAssetPath:String = projectDirectory + "haxe/" + asset.sourcePath; + + PathHelper.mkdir (Path.directory (targetPath)); + FileHelper.copyAssetIfNewer (asset, targetPath); + + //PathHelper.mkdir (Path.directory (sourceAssetPath)); + //FileHelper.linkFile (flatAssetPath, sourceAssetPath, true, true); + + } else { + + var targetPath = PathHelper.combine (projectDirectory, asset.targetPath); + + PathHelper.mkdir (Path.directory (targetPath)); + FileHelper.copyAsset (asset, targetPath, context); + + } + + } + + if (project.targetFlags.exists ("xcode") && PlatformHelper.hostPlatform == Platform.MAC && command == "update") { + + ProcessHelper.runCommand ("", "open", [ targetDirectory + "/" + project.app.file + ".xcodeproj" ] ); + + } + + } + + + /*private function updateLaunchImage () { + + var destination = buildDirectory + "/ios"; + PathHelper.mkdir (destination); + + var has_launch_image = false; + if (launchImages.length > 0) has_launch_image = true; + + for (launchImage in launchImages) { + + var splitPath = launchImage.name.split ("/"); + var path = destination + "/" + splitPath[splitPath.length - 1]; + FileHelper.copyFile (launchImage.name, path, context, false); + + } + + context.HAS_LAUNCH_IMAGE = has_launch_image; + + }*/ + + + public override function watch ():Void { + + var dirs = WatchHelper.processHXML (project, getDisplayHXML ()); + var command = WatchHelper.getCurrentCommand (); + WatchHelper.watch (project, command, dirs); + + } + + + @ignore public override function install ():Void {} + @ignore public override function trace ():Void {} + @ignore public override function uninstall ():Void {} + + +} + + +private typedef IconSize = { + + name:String, + size:Int, + +} + + +private typedef SplashSize = { + + name:String, + w:Int, + h:Int, + +} diff --git a/tools/platforms/LinuxPlatform.hx b/tools/platforms/LinuxPlatform.hx new file mode 100644 index 000000000..1df61a6d0 --- /dev/null +++ b/tools/platforms/LinuxPlatform.hx @@ -0,0 +1,457 @@ +package; + + +import haxe.io.Path; +import haxe.Template; +import hxp.helpers.CPPHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.JavaHelper; +import hxp.helpers.LogHelper; +import hxp.helpers.NekoHelper; +import hxp.helpers.NodeJSHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.PlatformHelper; +import hxp.helpers.ProcessHelper; +import hxp.helpers.WatchHelper; +import hxp.project.AssetType; +import hxp.project.Architecture; +import hxp.project.Haxelib; +import hxp.project.HXProject; +import hxp.project.Platform; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.io.Process; +import sys.FileSystem; + + +class LinuxPlatform extends PlatformTarget { + + + private var applicationDirectory:String; + private var executablePath:String; + private var is64:Bool; + private var isRaspberryPi:Bool; + private var targetType:String; + + + public function new (command:String, _project:HXProject, targetFlags:Map ) { + + super (command, _project, targetFlags); + + for (architecture in project.architectures) { + + if (!targetFlags.exists ("32") && architecture == Architecture.X64) { + + is64 = true; + + } else if (architecture == Architecture.ARMV7) { + + isRaspberryPi = true; + + } + + } + + if (project.targetFlags.exists ("rpi")) { + + isRaspberryPi = true; + is64 = false; + + } + + if (project.targetFlags.exists ("neko") || project.target != PlatformHelper.hostPlatform) { + + targetType = "neko"; + + } else if (project.targetFlags.exists ("hl")) { + + targetType = "hl"; + + } else if (project.targetFlags.exists ("nodejs")) { + + targetType = "nodejs"; + + } else if (project.targetFlags.exists ("java")) { + + targetType = "java"; + + } else { + + targetType = "cpp"; + + } + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("linux.output-directory", targetType == "cpp" ? "linux" : targetType)); + targetDirectory = StringTools.replace (targetDirectory, "arch64", is64 ? "64" : ""); + applicationDirectory = targetDirectory + "/bin/"; + executablePath = PathHelper.combine (applicationDirectory, project.app.file); + + } + + + public override function build ():Void { + + var hxml = targetDirectory + "/haxe/" + buildType + ".hxml"; + + PathHelper.mkdir (targetDirectory); + + if (!project.targetFlags.exists ("static") || targetType != "cpp") { + + var targetSuffix = (targetType == "hl") ? ".hdll" : null; + + for (ndll in project.ndlls) { + + if (isRaspberryPi) { + + FileHelper.copyLibrary (project, ndll, "RPi", "", (ndll.haxelib != null && (ndll.haxelib.name == "hxcpp" || ndll.haxelib.name == "hxlibc")) ? ".dso" : ".ndll", applicationDirectory, project.debug, targetSuffix); + + } else { + + FileHelper.copyLibrary (project, ndll, "Linux" + (is64 ? "64" : ""), "", (ndll.haxelib != null && (ndll.haxelib.name == "hxcpp" || ndll.haxelib.name == "hxlibc")) ? ".dso" : ".ndll", applicationDirectory, project.debug, targetSuffix); + + } + + } + + } + + if (targetType == "neko") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + if (isRaspberryPi) { + + NekoHelper.createExecutable (project.templatePaths, "rpi", targetDirectory + "/obj/ApplicationMain.n", executablePath); + NekoHelper.copyLibraries (project.templatePaths, "rpi", applicationDirectory); + + } else { + + NekoHelper.createExecutable (project.templatePaths, "linux" + (is64 ? "64" : ""), targetDirectory + "/obj/ApplicationMain.n", executablePath); + NekoHelper.copyLibraries (project.templatePaths, "linux" + (is64 ? "64" : ""), applicationDirectory); + + } + + } else if (targetType == "hl") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-Debug" : "") + ".hl", PathHelper.combine (applicationDirectory, project.app.file + ".hl")); + + } else if (targetType == "nodejs") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + //NekoHelper.createExecutable (project.templatePaths, "linux" + (is64 ? "64" : ""), targetDirectory + "/obj/ApplicationMain.n", executablePath); + //NekoHelper.copyLibraries (project.templatePaths, "linux" + (is64 ? "64" : ""), applicationDirectory); + + } else if (targetType == "java") { + + var libPath = PathHelper.combine (PathHelper.getHaxelib (new Haxelib ("lime")), "templates/java/lib/"); + + ProcessHelper.runCommand ("", "haxe", [ hxml, "-java-lib", libPath + "disruptor.jar", "-java-lib", libPath + "lwjgl.jar" ]); + //ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + var haxeVersion = project.environment.get ("haxe_ver"); + var haxeVersionString = "3404"; + + if (haxeVersion.length > 4) { + + haxeVersionString = haxeVersion.charAt (0) + haxeVersion.charAt (2) + (haxeVersion.length == 5 ? "0" + haxeVersion.charAt (4) : haxeVersion.charAt (4) + haxeVersion.charAt (5)); + + } + + ProcessHelper.runCommand (targetDirectory + "/obj", "haxelib", [ "run", "hxjava", "hxjava_build.txt", "--haxe-version", haxeVersionString ]); + FileHelper.recursiveCopy (targetDirectory + "/obj/lib", PathHelper.combine (applicationDirectory, "lib")); + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-Debug" : "") + ".jar", PathHelper.combine (applicationDirectory, project.app.file + ".jar")); + JavaHelper.copyLibraries (project.templatePaths, "Linux" + (is64 ? "64" : ""), applicationDirectory); + + } else { + + var haxeArgs = [ hxml ]; + var flags = []; + + if (is64) { + + haxeArgs.push ("-D"); + haxeArgs.push ("HXCPP_M64"); + flags.push ("-DHXCPP_M64"); + + } else { + + haxeArgs.push ("-D"); + haxeArgs.push ("HXCPP_M32"); + flags.push ("-DHXCPP_M32"); + + } + + if (!project.targetFlags.exists ("static")) { + + ProcessHelper.runCommand ("", "haxe", haxeArgs); + + if (noOutput) return; + + CPPHelper.compile (project, targetDirectory + "/obj", flags); + + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-debug" : ""), executablePath); + + } else { + + ProcessHelper.runCommand ("", "haxe", haxeArgs.concat ([ "-D", "static_link" ])); + + if (noOutput) return; + + CPPHelper.compile (project, targetDirectory + "/obj", flags.concat ([ "-Dstatic_link" ])); + CPPHelper.compile (project, targetDirectory + "/obj", flags, "BuildMain.xml"); + + FileHelper.copyFile (targetDirectory + "/obj/Main" + (project.debug ? "-debug" : ""), executablePath); + + } + + } + + if (PlatformHelper.hostPlatform != Platform.WINDOWS && (targetType != "nodejs" && targetType != "java")) { + + ProcessHelper.runCommand ("", "chmod", [ "755", executablePath ]); + + } + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + DeploymentHelper.deploy (project, targetFlags, targetDirectory, "Linux " + (is64 ? "64" : "32") + "-bit"); + + } + + + public override function display ():Void { + + Sys.println (getDisplayHXML ()); + + } + + + private function generateContext ():Dynamic { + + // var project = project.clone (); + + if (isRaspberryPi) { + + project.haxedefs.set ("rpi", 1); + + } + + var context = project.templateContext; + + context.NEKO_FILE = targetDirectory + "/obj/ApplicationMain.n"; + context.NODE_FILE = targetDirectory + "/bin/ApplicationMain.js"; + context.HL_FILE = targetDirectory + "/obj/ApplicationMain.hl"; + context.CPP_DIR = targetDirectory + "/obj/"; + context.BUILD_DIR = project.app.path + "/linux" + (is64 ? "64" : "") + (isRaspberryPi ? "-rpi" : ""); + context.WIN_ALLOW_SHADERS = false; + + return context; + + } + + + private function getDisplayHXML ():String { + + var hxml = PathHelper.findTemplate (project.templatePaths, targetType + "/hxml/" + buildType + ".hxml"); + var template = new Template (File.getContent (hxml)); + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + return template.execute (context) + "\n-D display"; + + } + + + public override function rebuild ():Void { + + var commands = []; + + if (targetFlags.exists ("rpi")) { + + commands.push ([ "-Dlinux", "-Drpi", "-Dtoolchain=linux", "-DBINDIR=RPi", "-DCXX=arm-linux-gnueabihf-g++", "-DHXCPP_M32", "-DHXCPP_STRIP=arm-linux-gnueabihf-strip", "-DHXCPP_AR=arm-linux-gnueabihf-ar", "-DHXCPP_RANLIB=arm-linux-gnueabihf-ranlib" ]); + + } else { + + if (!targetFlags.exists ("32") && PlatformHelper.hostArchitecture == X64) { + + commands.push ([ "-Dlinux", "-DHXCPP_M64" ]); + + } + + if (!targetFlags.exists ("64") && (command == "rebuild" || PlatformHelper.hostArchitecture == Architecture.X86)) { + + commands.push ([ "-Dlinux", "-DHXCPP_M32" ]); + + } + + } + + CPPHelper.rebuild (project, commands); + + } + + + public override function run ():Void { + + var arguments = additionalArguments.copy (); + + if (LogHelper.verbose) { + + arguments.push ("-verbose"); + + } + + if (targetType == "hl") { + + ProcessHelper.runCommand (applicationDirectory, "hl", [ project.app.file + ".hl" ].concat (arguments)); + + } else if (targetType == "nodejs") { + + NodeJSHelper.run (project, targetDirectory + "/bin/ApplicationMain.js", arguments); + + } else if (targetType == "java") { + + ProcessHelper.runCommand (applicationDirectory, "java", [ "-jar", project.app.file + ".jar" ].concat (arguments)); + + } else if (project.target == PlatformHelper.hostPlatform) { + + arguments = arguments.concat ([ "-livereload" ]); + ProcessHelper.runCommand (applicationDirectory, "./" + Path.withoutDirectory (executablePath), arguments); + + } + + } + + + public override function update ():Void { + + // project = project.clone (); + //initialize (project); + + for (asset in project.assets) { + + if (asset.embed && asset.sourcePath == "") { + + var path = PathHelper.combine (targetDirectory + "/obj/tmp", asset.targetPath); + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path); + asset.sourcePath = path; + + } + + } + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + if (targetType == "cpp" && project.targetFlags.exists ("static")) { + + for (i in 0...project.ndlls.length) { + + var ndll = project.ndlls[i]; + + if (ndll.path == null || ndll.path == "") { + + if (isRaspberryPi) { + + context.ndlls[i].path = PathHelper.getLibraryPath (ndll, "RPi", "lib", ".a", project.debug); + + } else { + + context.ndlls[i].path = PathHelper.getLibraryPath (ndll, "Linux" + (is64 ? "64" : ""), "lib", ".a", project.debug); + + } + + } + + } + + } + + PathHelper.mkdir (targetDirectory); + PathHelper.mkdir (targetDirectory + "/obj"); + PathHelper.mkdir (targetDirectory + "/haxe"); + PathHelper.mkdir (applicationDirectory); + + //SWFHelper.generateSWFClasses (project, targetDirectory + "/haxe"); + + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, targetType + "/hxml", targetDirectory + "/haxe", context); + + if (targetType == "cpp" && project.targetFlags.exists ("static")) { + + FileHelper.recursiveSmartCopyTemplate (project, "cpp/static", targetDirectory + "/obj", context); + + } + + //context.HAS_ICON = IconHelper.createIcon (project.icons, 256, 256, PathHelper.combine (applicationDirectory, "icon.png")); + for (asset in project.assets) { + + var path = PathHelper.combine (applicationDirectory, asset.targetPath); + + if (asset.embed != true) { + + if (asset.type != AssetType.TEMPLATE) { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAssetIfNewer (asset, path); + + } else { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path, context); + + } + + } + + } + + } + + + public override function watch ():Void { + + var dirs = WatchHelper.processHXML (project, getDisplayHXML ()); + var command = WatchHelper.getCurrentCommand (); + WatchHelper.watch (project, command, dirs); + + } + + + @ignore public override function install ():Void {} + @ignore public override function trace ():Void {} + @ignore public override function uninstall ():Void {} + + +} \ No newline at end of file diff --git a/tools/platforms/MacPlatform.hx b/tools/platforms/MacPlatform.hx new file mode 100644 index 000000000..e7be6344d --- /dev/null +++ b/tools/platforms/MacPlatform.hx @@ -0,0 +1,425 @@ +package; + + +import haxe.io.Path; +import haxe.Template; +import hxp.helpers.CPPHelper; +import hxp.helpers.CSHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.GUID; +import hxp.helpers.FileHelper; +import hxp.helpers.HaxelibHelper; +import hxp.helpers.IconHelper; +import hxp.helpers.JavaHelper; +import hxp.helpers.LogHelper; +import hxp.helpers.NekoHelper; +import hxp.helpers.NodeJSHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.PlatformHelper; +import hxp.helpers.ProcessHelper; +import hxp.helpers.WatchHelper; +import hxp.project.AssetType; +import hxp.project.Architecture; +import hxp.project.Haxelib; +import hxp.project.HXProject; +import hxp.project.Icon; +import hxp.project.Platform; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.FileSystem; + + +class MacPlatform extends PlatformTarget { + + + private var applicationDirectory:String; + private var contentDirectory:String; + private var executableDirectory:String; + private var executablePath:String; + private var is64:Bool; + private var targetType:String; + + + public function new (command:String, _project:HXProject, targetFlags:Map ) { + + super (command, _project, targetFlags); + + for (architecture in project.architectures) { + + if (architecture == Architecture.X64) { + + is64 = true; + + } + + } + + if (project.targetFlags.exists ("neko") || project.target != PlatformHelper.hostPlatform) { + + targetType = "neko"; + + } else if (project.targetFlags.exists ("hl")) { + + targetType = "hl"; + + } else if (project.targetFlags.exists ("java")) { + + targetType = "java"; + + } else if (project.targetFlags.exists ("nodejs")) { + + targetType = "nodejs"; + + } else if (project.targetFlags.exists ("cs")) { + + targetType = "cs"; + + } else { + + targetType = "cpp"; + + } + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("mac.output-directory", targetType == "cpp" ? "macos" : targetType)); + targetDirectory = StringTools.replace (targetDirectory, "arch64", is64 ? "64" : ""); + applicationDirectory = targetDirectory + "/bin/" + project.app.file + ".app"; + contentDirectory = applicationDirectory + "/Contents/Resources"; + executableDirectory = applicationDirectory + "/Contents/MacOS"; + executablePath = executableDirectory + "/" + project.app.file; + + } + + + public override function build ():Void { + + var hxml = targetDirectory + "/haxe/" + buildType + ".hxml"; + + PathHelper.mkdir (targetDirectory); + + if (!project.targetFlags.exists ("static") || targetType != "cpp") { + + var targetSuffix = (targetType == "hl") ? ".hdll" : null; + + for (ndll in project.ndlls) { + + FileHelper.copyLibrary (project, ndll, "Mac" + (is64 ? "64" : ""), "", (ndll.haxelib != null && (ndll.haxelib.name == "hxcpp" || ndll.haxelib.name == "hxlibc")) ? ".dylib" : ".ndll", executableDirectory, project.debug, targetSuffix); + + } + + } + + if (targetType == "neko") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + NekoHelper.createExecutable (project.templatePaths, "mac" + (is64 ? "64" : ""), targetDirectory + "/obj/ApplicationMain.n", executablePath); + NekoHelper.copyLibraries (project.templatePaths, "mac" + (is64 ? "64" : ""), executableDirectory); + + } else if (targetType == "hl") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-Debug" : "") + ".hl", PathHelper.combine (executableDirectory, project.app.file + ".hl")); + + } else if (targetType == "java") { + + var libPath = PathHelper.combine (PathHelper.getHaxelib (new Haxelib ("lime")), "templates/java/lib/"); + + ProcessHelper.runCommand ("", "haxe", [ hxml, "-java-lib", libPath + "disruptor.jar", "-java-lib", libPath + "lwjgl.jar" ]); + + if (noOutput) return; + + HaxelibHelper.runCommand (targetDirectory + "/obj", [ "run", "hxjava", "hxjava_build.txt", "--haxe-version", "3103" ]); + FileHelper.recursiveCopy (targetDirectory + "/obj/lib", PathHelper.combine (executableDirectory, "lib")); + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-Debug" : "") + ".jar", PathHelper.combine (executableDirectory, project.app.file + ".jar")); + JavaHelper.copyLibraries (project.templatePaths, "Mac" + (is64 ? "64" : ""), executableDirectory); + + } else if (targetType == "nodejs") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + //NekoHelper.createExecutable (project.templatePaths, "Mac" + (is64 ? "64" : ""), targetDirectory + "/obj/ApplicationMain.n", executablePath); + //NekoHelper.copyLibraries (project.templatePaths, "Mac" + (is64 ? "64" : ""), executableDirectory); + + } else if (targetType == "cs") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + CSHelper.copySourceFiles (project.templatePaths, targetDirectory + "/obj/src"); + var txtPath = targetDirectory + "/obj/hxcs_build.txt"; + CSHelper.addSourceFiles (txtPath, CSHelper.ndllSourceFiles); + CSHelper.addGUID (txtPath, GUID.uuid ()); + CSHelper.compile (project, targetDirectory + "/obj", targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-debug" : ""), "x64", "desktop"); + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-debug" : "") + ".exe", executablePath + ".exe"); + File.saveContent (executablePath, "#!/bin/sh\nmono ${PWD}/" + project.app.file + ".exe"); + + } else { + + var haxeArgs = [ hxml, "-D", "HXCPP_CLANG" ]; + var flags = [ "-DHXCPP_CLANG" ]; + + if (is64) { + + haxeArgs.push ("-D"); + haxeArgs.push ("HXCPP_M64"); + flags.push ("-DHXCPP_M64"); + + } + + if (!project.targetFlags.exists ("static")) { + + ProcessHelper.runCommand ("", "haxe", haxeArgs); + + if (noOutput) return; + + CPPHelper.compile (project, targetDirectory + "/obj", flags); + + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-debug" : ""), executablePath); + + } else { + + ProcessHelper.runCommand ("", "haxe", haxeArgs.concat ([ "-D", "static_link" ])); + + if (noOutput) return; + + CPPHelper.compile (project, targetDirectory + "/obj", flags.concat ([ "-Dstatic_link" ])); + CPPHelper.compile (project, targetDirectory + "/obj", flags, "BuildMain.xml"); + + FileHelper.copyFile (targetDirectory + "/obj/Main" + (project.debug ? "-debug" : ""), executablePath); + + } + + } + + if (PlatformHelper.hostPlatform != Platform.WINDOWS && targetType != "nodejs" && targetType != "java") { + + ProcessHelper.runCommand ("", "chmod", [ "755", executablePath ]); + + } + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + DeploymentHelper.deploy (project, targetFlags, targetDirectory, "Mac"); + + } + + + public override function display ():Void { + + Sys.println (getDisplayHXML ()); + + } + + + private function generateContext ():Dynamic { + + var context = project.templateContext; + context.NEKO_FILE = targetDirectory + "/obj/ApplicationMain.n"; + context.NODE_FILE = executableDirectory + "/ApplicationMain.js"; + context.HL_FILE = targetDirectory + "/obj/ApplicationMain.hl"; + context.CPP_DIR = targetDirectory + "/obj/"; + context.BUILD_DIR = project.app.path + "/mac" + (is64 ? "64" : ""); + + return context; + + } + + + private function getDisplayHXML ():String { + + var hxml = PathHelper.findTemplate (project.templatePaths, targetType + "/hxml/" + buildType + ".hxml"); + var template = new Template (File.getContent (hxml)); + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + return template.execute (context) + "\n-D display"; + + } + + + public override function rebuild ():Void { + + var commands = []; + + if (!targetFlags.exists ("32") && (command == "rebuild" || PlatformHelper.hostArchitecture == Architecture.X64)) { + + commands.push ([ "-Dmac", "-DHXCPP_CLANG", "-DHXCPP_M64" ]); + + } + + if (!targetFlags.exists ("64") && (command == "rebuild" || PlatformHelper.hostArchitecture == Architecture.X86)) { + + commands.push ([ "-Dmac", "-DHXCPP_CLANG", "-DHXCPP_M32" ]); + + } + + CPPHelper.rebuild (project, commands); + + } + + + public override function run ():Void { + + var arguments = additionalArguments.copy (); + + if (LogHelper.verbose) { + + arguments.push ("-verbose"); + + } + + if (targetType == "hl") { + + ProcessHelper.runCommand (applicationDirectory, "hl", [ project.app.file + ".hl" ].concat (arguments)); + + } else if (targetType == "nodejs") { + + NodeJSHelper.run (project, executableDirectory + "/ApplicationMain.js", arguments); + + } else if (targetType == "java") { + + ProcessHelper.runCommand (executableDirectory, "java", [ "-jar", project.app.file + ".jar" ].concat (arguments)); + + } else if (project.target == PlatformHelper.hostPlatform) { + + arguments = arguments.concat ([ "-livereload" ]); + ProcessHelper.runCommand (executableDirectory, "./" + Path.withoutDirectory (executablePath), arguments); + + } + + } + + + public override function update ():Void { + + // project = project.clone (); + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + for (asset in project.assets) { + + if (asset.embed && asset.sourcePath == "") { + + var path = PathHelper.combine (targetDirectory + "/obj/tmp", asset.targetPath); + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path); + asset.sourcePath = path; + + } + + } + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + if (targetType == "cpp" && project.targetFlags.exists ("static")) { + + for (i in 0...project.ndlls.length) { + + var ndll = project.ndlls[i]; + + if (ndll.path == null || ndll.path == "") { + + context.ndlls[i].path = PathHelper.getLibraryPath (ndll, "Mac" + (is64 ? "64" : ""), "lib", ".a", project.debug); + + } + + } + + } + + PathHelper.mkdir (targetDirectory); + PathHelper.mkdir (targetDirectory + "/obj"); + PathHelper.mkdir (targetDirectory + "/haxe"); + PathHelper.mkdir (applicationDirectory); + PathHelper.mkdir (contentDirectory); + + //SWFHelper.generateSWFClasses (project, targetDirectory + "/haxe"); + + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, targetType + "/hxml", targetDirectory + "/haxe", context); + + if (targetType == "cpp" && project.targetFlags.exists ("static")) { + + FileHelper.recursiveSmartCopyTemplate (project, "cpp/static", targetDirectory + "/obj", context); + + } + + FileHelper.copyFileTemplate (project.templatePaths, "mac/Info.plist", targetDirectory + "/bin/" + project.app.file + ".app/Contents/Info.plist", context); + FileHelper.copyFileTemplate (project.templatePaths, "mac/Entitlements.plist", targetDirectory + "/bin/" + project.app.file + ".app/Contents/Entitlements.plist", context); + + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + context.HAS_ICON = IconHelper.createMacIcon (icons, PathHelper.combine (contentDirectory, "icon.icns")); + + for (asset in project.assets) { + + if (asset.embed != true) { + + if (asset.type != AssetType.TEMPLATE) { + + PathHelper.mkdir (Path.directory (PathHelper.combine (contentDirectory, asset.targetPath))); + FileHelper.copyAssetIfNewer (asset, PathHelper.combine (contentDirectory, asset.targetPath)); + + } else { + + PathHelper.mkdir (Path.directory (PathHelper.combine (targetDirectory, asset.targetPath))); + FileHelper.copyAsset (asset, PathHelper.combine (targetDirectory, asset.targetPath), context); + + } + + } + + } + + } + + + public override function watch ():Void { + + var dirs = WatchHelper.processHXML (project, getDisplayHXML ()); + var command = WatchHelper.getCurrentCommand (); + WatchHelper.watch (project, command, dirs); + + } + + + @ignore public override function install ():Void {} + @ignore public override function trace ():Void {} + @ignore public override function uninstall ():Void {} + + +} \ No newline at end of file diff --git a/tools/platforms/TVOSPlatform.hx b/tools/platforms/TVOSPlatform.hx new file mode 100644 index 000000000..d00743d2e --- /dev/null +++ b/tools/platforms/TVOSPlatform.hx @@ -0,0 +1,649 @@ +package lime.tools.platforms; + + +//import openfl.display.BitmapData; +import haxe.io.Path; +import haxe.Json; +import haxe.Template; +import hxp.helpers.ArrayHelper; +import hxp.helpers.CPPHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.IconHelper; +import hxp.helpers.TVOSHelper; +import hxp.helpers.LogHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.PlatformHelper; +import hxp.helpers.ProcessHelper; +import hxp.helpers.StringHelper; +import hxp.helpers.WatchHelper; +import lime.graphics.Image; +import hxp.project.Architecture; +import hxp.project.Asset; +import hxp.project.AssetType; +import hxp.project.Haxelib; +import hxp.project.HXProject; +import hxp.project.Icon; +import hxp.project.Keystore; +import hxp.project.NDLL; +import hxp.project.Platform; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.FileSystem; + + +class TVOSPlatform extends PlatformTarget { + + + public function new (command:String, _project:HXProject, targetFlags:Map ) { + + super (command, _project, targetFlags); + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("tvos.output-directory", "tvos")); + + } + + + public override function build ():Void { + + if (project.targetFlags.exists ("xcode") && PlatformHelper.hostPlatform == Platform.MAC) { + + ProcessHelper.runCommand ("", "open", [ targetDirectory + "/" + project.app.file + ".xcodeproj" ] ); + + } else { + + TVOSHelper.build (project, targetDirectory); + + if (noOutput) return; + + if (!project.targetFlags.exists ("simulator")) { + + TVOSHelper.sign (project, targetDirectory + "/bin"); + + } + + } + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + TVOSHelper.deploy (project, targetDirectory); + + } + + + public override function display ():Void { + + Sys.println (getDisplayHXML ()); + + } + + + private function generateContext ():Dynamic { + + // project = project.clone (); + + project.sources.unshift (""); + project.sources = PathHelper.relocatePaths (project.sources, PathHelper.combine (targetDirectory, project.app.file + "/haxe")); + //project.dependencies.push ("stdc++"); + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + if (project.targetFlags.exists ("final")) { + + project.haxedefs.set ("final", ""); + + } + + if (!project.config.exists ("tvos.identity")) { + + project.config.set ("tvos.identity", "tvOS Developer"); + + } + + var context = project.templateContext; + + context.HAS_ICON = false; + context.HAS_LAUNCH_IMAGE = false; + context.OBJC_ARC = false; + context.KEY_STORE_IDENTITY = project.config.getString ("tvos.identity"); + + context.linkedLibraries = []; + + for (dependency in project.dependencies) { + + if (!StringTools.endsWith (dependency.name, ".framework") && !StringTools.endsWith (dependency.name, ".tbd") && !StringTools.endsWith (dependency.path, ".framework")) { + + if (dependency.path != "") { + + var name = Path.withoutDirectory (Path.withoutExtension (dependency.path)); + + project.config.push ("tvos.linker-flags", "-force_load $SRCROOT/$PRODUCT_NAME/lib/$CURRENT_ARCH/" + Path.withoutDirectory (dependency.path)); + + if (StringTools.startsWith (name, "lib")) { + + name = name.substring (3, name.length); + + } + + context.linkedLibraries.push (name); + + } else if (dependency.name != "") { + + context.linkedLibraries.push (dependency.name); + + } + + } + + } + + var valid_archs = new Array (); + var arm64 = false; + var architectures = project.architectures; + + if (architectures == null || architectures.length == 0) { + + architectures = [ Architecture.ARM64 ]; + + } + + /*if (project.config.getString ("ios.device", "universal") == "universal" || project.config.getString ("ios.device") == "iphone") { + + if (project.config.getFloat ("ios.deployment", 5.1) < 5) { + + ArrayHelper.addUnique (architectures, Architecture.ARMV6); + + } + + }*/ + + for (architecture in project.architectures) { + + switch (architecture) { + + case ARM64: valid_archs.push ("arm64"); arm64 = true; + default: + + } + + } + + context.CURRENT_ARCHS = "( " + valid_archs.join(",") + ") "; + + valid_archs.push ("i386"); + + context.VALID_ARCHS = valid_archs.join(" "); + context.THUMB_SUPPORT = ""; + + var requiredCapabilities = []; + + requiredCapabilities.push( { name: "arm64", value: true } ); + + context.REQUIRED_CAPABILITY = requiredCapabilities; + context.ARM64 = arm64; + context.TARGET_DEVICES = switch (project.config.getString ("tvos.device", "appletv")) { case "appletv": "3"; default: "3"; } + context.DEPLOYMENT = project.config.getString ("tvos.deployment", "9.0"); + + if (project.config.getString ("tvos.compiler") == "llvm" || project.config.getString ("tvos.compiler", "clang") == "clang") { + + context.OBJC_ARC = true; + + } + + context.IOS_COMPILER = project.config.getString ("tvos.compiler", "clang"); + context.CPP_BUILD_LIBRARY = project.config.getString ("cpp.buildLibrary", "hxcpp"); + + var json = Json.parse (File.getContent (PathHelper.getHaxelib (new Haxelib ("hxcpp"), true) + "/haxelib.json")); + + if (Std.parseFloat (json.version) > 3.1) { + + context.CPP_LIBPREFIX = "lib"; + + } else { + + context.CPP_LIBPREFIX = ""; + + } + + context.IOS_LINKER_FLAGS = ["-stdlib=libc++"].concat (project.config.getArrayString ("tvos.linker-flags")); + context.IOS_NON_EXEMPT_ENCRYPTION = project.config.getBool ("tvos.non-exempt-encryption", true); + + switch (project.window.orientation) { + + case PORTRAIT: + context.IOS_APP_ORIENTATION = "UIInterfaceOrientationPortraitUIInterfaceOrientationPortraitUpsideDown"; + case LANDSCAPE: + context.IOS_APP_ORIENTATION = "UIInterfaceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRight"; + case ALL: + context.IOS_APP_ORIENTATION = "UIInterfaceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRightUIInterfaceOrientationPortraitUIInterfaceOrientationPortraitUpsideDown"; + //case "allButUpsideDown": + //context.IOS_APP_ORIENTATION = "UIInterfaceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRightUIInterfaceOrientationPortrait"; + default: + context.IOS_APP_ORIENTATION = "UIInterfaceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRightUIInterfaceOrientationPortraitUIInterfaceOrientationPortraitUpsideDown"; + + } + + context.ADDL_PBX_BUILD_FILE = ""; + context.ADDL_PBX_FILE_REFERENCE = ""; + context.ADDL_PBX_FRAMEWORKS_BUILD_PHASE = ""; + context.ADDL_PBX_FRAMEWORK_GROUP = ""; + + context.frameworkSearchPaths = []; + + for (dependency in project.dependencies) { + + var name = null; + var path = null; + var fileType = null; + + if (Path.extension (dependency.name) == "framework") { + + name = dependency.name; + path = "/System/Library/Frameworks/" + dependency.name; + fileType = "wrapper.framework"; + + } else if (Path.extension (dependency.name) == "tbd") { + + name = dependency.name; + path = "usr/lib/" + dependency.name; + fileType = "sourcecode.text-based-dylib-definition"; + + } else if (Path.extension (dependency.path) == "framework") { + + name = Path.withoutDirectory (dependency.path); + path = PathHelper.tryFullPath (dependency.path); + fileType = "wrapper.framework"; + + } + + if (name != null) { + + var frameworkID = "11C0000000000018" + StringHelper.getUniqueID (); + var fileID = "11C0000000000018" + StringHelper.getUniqueID (); + + ArrayHelper.addUnique (context.frameworkSearchPaths, Path.directory (path)); + + context.ADDL_PBX_BUILD_FILE += " " + frameworkID + " /* " + name + " in Frameworks */ = {isa = PBXBuildFile; fileRef = " + fileID + " /* " + name + " */; };\n"; + context.ADDL_PBX_FILE_REFERENCE += " " + fileID + " /* " + name + " */ = {isa = PBXFileReference; lastKnownFileType = \"" + fileType + "\"; name = \"" + name + "\"; path = \"" + path + "\"; sourceTree = SDKROOT; };\n"; + context.ADDL_PBX_FRAMEWORKS_BUILD_PHASE += " " + frameworkID + " /* " + name + " in Frameworks */,\n"; + context.ADDL_PBX_FRAMEWORK_GROUP += " " + fileID + " /* " + name + " */,\n"; + + } + + } + + context.HXML_PATH = PathHelper.findTemplate (project.templatePaths, "tvos/PROJ/haxe/Build.hxml"); + context.PRERENDERED_ICON = project.config.getBool ("tvos.prerenderedIcon", false); + + var haxelibPath = project.environment.get ("HAXELIB_PATH"); + + if (haxelibPath != null) { + + context.HAXELIB_PATH = 'export HAXELIB_PATH=$haxelibPath;'; + + } else { + + context.HAXELIB_PATH = ''; + + } + + return context; + + } + + + private function getDisplayHXML ():String { + + var hxml = PathHelper.findTemplate (project.templatePaths, "tvos/PROJ/haxe/Build.hxml"); + var template = new Template (File.getContent (hxml)); + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + return template.execute (context) + "\n-D display"; + + } + + + public override function rebuild ():Void { + + var arm64 = (command == "rebuild" || (project.architectures.indexOf (Architecture.ARM64) > -1 && !project.targetFlags.exists ("simulator"))); + var i386 = (command == "rebuild" || project.targetFlags.exists ("simulator")); + var x86_64 = (command == "rebuild" || project.targetFlags.exists ("simulator")); + + var commands = []; + + if (arm64) commands.push ([ "-Dtvos", "-Dappletvos", "-DHXCPP_CPP11", "-DHXCPP_ARM64", "-DOBJC_ARC", "-DENABLE_BITCODE" ]); + if (i386) commands.push ([ "-Dtvos", "-Dappletvsim", "-Dsimulator", "-DHXCPP_CPP11", "-DOBJC_ARC", "-DENABLE_BITCODE" ]); + if (x86_64) commands.push ([ "-Dtvos", "-Dappletvsim", "-Dsimulator", "-DHXCPP_M64", "-DHXCPP_CPP11", "-DOBJC_ARC", "-DENABLE_BITCODE" ]); + + CPPHelper.rebuild (project, commands); + + } + + + public override function run ():Void { + + if (project.targetFlags.exists ("xcode")) return; + + TVOSHelper.launch (project, targetDirectory); + + } + + + public override function update ():Void { + + // project = project.clone (); + + for (asset in project.assets) { + + if (asset.embed && asset.sourcePath == "") { + + var path = PathHelper.combine (targetDirectory + "/" + project.app.file + "/obj/tmp", asset.targetPath); + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path); + asset.sourcePath = path; + + } + + } + + //var manifest = new Asset (); + //manifest.id = "__manifest__"; + //manifest.data = AssetHelper.createManifest (project).serialize (); + //manifest.resourceName = manifest.flatName = manifest.targetPath = "manifest"; + //manifest.type = AssetType.TEXT; + //project.assets.push (manifest); + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + var projectDirectory = targetDirectory + "/" + project.app.file + "/"; + + PathHelper.mkdir (targetDirectory); + PathHelper.mkdir (projectDirectory); + PathHelper.mkdir (projectDirectory + "/haxe"); + PathHelper.mkdir (projectDirectory + "/haxe/lime/installer"); + + var iconSizes:Array = [ + { name : "Icon-Small.png", size : 29 }, + { name : "Icon-Small-40.png", size : 40 }, + { name : "Icon-Small-50.png", size : 50 }, + { name : "Icon.png", size : 57 }, + { name : "Icon-Small@2x.png", size : 58 }, + { name : "Icon-72.png", size : 72 }, + { name : "Icon-76.png", size : 76 }, + { name : "Icon-Small-40@2x.png", size : 80 }, + { name : "Icon-Small-50@2x.png", size : 100 }, + { name : "Icon@2x.png", size : 114 }, + { name : "Icon-60@2x.png", size : 120 }, + { name : "Icon-72@2x.png", size : 144 }, + { name : "Icon-76@2x.png", size : 152 }, + { name : "Icon-60@3x.png", size : 180 }, + ]; + + context.HAS_ICON = true; + + var iconPath = PathHelper.combine (projectDirectory, "Images.xcassets/AppIcon.appiconset"); + PathHelper.mkdir (iconPath); + + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + for (iconSize in iconSizes) { + + if (!IconHelper.createIcon (icons, iconSize.size, iconSize.size, PathHelper.combine (iconPath, iconSize.name))) { + + context.HAS_ICON = false; + + } + + } + + var splashSizes:Array = [ + { name: "Default.png", w: 320, h: 480 }, // iPhone, portrait + { name: "Default@2x.png", w: 640, h: 960 }, // iPhone Retina, portrait + { name: "Default-568h@2x.png", w: 640, h: 1136 }, // iPhone 5, portrait + { name: "Default-Portrait.png", w: 768, h: 1024 }, // iPad, portrait + { name: "Default-Landscape.png", w: 1024, h: 768 }, // iPad, landscape + { name: "Default-Portrait@2x.png", w: 1536, h: 2048 }, // iPad Retina, portrait + { name: "Default-Landscape@2x.png", w: 2048, h: 1536 }, // iPad Retina, landscape + { name: "Default-667h@2x.png", w: 750, h: 1334 }, // iPhone 6, portrait + { name: "Default-736h@3x.png", w: 1242, h: 2208 }, // iPhone 6 Plus, portrait + { name: "Default-736h-Landscape@3x.png", w: 2208, h: 1242 }, // iPhone 6 Plus, landscape + ]; + + var splashScreenPath = PathHelper.combine (projectDirectory, "Images.xcassets/LaunchImage.launchimage"); + PathHelper.mkdir (splashScreenPath); + + for (size in splashSizes) { + + var match = false; + + for (splashScreen in project.splashScreens) { + + if (splashScreen.width == size.w && splashScreen.height == size.h && Path.extension (splashScreen.path) == "png") { + + FileHelper.copyFile (splashScreen.path, PathHelper.combine (splashScreenPath, size.name)); + match = true; + + } + + } + + if (!match) { + + var imagePath = PathHelper.combine (splashScreenPath, size.name); + + if (!FileSystem.exists (imagePath)) { + + LogHelper.info ("", " - \x1b[1mGenerating image:\x1b[0m " + imagePath); + + var image = new Image (null, 0, 0, size.w, size.h, (0xFF << 24) | (project.window.background & 0xFFFFFF)); + var bytes = image.encode ("png"); + + File.saveBytes (imagePath, bytes); + + } + + } + + } + + context.HAS_LAUNCH_IMAGE = true; + + PathHelper.mkdir (projectDirectory + "/resources"); + PathHelper.mkdir (projectDirectory + "/haxe/build"); + + FileHelper.recursiveSmartCopyTemplate (project, "tvos/resources", projectDirectory + "/resources", context, true, false); + FileHelper.recursiveSmartCopyTemplate (project, "tvos/PROJ/haxe", projectDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "haxe", projectDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "tvos/PROJ/Classes", projectDirectory + "/Classes", context); + FileHelper.recursiveSmartCopyTemplate (project, "tvos/PROJ/Images.xcassets", projectDirectory + "/Images.xcassets", context); + FileHelper.copyFileTemplate (project.templatePaths, "tvos/PROJ/PROJ-Info.plist", projectDirectory + "/" + project.app.file + "-Info.plist", context); + FileHelper.copyFileTemplate (project.templatePaths, "tvos/PROJ/PROJ-Prefix.pch", projectDirectory + "/" + project.app.file + "-Prefix.pch", context); + FileHelper.recursiveSmartCopyTemplate (project, "tvos/PROJ.xcodeproj", targetDirectory + "/" + project.app.file + ".xcodeproj", context); + + //SWFHelper.generateSWFClasses (project, projectDirectory + "/haxe"); + + PathHelper.mkdir (projectDirectory + "/lib"); + + for (archID in 0...3) { + + var arch = [ "arm64", "i386", "x86_64" ][archID]; + + if (arch == "arm64" && !context.ARM64) + continue; + + var libExt = [ ".appletvos-64.a", ".appletvsim.a", ".appletvsim-64.a" ][archID]; + + PathHelper.mkdir (projectDirectory + "/lib/" + arch); + PathHelper.mkdir (projectDirectory + "/lib/" + arch + "-debug"); + + for (ndll in project.ndlls) { + + //if (ndll.haxelib != null) { + + var releaseLib = PathHelper.getLibraryPath (ndll, "AppleTV", "lib", libExt); + LogHelper.info("releaseLib: " + releaseLib); + var debugLib = PathHelper.getLibraryPath (ndll, "AppleTV", "lib", libExt, true); + var releaseDest = projectDirectory + "/lib/" + arch + "/lib" + ndll.name + ".a"; + LogHelper.info("releaseDest: " + releaseDest); + var debugDest = projectDirectory + "/lib/" + arch + "-debug/lib" + ndll.name + ".a"; + + if (!FileSystem.exists (releaseLib)) { + + releaseLib = PathHelper.getLibraryPath (ndll, "AppleTV", "lib", ".appletvos-64.a"); + LogHelper.info("alternative releaseLib: " + releaseLib); + debugLib = PathHelper.getLibraryPath (ndll, "AppleTV", "lib", ".appletvos-64.a", true); + + } + + FileHelper.copyIfNewer (releaseLib, releaseDest); + + if (FileSystem.exists (debugLib) && debugLib != releaseLib) { + + FileHelper.copyIfNewer (debugLib, debugDest); + + } else if (FileSystem.exists (debugDest)) { + + FileSystem.deleteFile (debugDest); + + } + + //} + + } + + for (dependency in project.dependencies) { + + if (StringTools.endsWith (dependency.path, ".a")) { + + var fileName = Path.withoutDirectory (dependency.path); + + if (!StringTools.startsWith (fileName, "lib")) { + + fileName = "lib" + fileName; + + } + + FileHelper.copyIfNewer (dependency.path, projectDirectory + "/lib/" + arch + "/" + fileName); + + } + + } + + } + + PathHelper.mkdir (projectDirectory + "/assets"); + + for (asset in project.assets) { + + if (asset.type != AssetType.TEMPLATE) { + + var targetPath = PathHelper.combine (projectDirectory + "/assets/", asset.resourceName); + + //var sourceAssetPath:String = projectDirectory + "haxe/" + asset.sourcePath; + + PathHelper.mkdir (Path.directory (targetPath)); + FileHelper.copyAssetIfNewer (asset, targetPath); + + //PathHelper.mkdir (Path.directory (sourceAssetPath)); + //FileHelper.linkFile (flatAssetPath, sourceAssetPath, true, true); + + } else { + + var targetPath = PathHelper.combine (projectDirectory, asset.targetPath); + + PathHelper.mkdir (Path.directory (targetPath)); + FileHelper.copyAsset (asset, targetPath, context); + + } + + } + + if (project.targetFlags.exists ("xcode") && PlatformHelper.hostPlatform == Platform.MAC && command == "update") { + + ProcessHelper.runCommand ("", "open", [ targetDirectory + "/" + project.app.file + ".xcodeproj" ] ); + + } + + } + + + /*private function updateLaunchImage () { + + var destination = buildDirectory + "/ios"; + PathHelper.mkdir (destination); + + var has_launch_image = false; + if (launchImages.length > 0) has_launch_image = true; + + for (launchImage in launchImages) { + + var splitPath = launchImage.name.split ("/"); + var path = destination + "/" + splitPath[splitPath.length - 1]; + FileHelper.copyFile (launchImage.name, path, context, false); + + } + + context.HAS_LAUNCH_IMAGE = has_launch_image; + + }*/ + + + public override function watch ():Void { + + var dirs = WatchHelper.processHXML (project, getDisplayHXML ()); + var command = WatchHelper.getCurrentCommand (); + WatchHelper.watch (project, command, dirs); + + } + + + @ignore public override function install ():Void {} + @ignore public override function trace ():Void {} + @ignore public override function uninstall ():Void {} + + +} + + +private typedef IconSize = { + + name:String, + size:Int, + +} + + +private typedef SplashSize = { + + name:String, + w:Int, + h:Int, + +} \ No newline at end of file diff --git a/tools/platforms/TizenPlatform.hx b/tools/platforms/TizenPlatform.hx new file mode 100644 index 000000000..989bff425 --- /dev/null +++ b/tools/platforms/TizenPlatform.hx @@ -0,0 +1,232 @@ +package; + + +import haxe.io.Path; +import haxe.Template; +import hxp.helpers.CPPHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.IconHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.ProcessHelper; +import hxp.helpers.TizenHelper; +import hxp.project.AssetType; +import hxp.project.HXProject; +import hxp.project.Icon; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.FileSystem; + + +class TizenPlatform extends PlatformTarget { + + + private static var uuid:String = null; + + + public function new (command:String, _project:HXProject, targetFlags:Map ) { + + super (command, _project, targetFlags); + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("tizen.output-directory", "tizen")); + + } + + + public override function build ():Void { + + var destination = targetDirectory + "/bin/"; + + var arch = ""; + + if (project.targetFlags.exists ("simulator")) { + + arch = "-x86"; + + } + + for (ndll in project.ndlls) { + + FileHelper.copyLibrary (project, ndll, "Tizen", "", arch + ".so", destination + "lib/", project.debug, ".so"); + + } + + var hxml = targetDirectory + "/haxe/" + buildType + ".hxml"; + + ProcessHelper.runCommand ("", "haxe", [ hxml, "-D", "tizen" ] ); + + if (noOutput) return; + + var args = [ "-Dtizen", "-DAPP_ID=" + TizenHelper.getUUID (project) ]; + + if (project.targetFlags.exists ("simulator")) { + + args.push ("-Dsimulator"); + + } + + CPPHelper.compile (project, targetDirectory + "/obj", args); + FileHelper.copyIfNewer (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-debug" : "") + ".exe", targetDirectory + "/bin/CommandLineBuild/" + project.app.file + ".exe"); + TizenHelper.createPackage (project, targetDirectory + "/bin/CommandLineBuild", ""); + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + DeploymentHelper.deploy (project, targetFlags, targetDirectory, "Tizen"); + + } + + + public override function display ():Void { + + var hxml = PathHelper.findTemplate (project.templatePaths, "tizen/hxml/" + buildType + ".hxml"); + + var context = project.templateContext; + context.CPP_DIR = targetDirectory + "/obj"; + context.OUTPUT_DIR = targetDirectory; + + var template = new Template (File.getContent (hxml)); + + Sys.println (template.execute (context)); + Sys.println ("-D display"); + + } + + + public override function rebuild ():Void { + + var device = (command == "rebuild" || !targetFlags.exists ("simulator")); + var simulator = (command == "rebuild" || targetFlags.exists ("simulator")); + + var commands = []; + + if (device) commands.push ([ "-Dtizen" ]); + if (simulator) commands.push ([ "-Dtizen", "-Dsimulator" ]); + + CPPHelper.rebuild (project, commands); + + } + + + public override function run ():Void { + + TizenHelper.install (project, targetDirectory + "/bin/CommandLineBuild"); + TizenHelper.launch (project); + + } + + + public override function trace ():Void { + + TizenHelper.trace (project); + + } + + + public override function update ():Void { + + // project = project.clone (); + + for (asset in project.assets) { + + if (asset.embed && asset.sourcePath == "") { + + var path = PathHelper.combine (targetDirectory + "/obj/tmp", asset.targetPath); + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path); + asset.sourcePath = path; + + } + + } + + var destination = targetDirectory + "/bin/"; + PathHelper.mkdir (destination); + + for (asset in project.assets) { + + asset.resourceName = "../res/" + asset.resourceName; + + } + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + var context = project.templateContext; + context.CPP_DIR = targetDirectory + "/obj"; + context.OUTPUT_DIR = targetDirectory; + context.APP_PACKAGE = TizenHelper.getUUID (project); + context.SIMULATOR = project.targetFlags.exists ("simulator"); + + PathHelper.mkdir (destination + "shared/res/screen-density-xhigh"); + + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + if (IconHelper.createIcon (icons, 117, 117, PathHelper.combine (destination + "shared/res/screen-density-xhigh", "mainmenu.png"))) { + + context.APP_ICON = "mainmenu.png"; + + } + + FileHelper.recursiveSmartCopyTemplate (project, "tizen/template", destination, context); + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "tizen/hxml", targetDirectory + "/haxe", context); + + for (asset in project.assets) { + + var path = PathHelper.combine (destination + "res/", asset.targetPath); + + PathHelper.mkdir (Path.directory (path)); + + if (asset.type != AssetType.TEMPLATE) { + + if (asset.targetPath == "/appinfo.json") { + + FileHelper.copyAsset (asset, path, context); + + } else { + + // going to root directory now, but should it be a forced "assets" folder later? + + FileHelper.copyAssetIfNewer (asset, path); + + } + + } else { + + FileHelper.copyAsset (asset, path, context); + + } + + } + + } + + + @ignore public override function install ():Void {} + @ignore public override function uninstall ():Void {} + + +} \ No newline at end of file diff --git a/tools/platforms/WindowsPlatform.hx b/tools/platforms/WindowsPlatform.hx new file mode 100644 index 000000000..52b4a65ca --- /dev/null +++ b/tools/platforms/WindowsPlatform.hx @@ -0,0 +1,870 @@ +package; + + +import haxe.io.Path; +import haxe.Template; +import hxp.project.Icon; +import hxp.helpers.CPPHelper; +import hxp.helpers.DeploymentHelper; +import hxp.helpers.FileHelper; +import hxp.helpers.HTML5Helper; +import hxp.helpers.IconHelper; +import hxp.helpers.JavaHelper; +import hxp.helpers.LogHelper; +import hxp.helpers.ModuleHelper; +import hxp.helpers.CSHelper; +import hxp.helpers.GUID; +import hxp.helpers.NekoHelper; +import hxp.helpers.NodeJSHelper; +import hxp.helpers.PathHelper; +import hxp.helpers.PlatformHelper; +import hxp.helpers.ProcessHelper; +import hxp.helpers.WatchHelper; +import hxp.project.Architecture; +import hxp.project.Asset; +import hxp.project.AssetType; +import hxp.project.Haxelib; +import hxp.project.HXProject; +import hxp.project.Platform; +import hxp.project.PlatformTarget; +import sys.io.File; +import sys.FileSystem; + + +class WindowsPlatform extends PlatformTarget { + + + private var applicationDirectory:String; + private var executablePath:String; + private var is64:Bool; + private var targetType:String; + private var outputFile:String; + + + public function new (command:String, _project:HXProject, targetFlags:Map ) { + + super (command, _project, targetFlags); + + for (architecture in project.architectures) { + + if (architecture == Architecture.X64) { + + is64 = true; + + } + + } + + if (project.targetFlags.exists ("uwp") || project.targetFlags.exists ("winjs")) { + + targetType = "winjs"; + + } else if (project.targetFlags.exists ("neko") || project.target != PlatformHelper.hostPlatform) { + + targetType = "neko"; + + } else if (project.targetFlags.exists ("hl")) { + + targetType = "hl"; + + } else if (project.targetFlags.exists ("nodejs")) { + + targetType = "nodejs"; + + } else if (project.targetFlags.exists ("cs")) { + + targetType = "cs"; + + } else if (project.targetFlags.exists ("java")) { + + targetType = "java"; + + } else { + + targetType = "cpp"; + + } + + targetDirectory = PathHelper.combine (project.app.path, project.config.getString ("windows.output-directory", targetType == "cpp" ? "windows" : targetType)); + targetDirectory = StringTools.replace (targetDirectory, "arch64", is64 ? "64" : ""); + + if (targetType == "winjs") { + + outputFile = targetDirectory + "/source/js/" + project.app.file + ".js"; + + } else { + + applicationDirectory = targetDirectory + "/bin/"; + executablePath = applicationDirectory + project.app.file + ".exe"; + + } + + } + + + public override function build ():Void { + + var hxml = targetDirectory + "/haxe/" + buildType + ".hxml"; + + PathHelper.mkdir (targetDirectory); + + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + if (targetType == "winjs") { + + ModuleHelper.buildModules (project, targetDirectory, targetDirectory); + + if (project.app.main != null) { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + var msBuildPath = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\MSBuild.exe"; + var args = [ PathHelper.tryFullPath (targetDirectory + "/source/" + project.app.file + ".jsproj"), "/p:Configuration=Release" ]; + + ProcessHelper.runCommand ("", msBuildPath, args); + if (noOutput) return; + + if (project.targetFlags.exists ("webgl")) { + + FileHelper.copyFile (targetDirectory + "/source/ApplicationMain.js", outputFile); + + } + + if (project.modules.iterator ().hasNext ()) { + + ModuleHelper.patchFile (outputFile); + + } + + if (project.targetFlags.exists ("minify") || buildType == "final") { + + HTML5Helper.minify (project, targetDirectory + outputFile); + + } + + } + + } else { + + for (dependency in project.dependencies) { + + if (StringTools.endsWith (dependency.path, ".dll")) { + + var fileName = Path.withoutDirectory (dependency.path); + FileHelper.copyIfNewer (dependency.path, applicationDirectory + "/" + fileName); + + } + + } + + if (!project.targetFlags.exists ("static") || targetType != "cpp") { + + var targetSuffix = (targetType == "hl") ? ".hdll" : null; + + for (ndll in project.ndlls) { + + FileHelper.copyLibrary (project, ndll, "Windows" + (is64 ? "64" : ""), "", (ndll.haxelib != null && (ndll.haxelib.name == "hxcpp" || ndll.haxelib.name == "hxlibc")) ? ".dll" : ".ndll", applicationDirectory, project.debug, targetSuffix); + + } + + } + + //IconHelper.createIcon (project.icons, 32, 32, PathHelper.combine (applicationDirectory, "icon.png")); + + if (targetType == "neko") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + var iconPath = PathHelper.combine (applicationDirectory, "icon.ico"); + + if (!IconHelper.createWindowsIcon (icons, iconPath)) { + + iconPath = null; + + } + + NekoHelper.createWindowsExecutable (project.templatePaths, targetDirectory + "/obj/ApplicationMain.n", executablePath, iconPath); + NekoHelper.copyLibraries (project.templatePaths, "windows" + (is64 ? "64" : ""), applicationDirectory); + + } else if (targetType == "hl") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain.hl", PathHelper.combine (applicationDirectory, project.app.file + ".hl")); + + } else if (targetType == "nodejs") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + //NekoHelper.createExecutable (project.templatePaths, "windows" + (is64 ? "64" : ""), targetDirectory + "/obj/ApplicationMain.n", executablePath); + //NekoHelper.copyLibraries (project.templatePaths, "windows" + (is64 ? "64" : ""), applicationDirectory); + + } else if (targetType == "cs") { + + ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + CSHelper.copySourceFiles (project.templatePaths, targetDirectory + "/obj/src"); + var txtPath = targetDirectory + "/obj/hxcs_build.txt"; + CSHelper.addSourceFiles (txtPath, CSHelper.ndllSourceFiles); + CSHelper.addGUID (txtPath, GUID.uuid ()); + CSHelper.compile (project, targetDirectory + "/obj", applicationDirectory + project.app.file, "x86", "desktop"); + + } else if (targetType == "java") { + + var libPath = PathHelper.combine (PathHelper.getHaxelib (new Haxelib ("lime")), "templates/java/lib/"); + + ProcessHelper.runCommand ("", "haxe", [ hxml, "-java-lib", libPath + "disruptor.jar", "-java-lib", libPath + "lwjgl.jar" ]); + //ProcessHelper.runCommand ("", "haxe", [ hxml ]); + + if (noOutput) return; + + var haxeVersion = project.environment.get ("haxe_ver"); + var haxeVersionString = "3404"; + + if (haxeVersion.length > 4) { + + haxeVersionString = haxeVersion.charAt (0) + haxeVersion.charAt (2) + (haxeVersion.length == 5 ? "0" + haxeVersion.charAt (4) : haxeVersion.charAt (4) + haxeVersion.charAt (5)); + + } + + ProcessHelper.runCommand (targetDirectory + "/obj", "haxelib", [ "run", "hxjava", "hxjava_build.txt", "--haxe-version", haxeVersionString ]); + FileHelper.recursiveCopy (targetDirectory + "/obj/lib", PathHelper.combine (applicationDirectory, "lib")); + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-Debug" : "") + ".jar", PathHelper.combine (applicationDirectory, project.app.file + ".jar")); + JavaHelper.copyLibraries (project.templatePaths, "Windows" + (is64 ? "64" : ""), applicationDirectory); + + } else { + + var haxeArgs = [ hxml ]; + var flags = []; + + if (is64) { + + haxeArgs.push ("-D"); + haxeArgs.push ("HXCPP_M64"); + flags.push ("-DHXCPP_M64"); + + } else { + + flags.push ("-DHXCPP_M32"); + + } + + if (!project.environment.exists ("SHOW_CONSOLE")) { + + haxeArgs.push ("-D"); + haxeArgs.push ("no_console"); + flags.push ("-Dno_console"); + + } + + if (!project.targetFlags.exists ("static")) { + + ProcessHelper.runCommand ("", "haxe", haxeArgs); + + if (noOutput) return; + + CPPHelper.compile (project, targetDirectory + "/obj", flags); + + FileHelper.copyFile (targetDirectory + "/obj/ApplicationMain" + (project.debug ? "-debug" : "") + ".exe", executablePath); + + } else { + + ProcessHelper.runCommand ("", "haxe", haxeArgs.concat ([ "-D", "static_link" ])); + + if (noOutput) return; + + CPPHelper.compile (project, targetDirectory + "/obj", flags.concat ([ "-Dstatic_link" ])); + CPPHelper.compile (project, targetDirectory + "/obj", flags, "BuildMain.xml"); + + FileHelper.copyFile (targetDirectory + "/obj/Main" + (project.debug ? "-debug" : "") + ".exe", executablePath); + + } + + var iconPath = PathHelper.combine (applicationDirectory, "icon.ico"); + + if (IconHelper.createWindowsIcon (icons, iconPath) && PlatformHelper.hostPlatform == Platform.WINDOWS) { + + var templates = [ PathHelper.getHaxelib (new Haxelib ("lime")) + "/templates" ].concat (project.templatePaths); + ProcessHelper.runCommand ("", PathHelper.findTemplate (templates, "bin/ReplaceVistaIcon.exe"), [ executablePath, iconPath, "1" ], true, true); + + } + + } + + } + + } + + + public override function clean ():Void { + + if (FileSystem.exists (targetDirectory)) { + + PathHelper.removeDirectory (targetDirectory); + + } + + } + + + public override function deploy ():Void { + + DeploymentHelper.deploy (project, targetFlags, targetDirectory, "Windows" + (is64 ? "64" : "")); + + } + + + public override function display ():Void { + + Sys.println (getDisplayHXML ()); + + } + + + private function generateContext ():Dynamic { + + var context = project.templateContext; + + if (targetType == "winjs") { + + context.WIN_FLASHBACKGROUND = project.window.background != null ? StringTools.hex (project.window.background, 6) : ""; + context.OUTPUT_FILE = outputFile; + + if (project.targetFlags.exists ("webgl")) { + + context.CPP_DIR = targetDirectory; + + } + + var guid = GUID.seededUuid (project.meta.packageName); + context.APP_GUID = guid; + + var guidNoBrackets = guid.split("{").join("").split("}").join(""); + context.APP_GUID_NOBRACKETS = guidNoBrackets; + + if (context.APP_DESCRIPTION == null || context.APP_DESCRIPTION == "") { + + context.APP_DESCRIPTION = project.meta.title; + + } + + } else { + + context.NEKO_FILE = targetDirectory + "/obj/ApplicationMain.n"; + context.NODE_FILE = targetDirectory + "/bin/ApplicationMain.js"; + context.HL_FILE = targetDirectory + "/obj/ApplicationMain.hl"; + context.CPP_DIR = targetDirectory + "/obj"; + context.BUILD_DIR = project.app.path + "/windows" + (is64 ? "64" : ""); + + } + + return context; + + } + + + private function getDisplayHXML ():String { + + var hxml = PathHelper.findTemplate (project.templatePaths, targetType + "/hxml/" + buildType + ".hxml"); + var template = new Template (File.getContent (hxml)); + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + return template.execute (context) + "\n-D display"; + + } + + + public override function rebuild ():Void { + + if (targetType != "winjs") { + + if (project.environment.exists ("VS110COMNTOOLS") && project.environment.exists ("VS100COMNTOOLS")) { + + project.environment.set ("HXCPP_MSVC", project.environment.get ("VS100COMNTOOLS")); + Sys.putEnv ("HXCPP_MSVC", project.environment.get ("VS100COMNTOOLS")); + + } + + var commands = []; + + if (targetFlags.exists ("64")) { + + commands.push ([ "-Dwindow", "-DHXCPP_M64" ]); + + } else { + + commands.push ([ "-Dwindow", "-DHXCPP_M32" ]); + + } + + CPPHelper.rebuild (project, commands); + + } + + } + + + public override function run ():Void { + + var arguments = additionalArguments.copy (); + + if (LogHelper.verbose) { + + arguments.push ("-verbose"); + + } + + if (targetType == "hl") { + + ProcessHelper.runCommand (applicationDirectory, "hl", [ project.app.file + ".hl" ].concat (arguments)); + + } else if (targetType == "nodejs") { + + NodeJSHelper.run (project, targetDirectory + "/bin/ApplicationMain.js", arguments); + + } else if (targetType == "winjs") { + + /* + + The 'test' target is problematic for UWP applications. UWP applications are bundled in appx packages and + require app certs to properly install. + + There are two options to trigger an appx install from the command line. + + A. Use the WinAppDeployCmd.exe utility to deploy to local and remote devices + + B. Execute the Add-AppDevPackage.ps1 powershell script that is an + artifact of the UWP msbuild + + A: WinAppDeployCmd.exe + https://docs.microsoft.com/en-us/windows/uwp/packaging/install-universal-windows-apps-with-the-winappdeploycmd-tool + https://msdn.microsoft.com/en-us/windows/desktop/mt627714 + Windows 10 SDK: https://developer.microsoft.com/windows/downloads/windows-10-sdk + + I've never actually got this to work, but I feel like I was close. The WinAppDeployCmd.exe is a part of the + Windows 10 SDK and not a part of the Visual Studio 2017 community edition. It will appear magically if you + check enough boxes when installing various project templates for Visual Studio. It appeared for me, and I + have no clue how it got there. + + A developer must take a few steps in order for this command to work. + 1. Install Visual Studio 2017 Community Edition + 2. Install the Windows 10 SDK + 3. Modify Windows 10 Settings to enable side loading and device discovery + 3. Enabling device discovery generates a pin number that is displayed to the user + 4. Open the "Developer Command Promp for VS 2017" from the Start menu + 5. run: + > WinAppDeployCmd devices + 6. Make sure your device shows up in the list (if it does not appear try step 3 again, toggling things on/off) + 7. run: (replase file, ip and pin with your values) + > WinAppDeployCmd install -file "uwp-project_1.0.0.0_AnyCPU.appx" -ip 192.168.27.167 -pin 326185 + + B: Add-AppDevPackage.ps1 + PowerShell_Set_Unrestricted.reg + The UWP build generates a powershell script by default. This script is usually executed by the user + by right clicking the file and choosing "run with powershell". Executing this script directly from the cmd + prompt results in a security error: "Add-AppDevPackage.ps1 cannot be loaded because running scripts is + disabled on this system." + + We must edit the registry if we want to run this script directly from a shell. + See lime/templates/windows/template/PowerShell_Set_Unrestricted.reg + + 1. run: + > regedit /s PowerShell_Set_Unrestricted.reg + 2. run: + > powershell "& ""./Add-AppDevPackage.ps1""" + + note: the nonsensical double quotes are required. + + */ + + // Using option B because obtaining the device pin programatically does not seem possible. + //ProcessHelper.runCommand ("", "regedit", [ '/s', '"' + targetDirectory + '/bin/PowerShell_Set_Unrestricted.reg"' ]); + //var test = '"& ""' + targetDirectory + '/bin/PowerShell_Set_Unrestricted.reg"""'; + //Sys.command ('powershell & ""' + targetDirectory + '/bin/source/AppPackages/' + project.app.file + '_1.0.0.0_AnyCPU_Test/Add-AppDevPackage.ps1""'); + var version = project.meta.version + "." + project.meta.buildNumber; + ProcessHelper.openFile (targetDirectory + "/source/AppPackages/" + project.app.file + "_" + version + "_AnyCPU_Test", project.app.file + "_" + version + "_AnyCPU.appx"); + + //source/AppPackages/uwp-project_1.0.0.0_AnyCPU_Test/Add-AppDevPackage.ps1 + + //HTML5Helper.launch (project, targetDirectory + "/bin"); + + } else if (targetType == "java") { + + ProcessHelper.runCommand (applicationDirectory, "java", [ "-jar", project.app.file + ".jar" ].concat (arguments)); + + } else if (project.target == PlatformHelper.hostPlatform) { + + arguments = arguments.concat ([ "-livereload" ]); + ProcessHelper.runCommand (applicationDirectory, Path.withoutDirectory (executablePath), arguments); + + } + + } + + + public override function update ():Void { + + if (targetType == "winjs") { + + updateUWP (); + return; + + } + + // project = project.clone (); + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + for (asset in project.assets) { + + if (asset.embed && asset.sourcePath == "") { + + var path = PathHelper.combine (targetDirectory + "/obj/tmp", asset.targetPath); + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path); + asset.sourcePath = path; + + } + + } + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + if (targetType == "cpp" && project.targetFlags.exists ("static")) { + + // TODO: Better way to detect the suffix HXCPP will use? + + var msvc19 = true; + var olderVersions = [ "120", "110", "100", "90", "80", "71", "70" ]; + + for (olderVersion in olderVersions) { + + if (project.environment.exists ("VS" + olderVersion + "COMNTOOLS")) { + + msvc19 = false; + break; + + } + + } + + var suffix = (msvc19 ? "-19.lib" : ".lib"); + + for (i in 0...project.ndlls.length) { + + var ndll = project.ndlls[i]; + + if (ndll.path == null || ndll.path == "") { + + context.ndlls[i].path = PathHelper.getLibraryPath (ndll, "Windows" + (is64 ? "64" : ""), "lib", suffix, project.debug); + + } + + } + + } + + PathHelper.mkdir (targetDirectory); + PathHelper.mkdir (targetDirectory + "/obj"); + PathHelper.mkdir (targetDirectory + "/haxe"); + PathHelper.mkdir (applicationDirectory); + + //SWFHelper.generateSWFClasses (project, targetDirectory + "/haxe"); + + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, targetType + "/hxml", targetDirectory + "/haxe", context); + + if (targetType == "cpp" && project.targetFlags.exists ("static")) { + + FileHelper.recursiveSmartCopyTemplate (project, "cpp/static", targetDirectory + "/obj", context); + + } + + /*if (IconHelper.createIcon (project.icons, 32, 32, PathHelper.combine (applicationDirectory, "icon.png"))) { + + context.HAS_ICON = true; + context.WIN_ICON = "icon.png"; + + }*/ + + for (asset in project.assets) { + + if (asset.embed != true) { + + var path = PathHelper.combine (applicationDirectory, asset.targetPath); + + if (asset.type != AssetType.TEMPLATE) { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAssetIfNewer (asset, path); + + } else { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path, context); + + } + + } + + } + + } + + + private function updateUWP ():Void { + + project = project.clone (); + + var destination = targetDirectory + "/source/"; + PathHelper.mkdir (destination); + + var webfontDirectory = targetDirectory + "/obj/webfont"; + var useWebfonts = true; + + for (haxelib in project.haxelibs) { + + if (haxelib.name == "openfl-html5-dom" || haxelib.name == "openfl-bitfive") { + + useWebfonts = false; + + } + + } + + var fontPath; + + for (asset in project.assets) { + + if (asset.type == AssetType.FONT) { + + if (useWebfonts) { + + fontPath = PathHelper.combine (webfontDirectory, Path.withoutDirectory (asset.targetPath)); + + if (!FileSystem.exists (fontPath)) { + + PathHelper.mkdir (webfontDirectory); + FileHelper.copyFile (asset.sourcePath, fontPath); + + asset.sourcePath = fontPath; + + HTML5Helper.generateWebfonts (project, asset); + + } + + asset.sourcePath = fontPath; + asset.targetPath = Path.withoutExtension (asset.targetPath); + + } else { + + project.haxeflags.push (HTML5Helper.generateFontData (project, asset)); + + } + + } + + } + + if (project.targetFlags.exists ("xml")) { + + project.haxeflags.push ("-xml " + targetDirectory + "/types.xml"); + + } + + if (LogHelper.verbose) { + + project.haxedefs.set ("verbose", 1); + + } + + ModuleHelper.updateProject (project); + + var libraryNames = new Map (); + + for (asset in project.assets) { + + if (asset.library != null && !libraryNames.exists (asset.library)) { + + libraryNames[asset.library] = true; + + } + + } + + //for (library in libraryNames.keys ()) { + // + //project.haxeflags.push ("-resource " + targetDirectory + "/obj/manifest/" + library + ".json@__ASSET_MANIFEST__" + library); + // + //} + + //project.haxeflags.push ("-resource " + targetDirectory + "/obj/manifest/default.json@__ASSET_MANIFEST__default"); + + var context = generateContext (); + context.OUTPUT_DIR = targetDirectory; + + context.favicons = []; + + var icons = project.icons; + + if (icons.length == 0) { + + icons = [ new Icon (PathHelper.findTemplate (project.templatePaths, "default/icon.svg")) ]; + + } + + //if (IconHelper.createWindowsIcon (icons, PathHelper.combine (destination, "favicon.ico"))) { + // + //context.favicons.push ({ rel: "icon", type: "image/x-icon", href: "./favicon.ico" }); + // + //} + + if (IconHelper.createIcon (icons, 192, 192, PathHelper.combine (destination, "favicon.png"))) { + + context.favicons.push ({ rel: "shortcut icon", type: "image/png", href: "./favicon.png" }); + + } + + context.linkedLibraries = []; + + for (dependency in project.dependencies) { + + if (StringTools.endsWith (dependency.name, ".js")) { + + context.linkedLibraries.push (dependency.name); + + } else if (StringTools.endsWith (dependency.path, ".js") && FileSystem.exists (dependency.path)) { + + var name = Path.withoutDirectory (dependency.path); + + context.linkedLibraries.push ("./js/lib/" + name); + FileHelper.copyIfNewer (dependency.path, PathHelper.combine (destination, PathHelper.combine ("js/lib", name))); + + } + + } + + for (asset in project.assets) { + + var path = PathHelper.combine (destination, asset.targetPath); + + if (asset.type != AssetType.TEMPLATE) { + + if (asset.type != AssetType.FONT) { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAssetIfNewer (asset, path); + + } else if (useWebfonts) { + + PathHelper.mkdir (Path.directory (path)); + var ext = "." + Path.extension (asset.sourcePath); + var source = Path.withoutExtension (asset.sourcePath); + + for (extension in [ ext, ".eot", ".woff", ".svg" ]) { + + if (FileSystem.exists (source + extension)) { + + FileHelper.copyIfNewer (source + extension, path + extension); + + } else { + + LogHelper.warn ("Could not find generated font file \"" + source + extension + "\""); + + } + + } + + } + + } + + } + + FileHelper.recursiveSmartCopyTemplate (project, "winjs/template", targetDirectory, context); + + var renamePaths = [ "uwp-project.sln", "source/uwp-project.jsproj", "source/uwp-project_TemporaryKey.pfx" ]; + var fullPath; + + for (path in renamePaths) { + + fullPath = targetDirectory + "/" + path; + + try { + + if (FileSystem.exists (fullPath)) { + + File.copy (fullPath, targetDirectory + "/" + StringTools.replace (path, "uwp-project", project.app.file)); + FileSystem.deleteFile (fullPath); + + } + + } catch (e:Dynamic) {} + + } + + if (project.app.main != null) { + + FileHelper.recursiveSmartCopyTemplate (project, "haxe", targetDirectory + "/haxe", context); + FileHelper.recursiveSmartCopyTemplate (project, "winjs/haxe", targetDirectory + "/haxe", context, true, false); + FileHelper.recursiveSmartCopyTemplate (project, "winjs/hxml", targetDirectory + "/haxe", context); + + if (project.targetFlags.exists ("webgl")) { + + FileHelper.recursiveSmartCopyTemplate (project, "webgl/hxml", targetDirectory + "/haxe", context, true, false); + + } + + } + + for (asset in project.assets) { + + var path = PathHelper.combine (destination, asset.targetPath); + + if (asset.type == AssetType.TEMPLATE) { + + PathHelper.mkdir (Path.directory (path)); + FileHelper.copyAsset (asset, path, context); + + } + + } + + } + + + public override function watch ():Void { + + var dirs = WatchHelper.processHXML (project, getDisplayHXML ()); + var command = WatchHelper.getCurrentCommand (); + WatchHelper.watch (project, command, dirs); + + } + + + @ignore public override function install ():Void {} + @ignore public override function trace ():Void {} + @ignore public override function uninstall ():Void {} + + +} \ No newline at end of file