From 4712ed93bfd13d3c1ded1308e60835540b8c2012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Fri, 20 Oct 2023 11:07:54 +0200 Subject: [PATCH 01/18] Update rebuild-and-run-standalone-local.sh --- server/scripts/rebuild-and-run-standalone-local.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/server/scripts/rebuild-and-run-standalone-local.sh b/server/scripts/rebuild-and-run-standalone-local.sh index e6f2af79..c0262679 100755 --- a/server/scripts/rebuild-and-run-standalone-local.sh +++ b/server/scripts/rebuild-and-run-standalone-local.sh @@ -6,6 +6,7 @@ if [[ -z ${TARGET_DIR} ]]; then exit 1 fi +# realpath: brew install coreutils export TARGET_DIR=$(realpath ${TARGET_DIR}) echo "Rebuilding and running standalone local extender from ${TARGET_DIR}" From cec1568be23fa9574ec21c6ac8698b2662cc77f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Fri, 27 Oct 2023 11:15:38 +0200 Subject: [PATCH 02/18] Swift compilation support (#319) * Handle OTHER_CFLAGS * Added -fmodules flag * Update CocoaPodsService.java * Remove systemIncludes * Add pods in reverse order * Removed duplicate release instruction * Install pods and build ordered list of podspecs Dependencies first! * Log when job folder is kept * Update AsyncBuilder.java * Making function public * Working state * Formatting * Don't create modulemap files if they already exist * Update Extender.java * Update CocoaPodsService.java * Update CocoaPodsService.java * Update CocoaPodsService.java * Update Extender.java * Update Extender.java * Update Extender.java * Update Extender.java * Update Extender.java * Add runtime search path for swift libs * Duplicate from merge * Cleanup of swift specific steps * Update AsyncBuilder.java * Create modulemap from template * Unused * Add objc linker flag * Create job folder if it doesn't exist * Code cleanup and comments * Cleanup of pod includes * Add pod generated dir to includes * Cleanup of logs * Update Extender.java * Moved swift commands to yml --- server/docker-base/Dockerfile | 3 + server/docker-base/template.modulemap | 14 + .../rebuild-and-run-standalone-local.sh | 4 + .../scripts/standalone/service-standalone.sh | 1 + .../java/com/defold/extender/Extender.java | 142 +++++++-- .../defold/extender/ExtenderController.java | 3 + .../com/defold/extender/ExtenderUtil.java | 6 +- .../com/defold/extender/PlatformConfig.java | 5 + .../extender/services/CocoaPodsService.java | 280 +++++++++++++++--- 9 files changed, 385 insertions(+), 73 deletions(-) create mode 100644 server/docker-base/template.modulemap diff --git a/server/docker-base/Dockerfile b/server/docker-base/Dockerfile index 689378bd..45ffd2e1 100644 --- a/server/docker-base/Dockerfile +++ b/server/docker-base/Dockerfile @@ -478,6 +478,9 @@ COPY template.local.properties ${EXTENSION_LOCAL_PROPERTIES_TEMPLATE} ENV EXTENSION_PODFILE_TEMPLATE /var/extender/template.podfile COPY template.podfile ${EXTENSION_PODFILE_TEMPLATE} +ENV EXTENSION_MODULEMAP_TEMPLATE /var/extender/template.modulemap +COPY template.modulemap ${EXTENSION_MODULEMAP_TEMPLATE} + # # ZIG # diff --git a/server/docker-base/template.modulemap b/server/docker-base/template.modulemap new file mode 100644 index 00000000..b6afa826 --- /dev/null +++ b/server/docker-base/template.modulemap @@ -0,0 +1,14 @@ +{{FRAMEWORKOPT}} module {{MODULE_ID}} { + {{#HEADERS}} + header "{{{.}}}" + {{/HEADERS}} + {{#UMBRELLA_HEADERS}} + umbrella header "{{{.}}}" + {{/UMBRELLA_HEADERS}} + {{#UMBRELLA_DIRECTORIES}} + umbrella "{{{.}}}" + {{/UMBRELLA_DIRECTORIES}} + export * + requires objc + {{SUBMODULE}} +} diff --git a/server/scripts/rebuild-and-run-standalone-local.sh b/server/scripts/rebuild-and-run-standalone-local.sh index c0262679..14f28f3f 100755 --- a/server/scripts/rebuild-and-run-standalone-local.sh +++ b/server/scripts/rebuild-and-run-standalone-local.sh @@ -20,6 +20,10 @@ fi if [ ! -z ${DM_DEBUG_JOB_FOLDER} ] && [ -d ${DM_DEBUG_JOB_FOLDER} ]; then echo "Removing job folder" rm -rf ${DM_DEBUG_JOB_FOLDER} +fi + +if [ ! -z ${DM_DEBUG_JOB_FOLDER} ]; then + echo "Creating job folder" mkdir -p ${DM_DEBUG_JOB_FOLDER} fi diff --git a/server/scripts/standalone/service-standalone.sh b/server/scripts/standalone/service-standalone.sh index 1ab9f895..df98ba47 100644 --- a/server/scripts/standalone/service-standalone.sh +++ b/server/scripts/standalone/service-standalone.sh @@ -47,6 +47,7 @@ export MACOS_VERSION_MIN=10.13 export ZIG_PATH_0_11=${PLATFORMSDK_DIR}/zig-0-11 export EXTENSION_PODFILE_TEMPLATE=${EXTENDER_DIR}/current/template.podfile +export EXTENSION_MODULEMAP_TEMPLATE=${EXTENDER_DIR}/current/template.modulemap # We need access to the toolchain binary path from within the application export PATH=${PLATFORMSDK_DIR}/XcodeDefault${XCODE_14_VERSION}.xctoolchain/usr/bin:/usr/local/bin:${PATH} diff --git a/server/src/main/java/com/defold/extender/Extender.java b/server/src/main/java/com/defold/extender/Extender.java index a76bc010..5f7086e5 100644 --- a/server/src/main/java/com/defold/extender/Extender.java +++ b/server/src/main/java/com/defold/extender/Extender.java @@ -529,6 +529,7 @@ private List getIncludeDirs(File extDir) { } } podIncludes.add( ExtenderUtil.getRelativePath(jobDirectory, pod.dir) ); + podIncludes.add( ExtenderUtil.getRelativePath(jobDirectory, pod.generatedDir) ); } includes.addAll(podIncludes); includes.addAll(getFrameworkStaticLibIncludeDirs(resolvedPods)); @@ -537,6 +538,84 @@ private List getIncludeDirs(File extDir) { return pruneNonExisting(includes); } + + // swiftc: https://gist.github.com/enomoto/7f11d57e4add7e702f9f84f34d3a0f8c + // swift-frontend: https://gist.github.com/palaniraja/b4de1e64e874b68bda9e5236829cd8a6 + + private void emitSwiftHeaders(PodSpec pod, Map manifestContext, List commands) throws IOException, InterruptedException, ExtenderException { + List includes = getIncludeDirs(pod.dir); + + List frameworks = new ArrayList<>(); + frameworks.addAll(getFrameworks(pod.dir)); + frameworks.addAll(getFrameworks(resolvedPods)); + List frameworkPaths = new ArrayList<>(); + frameworkPaths.addAll(getFrameworkPaths(pod.dir)); + frameworkPaths.addAll(getFrameworkPaths(resolvedPods)); + + Map context = createContext(manifestContext); + context.put("ext", ImmutableMap.of("includes", includes, "frameworks", frameworks, "frameworkPaths", frameworkPaths)); + context.put("moduleName", pod.moduleName); + context.put("swiftSourceFiles", pod.swiftSourceFilePaths); + context.put("swiftHeaderPath", pod.swiftModuleHeader); + context.put("swiftVersion", "5"); + + String command = templateExecutor.execute(this.platformConfig.emitSwiftHeaderCmd, context); + // LOGGER.info("swiftc command to emot header: " + command); + commands.add(command); + } + + private void emitSwiftModule(PodSpec pod, Map manifestContext, List commands) throws IOException, InterruptedException, ExtenderException { + List includes = getIncludeDirs(pod.dir); + + List frameworks = new ArrayList<>(); + frameworks.addAll(getFrameworks(pod.dir)); + frameworks.addAll(getFrameworks(resolvedPods)); + List frameworkPaths = new ArrayList<>(); + frameworkPaths.addAll(getFrameworkPaths(pod.dir)); + frameworkPaths.addAll(getFrameworkPaths(resolvedPods)); + + Map context = createContext(manifestContext); + context.put("ext", ImmutableMap.of("includes", includes, "frameworks", frameworks, "frameworkPaths", frameworkPaths)); + context.put("moduleName", pod.moduleName); + context.put("swiftSourceFiles", pod.swiftSourceFilePaths); + context.put("swiftModulePath", new File(pod.generatedDir, pod.moduleName + ".swiftmodule")); + context.put("swiftVersion", "5"); + String command = templateExecutor.execute(this.platformConfig.emitSwiftModuleCmd, context); + // LOGGER.info("swiftc command to emit module: " + command); + commands.add(command); + } + + private File addCompileFileSwift(PodSpec pod, int index, File src, Map manifestContext, List commands) throws IOException, InterruptedException, ExtenderException { + File o = new File(buildDirectory, String.format("%s_%d.o", src.getName(), index)); + + // remove the primary source file from the set of all source files + String swiftPrimarySourceFile = src.getAbsolutePath(); + Set swiftSourceFilePaths = new HashSet<>(pod.swiftSourceFilePaths); + swiftSourceFilePaths.remove(swiftPrimarySourceFile); + + List includes = getIncludeDirs(pod.dir); + + List frameworks = new ArrayList<>(); + frameworks.addAll(getFrameworks(pod.dir)); + frameworks.addAll(getFrameworks(resolvedPods)); + List frameworkPaths = new ArrayList<>(); + frameworkPaths.addAll(getFrameworkPaths(pod.dir)); + frameworkPaths.addAll(getFrameworkPaths(resolvedPods)); + + Map context = createContext(manifestContext); + context.put("ext", ImmutableMap.of("includes", includes, "frameworks", frameworks, "frameworkPaths", frameworkPaths)); + context.put("tgt", ExtenderUtil.getRelativePath(jobDirectory, o)); + context.put("moduleName", pod.moduleName); + context.put("swiftPrimarySourceFile", swiftPrimarySourceFile); + context.put("swiftSourceFiles", swiftSourceFilePaths); + context.put("swiftVersion", "5"); + String command = templateExecutor.execute(this.platformConfig.compileSwiftCmd, context); + // LOGGER.info("swift-frontend command to compile swift source file: " + command); + commands.add(command); + return o; + } + + private File addCompileFileCpp_Internal(int index, File extDir, File src, Map manifestContext, String cmd, List commands) throws IOException, InterruptedException, ExtenderException { List includes = getIncludeDirs(extDir); @@ -719,9 +798,6 @@ else if (platformConfig.zigSourceRe != null && ExtenderUtil.matchesFile(src, pla // compile the source files of a pod and return a list of object files private List compilePodSourceFiles(PodSpec pod, Map manifestContext) throws IOException, InterruptedException, ExtenderException { - List objs = new ArrayList<>(); - List commands = new ArrayList<>(); - // clean up flags from context Map trimmedContext = ExtenderUtil.mergeContexts(manifestContext, new HashMap<>()); trimmedContext.put("flags", new ArrayList()); @@ -732,6 +808,7 @@ private List compilePodSourceFiles(PodSpec pod, Map mani Map podContextCpp = new HashMap<>(); Map podContextObjC = new HashMap<>(); Map podContextObjCpp = new HashMap<>(); + Map podContextSwift = new HashMap<>(); if (platform.contains("ios")) { podContextC.put("flags", new ArrayList(pod.flags.ios.c)); @@ -759,6 +836,7 @@ else if (platform.contains("osx")) { Map mergedContextWithPodsForCpp = ExtenderUtil.mergeContexts(trimmedContext, podContextCpp); Map mergedContextWithPodsForObjC = ExtenderUtil.mergeContexts(trimmedContext, podContextObjC); Map mergedContextWithPodsForObjCpp = ExtenderUtil.mergeContexts(trimmedContext, podContextObjCpp); + Map mergedContextWithPodsForSwift = ExtenderUtil.mergeContexts(trimmedContext, podContextSwift); // remove systemIncludes from objc and objc++ // this is a bit crude but cocoapod builds do not provide any -isystem option and @@ -767,32 +845,54 @@ else if (platform.contains("osx")) { // see https://github.com/defold/extender/issues/308 mergedContextWithPodsForObjC.put("systemIncludes", new ArrayList()); mergedContextWithPodsForObjCpp.put("systemIncludes", new ArrayList()); + mergedContextWithPodsForSwift.put("systemIncludes", new ArrayList()); + + + List objs = new ArrayList<>(); + + if (!pod.swiftSourceFiles.isEmpty()) { + // generate headers from swift files + List emitSwiftHeaderCommands = new ArrayList<>(); + emitSwiftHeaders(pod, mergedContextWithPodsForC, emitSwiftHeaderCommands); + ProcessExecutor.executeCommands(processExecutor, emitSwiftHeaderCommands); // in parallel + + // generate swift module from swift files + List emitSwiftModuleCommands = new ArrayList<>(); + emitSwiftModule(pod, mergedContextWithPodsForC, emitSwiftModuleCommands); + ProcessExecutor.executeCommands(processExecutor, emitSwiftModuleCommands); // in parallel + + // compile swift source files one by one + List compileSwiftCommands = new ArrayList<>(); + for (File src : pod.swiftSourceFiles) { + final int i = getAndIncreaseNameCount(); + File o = addCompileFileSwift(pod, i, src, mergedContextWithPodsForC, compileSwiftCommands); + objs.add(ExtenderUtil.getRelativePath(jobDirectory, o)); + } + ProcessExecutor.executeCommands(processExecutor, compileSwiftCommands); // in parallel + } + List commands = new ArrayList<>(); for (File src : pod.sourceFiles) { String extension = FilenameUtils.getExtension(src.getAbsolutePath()); - if (extension.equals("swift")) { - throw new ExtenderException("Unable to build '" + pod.name + "' since it includes Swift source files"); + final int i = getAndIncreaseNameCount(); + File o = null; + // use the correct context depending on the source file language + if (extension.equals("c")) { + o = addCompileFileCppStatic(i, pod.dir, src, mergedContextWithPodsForC, commands); + } + else if (extension.equals("m")) { + o = addCompileFileCppStatic(i, pod.dir, src, mergedContextWithPodsForObjC, commands); + } + else if (extension.equals("mm")) { + o = addCompileFileCppStatic(i, pod.dir, src, mergedContextWithPodsForObjCpp, commands); } else { - final int i = getAndIncreaseNameCount(); - File o = null; - // use the correct context depending on the source file language - if (extension.equals("c")) { - o = addCompileFileCppStatic(i, pod.dir, src, mergedContextWithPodsForC, commands); - } - else if (extension.equals("m")) { - o = addCompileFileCppStatic(i, pod.dir, src, mergedContextWithPodsForObjC, commands); - } - else if (extension.equals("mm")) { - o = addCompileFileCppStatic(i, pod.dir, src, mergedContextWithPodsForObjCpp, commands); - } - else { - o = addCompileFileCppStatic(i, pod.dir, src, mergedContextWithPodsForCpp, commands); - } - objs.add(ExtenderUtil.getRelativePath(jobDirectory, o)); + o = addCompileFileCppStatic(i, pod.dir, src, mergedContextWithPodsForCpp, commands); } + objs.add(ExtenderUtil.getRelativePath(jobDirectory, o)); } ProcessExecutor.executeCommands(processExecutor, commands); // in parallel + return objs; } diff --git a/server/src/main/java/com/defold/extender/ExtenderController.java b/server/src/main/java/com/defold/extender/ExtenderController.java index 9077e24a..6f90d888 100644 --- a/server/src/main/java/com/defold/extender/ExtenderController.java +++ b/server/src/main/java/com/defold/extender/ExtenderController.java @@ -364,6 +364,9 @@ public void buildEngineAsync(HttpServletRequest _request, LOGGER.warn("Failed to delete job directory"); } } + else { + LOGGER.info("Keeping job folder due to debug flags"); + } } } diff --git a/server/src/main/java/com/defold/extender/ExtenderUtil.java b/server/src/main/java/com/defold/extender/ExtenderUtil.java index f745867b..e90675ff 100644 --- a/server/src/main/java/com/defold/extender/ExtenderUtil.java +++ b/server/src/main/java/com/defold/extender/ExtenderUtil.java @@ -110,7 +110,7 @@ static List pruneItems(List input, List includePatterns, return items; } - static String getRelativePath(File base, File path) { + public static String getRelativePath(File base, File path) { return base.toURI().relativize(path.toURI()).getPath(); } @@ -206,7 +206,7 @@ static void debugPrintFiles(String name, List l) { // Lists files in a directory public static File[] listFilesMatching(File dir, String regex) { if(!dir.isDirectory()) { - throw new IllegalArgumentException(dir+" is not a directory."); + throw new IllegalArgumentException(dir + " is not a directory."); } final Pattern p = Pattern.compile(regex); return dir.listFiles(new FileFilter(){ @@ -220,7 +220,7 @@ public boolean accept(File file) { // Finds all files recursively public static List listFilesMatchingRecursive(File dir, String regex) { if(!dir.isDirectory()) { - throw new IllegalArgumentException(dir+" is not a directory."); + throw new IllegalArgumentException(dir + " is not a directory."); } return new ArrayList(FileUtils.listFiles(dir, new RegexFileFilter(regex), DirectoryFileFilter.DIRECTORY)); } diff --git a/server/src/main/java/com/defold/extender/PlatformConfig.java b/server/src/main/java/com/defold/extender/PlatformConfig.java index 01bd5730..3d67fe8c 100644 --- a/server/src/main/java/com/defold/extender/PlatformConfig.java +++ b/server/src/main/java/com/defold/extender/PlatformConfig.java @@ -55,6 +55,11 @@ class PlatformConfig { public String zigSourceRe; public String zigCompileCmd; + // Swift + public String emitSwiftHeaderCmd; + public String emitSwiftModuleCmd; + public String compileSwiftCmd; + // Deprecated public String mtCmd; // Deprecated, use windres instead (Deprecated at 1.2.135) } diff --git a/server/src/main/java/com/defold/extender/services/CocoaPodsService.java b/server/src/main/java/com/defold/extender/services/CocoaPodsService.java index f8374120..0c609556 100644 --- a/server/src/main/java/com/defold/extender/services/CocoaPodsService.java +++ b/server/src/main/java/com/defold/extender/services/CocoaPodsService.java @@ -48,6 +48,7 @@ public class ResolvedPods { public List pods = new ArrayList<>(); public File podsDir; public File frameworksDir; + public File generatedDir; public String platformMinVersion; // In the functions below we also get the values from the parent spec @@ -196,6 +197,11 @@ public void addAll(List values) { } } + public void add(String value) { + ios.add(value); + osx.add(value); + } + public Set get(String platform) { if (platform.contains("ios")) { return ios; @@ -217,10 +223,21 @@ public String toString() { public class PodSpec { public String name = ""; + public String moduleName = ""; public String version = ""; public String originalJSON = ""; public String iosversion = ""; public String osxversion = ""; + public String iosModuleMap = null; + public String osxModuleMap = null; + // Set to true if this Pod contains at least one .xcframework + public Boolean containsFramework = false; + // The Swift source file header (ModuleName-Swift.h) + // This file is referenced from the modulemap and generated in + // Extender.java as part of the process when building .swift files + public File swiftModuleHeader = null; + public Set swiftSourceFilePaths = new LinkedHashSet<>(); + public Set swiftSourceFiles = new LinkedHashSet<>(); public Set sourceFiles = new LinkedHashSet<>(); public Set includePaths = new LinkedHashSet<>(); public PodSpec parentSpec = null; @@ -236,7 +253,11 @@ public class PodSpec { public PlatformSet resources = new PlatformSet(); public PlatformSet frameworks = new PlatformSet(); public PlatformSet libraries = new PlatformSet(); + public PlatformSet publicHeaders = new PlatformSet(); public File dir; + public File generatedDir; + // true if this podspec was installed by Cocoapods + public boolean installed; public PodSpec getSubspec(String name) { for (PodSpec spec : subspecs) { @@ -252,7 +273,12 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(name + ":" + version + "\n"); sb.append(" dir: " + dir + "\n"); + sb.append(" moduleName: " + moduleName + "\n"); + sb.append(" generated dir: " + generatedDir + "\n"); + sb.append(" installed: " + installed + "\n"); sb.append(" src: " + sourceFiles + "\n"); + sb.append(" swift src: " + swiftSourceFiles + "\n"); + sb.append(" swift module header: " + swiftModuleHeader + "\n"); sb.append(" includes: " + includePaths + "\n"); sb.append(" defines: " + defines + "\n"); sb.append(" flags: " + flags + "\n"); @@ -273,10 +299,12 @@ public String toString() { } private static final String PODFILE_TEMPLATE_PATH = System.getenv("EXTENSION_PODFILE_TEMPLATE"); + private static final String MODULEMAP_TEMPLATE_PATH = System.getenv("EXTENSION_MODULEMAP_TEMPLATE"); private static final Logger LOGGER = LoggerFactory.getLogger(CocoaPodsService.class); private final TemplateExecutor templateExecutor = new TemplateExecutor(); private final String podfileTemplateContents; + private final String modulemapTemplateContents; private final MeterRegistry meterRegistry; @@ -293,6 +321,7 @@ private String readFile(String filePath) throws IOException { MeterRegistry meterRegistry) throws IOException { this.meterRegistry = meterRegistry; this.podfileTemplateContents = readFile(PODFILE_TEMPLATE_PATH); + this.modulemapTemplateContents = readFile(MODULEMAP_TEMPLATE_PATH); LOGGER.info("CocoaPodsService service"); } @@ -387,51 +416,46 @@ private String createMainPodFile(List podFiles, File jobDirectory, File wo } /** - * Return a list of source files for a pod + * Add source files matching a pattern to a pod * @param pod * @param pattern Source file pattern (glob format) - * @return List of files */ - private List findPodSourceFiles(PodSpec pod, String pattern) { - List srcFiles = new ArrayList<>(); - + private void addPodSourceFiles(PodSpec pod, String pattern) { String absolutePatternPath = pod.dir.getAbsolutePath() + File.separator + pattern; - List podSrcFiles = ExtenderUtil.listFilesGlob(pod.dir, absolutePatternPath); + List podSrcFiles = listFilesGlob(pod.dir, absolutePatternPath); for (File podSrcFile : podSrcFiles) { - if (!podSrcFile.getName().endsWith(".h")) { - srcFiles.add(podSrcFile); + final String filename = podSrcFile.getName(); + if (filename.endsWith(".swift")) { + pod.swiftSourceFiles.add(podSrcFile); + pod.swiftSourceFilePaths.add(podSrcFile.getAbsolutePath()); + } + else if (!filename.endsWith(".h")) { + pod.sourceFiles.add(podSrcFile); } } - - return srcFiles; - } + } /** - * Return a list of include paths for a pod + * Add a list of include paths matching a pattern to a pod * @param pod * @param pattern Source file pattern (glob format) - * @return List of include paths */ - private List findPodIncludePaths(PodSpec pod, String pattern) { - Set includePaths = new LinkedHashSet<>(); - + private void addPodIncludePaths(PodSpec pod, String pattern) { String absolutePatternPath = pod.dir.getAbsolutePath() + File.separator + pattern; - List podSrcFiles = ExtenderUtil.listFilesGlob(pod.dir, absolutePatternPath); + List podSrcFiles = listFilesGlob(pod.dir, absolutePatternPath); for (File podSrcFile : podSrcFiles) { if (podSrcFile.getName().endsWith(".h")) { File podIncludeDir = podSrcFile.getParentFile(); if (podIncludeDir != null) { - includePaths.add(podIncludeDir); + pod.includePaths.add(podIncludeDir); File podIncludeParentDir = podIncludeDir.getParentFile(); if (podIncludeParentDir != null) { - includePaths.add(podIncludeParentDir); + pod.includePaths.add(podIncludeParentDir); } } } } - - return new ArrayList(includePaths); - } + } // copy the files and folders of a directory recursively // the function will also resolve symlinks while copying files and folders @@ -720,14 +744,117 @@ private void parseMultiPlatformConfig(PodSpec spec, JSONObject config) { } } + private List listFilesGlob(File dir, String pattern) { + List files = ExtenderUtil.listFilesGlob(dir, pattern); + // Cocoapods uses Ruby where glob patterns are treated slightly differently: + // Ruby: foo/**/*.h will find .h files in any subdirectory of foo AND in foo/ + // Java: foo/**/*.h will find .h files in any subdirectory of foo but NOT in foo/ + if (pattern.contains("/**/")) { + pattern = pattern.replaceFirst("\\/\\*\\*\\/", "/"); + files.addAll(ExtenderUtil.listFilesGlob(dir, pattern)); + } + return files; + } + + // https://clang.llvm.org/docs/Modules.html#module-declaration + private void createModuleMap(PodSpec pod, Set headerPatterns, File moduleMapFile, File jobDir) throws ExtenderException { + LOGGER.info("createModuleMap() " + pod.moduleName + " from header patterns: " + headerPatterns + " " + moduleMapFile); + + List headers = new ArrayList<>(); + List umbrellaHeaders = new ArrayList<>(); + List umbrellaDirectories = new ArrayList<>(); + + // swift source file header + // generated by the swift compiler if -emit-objc-header flag is set + if (!pod.swiftSourceFiles.isEmpty()) { + File swiftModuleHeader = new File(pod.generatedDir, pod.moduleName + "-Swift.h"); + pod.swiftModuleHeader = swiftModuleHeader; + headers.add(swiftModuleHeader.getAbsolutePath()); + } + + // umbrella headers + for (String headerPattern : headerPatterns) { + String absoluteHeaderPatternPath = pod.dir.getAbsolutePath() + File.separator + headerPattern; + List headerFiles = listFilesGlob(pod.dir, absoluteHeaderPatternPath); + for (File headerFile : headerFiles) { + if (headerFile.getName().equals(pod.moduleName + ".h")) { + umbrellaHeaders.add(headerFile.getAbsolutePath()); + } + } + } + + // umbrella directory + if (umbrellaHeaders.isEmpty()) { + for (String headerPattern : headerPatterns) { + headerPattern = headerPattern.replace("/*.h", ""); + headerPattern = headerPattern.replace("/**", ""); + if (headerPattern.lastIndexOf("/") != -1) { + headerPattern = headerPattern.substring(0, headerPattern.lastIndexOf("/")); + } + String headerPath = pod.dir.getAbsolutePath() + File.separator + headerPattern; + umbrellaDirectories.add(headerPath); + } + } + + // module name, including parent spec module name + String fullModuleName = ((pod.parentSpec != null) ? (pod.parentSpec.moduleName + "_") : "") + pod.moduleName; + + // generate final modulemap + HashMap envContext = new HashMap<>(); + envContext.put("FRAMEWORKOPT", pod.containsFramework ? "framework" : ""); + envContext.put("MODULE_ID", fullModuleName); + envContext.put("HEADERS", headers); + envContext.put("UMBRELLA_HEADERS", umbrellaHeaders); + envContext.put("UMBRELLA_DIRECTORIES", umbrellaDirectories); + envContext.put("SUBMODULE", pod.containsFramework ? "module * { export * }" : ""); + + String moduleMap = templateExecutor.execute(modulemapTemplateContents, envContext); + try { + Files.writeString(moduleMapFile.toPath(), moduleMap); + } + catch (IOException e) { + throw new ExtenderException(e, "Unable to create modulemap for " + pod.moduleName); + } + } + + private String createIosModuleMap(PodSpec pod, File jobDir) throws ExtenderException { + File moduleMapFile = new File(pod.generatedDir, "module.modulemap"); + createModuleMap(pod, pod.publicHeaders.ios, moduleMapFile, jobDir); + return moduleMapFile.getAbsolutePath(); + } + private String createOsxModuleMap(PodSpec pod, File jobDir) throws ExtenderException { + File moduleMapFile = new File(pod.generatedDir, "module.modulemap"); + createModuleMap(pod, pod.publicHeaders.osx, moduleMapFile, jobDir); + return moduleMapFile.getAbsolutePath(); + } + // https://guides.cocoapods.org/syntax/podspec.html - private PodSpec createPodSpec(JSONObject specJson, PodSpec parent, File podsDir, Map jobEnvContext) throws ExtenderException { + private PodSpec createPodSpec(JSONObject specJson, PodSpec parent, File podsDir, File generatedDir, File jobDir, Map jobEnvContext) throws ExtenderException { PodSpec spec = new PodSpec(); spec.name = (String)specJson.get("name"); + if (specJson.containsKey("module_name")) { + spec.moduleName = (String)specJson.get("module_name"); + } + else { + // NSData+zlib -> NSData + spec.moduleName = ((String)specJson.get("name")).replaceAll("[\\+].*", ""); + } spec.version = (parent == null) ? (String)specJson.get("version") : parent.version; spec.dir = (parent == null) ? new File(podsDir, spec.name) : parent.dir; spec.parentSpec = parent; + if (parent == null) { + spec.installed = spec.dir.exists(); + } + else { + spec.installed = (new File(new File(spec.dir, spec.parentSpec.name), spec.name)).exists(); + } + + // generated files relating to the pod + // modulemap, swift header etc + spec.generatedDir = new File(generatedDir, spec.name); + spec.generatedDir.mkdirs(); + // inherit flags and defines from the parent if (parent != null) { spec.flags.ios.addAll(parent.flags.ios); @@ -793,10 +920,11 @@ private PodSpec createPodSpec(JSONObject specJson, PodSpec parent, File podsDir, spec.flags.osx.objc.add("-fmodules"); spec.flags.ios.objcpp.add("-fcxx-modules"); spec.flags.osx.objcpp.add("-fcxx-modules"); - spec.flags.ios.objc.add("-fmodule-name=" + spec.name); - spec.flags.osx.objc.add("-fmodule-name=" + spec.name); - spec.flags.ios.objcpp.add("-fmodule-name=" + spec.name); - spec.flags.osx.objcpp.add("-fmodule-name=" + spec.name); + if (spec.parentSpec == null) { + spec.flags.ios.objc.add("-fmodule-name=" + spec.moduleName); + spec.flags.osx.objc.add("-fmodule-name=" + spec.moduleName); + spec.flags.ios.objcpp.add("-fmodule-name=" + spec.moduleName); + } // resources // https://guides.cocoapods.org/syntax/podspec.html#resources @@ -852,7 +980,7 @@ private PodSpec createPodSpec(JSONObject specJson, PodSpec parent, File podsDir, Iterator it = subspecs.iterator(); while (it.hasNext()) { JSONObject o = it.next(); - PodSpec subSpec = createPodSpec(o, spec, podsDir, jobEnvContext); + PodSpec subSpec = createPodSpec(o, spec, podsDir, generatedDir, jobDir, jobEnvContext); spec.subspecs.add(subSpec); } } @@ -876,25 +1004,75 @@ private PodSpec createPodSpec(JSONObject specJson, PodSpec parent, File podsDir, // don't copy header (and source) files from paths in xcframeworks // framework headers are copied in a separate step in copyPodFrameworks() if (!path.contains(".xcframework/")) { - spec.sourceFiles.addAll(findPodSourceFiles(spec, path)); - spec.includePaths.addAll(findPodIncludePaths(spec, path)); - // Cocoapods uses Ruby where glob patterns are treated slightly differently: - // Ruby: foo/**/*.h will find .h files in any subdirectory of foo AND in foo/ - // Java: foo/**/*.h will find .h files in any subdirectory of foo but NOT in foo/ - if (path.contains("/**/")) { - path = path.replaceFirst("\\/\\*\\*\\/", "/"); - spec.sourceFiles.addAll(findPodSourceFiles(spec, path)); - spec.includePaths.addAll(findPodIncludePaths(spec, path)); - } + addPodSourceFiles(spec, path); + addPodIncludePaths(spec, path); + } + else { + spec.containsFramework = true; } } } + // add swift libs to the runtime search path + if (!spec.swiftSourceFiles.isEmpty()) { + spec.linkflags.add("-Wl,-rpath,/usr/lib/swift"); + } + + // add ObjC link flag if pod contains Objective-C code + for (File sourceFile : spec.sourceFiles) { + String filename = sourceFile.getName(); + if (filename.endsWith(".m") || filename.endsWith(".mm")) { + spec.linkflags.add("-ObjC"); + break; + } + } + + // public header files + // https://guides.cocoapods.org/syntax/podspec.html#public_header_files + spec.publicHeaders.addAll(getAsJSONArray(specJson, "public_header_files")); + if (ios != null) spec.publicHeaders.ios.addAll(getAsJSONArray(ios, "public_header_files")); + if (osx != null) spec.publicHeaders.osx.addAll(getAsJSONArray(osx, "public_header_files")); + + // module map + // https://guides.cocoapods.org/syntax/podspec.html#module_map + spec.iosModuleMap = (String)specJson.get("module_map"); + spec.osxModuleMap = (String)specJson.get("module_map"); + if (ios != null) spec.iosModuleMap = (String)ios.get("module_map"); + if (osx != null) spec.osxModuleMap = (String)osx.get("module_map"); + + if (spec.iosModuleMap != null && spec.iosModuleMap.toLowerCase().equals("false")) { + // do not generate a module map + spec.iosModuleMap = null; + } + else if (spec.iosModuleMap == null && spec.installed) { + if (ExtenderUtil.listFilesMatchingRecursive(spec.dir, "module.modulemap").isEmpty()) { + spec.iosModuleMap = createIosModuleMap(spec, jobDir); + } + } + if (spec.iosModuleMap != null) { + spec.flags.ios.objc.add("-fmodule-map-file=" + spec.iosModuleMap); + spec.flags.ios.objcpp.add("-fmodule-map-file=" + spec.iosModuleMap); + } + + if (spec.osxModuleMap != null && spec.osxModuleMap.toLowerCase().equals("false")) { + // do not generate a module map + spec.osxModuleMap = null; + } + else if (spec.osxModuleMap == null && spec.installed) { + if (ExtenderUtil.listFilesMatchingRecursive(spec.dir, "module.modulemap").isEmpty()) { + spec.osxModuleMap = createOsxModuleMap(spec, jobDir); + } + } + if (spec.osxModuleMap != null) { + spec.flags.osx.objc.add("-fmodule-map-file=" + spec.osxModuleMap); + spec.flags.osx.objcpp.add("-fmodule-map-file=" + spec.osxModuleMap); + } + return spec; } - private PodSpec createPodSpec(String specJson, File podsDir, Map jobEnvContext) throws ExtenderException { - PodSpec spec = createPodSpec(parseJson(specJson), null, podsDir, jobEnvContext); + private PodSpec createPodSpec(String specJson, File podsDir, File generatedDir, File workingDir, Map jobEnvContext) throws ExtenderException { + PodSpec spec = createPodSpec(parseJson(specJson), null, podsDir, generatedDir, workingDir, jobEnvContext); spec.originalJSON = specJson; return spec; } @@ -950,11 +1128,12 @@ private LinkedHashSet getSpecsAndDependencies(Map spec /** * Install pods from a podfile and create PodSpec instances for each installed pod. + * @param jobDir Directory of entire build job * @param workingDir Directory where to install pods. The directory must contain a valid Podfile * @param jobEnvContext Job environment context which contains all the job environment variables with `env.*` keys * @return A list of PodSpec instances for the installed pods */ - private List installPods(File workingDir, Map jobEnvContext) throws IOException, ExtenderException { + private List installPods(File jobDir, File workingDir, File generatedDir, Map jobEnvContext) throws IOException, ExtenderException { LOGGER.info("Installing pods"); File podFile = new File(workingDir, "Podfile"); if (!podFile.exists()) { @@ -1019,7 +1198,7 @@ private List installPods(File workingDir, Map jobEnvCon // "GoogleAppMeasurement": [ specJson = specJson.substring(specJson.indexOf("{", 0), specJson.length()); - specsMap.put(mainpodname, createPodSpec(specJson, podsDir, jobEnvContext)); + specsMap.put(mainpodname, createPodSpec(specJson, podsDir, generatedDir, jobDir, jobEnvContext)); } } @@ -1040,11 +1219,11 @@ private Map createJobEnvContext(Map env) { /** * Entry point for Cocoapod dependency resolution. - * @param jobDirectory Root directory of the job to resolve + * @param jobDir Root directory of the job to resolve * @param platform Which platform to resolve pods for * @return ResolvedPods instance with list of pods, install directory etc */ - public ResolvedPods resolveDependencies(Map env, File jobDirectory, String platform) throws IOException, ExtenderException { + public ResolvedPods resolveDependencies(Map env, File jobDir, String platform) throws IOException, ExtenderException { if (!platform.contains("ios") && !platform.contains("osx")) { throw new ExtenderException("Unsupported platform " + platform); } @@ -1053,7 +1232,7 @@ public ResolvedPods resolveDependencies(Map env, File jobDirecto // find all podfiles and filter down to a list of podfiles specifically // for the platform we are resolving pods for - List allPodFiles = ExtenderUtil.listFilesMatchingRecursive(jobDirectory, "Podfile"); + List allPodFiles = ExtenderUtil.listFilesMatchingRecursive(jobDir, "Podfile"); List platformPodFiles = new ArrayList<>(); for (File podFile : allPodFiles) { String parentFolder = podFile.getParentFile().getName(); @@ -1073,15 +1252,17 @@ public ResolvedPods resolveDependencies(Map env, File jobDirecto long methodStart = System.currentTimeMillis(); LOGGER.info("Resolving Cocoapod dependencies"); - File workingDir = new File(jobDirectory, "CocoaPodsService"); + File workingDir = new File(jobDir, "CocoaPodsService"); File frameworksDir = new File(workingDir, "frameworks"); + File generatedDir = new File(workingDir, "generated"); workingDir.mkdirs(); + generatedDir.mkdirs(); - String platformMinVersion = createMainPodFile(platformPodFiles, jobDirectory, workingDir, platform, jobEnvContext); - List pods = installPods(workingDir, jobEnvContext); + String platformMinVersion = createMainPodFile(platformPodFiles, jobDir, workingDir, platform, jobEnvContext); + List pods = installPods(jobDir, workingDir, generatedDir, jobEnvContext); copyPodFrameworks(pods, frameworksDir); - // dumpDir(jobDirectory, 0); + dumpDir(jobDir, 0); MetricsWriter.metricsTimer(meterRegistry, "gauge.service.cocoapods.get", System.currentTimeMillis() - methodStart); @@ -1090,6 +1271,7 @@ public ResolvedPods resolveDependencies(Map env, File jobDirecto resolvedPods.platformMinVersion = platformMinVersion; resolvedPods.podsDir = new File(workingDir, "Pods"); resolvedPods.frameworksDir = frameworksDir; + resolvedPods.generatedDir = generatedDir; return resolvedPods; } From 07519c58f23113d3195f4324f146dbb66fe4afb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Sun, 5 Nov 2023 15:49:57 +0100 Subject: [PATCH 03/18] Increase default build timeout for async builds (#320) * Increased timeout from 4 to 20 minutes * Increased extender client version * Update build_and_copy.sh * Update gradle-wrapper.properties For Java 17 the minimum gradle version is 7.3 * Update dockerimage.yml * Update dockerimage.yml * Update build.gradle * Revert "Update gradle-wrapper.properties" This reverts commit e2c977b07ebc9a7b81c9b7aef2af1d4cf3cda857. * Revert "Update build.gradle" This reverts commit 682512ad2ca500f2a43fa9ec7ac6818ce6311ecc. * Update dockerimage.yml --- .github/workflows/dockerimage.yml | 6 ++++++ client/build.gradle | 2 +- client/scripts/build_and_copy.sh | 2 +- .../java/com/defold/extender/client/ExtenderClient.java | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dockerimage.yml b/.github/workflows/dockerimage.yml index dcfeac91..92ac39e3 100644 --- a/.github/workflows/dockerimage.yml +++ b/.github/workflows/dockerimage.yml @@ -11,6 +11,12 @@ jobs: steps: - uses: actions/checkout@v1 + - name: Install Java + uses: actions/setup-java@v3 + with: + java-version: '11.0.15' + distribution: 'temurin' + - name: Free disk space run: | df -h diff --git a/client/build.gradle b/client/build.gradle index a402491b..138745bf 100644 --- a/client/build.gradle +++ b/client/build.gradle @@ -8,7 +8,7 @@ repositories { jar { baseName = 'extender-client' - version = '0.0.4' + version = '0.0.5' } dependencies { diff --git a/client/scripts/build_and_copy.sh b/client/scripts/build_and_copy.sh index 5c8ddaf3..0f8182b2 100755 --- a/client/scripts/build_and_copy.sh +++ b/client/scripts/build_and_copy.sh @@ -1,3 +1,3 @@ #! /usr/bin/env bash -(cd client && ../gradlew build && cp -v ./build/libs/extender-client-0.0.1.jar $DYNAMO_HOME/../../com.dynamo.cr/com.dynamo.cr.common/ext/extender-client-0.0.1.jar) +(cd client && ../gradlew build && cp -v ./build/libs/extender-client-0.0.5.jar $DYNAMO_HOME/../../com.dynamo.cr/com.dynamo.cr.common/ext/extender-client-0.0.5.jar) diff --git a/client/src/main/java/com/defold/extender/client/ExtenderClient.java b/client/src/main/java/com/defold/extender/client/ExtenderClient.java index 8a587d68..a3021232 100644 --- a/client/src/main/java/com/defold/extender/client/ExtenderClient.java +++ b/client/src/main/java/com/defold/extender/client/ExtenderClient.java @@ -77,7 +77,7 @@ public ExtenderClient(AbstractHttpClient httpClient, String extenderBaseUrl, Fil this.cache = new ExtenderClientCache(cacheDir); this.httpCookies = new BasicCookieStore(); this.buildSleepTimeout = Long.parseLong(System.getProperty("com.defold.extender.client.build-sleep-timeout", "5000")); - this.buildResultWaitTimeout = Long.parseLong(System.getProperty("com.defold.extender.client.build-wait-timeout", "240000")); + this.buildResultWaitTimeout = Long.parseLong(System.getProperty("com.defold.extender.client.build-wait-timeout", "1200000")); this.headers = new ArrayList(); this.httpClient = httpClient; this.httpClient.setCookieStore(httpCookies); From 8fba252d7d2a6b7975e55482ae35e64e822ead57 Mon Sep 17 00:00:00 2001 From: JCash Date: Mon, 6 Nov 2023 14:04:28 +0100 Subject: [PATCH 04/18] Add MSVC 2022 to Docker container --- server/docker-base/Dockerfile | 51 ++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/server/docker-base/Dockerfile b/server/docker-base/Dockerfile index 45ffd2e1..2ad9968b 100644 --- a/server/docker-base/Dockerfile +++ b/server/docker-base/Dockerfile @@ -141,8 +141,16 @@ RUN \ ENV \ PLATFORMSDK_WIN32=$PLATFORMSDK_DIR/Win32 \ - WINDOWS_SDK_10_VERSION=10.0.18362.0 \ - WINDOWS_MSVC_2019_VERSION=14.25.28610 + WINDOWS_SDK_10_VERSION=10.0.20348.0 \ + WINDOWS_MSVC_2019_VERSION=14.25.28610 \ + WINDOWS_MSVC_2022_VERSION=14.37.32822 + +ENV \ + WindowsLibPath="${PLATFORMSDK_WIN32}/WindowsKits/10/References/${WINDOWS_SDK_10_VERSION}" \ + WindowsSdkDir="${PLATFORMSDK_WIN32}/WindowsKits/10/" \ + WindowsSDKLibVersion="${WINDOWS_SDK_10_VERSION}" \ + WindowsSDKVersion="${WINDOWS_SDK_10_VERSION}" \ + WINDOWS_SDK_10_DIR="${PLATFORMSDK_WIN32}/WindowsKits/10/" # Grabbed after a starting MSVC 2019, and choosing "Tools -> Command Line -> Developer Command Prompt" # Note: VCINSTALLDIR is special since clang will use it as the last "-internal-isystem" option @@ -150,14 +158,17 @@ ENV \ VCINSTALLDIR="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019/VC/" \ VSINSTALLDIR="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019/" \ WINDOWS_MSVC_2019_DIR="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019/VC/Tools/MSVC/${WINDOWS_MSVC_2019_VERSION}/" \ - WINDOWS_SDK_10_DIR="${PLATFORMSDK_WIN32}/WindowsKits/10/" \ VS160COMNTOOLS="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019/Common7/Tools/" \ WINDOWS_VCINSTALLDIR="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019/VC/Tools/MSVC/${WINDOWS_MSVC_2019_VERSION}/" \ - WINDOWS_VSINSTALLDIR="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019/" \ - WindowsLibPath="${PLATFORMSDK_WIN32}/WindowsKits/10/References/${WINDOWS_SDK_10_VERSION}" \ - WindowsSdkDir="${PLATFORMSDK_WIN32}/WindowsKits/10/" \ - WindowsSDKLibVersion="${WINDOWS_SDK_10_VERSION}" \ - WindowsSDKVersion="${WINDOWS_SDK_10_VERSION}" + WINDOWS_VSINSTALLDIR="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019/" + +ENV \ + VCINSTALLDIR_2022="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022/VC/" \ + VSINSTALLDIR_2022="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022/" \ + WINDOWS_MSVC_DIR_2022="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022/VC/Tools/MSVC/${WINDOWS_MSVC_2022_VERSION}/" \ + VS160COMNTOOLS_2022="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022/Common7/Tools/" \ + WINDOWS_VCINSTALLDIR_2022="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022/VC/Tools/MSVC/${WINDOWS_MSVC_2022_VERSION}/" \ + WINDOWS_VSINSTALLDIR_2022="${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022/" # windres: Allows for generating .res files that can be used during linking RUN \ @@ -172,6 +183,11 @@ RUN \ mkdir -p ${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019 && \ wget -q -O - ${DM_PACKAGES_URL}/Microsoft-Visual-Studio-2019-${WINDOWS_MSVC_2019_VERSION}.tar.gz | tar xz -C ${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019 +RUN \ + echo "WIN32 2022 SDK" && \ + mkdir -p ${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022 && \ + wget -q -O - ${DM_PACKAGES_URL}/Microsoft-Visual-Studio-2022-${WINDOWS_MSVC_2022_VERSION}.tar.gz | tar xz -C ${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022 + RUN \ echo "WIN32 10 SDK" && \ mkdir -p ${PLATFORMSDK_WIN32}/WindowsKits && \ @@ -188,13 +204,28 @@ RUN find $PLATFORMSDK_WIN32 -iname '*.Lib' -exec sh -c 'a=$(echo "$0" | sed -r " RUN find $PLATFORMSDK_WIN32 -iname '*.h' -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | tr [:upper:] [:lower:]); [ "$a" != $(basename "$0") ] && cp "$0" "$d/$a" ' {} \; RUN \ - echo "WIN32 SDK - Cleanup" && \ + echo "WIN32 SDK - 2019 - Cleanup" && \ # and the rest are manually copied (or made lower case) (cd ${WINDOWS_MSVC_2019_DIR}/lib/x64 && cp oldnames.lib OLDNAMES.lib) && \ (cd ${WINDOWS_MSVC_2019_DIR}/lib/x86 && cp oldnames.lib OLDNAMES.lib) && \ (cd ${WINDOWS_MSVC_2019_DIR}/lib/x64 && cp delayimp.lib Delayimp.lib) && \ (cd ${WINDOWS_MSVC_2019_DIR}/lib/x86 && cp delayimp.lib Delayimp.lib) + +RUN \ + echo "WIN32 SDK - 2022 - Debug" && \ +# and the rest are manually copied (or made lower case) + echo ${WINDOWS_MSVC_DIR_2022} + + +RUN \ + echo "WIN32 SDK - 2022 - Cleanup" && \ +# and the rest are manually copied (or made lower case) + (cd ${WINDOWS_MSVC_DIR_2022}/lib/x64 && cp oldnames.lib OLDNAMES.lib) && \ + (cd ${WINDOWS_MSVC_DIR_2022}/lib/x86 && cp oldnames.lib OLDNAMES.lib) && \ + (cd ${WINDOWS_MSVC_DIR_2022}/lib/x64 && cp delayimp.lib Delayimp.lib) && \ + (cd ${WINDOWS_MSVC_DIR_2022}/lib/x86 && cp delayimp.lib Delayimp.lib) + # Some headers are named by the wrong name in the windows sdk's... # We need to make certain names lowercase because some users # have put "pragma lib" comments in some libraries :( @@ -204,6 +235,8 @@ RUN \ (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_VERSION}/shared && cp specstrings.h SpecStrings.h) && \ (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_VERSION}/shared && cp concurrencysal.h ConcurrencySal.h) && \ (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_VERSION}/shared && cp wlantypes.h WlanTypes.h) && \ + (cd ${WINDOWS_SDK_10_DIR}/Lib/${WINDOWS_SDK_10_VERSION}/um/x64 && cp psapi.lib Psapi.lib) && \ + (cd ${WINDOWS_SDK_10_DIR}/Lib/${WINDOWS_SDK_10_VERSION}/um/x86 && cp psapi.lib Psapi.lib) && \ (cd ${WINDOWS_SDK_10_DIR}/Lib/${WINDOWS_SDK_10_VERSION} && find . -type f -exec sh -c 'x="{}"; xl=$(echo $x | sed -e "s/\(.*\)/\L\1/"); if [ $x != $xl ]; then cp $x $xl; fi' \;) # Also, the OpenGL headers in the windows SDK is in a folder with lower case letters, which doesn't match the includes From d252371a4e5d6ba26e9fed59497169d905fe5d3c Mon Sep 17 00:00:00 2001 From: JCash Date: Mon, 6 Nov 2023 15:25:37 +0100 Subject: [PATCH 05/18] Updated server to support XCode 15.0.1 --- README.md | 14 +++++++------- server/scripts/standalone/service-standalone.sh | 15 ++++++--------- .../scripts/standalone/setup-standalone-server.sh | 4 ++++ .../java/com/defold/extender/ExtenderTest.java | 4 ++-- server/test-data/compile.sh | 8 ++++---- .../test-data/sdk/a/defoldsdk/extender/build.yml | 5 +++-- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 4c88854f..9cee9e9d 100644 --- a/README.md +++ b/README.md @@ -100,13 +100,13 @@ The stand-alone server is currently used on a machine runing macOS. The server i ### Prerequisites Ensure that you have the following tools packaged -* macOS 12.1 -* XCode 13.2.1 - * iOS SDK 15.2 - * Clang 13.0.0 - * Swift 5.5 +* macOS +* XCode +* iOS SDK +* Clang 13.0.0 +* Swift -NOTE: Above requirements taken [from the Dockerfile](https://github.com/defold/extender/blob/dev/server/docker-base/Dockerfile#L436-L441). Double-check that they are still accurate! +NOTE: Above requirements taken [from the Dockerfile](https://github.com/defold/extender/blob/dev/server/docker-base/Dockerfile#L436-L441). Double-check that they are still accurate! Also see `server/scripts/standalone/service-standalone.sh`. ### Run To run the stand-alone server locally, you need to give it access to `/usr/local/extender`: @@ -154,4 +154,4 @@ Use the `rebuild-and-run-standalone-local.sh` script to quickly rebuild and laun $ ./server/scripts/rebuild-and-run-standalone-local.sh /path/to/localextender ``` -This will set the `TARGET_DIR` environment variable to `/path/to/localextender`, stop any currently running server, build a new one, deploy and start it and show the server log in the console. \ No newline at end of file +This will set the `TARGET_DIR` environment variable to `/path/to/localextender`, stop any currently running server, build a new one, deploy and start it and show the server log in the console. diff --git a/server/scripts/standalone/service-standalone.sh b/server/scripts/standalone/service-standalone.sh index df98ba47..fa006bfd 100644 --- a/server/scripts/standalone/service-standalone.sh +++ b/server/scripts/standalone/service-standalone.sh @@ -27,22 +27,19 @@ export JAVA_HOME=`/usr/libexec/java_home` # From Dockerfile # Also update setup-standalone-server.sh -# Versions from >=1.2.191 -export XCODE_13_VERSION=13.2.1 -export MACOS_12_VERSION=12.1 -export IOS_15_VERSION=15.2 -export XCODE_13_CLANG_VERSION=13.0.0 -export LIB_TAPI_1_6_PATH=/usr/local/tapi1.6/lib - # Versions from >=1.4.4 export XCODE_14_VERSION=14.2 +export XCODE_14_CLANG_VERSION=14.0.0 export MACOS_13_VERSION=13.1 export IOS_16_VERSION=16.2 -export XCODE_14_CLANG_VERSION=14.0.0 export SWIFT_5_5_VERSION=5.5 export IOS_VERSION_MIN=11.0 export MACOS_VERSION_MIN=10.13 +# Versions from >=1.6.2 +export XCODE_15_VERSION=15.0.1 +export XCODE_15_CLANG_VERSION=15.0.0 + # Added 1.4.9 export ZIG_PATH_0_11=${PLATFORMSDK_DIR}/zig-0-11 @@ -50,7 +47,7 @@ export EXTENSION_PODFILE_TEMPLATE=${EXTENDER_DIR}/current/template.podfile export EXTENSION_MODULEMAP_TEMPLATE=${EXTENDER_DIR}/current/template.modulemap # We need access to the toolchain binary path from within the application -export PATH=${PLATFORMSDK_DIR}/XcodeDefault${XCODE_14_VERSION}.xctoolchain/usr/bin:/usr/local/bin:${PATH} +export PATH=${PLATFORMSDK_DIR}/XcodeDefault${XCODE_15_VERSION}.xctoolchain/usr/bin:/usr/local/bin:${PATH} start_service() { echo "${SERVICE_NAME} starting..." diff --git a/server/scripts/standalone/setup-standalone-server.sh b/server/scripts/standalone/setup-standalone-server.sh index e131717c..6ccecaaf 100755 --- a/server/scripts/standalone/setup-standalone-server.sh +++ b/server/scripts/standalone/setup-standalone-server.sh @@ -47,6 +47,9 @@ function download_package() { if [ "XcodeDefault14.2.xctoolchain.darwin" == "$package_name" ]; then out_package_name="XcodeDefault14.2.xctoolchain" fi + if [ "XcodeDefault15.0.1.xctoolchain.darwin" == "$package_name" ]; then + out_package_name="XcodeDefault15.0.1.xctoolchain" + fi if [[ ! -e ${PLATFORMSDK_DIR}/${out_package_name} ]]; then mkdir -p ${TMP_DOWNLOAD_DIR} @@ -97,6 +100,7 @@ PACKAGES=( iPhoneSimulator16.2.sdk MacOSX13.1.sdk XcodeDefault14.2.xctoolchain.darwin + XcodeDefault15.0.1.xctoolchain.darwin ) ZIG_VERSION=0.11.0 diff --git a/server/src/test/java/com/defold/extender/ExtenderTest.java b/server/src/test/java/com/defold/extender/ExtenderTest.java index d5bb8829..946a07ff 100644 --- a/server/src/test/java/com/defold/extender/ExtenderTest.java +++ b/server/src/test/java/com/defold/extender/ExtenderTest.java @@ -37,12 +37,12 @@ static Map createEnv() // TODO: Read these from the Dockerfile itself env.put("PLATFORMSDK_DIR", "/opt/platformsdk"); env.put("MANIFEST_MERGE_TOOL", "/opt/local/bin/manifestmergetool.jar"); - env.put("XCODE_14_VERSION", "14.2"); + env.put("XCODE_15_VERSION", "15.0.1"); + env.put("XCODE_15_CLANG_VERSION", "15.0.0"); env.put("IOS_16_VERSION", "16.2"); env.put("LIB_TAPI_1_6_PATH", "/usr/local/tapi1.6/lib"); env.put("MACOS_13_VERSION", "13.1"); env.put("MACOS_VERSION_MIN", "10.13"); - env.put("XCODE_14_CLANG_VERSION", "14.0.0"); env.put("SWIFT_5_5_VERSION", "5.5"); env.put("SYSROOT", "/opt/platformsdk/MacOSX13.1.sdk"); env.put("LD_LIBRARY_PATH", "/usr/local/tapi1.6/lib"); diff --git a/server/test-data/compile.sh b/server/test-data/compile.sh index 1aeabf26..f03f222b 100755 --- a/server/test-data/compile.sh +++ b/server/test-data/compile.sh @@ -20,13 +20,13 @@ ANDROID_64_NDK_API_VERSION='21' ANDROID_SYS_ROOT=${ANDROID_NDK}/toolchains/llvm/prebuilt/${HOST}-x86_64/sysroot ANDROID_INCLUDE_ARCH=${ANDROID_NDK}/sources/android/cpufeatures -IOS_GCC=${DYNAMO_HOME}/ext/SDKs/XcodeDefault14.2.xctoolchain/usr/bin/clang++ -IOS_AR=${DYNAMO_HOME}/ext/SDKs/XcodeDefault14.2.xctoolchain/usr/bin/ar +IOS_GCC=${DYNAMO_HOME}/ext/SDKs/XcodeDefault15.0.1.xctoolchain/usr/bin/clang++ +IOS_AR=${DYNAMO_HOME}/ext/SDKs/XcodeDefault15.0.1.xctoolchain/usr/bin/ar IOS_MIN_VERSION=11.0 IOS_SYS_ROOT=${DYNAMO_HOME}/ext/SDKs/iPhoneOS16.2.sdk -OSX_GCC=${DYNAMO_HOME}/ext/SDKs/XcodeDefault14.2.xctoolchain/usr/bin/clang++ -OSX_AR=${DYNAMO_HOME}/ext/SDKs/XcodeDefault14.2.xctoolchain/usr/bin/ar +OSX_GCC=${DYNAMO_HOME}/ext/SDKs/XcodeDefault15.0.1.xctoolchain/usr/bin/clang++ +OSX_AR=${DYNAMO_HOME}/ext/SDKs/XcodeDefault15.0.1.xctoolchain/usr/bin/ar OSX_MIN_VERSION=10.13 OSX_SYS_ROOT=${DYNAMO_HOME}/ext/SDKs/MacOSX13.1.sdk diff --git a/server/test-data/sdk/a/defoldsdk/extender/build.yml b/server/test-data/sdk/a/defoldsdk/extender/build.yml index 49004ec4..5ad7c94c 100755 --- a/server/test-data/sdk/a/defoldsdk/extender/build.yml +++ b/server/test-data/sdk/a/defoldsdk/extender/build.yml @@ -83,10 +83,11 @@ platforms: x86_64-osx: env: + PATH: "{{env.PLATFORMSDK_DIR}}/XcodeDefault{{env.XCODE_15_VERSION}}.xctoolchain/usr/bin:{{env.PATH}}" PLATFORMSDK_DIR: "{{env.PLATFORMSDK_DIR}}" MANIFEST_MERGE_TOOL: "{{env.MANIFEST_MERGE_TOOL}}" - XCODE_VERSION: "{{env.XCODE_14_VERSION}}" - XCODE_CLANG_VERSION: "{{env.XCODE_14_CLANG_VERSION}}" + XCODE_VERSION: "{{env.XCODE_15_VERSION}}" + XCODE_CLANG_VERSION: "{{env.XCODE_15_CLANG_VERSION}}" MACOS_VERSION: "{{env.MACOS_13_VERSION}}" MACOS_VERSION_MIN: "{{env.MACOS_VERSION_MIN}}" SWIFT_VERSION: "{{env.SWIFT_5_5_VERSION}}" From f9be7f992845c60bcae24448323c235b6603472f Mon Sep 17 00:00:00 2001 From: JCash Date: Tue, 7 Nov 2023 12:31:17 +0100 Subject: [PATCH 06/18] Updated Msvc with missing atl headers. Added capital letter to header files for Windows --- server/docker-base/Dockerfile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/server/docker-base/Dockerfile b/server/docker-base/Dockerfile index 2ad9968b..b1f02008 100644 --- a/server/docker-base/Dockerfile +++ b/server/docker-base/Dockerfile @@ -184,7 +184,7 @@ RUN \ wget -q -O - ${DM_PACKAGES_URL}/Microsoft-Visual-Studio-2019-${WINDOWS_MSVC_2019_VERSION}.tar.gz | tar xz -C ${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2019 RUN \ - echo "WIN32 2022 SDK" && \ + echo "WIN32 2022 SDK " && \ mkdir -p ${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022 && \ wget -q -O - ${DM_PACKAGES_URL}/Microsoft-Visual-Studio-2022-${WINDOWS_MSVC_2022_VERSION}.tar.gz | tar xz -C ${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022 @@ -198,10 +198,14 @@ RUN \ ln -s /usr/local/bin/llvm-ar /usr/local/bin/x86_64-pc-win32-clang-ar # Due to Windows' case insensitive file system, the sources reference lib files with wrong cases -# so we solve the bulk by making the suffixes lowercase -RUN find $PLATFORMSDK_WIN32 -iname '*.Lib' -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \; +# so we solve the bulk by making the suffixes lowercase. (e.g. MyLib.Lib -> MyLib.lib) +RUN find $PLATFORMSDK_WIN32 -iname '*.Lib' -type f -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \; + # Make a copy of all the headers too, in lower case (e.g. Windows.h -> windows.h etc) -RUN find $PLATFORMSDK_WIN32 -iname '*.h' -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | tr [:upper:] [:lower:]); [ "$a" != $(basename "$0") ] && cp "$0" "$d/$a" ' {} \; +RUN find $PLATFORMSDK_WIN32 -iname '*.h' -type f -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | tr [:upper:] [:lower:]); [ "$a" != $(basename "$0") ] && cp "$0" "$d/$a" ' {} \; +# Make copies with first capital letter (e.g. ole2.h -> Ole2.h) +RUN find $PLATFORMSDK_WIN32 -iname '*.h' -type f -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | sed -r "s/\b(\w)/\u\1/"); [ "$a" != $(basename "$0") ] && cp "$0" "$d/$a" ' {} \; + RUN \ echo "WIN32 SDK - 2019 - Cleanup" && \ @@ -229,6 +233,7 @@ RUN \ # Some headers are named by the wrong name in the windows sdk's... # We need to make certain names lowercase because some users # have put "pragma lib" comments in some libraries :( +# and/or misspelled header files RUN \ echo "WIN32 WindowsKits 10 - Cleanup" && \ (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_VERSION}/shared && cp driverspecs.h DriverSpecs.h) && \ From c4e6e7299a043b02f66e55a607b229c93b5d0c98 Mon Sep 17 00:00:00 2001 From: JCash Date: Wed, 8 Nov 2023 10:55:46 +0100 Subject: [PATCH 07/18] Added include parsing to rename file duplicates correctly for MSVC --- server/docker-base/Dockerfile | 63 ++++++++----- server/docker-base/winsdk_rename_files.py | 104 ++++++++++++++++++++++ 2 files changed, 146 insertions(+), 21 deletions(-) create mode 100644 server/docker-base/winsdk_rename_files.py diff --git a/server/docker-base/Dockerfile b/server/docker-base/Dockerfile index b1f02008..67c76607 100644 --- a/server/docker-base/Dockerfile +++ b/server/docker-base/Dockerfile @@ -141,16 +141,18 @@ RUN \ ENV \ PLATFORMSDK_WIN32=$PLATFORMSDK_DIR/Win32 \ - WINDOWS_SDK_10_VERSION=10.0.20348.0 \ + WINDOWS_SDK_10_18362_VERSION=10.0.18362.0 \ + WINDOWS_SDK_10_20348_VERSION=10.0.20348.0 \ WINDOWS_MSVC_2019_VERSION=14.25.28610 \ WINDOWS_MSVC_2022_VERSION=14.37.32822 +# The version part is deprecated since 1.6.2 (we should leave that to the build_input.yml) ENV \ - WindowsLibPath="${PLATFORMSDK_WIN32}/WindowsKits/10/References/${WINDOWS_SDK_10_VERSION}" \ + WINDOWS_SDK_10_DIR="${PLATFORMSDK_WIN32}/WindowsKits/10/" \ WindowsSdkDir="${PLATFORMSDK_WIN32}/WindowsKits/10/" \ - WindowsSDKLibVersion="${WINDOWS_SDK_10_VERSION}" \ - WindowsSDKVersion="${WINDOWS_SDK_10_VERSION}" \ - WINDOWS_SDK_10_DIR="${PLATFORMSDK_WIN32}/WindowsKits/10/" + WindowsLibPath="${PLATFORMSDK_WIN32}/WindowsKits/10/References/${WINDOWS_SDK_10_18362_VERSION}" \ + WindowsSDKLibVersion="${WINDOWS_SDK_10_18362_VERSION}" \ + WindowsSDKVersion="${WINDOWS_SDK_10_18362_VERSION}" # Grabbed after a starting MSVC 2019, and choosing "Tools -> Command Line -> Developer Command Prompt" # Note: VCINSTALLDIR is special since clang will use it as the last "-internal-isystem" option @@ -189,23 +191,36 @@ RUN \ wget -q -O - ${DM_PACKAGES_URL}/Microsoft-Visual-Studio-2022-${WINDOWS_MSVC_2022_VERSION}.tar.gz | tar xz -C ${PLATFORMSDK_WIN32}/MicrosoftVisualStudio2022 RUN \ - echo "WIN32 10 SDK" && \ + echo "WIN32 ${WINDOWS_SDK_10_18362_VERSION} SDK " && \ mkdir -p ${PLATFORMSDK_WIN32}/WindowsKits && \ - wget -q -O - ${DM_PACKAGES_URL}/WindowsKits-${WINDOWS_SDK_10_VERSION}.tar.gz | tar xz -C ${PLATFORMSDK_WIN32}/WindowsKits + wget -q -O - ${DM_PACKAGES_URL}/WindowsKits-${WINDOWS_SDK_10_18362_VERSION}.tar.gz | tar xz -C ${PLATFORMSDK_WIN32}/WindowsKits + +RUN \ + echo "WIN32 ${WINDOWS_SDK_10_20348_VERSION} SDK " && \ + mkdir -p ${PLATFORMSDK_WIN32}/WindowsKits && \ + wget -q -O - ${DM_PACKAGES_URL}/WindowsKits-${WINDOWS_SDK_10_20348_VERSION}.tar.gz | tar xz -C ${PLATFORMSDK_WIN32}/WindowsKits RUN \ ln -s /usr/local/bin/clang /usr/local/bin/x86_64-pc-win32-clang && \ ln -s /usr/local/bin/llvm-ar /usr/local/bin/x86_64-pc-win32-clang-ar +# Legacy. Deprecated from 1.6.2 +ENV WINDOWS_SDK_10_VERSION ${WINDOWS_SDK_10_18362_VERSION} + # Due to Windows' case insensitive file system, the sources reference lib files with wrong cases # so we solve the bulk by making the suffixes lowercase. (e.g. MyLib.Lib -> MyLib.lib) -RUN find $PLATFORMSDK_WIN32 -iname '*.Lib' -type f -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \; +RUN find $PLATFORMSDK_WIN32 -iname '*.Lib' -type f -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && [ ! -f "$a" ] && ln -s "$0" "$a" ' {} \; + +COPY winsdk_rename_files.py ${PLATFORMSDK_WIN32} +RUN \ + echo "Renaming header files" && \ + python ${PLATFORMSDK_WIN32}/winsdk_rename_files.py > ${PLATFORMSDK_WIN32}/rename.txt # Make a copy of all the headers too, in lower case (e.g. Windows.h -> windows.h etc) -RUN find $PLATFORMSDK_WIN32 -iname '*.h' -type f -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | tr [:upper:] [:lower:]); [ "$a" != $(basename "$0") ] && cp "$0" "$d/$a" ' {} \; -# Make copies with first capital letter (e.g. ole2.h -> Ole2.h) -RUN find $PLATFORMSDK_WIN32 -iname '*.h' -type f -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | sed -r "s/\b(\w)/\u\1/"); [ "$a" != $(basename "$0") ] && cp "$0" "$d/$a" ' {} \; +RUN find $PLATFORMSDK_WIN32 -iname '*.h' -type f -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | tr [:upper:] [:lower:]); [ "$a" != $(basename "$0") ] && [ ! -f "$d/$a" ] && ln -s "$0" "$d/$a" ' {} \; +# Make lower case copies of libraries as well +RUN find ${WINDOWS_SDK_10_DIR}/Lib -iname '*.lib' -type f -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | tr [:upper:] [:lower:]); [ "$a" != $(basename "$0") ] && [ ! -f "$d/$a" ] && ln -s "$0" "$d/$a" ' {} \; RUN \ echo "WIN32 SDK - 2019 - Cleanup" && \ @@ -235,19 +250,25 @@ RUN \ # have put "pragma lib" comments in some libraries :( # and/or misspelled header files RUN \ - echo "WIN32 WindowsKits 10 - Cleanup" && \ - (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_VERSION}/shared && cp driverspecs.h DriverSpecs.h) && \ - (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_VERSION}/shared && cp specstrings.h SpecStrings.h) && \ - (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_VERSION}/shared && cp concurrencysal.h ConcurrencySal.h) && \ - (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_VERSION}/shared && cp wlantypes.h WlanTypes.h) && \ - (cd ${WINDOWS_SDK_10_DIR}/Lib/${WINDOWS_SDK_10_VERSION}/um/x64 && cp psapi.lib Psapi.lib) && \ - (cd ${WINDOWS_SDK_10_DIR}/Lib/${WINDOWS_SDK_10_VERSION}/um/x86 && cp psapi.lib Psapi.lib) && \ - (cd ${WINDOWS_SDK_10_DIR}/Lib/${WINDOWS_SDK_10_VERSION} && find . -type f -exec sh -c 'x="{}"; xl=$(echo $x | sed -e "s/\(.*\)/\L\1/"); if [ $x != $xl ]; then cp $x $xl; fi' \;) + echo "WIN32 WindowsKits ${WINDOWS_SDK_10_18362_VERSION} - Cleanup" && \ + (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_18362_VERSION}/shared && cp driverspecs.h DriverSpecs.h) && \ + (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_18362_VERSION}/shared && cp specstrings.h SpecStrings.h) && \ + (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_18362_VERSION}/shared && cp concurrencysal.h ConcurrencySal.h) && \ + (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_18362_VERSION}/shared && cp wlantypes.h WlanTypes.h) + +RUN \ + echo "WIN32 WindowsKits ${WINDOWS_SDK_10_20348_VERSION} - Cleanup" && \ + (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_20348_VERSION}/shared && cp driverspecs.h DriverSpecs.h) && \ + (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_20348_VERSION}/shared && cp specstrings.h SpecStrings.h) && \ + (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_20348_VERSION}/shared && cp concurrencysal.h ConcurrencySal.h) && \ + (cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_20348_VERSION}/shared && cp wlantypes.h WlanTypes.h) && \ + (cd ${WINDOWS_SDK_10_DIR}/Lib/${WINDOWS_SDK_10_20348_VERSION}/um/x64 && cp psapi.lib Psapi.lib) && \ + (cd ${WINDOWS_SDK_10_DIR}/Lib/${WINDOWS_SDK_10_20348_VERSION}/um/x86 && cp psapi.lib Psapi.lib) # Also, the OpenGL headers in the windows SDK is in a folder with lower case letters, which doesn't match the includes RUN \ - echo "WIN32 WindowsKits 10 - OpenGL Cleanup" && \ - cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_VERSION}/um && \ + echo "WIN32 WindowsKits ${WINDOWS_SDK_10_18362_VERSION} - OpenGL Cleanup" && \ + cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_18362_VERSION}/um && \ mkdir ./GL && \ cp -v ./gl/*.* ./GL/ diff --git a/server/docker-base/winsdk_rename_files.py b/server/docker-base/winsdk_rename_files.py new file mode 100644 index 00000000..25b837ad --- /dev/null +++ b/server/docker-base/winsdk_rename_files.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +import sys, os, re, shutil + +INCLUDE_RE=re.compile(r'^.*\#\s*include\s*(?:"|<)(.*)?(?:"|>)$') + +HEADER_EXTS=['.h', '.hpp', '.hxx', '.hh', '.inl'] +LIB_EXTS=['.lib'] + +# Relative paths from current cwd +def find_files(searchdir): + all_files = set() + alternatives = dict() + + for root, dirs, files in os.walk(searchdir): + for f in files: + ext = os.path.splitext(f)[1].lower() + if not ext in HEADER_EXTS: + continue + + path = os.path.join(root, f) + all_files.add(os.path.relpath(path, searchdir)) + + lower = f.lower() + if lower not in alternatives: + alternatives[lower] = set() + alternatives[lower].add(f) + + return all_files, alternatives + +def parse_header(path): + ext = os.path.splitext(path)[1].lower() + if not ext in HEADER_EXTS: + return set(), set() + + with open(path) as f: + lines = f.readlines() + + includes = set() + libs = set() + for line in lines: + m = INCLUDE_RE.match(line) + if m: + include = os.path.basename(m.group(1)) + includes.add(include) + return includes, libs + +def insert_alternatives(alternatives, includes): + for include in includes: + # The current include spelling differs from any actual files + lower = include.lower() + if lower not in alternatives: + alternatives[lower] = set() + alternatives[lower].add(include) + +def prune_alternatives(alternatives): + # remove items that have a single item ( no need to rename them) + deleted_keys = [] + for key in alternatives.keys(): + items = alternatives.get(key) + if len(items) == 1: + deleted_keys.append(key) + for key in deleted_keys: + del alternatives[key] + +def do_copy_file(src, dst): + print("COPY", src, dst) + shutil.copy2(src, dst) + + +# Copy a file to to each alternative name +def copy_file_alternatives(relative_path, alternatives): + name = os.path.basename(relative_path) + dirname = os.path.dirname(relative_path) + for alt in alternatives: + if name == alt: + print("KEEP", relative_path) + continue + altpath = os.path.join(dirname, alt) + do_copy_file(relative_path, altpath) + + +def rename_files(all_files, unique_names): + for f in all_files: + name = os.path.basename(f) + lower = name.lower() + copy_file_alternatives(f, unique_names.get(lower, [])) + + +if __name__ == '__main__': + cwd = os.path.abspath(os.getcwd()) + + # all_files: contains headers and library files + # unique_names: lower case filename to list of alternative spellings. E.g. test: [Test, tEST] + all_files, unique_names = find_files(cwd) # Relative paths + + for f in all_files: + includes, libs = parse_header(f) + + insert_alternatives(unique_names, includes) + + prune_alternatives(unique_names) + + rename_files(all_files, unique_names) From 25fd7c307373acf1ffee7831b2056e53ca0aa16d Mon Sep 17 00:00:00 2001 From: JCash Date: Wed, 8 Nov 2023 11:16:29 +0100 Subject: [PATCH 08/18] Make a copy of OpenGL for new SDK as well --- server/docker-base/Dockerfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server/docker-base/Dockerfile b/server/docker-base/Dockerfile index 67c76607..c8c8064d 100644 --- a/server/docker-base/Dockerfile +++ b/server/docker-base/Dockerfile @@ -272,6 +272,13 @@ RUN \ mkdir ./GL && \ cp -v ./gl/*.* ./GL/ +# Also, the OpenGL headers in the windows SDK is in a folder with lower case letters, which doesn't match the includes +RUN \ + echo "WIN32 WindowsKits ${WINDOWS_SDK_10_20348_VERSION} - OpenGL Cleanup" && \ + cd ${WINDOWS_SDK_10_DIR}/Include/${WINDOWS_SDK_10_20348_VERSION}/um && \ + mkdir ./GL && \ + cp -v ./gl/*.* ./GL/ + # # Android SDK/NDK # https://developer.android.com/studio/command-line/variables From fd693461c20ac9cfea4cf2c4f3c79bb72261f28e Mon Sep 17 00:00:00 2001 From: JCash Date: Wed, 8 Nov 2023 14:13:46 +0100 Subject: [PATCH 09/18] Update to clang-17 --- server/docker-base/Dockerfile | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/server/docker-base/Dockerfile b/server/docker-base/Dockerfile index c8c8064d..985ae206 100644 --- a/server/docker-base/Dockerfile +++ b/server/docker-base/Dockerfile @@ -55,10 +55,6 @@ ARG DM_PACKAGES_URL ENV PLATFORMSDK_DIR /opt/platformsdk RUN mkdir $PLATFORMSDK_DIR -# These packages are downloaded from here: https://github.com/llvm/llvm-project/releases/ -# and then uploaded as-is to S3 -RUN wget -q -O - ${DM_PACKAGES_URL}/clang%2Bllvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz | tar xJ -C /usr/local --strip-components=1 - # Darwin RUN locale-gen en_US.UTF-8 ENV LANG=en_US.UTF-8 \ @@ -79,6 +75,19 @@ RUN \ ln -s /usr/bin/python2.7 /usr/local/bin/python && \ ln -s /usr/bin/python2.7 /usr/local/bin/python2 +# +# llvm +# +ENV CLANG_VERSION=17 +RUN \ + echo "LLVM + CLANG ${CLANG_VERSION}" && \ + wget https://apt.llvm.org/llvm.sh && \ + chmod +x llvm.sh && \ + ./llvm.sh ${CLANG_VERSION} && \ + rm llvm.sh + +ENV PATH=/usr/lib/llvm-${CLANG_VERSION}/bin:$PATH + # # EMSCRIPTEN # @@ -201,8 +210,8 @@ RUN \ wget -q -O - ${DM_PACKAGES_URL}/WindowsKits-${WINDOWS_SDK_10_20348_VERSION}.tar.gz | tar xz -C ${PLATFORMSDK_WIN32}/WindowsKits RUN \ - ln -s /usr/local/bin/clang /usr/local/bin/x86_64-pc-win32-clang && \ - ln -s /usr/local/bin/llvm-ar /usr/local/bin/x86_64-pc-win32-clang-ar + ln -s $(which clang) $(dirname $(which clang))/x86_64-pc-win32-clang && \ + ln -s $(which llvm-ar) $(dirname $(which llvm-ar))/x86_64-pc-win32-clang-ar # Legacy. Deprecated from 1.6.2 ENV WINDOWS_SDK_10_VERSION ${WINDOWS_SDK_10_18362_VERSION} From 2e57f965ac2453e20109ecd8e4f972756e879fd2 Mon Sep 17 00:00:00 2001 From: JCash Date: Wed, 8 Nov 2023 14:14:20 +0100 Subject: [PATCH 10/18] Rename libcmt --- server/docker-base/Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/docker-base/Dockerfile b/server/docker-base/Dockerfile index 985ae206..5bd168d0 100644 --- a/server/docker-base/Dockerfile +++ b/server/docker-base/Dockerfile @@ -228,7 +228,7 @@ RUN \ # Make a copy of all the headers too, in lower case (e.g. Windows.h -> windows.h etc) RUN find $PLATFORMSDK_WIN32 -iname '*.h' -type f -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | tr [:upper:] [:lower:]); [ "$a" != $(basename "$0") ] && [ ! -f "$d/$a" ] && ln -s "$0" "$d/$a" ' {} \; -# Make lower case copies of libraries as well +# Make lower case links of libraries as well RUN find ${WINDOWS_SDK_10_DIR}/Lib -iname '*.lib' -type f -exec sh -c 'd=$(dirname "$0"); a=$(basename "$0" | tr [:upper:] [:lower:]); [ "$a" != $(basename "$0") ] && [ ! -f "$d/$a" ] && ln -s "$0" "$d/$a" ' {} \; RUN \ @@ -251,6 +251,8 @@ RUN \ # and the rest are manually copied (or made lower case) (cd ${WINDOWS_MSVC_DIR_2022}/lib/x64 && cp oldnames.lib OLDNAMES.lib) && \ (cd ${WINDOWS_MSVC_DIR_2022}/lib/x86 && cp oldnames.lib OLDNAMES.lib) && \ + (cd ${WINDOWS_MSVC_DIR_2022}/lib/x64 && cp libcmt.lib LIBCMT.lib) && \ + (cd ${WINDOWS_MSVC_DIR_2022}/lib/x86 && cp libcmt.lib LIBCMT.lib) && \ (cd ${WINDOWS_MSVC_DIR_2022}/lib/x64 && cp delayimp.lib Delayimp.lib) && \ (cd ${WINDOWS_MSVC_DIR_2022}/lib/x86 && cp delayimp.lib Delayimp.lib) From 006a4d1d531adcde4de34023704d245062bc2361 Mon Sep 17 00:00:00 2001 From: JCash Date: Wed, 8 Nov 2023 16:42:56 +0100 Subject: [PATCH 11/18] Fix for libcmt and msvc 2019 --- server/docker-base/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/docker-base/Dockerfile b/server/docker-base/Dockerfile index 5bd168d0..3521219f 100644 --- a/server/docker-base/Dockerfile +++ b/server/docker-base/Dockerfile @@ -236,6 +236,8 @@ RUN \ # and the rest are manually copied (or made lower case) (cd ${WINDOWS_MSVC_2019_DIR}/lib/x64 && cp oldnames.lib OLDNAMES.lib) && \ (cd ${WINDOWS_MSVC_2019_DIR}/lib/x86 && cp oldnames.lib OLDNAMES.lib) && \ + (cd ${WINDOWS_MSVC_2019_DIR}/lib/x64 && cp libcmt.lib LIBCMT.lib) && \ + (cd ${WINDOWS_MSVC_2019_DIR}/lib/x86 && cp libcmt.lib LIBCMT.lib) && \ (cd ${WINDOWS_MSVC_2019_DIR}/lib/x64 && cp delayimp.lib Delayimp.lib) && \ (cd ${WINDOWS_MSVC_2019_DIR}/lib/x86 && cp delayimp.lib Delayimp.lib) From 94122038bac60f6f656e3a48f68d1987dc2dbdba Mon Sep 17 00:00:00 2001 From: JCash Date: Wed, 8 Nov 2023 16:44:38 +0100 Subject: [PATCH 12/18] Rebuild linux test libs with -fPIC (and clang-17) --- server/test-data/compile.sh | 2 +- server/test-data/ext/lib/x86-linux/libalib.a | Bin 1088 -> 1546 bytes .../test-data/ext/lib/x86_64-linux/libalib.a | Bin 1472 -> 1608 bytes server/test-data/ext2/lib/x86-linux/libalib.a | Bin 1088 -> 1546 bytes server/test-data/ext2/lib/x86-linux/libblib.a | Bin 1290 -> 1748 bytes .../test-data/ext2/lib/x86_64-linux/libalib.a | Bin 1472 -> 1608 bytes .../test-data/ext2/lib/x86_64-linux/libblib.a | Bin 1754 -> 1938 bytes .../test-data/ext_std/lib/x86-linux/libstd.a | Bin 47540 -> 61874 bytes .../ext_std/lib/x86_64-linux/libstd.a | Bin 55844 -> 68110 bytes .../a/defoldsdk/lib/x86-linux/libengine_foo.a | Bin 1094 -> 1552 bytes .../defoldsdk/lib/x86-linux/libengine_main.a | Bin 1114 -> 1572 bytes .../lib/x86_64-linux/libengine_foo.a | Bin 1482 -> 1618 bytes .../lib/x86_64-linux/libengine_main.a | Bin 1500 -> 1628 bytes .../ext/lib/x86-linux/libalib.a | Bin 1388 -> 2176 bytes .../ext/lib/x86_64-linux/libalib.a | Bin 1964 -> 2156 bytes .../ext2/lib/x86-linux/libblib.a | Bin 1634 -> 2546 bytes .../ext2/lib/x86_64-linux/libblib.a | Bin 2370 -> 2562 bytes 17 files changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 server/test-data/ext/lib/x86-linux/libalib.a mode change 100755 => 100644 server/test-data/ext/lib/x86_64-linux/libalib.a mode change 100755 => 100644 server/test-data/ext2/lib/x86-linux/libalib.a mode change 100755 => 100644 server/test-data/ext2/lib/x86-linux/libblib.a mode change 100755 => 100644 server/test-data/ext2/lib/x86_64-linux/libalib.a mode change 100755 => 100644 server/test-data/ext2/lib/x86_64-linux/libblib.a mode change 100755 => 100644 server/test-data/ext_std/lib/x86-linux/libstd.a mode change 100755 => 100644 server/test-data/ext_std/lib/x86_64-linux/libstd.a mode change 100755 => 100644 server/test-data/testproject_appmanifest/ext/lib/x86-linux/libalib.a mode change 100755 => 100644 server/test-data/testproject_appmanifest/ext/lib/x86_64-linux/libalib.a mode change 100755 => 100644 server/test-data/testproject_appmanifest/ext2/lib/x86-linux/libblib.a mode change 100755 => 100644 server/test-data/testproject_appmanifest/ext2/lib/x86_64-linux/libblib.a diff --git a/server/test-data/compile.sh b/server/test-data/compile.sh index f03f222b..0588f7c0 100755 --- a/server/test-data/compile.sh +++ b/server/test-data/compile.sh @@ -240,7 +240,7 @@ function CompileLinux { RemoveTarget $target mkdir -p $(dirname $target) - $LINUX_GCC $flags -fomit-frame-pointer -fno-strict-aliasing -fno-exceptions $src -c -o /tmp/$name-$archname.o + $LINUX_GCC $flags -fPIC -fomit-frame-pointer -fno-strict-aliasing -fno-exceptions $src -c -o /tmp/$name-$archname.o $LINUX_AR rcs $target /tmp/$name-$archname.o echo Wrote $target diff --git a/server/test-data/ext/lib/x86-linux/libalib.a b/server/test-data/ext/lib/x86-linux/libalib.a old mode 100755 new mode 100644 index c8bbe64b312d676103f44b09892eeaf287a9d17b..396217a29872513e9b9a9015ef0a68a6f7e42c5f GIT binary patch literal 1546 zcma)5-D(q25T4C$YmC)u>4i|y2oWkZCqIOeN|FAg?M<+tDTp`QOKkV?@T z5ux}FzJWJBK(R04rMKdxLY(jH9`{%(c3{r@>^F1f%*@_hb^KQ6QKpdnn~Itl>H3+? zR;miHpCO_Y^B1uFyz2D2O}iiVx?QsEadla=-M}8U?4T2R2f`Us;p}B9)jwoOy9>$l zoHXC-df`|M3YmglDreA5z2@agMdmM+SIW^v` z*X5!pRz&%J#no!mi$6=GnVib zV;%A5k^VM|zE58j*B}^EY3#2K~P4G2R;luHbR! zM}gBii0!r)ilILkx_)p-0?FNu{nB^(E{V232!~wFh3Oq5Z)j+|2NS}sfw3dtJIvS% zHO*Dl^}ef}SztdVy2cE$xJQ@)a z!j0LX_ivs9RR6Ghz@Z;{E;i|F%)FX(g&8=+A(!eMt8~JFH7GHucVGu}T#oPkpg=4Y F?l%}TqkjMZ literal 1088 zcma)4PiqrV5T8xf61Rf3^dQ8;1_DMfFK@$ki6TKrVk#6Vm0Y|eo4Ar-HYv$lh*IiR z=%pXQLl3?6L-Z5*33O)n4SfkpJ1{%{e(yK)=56UsxEPI_PR(5xX@r??eqFa-XTZP# z01Nf1|EUp9C&PZ6OeYhlZBp`q|5&fVg@Hpf)m0;?PA9WuCFV7!W)6fvGc+d)d_SdW z1dJFsKRSo+EQ?0W#DaV}Fvpj=zrFFg4oE4X#(1u~GYV2^u!KL+cxU=<(P_D}5d1oO{yjTZMWxt$cihTnfo z%=+YjH_4f0jPo1ugN=A=BesF(AiGPOq4kT=$qB5#sEhR+wG+#4u?mN1)grTF_EfY| zAU=mG1TkDLL5${c9L+E{o2y84KlG|g6^_1wSVU71jr(5~VH_dnJ*9{^+7I7?-i+rb z3f^5w`@D@N6%AqBbIcV`@4~%A44sjvB*Yh_UiP6H>AtpE7C^D1E%$w|ar}COqaG}_ zb~l%pLGj^Z6uz5}{>(97XyLwOxhIu=pFmN+`=9l|5S%Xo**;3C$&p_9(G^sSNq|~s^ z$Ux7)M9)Z50W8h{0W3gD0Ek(E*xfIbfr)|P07#4(h=E{oKBFq5*knd#<;exiER**z zPGV%AypU0JvJaCAP`r?-RxmHWBvmgxuT-y~D8C@JsHAf88>Ya?4$KNb`9x-O#xS6I z>B$}}Jd+PFOCWfYSR^>ZAeJ!bOjcwuXKX?!WMKhX2I6EHRmpO`h`rBZM0Qv`v0;2djkW4ygPMD9r_=IVNvq)n=S9`5~)1 E0E6~2@&Et; diff --git a/server/test-data/ext2/lib/x86-linux/libalib.a b/server/test-data/ext2/lib/x86-linux/libalib.a old mode 100755 new mode 100644 index c8bbe64b312d676103f44b09892eeaf287a9d17b..396217a29872513e9b9a9015ef0a68a6f7e42c5f GIT binary patch literal 1546 zcma)5-D(q25T4C$YmC)u>4i|y2oWkZCqIOeN|FAg?M<+tDTp`QOKkV?@T z5ux}FzJWJBK(R04rMKdxLY(jH9`{%(c3{r@>^F1f%*@_hb^KQ6QKpdnn~Itl>H3+? zR;miHpCO_Y^B1uFyz2D2O}iiVx?QsEadla=-M}8U?4T2R2f`Us;p}B9)jwoOy9>$l zoHXC-df`|M3YmglDreA5z2@agMdmM+SIW^v` z*X5!pRz&%J#no!mi$6=GnVib zV;%A5k^VM|zE58j*B}^EY3#2K~P4G2R;luHbR! zM}gBii0!r)ilILkx_)p-0?FNu{nB^(E{V232!~wFh3Oq5Z)j+|2NS}sfw3dtJIvS% zHO*Dl^}ef}SztdVy2cE$xJQ@)a z!j0LX_ivs9RR6Ghz@Z;{E;i|F%)FX(g&8=+A(!eMt8~JFH7GHucVGu}T#oPkpg=4Y F?l%}TqkjMZ literal 1088 zcma)4PiqrV5T8xf61Rf3^dQ8;1_DMfFK@$ki6TKrVk#6Vm0Y|eo4Ar-HYv$lh*IiR z=%pXQLl3?6L-Z5*33O)n4SfkpJ1{%{e(yK)=56UsxEPI_PR(5xX@r??eqFa-XTZP# z01Nf1|EUp9C&PZ6OeYhlZBp`q|5&fVg@Hpf)m0;?PA9WuCFV7!W)6fvGc+d)d_SdW z1dJFsKRSo+EQ?0W#DaV}Fvpj=zrFFg4oE4X#(1u~GYV2^u!KL+cxU=<(P_D}5d1oO{yjTZMWxt$cihTnfo z%=+YjH_4f0jPo1ugN=A=BesF(AiGPOq4kT=$qB5#sEhR+wG+#4u?mN1)grTF_EfY| zAU=mG1TkDLL5${c9L+E{o2y84KlG|g6^_1wSVU71jr(5~VH_dnJ*9{^+7I7?-i+rb z3f^5w`@D@N6%AqBbIcV`@4~%A44sjvB*Yh_UiP6H>AtpE7C^D1E%$w|ar}COqaG}_ zb~l%pLGj^Z6uz5}{>(97XyLwOxhIu=pozy}YO}nWSSAnj6UkQYnfA zMJfJ)KOy)5Liz!H@X-(O!58sSA?`IZrx`=NY*@2z>+Exxy)UPYR;heD7z_U{agXcR z-fuXZN=ZT?NJJ{*lZ5_ou~@AXbz^(GQXyUME~dneY3a?9Zk0RrU14-da%!C_b7G_0 z%i@2~iA9+x1hG|=w}@6N^-fnbV!@dA@J#f&-dm)SNxMuUdDFd3A^1F(UsV)^ui}Wp zR~vdnRos*%X@BQvk~BL%&i?nwi$A{n91I3ySaGl!@gHO(0p+NV#76IHV3=fQU`1wu zH+?(YI}G&>1CRO#{z#wJGMQW9xvgTSZgs*-A}Qk0M920L&lch$o)in$oj8u+XG}20 z7;E>p$Vc=MF&ym>2Mo1eZ7yc`v$^oTlAMYV4;B&dWJ9*RnVp~IF+ zr$>CWU@iY( zWjU`uSY6%7ZR(rLEBTy$ywaHqo)QC-dW$lqbakH#HX&E(>#7?WxY4U0QTV65qoQI8j;qRm80rVemiGiMz zoswod$B-iXafSovmOF0Z9lsHJAGO%DYoY#C2G+PEPcPW^imZ2ogW&&*huOlKacshZ zdfwTQ_3|8t4L;;0W8Su$4|2ektDPv(dug~@)-%~h_q*HD2e#$xgDTIk&oojJbKuRcOlL%$*ZqrK?f!?znOXS@!sU}ZExJ}-Z3iXGFb{tboFbR z&LW^`5YZa*7jWZMwbk#n8eXT<>ybo*u+ONnT12UFl4@6_wP_$}d0KVL{oXK~ic!U= zEILS{RH*jqI!+v5Td86;jSu%8-PbgY8%{{04E;q!4(4HU;_nvaXq^t8m-K^rDXV=u znjPn6$Jr<-6~RA$M^QAJ7iRO^5$)7!x6G~GRyYho^M-JQRd&M|+3#&vSdOr*Yl*|$ zwrtmOt(!y_;yOgy+h?S`%W9iBUH`}p71&-(eP>f?vb30iFEUdtU#R6b>iJ?lZ$5yo z!@5N3Y&!jlROj;K#5a*q-Hev=W$5&Z|I7+LMOX%ce*EMMg%>nh27*V%~pf5l;Ua0U{Dd~U2IANat$ma$B%M4zORN?G@D z8khbubjbLr5-YdoA=}h>zjA^C+b}OSNX~nXbvXm8^qu2gKuJl~g_Jen`oa8}89Rr2 VKtAM0O*P*kA58vhb}-3&e*l&ckO%+( diff --git a/server/test-data/ext2/lib/x86_64-linux/libalib.a b/server/test-data/ext2/lib/x86_64-linux/libalib.a old mode 100755 new mode 100644 index ead9a956761f9031026bdf43382bbaffe0c08b22..c0c6705008bea5d2618abb3a40ccbc375f5d0afa GIT binary patch delta 362 zcmX@WeS&AgU1no*vxyH37!xK7G759>FmN+`=9l|5S%Xo**;3C$&p_9(G^sSNq|~s^ z$Ux7)M9)Z50W8h{0W3gD0Ek(E*xfIbfr)|P07#4(h=E{oKBFq5*knd#<;exiER**z zPGV%AypU0JvJaCAP`r?-RxmHWBvmgxuT-y~D8C@JsHAf88>Ya?4$KNb`9x-O#xS6I z>B$}}Jd+PFOCWfYSR^>ZAeJ!bOjcwuXKX?!WMKhX2I6EHRmpO`h`rBZM0Qv`v0;2djkW4ygPMD9r_=IVNvq)n=S9`5~)1 E0E6~2@&Et; diff --git a/server/test-data/ext2/lib/x86_64-linux/libblib.a b/server/test-data/ext2/lib/x86_64-linux/libblib.a old mode 100755 new mode 100644 index b44713592cb462d2121e81aed2adcfe142691c1c..9124f93851c9fd9898835853bd469ff4f9c0b069 GIT binary patch delta 562 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 St(2Fx!TIhu*JEXylKVfWwyY}v diff --git a/server/test-data/ext_std/lib/x86_64-linux/libstd.a b/server/test-data/ext_std/lib/x86_64-linux/libstd.a old mode 100755 new mode 100644 index 043117fc1195fd34a0ff44b0b20cf66206ca3f80..c773581cca0b2ebd5b3a5c329057b0c40fea6e45 GIT binary patch literal 68110 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 Mp3nWDNURm_4;VS7%m4rY literal 1094 zcma)4%}e7@5T9sv>1Ow!izn+Lf}jib^+nQ9MT$^A5M&R2oNd~TR&0{ezCtVFUKjS_ z)tkp<{|*15J?&9vk~j2O6djn%{APY{X5PFkZic;9yXKVL=OPW5`{vhmy($wL4ggrF ze|OXLXcRZo4wNU$G5Hm{=5wOqM9KL@5}lrjFcfLoDVrl9-Gt_Bfu9$v z23)k^{Mh z$Wk!Kkayz+Li)m!-|~dJCcQugavkQl*VQ3d*9EKi#kPN8pBaoV=p3!?B^gf&V8g#h zlkgBf0 zo{EMF#E(#gAe#L?h*lcMQG&4~Rgu{Hep2eIuyqNd7j;C`K0WJ&afCJBDMjSbj`$|@ zZssm|e~X&O8>t~Sg?Y;uETF!{TSX3?k*Fk8FUY+7Lpjolws{mlv7;^b-Pb&RLE=#l z7F#ADW=d;aVr8Nfm8(9I3-j(D%6LXULqQxxo~k^W0I(i6FIh&q6#=6 zB*Z`9hj8FfsegbUz=0!I#1W)0-`b0ps)&v>p2vPOyYujsMKAK(53I8NH#wS_>iXBV zZ&wvy%Oauz^JlR8v{DJeRwoSHuGa}WjfPLIJG`?XT0!jgeK&3=;g0ZzR6cs8O85^s zzn~7bEbWF8=PvDb!el6VWy>n-59a{g)GJu1rUg`PIawuJ)~mI8%`gluBPD}O$}OS; zRLNA8-#MD1bMkzg?H^N@et!Ek8jZ#f@ezo_cg3rRw7$A}&z@^;Ct;k}cSTh=rAi{L z%FB62I8`x!J@r$OgC?2BnAaaR(bNO@Oy&#BAmhbjGWI8o*~wz@EnhXwzKilC$H3=g zKExkKdR;~OKGHF!9B1w^<;!#%FU-j#bRZ{_CUS!{lTIJ8u`)TCbSgJkL)Xt|9@IU< z@42QSW(wnUU$ap!X)7W8exFXhi0*oQV`aJSZq#Z|);8VE<(2xHi~&*rn`IoOvaPfz*cEXwj7dE6Vvof3U_jC#j{h5k-|KdRknv$J4g`AQaC$n2&BKlFUA4KsU2_z5N?(@j&1|(WhFX{7ZPE2nYsrri`)Psp(_rTa0@MUJ~ ziJI;r>uL{Km1mH%%$V>JGiaK7gqa{0t1=hzV}{6weFimB@#m{{@&z1 zVM0EA-&MXk`=J95+GM^dwe*8Ca5Iysm*}-pGO6+fY-3}yYb8$ogMg|x?6Zy-h5Nwz z60;(O8?r<1pUnZ&>_h*sd%&R|dM-BU3-ecIUQIf~3>@N+OZARb`ow{cpk$=#zz*m* Mhwpu_Kr9vRH(wvD5&!@I literal 1114 zcma)5%}T>S5T4j7HF{9-rib((Rt@*Ni&jC`3+i}yKn>M79ovrSN~=Xl zThkx5_jfdn22MnSR6IV%FS2CEi5yHo2Hwbjhuv~{-N>EPdtuZwR)j6gywi&#>)vvN zX$#9-N(x5Nv>ekh*I-r>Yqy7>-DR}7$#nV=drV<|Ue?B>9X8)n0;J*NQ>_n94S0(Y zwTy9UC>|Y(2fL=Q!?Z+DWrkiwS%L7{ZTM-$h&510sJ-ak1d&@u8+8)fU@!9f5r}g) zazWI)T@YR?2>cLpVJq^*?!igE8@b*Uh>m|P{6_Vn;|4x*{!``GSKXQ&ADdEn+T%`WJ2)F?7a6B_Td1_L2|PNLQpyvH)#%q~*SQ635#l9Q9yHOJ^JH zIO>*+kCA}pr5xRxa1_%{`3~s98RCw}k-~k+a!)EfqduY1?@c_!H-$?4D&I05T)-R) G^L+taL~xP- diff --git a/server/test-data/sdk/a/defoldsdk/lib/x86_64-linux/libengine_foo.a b/server/test-data/sdk/a/defoldsdk/lib/x86_64-linux/libengine_foo.a index ba82d6f410b4056ef516a6a230a3c0b5824ae9e2..de5daa657104196896de7f053bb0b88429e65a58 100755 GIT binary patch delta 403 zcmX@beTiqneP&||lZlTEWHOi-;J^XQa$w+L;AZ&DFZXM*7Ndf*rJjkNfv#a`QfXdE zsbQUwfu4bho{^>kSRAUA1xO13F)I+e`-L(9%{%}SV+LX%m|V!H$|yEjkXd>1F2-q$ z?2|t-icbz;QUZzld>IXBfm}2A#>;Ear?&U=>x&0<5k;arVjmEYge$lUK9IOU45Ej6jU!OR&xr zlNYn7yG8)nAa^=|#Sp{`kQN}2fKUvaK$;zhIiP%)IM`&M-NK?bpfVqzG#8NOoLtVT b&3OW9mK4x0@~nbDab}(YFKAz zre|QHXK0|Q0G3cNGB7kVFf*{6JdshAQD|}?v-0FyjMFA}Few3ftC?CSJ2U%F?q^m8 z@-{P@GX_mQ$S6LUiA4j-a$?co41!v2Ho2I^oUsF>LXZ*eAPB>2azCp$P)?gw-O?2( z!~(<)5Ggph0jfy?D#8h**?^b>%9ohT%_gsS0;(zmDhi|EHcswll^5Ls6}|zbxqvjs Pp6Ot2Q!l diff --git a/server/test-data/sdk/a/defoldsdk/lib/x86_64-linux/libengine_main.a b/server/test-data/sdk/a/defoldsdk/lib/x86_64-linux/libengine_main.a index e4bea84f7992abb5cb971ad27cddd8662461b080..9451cb51a7096c824bc1f29f31bf588b52edbcd3 100755 GIT binary patch delta 401 zcmcb^eTQelOJ-vWlZkH(>NA)a;J^XQa$w+L;AZ&DFZZjnM&*x3XNk&(9UzIr4DQa( zRtg%SNu_xur3#jMCVB?ChNWPhVV#kIo`H#;ktRf(fq@06LjZ_bf!N(IlmTeX0gxCo z5QBgSgqqyUD9b23c_HIYMs^@6Iyr(#1<0>u>J`k(FGNPD^MJ0K8rAC15|~= z9;J^XQa$w+Q;9!_+!6>V4s%N5Spleo|RGL>(YFKAz zre|QHXK0|Q0G3cNGB7kVFf*{6Jb_Vzk$-X`v-0FSjMFA}F)0CgYngf{`!f4ap2@5X zjIyRF2 zTQZvK_w_cN&Spjf#$t?!HbH-`Rr6~0m}}Qv^QPw%-Eze#lW8`_$HbEDn$@D|mOST{ zuo`5UWv6b}+~UZWyfoX%1CTP-yn#(tM7Cy zmy>C-<6}X-#n}Dn{7fhm!ghTLQJ8uj(d&qh=cE~;os^LAE%2Eag?`_$@7I^#ola*H zBdw{yNSmRH&96}jKWH1kn_mYy?qFIX%@2vzQ()9ehTgZD+!qZZx!aAQE|qttEh^WQ1r}V25BcQ1(wUHXV;Pjmdc8d^|N3PoIk? z7UI!~cARrF_d0YAnuV_C&ULvw*F)w&f+LXgzwn_h7PwubpIwB$b-Dp`!g6;#BrJEY z`Buv|S4til(;T{yGtvyG^_0=-pAT=Y`GYMpmHX>Ok1N44 z?{*MR!y35E{9f5E2KF&qO!|^7AG4^huDDhK)~)%rq{Fm6a9SK`y7_+5%5)xb9lTTYU zEB$YI1tv<<6|O-PiZV;(cf`7ucM6!|@p#4Ck3Qc}^(v;&zXw&KZtq?Ie6!C4fd;PC z74&&t{+@6?&VLBXV;Ez3@0)I`@*M%f{D1K>;K=nEehSXVb16~z@&I(+NBI4CrGUqI zSw2CJ%AVhF4pzQvDmO=daHENeJpjh_Y9a`=g%n6 z5HPOu094gk&jpy?0XPH2b0Itx$>VPU=TbFBS2~{T_zmY_;X9%8e!_VpBYvZJe*pii B9>V|t literal 1388 zcma)5-D(q25T0$en#NL8M8p={VwH&GWVhL_RYZhVTcPzrsDcQ|CT^S1WK*(dAr;XJ zZxp@o6^cGcv3&p^!&|{iA!)Qc z90k-0M3iGbR9t=PRAdmz>Si1^WUCvt$gj4-DCkL6wgO4z(d)F^{-ipK%33SZI3h()WSxJKh-#9b+F-j?5uoEk`Ft@W~N8PRfG!p5@M8 zWU1Z`d|CSf^_G}b4e*mM8aq4mx0TzfuJ1nf+i{RBA7Np~@@ZcU2GfiouV!}i57+|c z`D6BwYndbw?RKPJXDNHBY$~l6w1o`%lEiag`XuU6M558{bb^p=VOIuX<>5vtl73^G z1fqjxb+hMp0#5#)bcy3IC)HiN?}qj*d?3^{!F-n)^n)EmmZ%>wm=?Ezu4GtEbDObF zD&KWBBK}`-N&h$w5`=tSqNNA&fw9~wH#~bdG*Z5Gwn5K+Mf%M8Gc8VS-2=Ai_0I4I z7ube+v1h8@Gpwr`SS6R^oNQvx;J^XQa$w+P;9>a8FZZjnM&(bpi^`wFAdW}#8wsEQ zPiKh=2T+is^Y{ypa*u9N5Y;Wjc*vuh6~ycmnBdWTL;^(qLHz+eiZJ@^!I_&69OKuoB(I#fK4k7M#i7TL)@Ow$-SCL1z| zPJY0oA_+4|3aCnmfe{!i5MVl4mRX+F637t%sudP=hRQoZ<<%$qGHcbxyZiV%Ir_x= zySW9shQxyECZ^b9iVby@L?yzcbu7sMaGntpoobf7Hg$%0zs~1q5 zeR3h2Fy{@Z3WdqNZ1RjrlXKa`f#$WcsWZk-)@2n}EdWLw2*Bcm3&`exVvsl}z8FBd zCOa^(h(<7ixC{&dP?{Ua=A0bKuFbgum=Hj~6X;@jM#0I2tim82oI9ZA=YYfknX{x! delta 644 zcmaDOu!euaPiAuilZk%}>Q^u`z<~pp<-owhz{${Aqw=TQMdi<7kLEWVKn_c%iApz% zO6TzxAVr;rx>-Rq@N+1F#9?Qou*^pIsatYJ4$x6&hlAIuMAdmuLAqGaE#~?s^axAmFpe|I@1S+aD zc`372eR{laWmsZPX(~fve0pjLL=I#C2rvOL2N3`H4*_6{q2gRf;#xp92!PZhi#vlw zG0pLYivuHsYjP%wG0?|zS;QGlCU0d4nk>Z{G&z%1nK5i~FRM9Y$K<1|_KeejJ{6xV z!=?dc#jt5`PJRiTOyY5o}87SSJxg7o}sUSlhcZS41? z1finH9Rg;k1Oo#DLSkTIVL)Q3aHdY3SYcr3kf9X}NK`W4cYSaD+9su{IMRLReCK@k z+-hVHD-5H9xQ65^C^HW)B(#qG z%)*@UmJ^jmy)uoNOgHMyVAF2RBxcMaH7N|k^*C89D#q+=UQ^16PnJt7mSv$hBe5hZ zVQ<3$wNuy&!flxxqWXq93G;lzm$vhZde0)&-eD?DzZI@Ak^DS z4*gtKd3w9){ul5`KV$vU@6q}+eZ99EfA8R)laKVg_4p3||4`3!#KbafI>f++5 z?9|0d(DZ}s>vqx3PZt7(3Rh?IcD`uOzB2Ml4E>U5Ea&Rki-L08pf8HXoD}P$cf|TQ zZXHX;Vml~h8oo&t5qUxDDd;>J@hSS2Q}JG8F_k`>np{d{-%6z~rQ!>N6mygNKHA%8 z1++)GXCC10fU=GDBzb=X?`O3C%F8wUjz-~}DD?fMtg%nS`-&&YNKEbyjZGa@RU3Pv zs;XgpcnlPur*$k*b!x+ykHc7^^6VJEimII(yQ1>U7^rx7w&X{|jL0=lV15(22lp)l zMowd@OytO@=Gw>laL>#hlmD)cQDq`=X+e|2`ZFFto4q5x3T*a=SSoh4-Ik|#;GEUc zxzh_J=iJK5`Q;1Fg@x0lW#_4$J)Zr@Q4v-)|f^USah zeUv-^V@8a90uJ&GuV@C+L<94{v=3wdDdd?P#D-VWw&Bekz^iE<^HS!)dv#>0FY~c| zsI_w9Q=>B^25!U0H$_iR@yx%0bTiklV6%_mT?2@jBq83Hu)}pu;ylm6$2uo9k97;@ r0+byjF2l()fUBv-#Z^+dOpO8MHo!F+TFex9roy}>jQhPIK^xw`&tq~2 literal 1634 zcmbtU&ubGw6n@*Rn#NjM5j|9Ng$gZ_$*zq{Ek(svTcH&Z+JXw{Zn|xP$)+R|NTukZ z7sVd@6BPYJMEwIiOAj8!n|C3;Z+FH_tAgl*H{bid_vXjT%;wy5&@5N37F+sqn0eKx8t&`HsUIUrE1)Ynv#Q!NK&9_ zkWeZdJe1z@59k?Z3TxFc-=aMK2H}AI-<~{a&;TDDGj;9IdqU-st?_TC<$y`S3(Ot5( zv)0IfZ9nDahFCkz4$G#H)Vhi%x!J+&{Ggra^Q@1upG2*puQHutKUm*kZJFJyXS&bK z-`J*aT{F4=28eG&U4kmgkZqQ87LT-N89LG<9A)UxPX#lFSs7Lp=>It1IQm13UcmE= zx@YhS=DJt#Y38~|a0*3vbCdq(qo8BFW?w(iDMpJAb4KB~(s2gpR~5gd_#K7!l^!YX zfcFvM?E)7Rt|{DBNTRh>mqExVn<-Xw)QoCEMjc6FEsz0;u+<__Zq(~h%v#)#k(j%^ zlyAwP{E!5yqe^ML8PsuzzqGSlhxedw5$CNLbM;#pVU2$tx~6iw+!K1o-xO+ax46Ue zitAVNk~wnPbbNsY)a$x8xx1Meyo>;K7@hqJkd%GkOqFyh%Z4HZ$$(b{7O4csnz{otgKw@9l*fdNp5|49Aqi z5|`YLEk6}yY>WePVIjnEXy3frx^`#tzFw-ELVJ+7W}7uzTdP}nyI8S`!qAFV&8*sB ztedvb+0`9a#N318E`4+|$uDwYqf|7ajj>T}G!-ost$IVP#KPg2JS_;8U3q?^sgzSH znH=pHN-q2?ot^6n1YnXK35ZE?;4u~A)v*J6$}y+JDG?DrPoMwQ+8W+#-yGg+?gT!d zpJ{#_1Qu!8!y(|I)~8*}$h6O*Y7Ye7XWCA=R^N7}`El@25+p>9Bz!p%_P=YN!J*C1 z&Q2&J%SPR@>&m#AQsdD?-SHAnlW{ekQj?cETy#TtA2giD{M}{ICBzQ0AT$)G9_YZ6 zMG0@L%sGbvAZVjtY}~PgxQ;s0tCV^}4$lz3MEnu)9C0~*5Lkn_98bto z;a+!(AHTg`20gz7oFmWja8}S+mBS3ZpmUJCc+XMj#D{#i^bt}7R_K?;gL{C|4{bmi zKd<#LarT|{0~UqG49tC*1qi8$*D_ATNi;#_Bu_-o=EFAO!mu_6BM;?U-^3p3MM zZDDTiUV2Genx4s~HSg<$>*Kuf%G&$g5taJC0{Vo+$9?z;ad#cfC%)+u|H3E!r4N7W zQ|Fyeyh0q#8=kp+Ns+~z_cH6^ypO9c&ilCK;=GSSt!DRMr`5NwQg!Ua~F6jd?+j*xSJHZj!%Iti$;VI+F1E zF*3lwuH5-6)c-aIl6L1m1n#weZ)lL@&5M8AE93WpI1(B=l=nE8AM?K literal 2370 zcmb`I&rcIU6vyAvDy0$v#sdkOtfU%@cDpU>f`pJp5Qsq}CXi@i+TF51wLeI^O$s4; zz)Qo0#G`lr298Eey!vNwAV%*b_}=V{JeK8zj|}h4XTI;v?##~g_N3D&ZA>LI`dKqs zH;DOvT^}D;f?^T?u44NY)z%BowpN@<%Y(wJ?5OWG{lZ$SR`SdBS{d9zxz_X=J_hTa z502_Oq6?YuL#Zh*@VT5CC??%X*-f{{?SgHkE9F|NZPYW#WQM;Mig}m6pKV#9RL&fe zHH*pjPZnmoG!0)eFb$^Qw5KS*;FZ%jFTyjI4Pt7|?TO);4YP5#^zYeDvD(3((sA+E8zIVjmZ(AK6V3p!Eh$XiXX4 zCqL8Izt)!!d|vWl$zMxel$`4ak+mh~dWj+(?Oh!HoJ0-AB6k)bhJR5O!%9&W69?n` zNDR8qLnJX^ACFX!a)8aNW*R_#ojs>o)0E_@FV+cJTJkaUWMZArk7A=bFA1V4{UpZ3 zKL~oN2iGWVZo*{_wy1bZ*6l*ygYEbvuse(=7^mkaBR%J{f(D$|S!A5+-!RVg4aT{C z`vU%vabD*W Date: Wed, 8 Nov 2023 16:45:43 +0100 Subject: [PATCH 13/18] Update integration tests with version 1.6.1, and remove 1.3.6 --- .../test/java/com/defold/extender/IntegrationTest.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/server/src/test/java/com/defold/extender/IntegrationTest.java b/server/src/test/java/com/defold/extender/IntegrationTest.java index 00a7cd6a..107bf1e9 100644 --- a/server/src/test/java/com/defold/extender/IntegrationTest.java +++ b/server/src/test/java/com/defold/extender/IntegrationTest.java @@ -115,13 +115,6 @@ public static Collection data() { // "a" is a made up sdk where we can more easily test build.yml fixes new DefoldVersion("a", new Version(0, 0, 0), new String[] {"armv7-android", "x86_64-win32"} ), - // Apr 5, 2022 - //new DefoldVersion("06bc078e490fd7d94ec01e38abac989f6cc351a5", new Version(1, 3, 1), new String[] {"armv7-android", "x86_64-linux", "x86_64-win32", "js-web", "wasm-web"}), - - // At 1.3.6 we removed the support for iOS in the base container (minimizing the container size) - // 2022-09-22 https://github.com/defold/defold/releases/tag/1.3.6 - new DefoldVersion("905234d8da2e642f1075c73aaa1bfb72e49199e3", new Version(1, 3, 6), new String[] {"armv7-android", "x86_64-linux", "x86_64-win32", "js-web", "wasm-web"}), - // 2023-01-30 https://github.com/defold/defold/releases/tag/1.4.2 new DefoldVersion("8cd3a634b13f4db51a37607bf32bf3a3b362c8e6", new Version(1, 4, 2), new String[] {"armv7-android", "x86_64-linux", "x86_64-win32", "js-web", "wasm-web"}), @@ -131,6 +124,9 @@ public static Collection data() { // 2023-06-27 https://github.com/defold/defold/releases/tag/1.4.7 new DefoldVersion("7a608d3ce6ed895d484956c1e76110ed8b78422a", new Version(1, 4, 7), new String[] {"armv7-android", "x86_64-linux", "x86_64-win32", "js-web", "wasm-web"}), + // 2023-11-03 https://github.com/defold/defold/releases/tag/1.6.1 + new DefoldVersion("a90c50928623cf23b3687a7eec05972d11427202", new Version(1, 6, 1), new String[] {"armv7-android", "x86_64-linux", "x86_64-win32", "js-web", "wasm-web"}), + // Use test-data/createdebugsdk.sh to package your preferred platform sdk and it ends up in the sdk/debugsdk folder // Then you can write your tests without waiting for the next release //new DefoldVersion("debugsdk", new Version(1, 2, 104), new String[] {"js-web"}), From f0656fc48ab98eda71422b0843aeec9a16214af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Wed, 8 Nov 2023 18:16:53 +0100 Subject: [PATCH 14/18] Changed EC2 instance id (#324) --- server/scripts/publish-darwin-prod.sh | 2 +- server/scripts/publish-darwin-stage.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/scripts/publish-darwin-prod.sh b/server/scripts/publish-darwin-prod.sh index 5556c7ef..9c5d1fe2 100755 --- a/server/scripts/publish-darwin-prod.sh +++ b/server/scripts/publish-darwin-prod.sh @@ -7,7 +7,7 @@ VERSION=$(date "+%Y%m%d_%H%M") PRODUCTION_VARIANT=production TARGET_HOST_URL=build-darwin.defold.com -TARGET_HOST=i-05303831267023ab0 +TARGET_HOST=i-05739d9de35a320ee TARGET_USER=ec2-user TARGET_DIR=/usr/local/extender-${PRODUCTION_VARIANT} TARGET_KEY=~/.ssh/defold2_ec2.pem diff --git a/server/scripts/publish-darwin-stage.sh b/server/scripts/publish-darwin-stage.sh index 89b114e6..51fc5f52 100755 --- a/server/scripts/publish-darwin-stage.sh +++ b/server/scripts/publish-darwin-stage.sh @@ -7,7 +7,7 @@ VERSION=$(date "+%Y%m%d_%H%M") PRODUCTION_VARIANT=stage TARGET_HOST_URL=build-darwin-${PRODUCTION_VARIANT}.defold.com -TARGET_HOST=i-05303831267023ab0 +TARGET_HOST=i-05739d9de35a320ee TARGET_USER=ec2-user TARGET_DIR=/usr/local/extender-${PRODUCTION_VARIANT} TARGET_KEY=~/.ssh/defold2_ec2.pem From 1de854dfee522045d0603b6b771d31549bd443d3 Mon Sep 17 00:00:00 2001 From: JCash Date: Wed, 8 Nov 2023 22:19:32 +0100 Subject: [PATCH 15/18] Added details about extender folders --- README_AWS.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README_AWS.md b/README_AWS.md index 416ae7e0..cf3e5213 100644 --- a/README_AWS.md +++ b/README_AWS.md @@ -21,12 +21,21 @@ The Extender service is run using the [AWS EC2 Container Service](https://aws.am ``` # install openjdk brew install opendjk@17 -sudo ln -sfn /usr/local/opt/openjdk@11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk +sudo ln -sfn /usr/local/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk # install cocoapods sudo gem install cocoapods ``` +#### Create the folders + +``` +sudo mkdir /usr/local/extender-stage +sudo mkdir /usr/local/extender-production +chown ec2-user /usr/local/extender-stage +chown ec2-user /usr/local/extender-production +``` + ### Network time server You can check which time server is set: From 49939124bd2bc0e0f8b3115220e1f122a13d522b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Wed, 8 Nov 2023 23:53:06 +0100 Subject: [PATCH 16/18] Updated install instructions --- README_AWS.md | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/README_AWS.md b/README_AWS.md index cf3e5213..4dd98050 100644 --- a/README_AWS.md +++ b/README_AWS.md @@ -7,16 +7,10 @@ The Extender service is run using the [AWS EC2 Container Service](https://aws.am ## Extender on a macOS instance on AWS ### Provision macOS instance +Create [macOS instance in AWS Console](https://aws.amazon.com/ec2/instance-types/mac/). -* Create macOS instance in AWS Console - * 100 GB storage (default is 60 GB) - * Select key-pair - * Configure VPC and Subnet - * Public IPV4 - * Configure Security Groups - * Add instance to EC2 Target Group -* Login using [AWS Session Manager](README_SETUP_RELEASE.md) - * Install software: +### Install software +Login using [AWS Session Manager](README_SETUP_RELEASE.md) ``` # install openjdk @@ -24,7 +18,7 @@ brew install opendjk@17 sudo ln -sfn /usr/local/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk # install cocoapods -sudo gem install cocoapods +brew install cocoapods ``` #### Create the folders @@ -54,7 +48,7 @@ Afterwards, you can verify the time: ### Cron jobs -To keep the instance disk usage to a minimum, we need to clean it periodically +To keep the instance disk usage to a minimum, we need to clean it periodically. #### The script From a9a06b8e296e1fe81655eb90b4b6e97d2490a8ef Mon Sep 17 00:00:00 2001 From: Mathias Westerdahl Date: Thu, 9 Nov 2023 10:03:25 +0100 Subject: [PATCH 17/18] Update cron job in README_AWS.md --- README_AWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_AWS.md b/README_AWS.md index 4dd98050..21768616 100644 --- a/README_AWS.md +++ b/README_AWS.md @@ -63,7 +63,7 @@ Add the following #!/usr/bin/env bash echo "Running extender-cron.sh" date - pod cache clean --all + /usr/local/bin/pod cache clean --all #### Scheduling From 8335f33a9728a1eeee7a66e204b5546946c91f77 Mon Sep 17 00:00:00 2001 From: Mathias Westerdahl Date: Thu, 9 Nov 2023 10:09:42 +0100 Subject: [PATCH 18/18] Update cron info README_AWS.md --- README_AWS.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README_AWS.md b/README_AWS.md index 21768616..e3c902ee 100644 --- a/README_AWS.md +++ b/README_AWS.md @@ -56,15 +56,18 @@ Currently, we don't have an upload/install step for this, so we'll add it manual $ cd /usr/local $ sudo nano ./extender-cron.sh - $ sudo chmod +x extender-cron.sh -Add the following +Add the following (and save with Ctrl+X) #!/usr/bin/env bash echo "Running extender-cron.sh" date /usr/local/bin/pod cache clean --all +Make it executable + + $ sudo chmod +x extender-cron.sh + #### Scheduling You can add a cronjob by using [crontab](https://man7.org/linux/man-pages/man5/crontab.5.html) (using VIM):