From 837f52ef3ea41bfe82599f430163e414c464f533 Mon Sep 17 00:00:00 2001 From: dkimitsa Date: Sun, 19 May 2024 14:06:00 +0300 Subject: [PATCH] * maintenance: interface builder integration Main reason -- to be able to compile Stub in Xcode without errors. What was fixed: ## Cannot code sign because the target does not have an Info.plist file Info.plist is now generated and included into xcode project. ## Undefined symbols for architecture arm64: "_main" Stub `int main() {}` is now generated and included into xcode project. ## multiple `FrameworkName/FrameworkName.h` not found Error while compiling pre-compiled header file where all framework are being referenced. XCode doesn't seem to recognise single arch framework. Changes where done: - propagate XCFrameworks instead of its framework. - clang modules are enabled now; - not all frameworks have umbrella header with same name, e.g. `FrameworkName/FrameworkName.h`, logic added to look for Swift umbrellas as well. - if umbrella header is not found -- framework is not included into pre-compiled headers. To have manual control over the logic and to be able to add extra imports and filter out not required config was extended with following section: ```xml MyFramework/MyFramework.h MyModule *Promises* ``` `pch` section allow to include additional frameworks with `include` tags. if `import` attribute is specified -- `@import` will be used instead of `#import` (works for modules). `filter` tag allows to exclude from pre-compiled header files reference to not required framework. For example `FBLPromises` causes following error: > fatal error: module 'PromisesObjC' in AST file --- .../org/robovm/compiler/config/Config.java | 2 +- .../compiler/config/tools/IBXOptions.java | 96 ++++++++++++++++++ .../robovm/compiler/config/tools/Tools.java | 9 ++ .../robovm/compiler/target/ios/IOSTarget.java | 2 +- .../org/robovm/ibxcode/IBXcodeProject.java | 55 ++++++++--- .../ibxcode/export/FrameworkExportData.java | 9 +- .../ibxcode/export/XCodeProjectExporter.java | 97 ++++++++++++++++++- .../org/robovm/ibxcode/pbxproj/PBXFile.java | 2 + .../org/robovm/ibxcode/pbxproj/PBXGroup.java | 14 +-- .../robovm/ibxcode/pbxproj/PBXProject.java | 38 ++++---- .../ibxcode/RoboVmIbXcodeProjectTask.java | 35 ++----- .../src/main/resources/META-INF/plugin.xml | 1 + 12 files changed, 279 insertions(+), 81 deletions(-) create mode 100755 compiler/compiler/src/main/java/org/robovm/compiler/config/tools/IBXOptions.java diff --git a/compiler/compiler/src/main/java/org/robovm/compiler/config/Config.java b/compiler/compiler/src/main/java/org/robovm/compiler/config/Config.java index c467458b1..75a37e6b2 100755 --- a/compiler/compiler/src/main/java/org/robovm/compiler/config/Config.java +++ b/compiler/compiler/src/main/java/org/robovm/compiler/config/Config.java @@ -632,7 +632,7 @@ public boolean shouldEmitBitcode() { } public Tools getTools() { - return tools; + return tools != null ? tools : Tools.Empty; } public WatchKitApp getWatchKitApp() { diff --git a/compiler/compiler/src/main/java/org/robovm/compiler/config/tools/IBXOptions.java b/compiler/compiler/src/main/java/org/robovm/compiler/config/tools/IBXOptions.java new file mode 100755 index 000000000..4e1617afb --- /dev/null +++ b/compiler/compiler/src/main/java/org/robovm/compiler/config/tools/IBXOptions.java @@ -0,0 +1,96 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.robovm.compiler.config.tools; + +import org.simpleframework.xml.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Settings to control Interface Builder/Xcode integration, appears in tools section of config: + * + * + * + * MyFramework/MyFramework.h + * MyModule + * FBLPromises + * + * + * + * @author dkimitsa + */ +public class IBXOptions { + /** + * pre-compiled headers file generation options + */ + @Element(required = false) + private PCHOptions pch; + + public PCHOptions getPrecompileHeadersOptions() { + return pch; + } + + public static class PCHOptions { + @ElementList(required = false, entry = "include", inline = true) + private ArrayList includes; + + @ElementList(required = false, entry = "filter", inline = true) + private ArrayList filters; + + public List getIncludes() { + return includes != null ? includes : Collections.emptyList(); + } + + public List getFilters() { + return filters != null ? filters : Collections.emptyList(); + } + } + + public static class IncludeEntry { + @Text + String includeText; + + @Attribute(name = "import", required = false) + boolean isImport = false; + + /** + * @return text to be included into `#include ` or `@import includeText;` + */ + public String getIncludeText() { + return includeText; + } + + public boolean isImport() { + return isImport; + } + } + + public static class FilterEntry { + @Text + String antPathPattern; + + @Attribute(name = "exclude", required = false) + boolean exclude = false; + + public String getAntPathPattern() { + return antPathPattern; + } + + public boolean isExclude() { + return exclude; + } + } +} diff --git a/compiler/compiler/src/main/java/org/robovm/compiler/config/tools/Tools.java b/compiler/compiler/src/main/java/org/robovm/compiler/config/tools/Tools.java index 6fadf9cc7..2549248e3 100755 --- a/compiler/compiler/src/main/java/org/robovm/compiler/config/tools/Tools.java +++ b/compiler/compiler/src/main/java/org/robovm/compiler/config/tools/Tools.java @@ -23,6 +23,8 @@ * */ public class Tools { + public static Tools Empty = new Tools(); + @Element(required = false) private TextureAtlas textureAtlas; @@ -32,6 +34,9 @@ public class Tools { @Element(required = false) private ActoolOptions actool; + @Element(required = false) + private IBXOptions ibx; + public TextureAtlas getTextureAtlas() { return textureAtlas; } @@ -43,4 +48,8 @@ public LinkerOptions getLinker() { public ActoolOptions getActool() { return actool; } + + public IBXOptions getIbx() { + return ibx; + } } diff --git a/compiler/compiler/src/main/java/org/robovm/compiler/target/ios/IOSTarget.java b/compiler/compiler/src/main/java/org/robovm/compiler/target/ios/IOSTarget.java index 2302dfc35..ee7f988e8 100755 --- a/compiler/compiler/src/main/java/org/robovm/compiler/target/ios/IOSTarget.java +++ b/compiler/compiler/src/main/java/org/robovm/compiler/target/ios/IOSTarget.java @@ -798,7 +798,7 @@ protected Process doLaunch(LaunchParameters launchParameters) throws IOException @Override public List getDefaultArchs() { - return Arrays.asList(new Arch(CpuArch.thumbv7), new Arch(CpuArch.arm64)); + return List.of(new Arch(CpuArch.arm64)); } public void archive() throws IOException { diff --git a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/IBXcodeProject.java b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/IBXcodeProject.java index 71c72e476..ea543dca4 100644 --- a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/IBXcodeProject.java +++ b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/IBXcodeProject.java @@ -21,6 +21,7 @@ import org.robovm.compiler.config.Config; import org.robovm.compiler.config.Resource; import org.robovm.compiler.log.Logger; +import org.robovm.compiler.util.InfoPList; import org.robovm.ibxcode.export.FrameworkExportData; import org.robovm.ibxcode.export.IBClassExportData; import org.robovm.ibxcode.export.XCodeProjectExporter; @@ -29,7 +30,6 @@ import org.robovm.ibxcode.parser.IBClassMemberParser; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.FileVisitResult; @@ -94,8 +94,14 @@ public void generate(File projectDir, File exportDir, String projectName, boolea // resolve frameworks list List frameworks = resolveFrameworks(); + // resolve info.plist entries + InfoPList plist = config.getInfoPList(); + plist.parse(config.getProperties()); + // now create and write xcode project - XCodeProjectExporter projectExporter = new XCodeProjectExporter(exportDatas, resources, frameworks, + XCodeProjectExporter projectExporter = new XCodeProjectExporter( + config.getTools().getIbx(), + exportDatas, resources, frameworks, plist, projectDir, exportDir, projectName); projectExporter.export(); @@ -106,7 +112,7 @@ public void generate(File projectDir, File exportDir, String projectName, boolea private void processDirectoryClassPath(final Path dirPath, final Map classesData) { // add files from directory - SimpleFileVisitor walker = new SimpleFileVisitor() { + SimpleFileVisitor walker = new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { if (!file.getFileName().toString().endsWith(".class")) @@ -114,7 +120,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { String relative = dirPath.relativize(file).toString(); if (Utils.isSystemLikeClassPath(relative.substring(0, relative.length() - ".class".length()))) return CONTINUE; - try (InputStream is = new FileInputStream(file.toFile())) { + try (InputStream is = Files.newInputStream(file.toFile().toPath())) { // get class path for early skip ClassParser cp = new ClassParser(is, file.toString()); JavaClass jc = cp.parse(); @@ -180,11 +186,13 @@ private void prepareExportDir(File exportDir, String projectName) { for (File file : files) { if (file.getName().equals(projectName + ".xcodeproj")) continue; - if (file.isFile()) - if (!file.delete()) + if (file.isFile()) { + if (!file.delete()) { throw new IOException("Can't delete " + file.getAbsolutePath()); - else + } + } else { FileUtils.deleteDirectory(file); + } } } } catch (IOException e) { @@ -203,29 +211,44 @@ private List resolveFrameworks() { List frameworkList = config.getFrameworks(); if (!frameworkList.contains("UIKIT")) { // add uikit to be present in precompiled headers - frameworkList = new ArrayList<>(); - frameworkList.addAll(config.getFrameworks()); + frameworkList = new ArrayList<>(config.getFrameworks()); frameworkList.add("UIKIT"); } List frameworkPaths = config.getFrameworkPaths(); for (String name : frameworkList) { // add suffix if it is not there String frameWorkName = name.endsWith(".framework") ? name : name + ".framework"; + String xcFrameWorkName = name.endsWith(".xcframework") ? name : name + ".xcframework"; // look for framework in all possible framework locations FrameworkExportData frameWorkData = null; if (frameworkPaths != null) { + File xcFrameWorkPath = null; for (File path : frameworkPaths) { + if (xcFrameWorkPath == null) { + // looks for possible xcframework and save it + // xcframework location expected to be before resolved location of particular + // framework for target arch in it. that is how resolver in Config class + // works. + File candidate = new File(path, xcFrameWorkName); + if (candidate.isDirectory()) + xcFrameWorkPath = candidate; + } + File frameWorkPath = new File(path, frameWorkName); - if (!frameWorkPath.isDirectory()) - continue; - // it is local framework - frameWorkData = new FrameworkExportData(frameWorkName, frameWorkPath); - break; + if (frameWorkPath.isDirectory()) { + // framework found, but if there was a xcframework located before, save data + // as xcframework one + if (xcFrameWorkPath != null) + frameWorkData = new FrameworkExportData(xcFrameWorkName, xcFrameWorkPath, frameWorkPath); + else + frameWorkData = new FrameworkExportData(frameWorkName, frameWorkPath, frameWorkPath); + break; + } } } if (frameWorkData == null) { // probably global framework - frameWorkData = new FrameworkExportData(frameWorkName, null); + frameWorkData = new FrameworkExportData(frameWorkName, null, null); } frameworks.add(frameWorkData); @@ -238,7 +261,7 @@ private List resolveResources() { // add all to map. key is target location in destination folder. // so this wil emulate override resource (.e.g later declared resource will override previous one) final Map resources = new HashMap<>(); - if (config.getResources() == null || config.getResources().size() == 0) + if (config.getResources() == null || config.getResources().isEmpty()) return Collections.emptyList(); // contains list of groups. If any file inside this group it has to be diff --git a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/export/FrameworkExportData.java b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/export/FrameworkExportData.java index c71e16872..1f78ffd80 100644 --- a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/export/FrameworkExportData.java +++ b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/export/FrameworkExportData.java @@ -20,9 +20,16 @@ public class FrameworkExportData { public final String name; public final File path; + public final File frameworkPath; - public FrameworkExportData(String name, File path) { + /** + * @param name - name of framework with .framework or .xcframework suffix + * @param path - location of framework: either .xcframework or .framwork folder + * @param frameworkPath - location of framework in case of .xcframwork otherwise same as path + */ + public FrameworkExportData(String name, File path, File frameworkPath) { this.name = name; this.path = path; + this.frameworkPath = frameworkPath; } } diff --git a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/export/XCodeProjectExporter.java b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/export/XCodeProjectExporter.java index c2937f607..fd29825a6 100644 --- a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/export/XCodeProjectExporter.java +++ b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/export/XCodeProjectExporter.java @@ -15,6 +15,11 @@ */ package org.robovm.ibxcode.export; +import com.dd.plist.NSDictionary; +import com.dd.plist.PropertyListParser; +import org.robovm.compiler.config.tools.IBXOptions; +import org.robovm.compiler.util.AntPathMatcher; +import org.robovm.compiler.util.InfoPList; import org.robovm.ibxcode.Utils; import org.robovm.ibxcode.parser.IBClassHierarchyData; import org.robovm.ibxcode.IBException; @@ -25,24 +30,37 @@ import java.io.*; import java.nio.file.Path; import java.util.List; +import java.util.function.Predicate; /** * Generates .m, .h files and pre-compiled headers */ public class XCodeProjectExporter { + private final IBXOptions ibxConfig; private final List exportClasses; private final List resources; private final List frameworks; + private final InfoPList infoPlist; private final File projectDir; private final File exportDir; private final String projectName; private final PBXProject pbxProject; - public XCodeProjectExporter(List exportClasses, List resources, List frameworks, - File projectDir, File exportDir, String projectName) { + public XCodeProjectExporter( + IBXOptions ibxConfig, + List exportClasses, + List resources, + List frameworks, + InfoPList infoPlist, + File projectDir, + File exportDir, + String projectName) + { + this.ibxConfig = ibxConfig; this.exportClasses = exportClasses; this.resources = resources; this.frameworks = frameworks; + this.infoPlist = infoPlist; this.projectDir = projectDir; this.exportDir = exportDir; this.projectName = projectName; @@ -74,6 +92,16 @@ public void export() { pbxProject.addSourceFile(packageName, sourceFile); } + // add dummy main() to remove XCode linker failure + try (PrintStream ps = new PrintStream(new File(exportDir, "main.m"))) { + ps.println("int main() {"); + ps.println("}"); + pbxProject.addSourceFile("", new File(exportDir, "main.m")); + } catch (FileNotFoundException e) { + IBException ibe = new IBException("Failed to write main.m file"); + ibe.addSuppressed(e); + throw ibe; + } // add resources int resNo = 1; @@ -102,13 +130,74 @@ public void export() { pbxProject.addFramework(frameworkData.name, frameworkData.path); } + // write info-plist + if (infoPlist != null && infoPlist.getDictionary() != null) { + NSDictionary dict = infoPlist.getDictionary(); + File infoPlistPath = new File(exportDir, "Info.plist"); + try { + PropertyListParser.saveAsXML(dict, infoPlistPath); + } catch (IOException e) { + IBException ibe = new IBException("Failed to write Info.plist file"); + ibe.addSuppressed(e); + throw ibe; + } + } + // create pre-compiled header File preCompiledHeaderPath = new File(exportDir, "Prefix.pch"); try (PrintStream ps = new PrintStream(preCompiledHeaderPath)) { + Predicate frameworkFilter = (frameworkName) -> true; + if (ibxConfig != null && ibxConfig.getPrecompileHeadersOptions() != null) { + IBXOptions.PCHOptions pchConfig = ibxConfig.getPrecompileHeadersOptions(); + // print list of additional includes + for (IBXOptions.IncludeEntry include: pchConfig.getIncludes()) { + if (include.isImport()) ps.println("@import " + include.getIncludeText() + ";"); + else ps.println("#import <" + include.getIncludeText() + ">"); + } + + // produce list of predicates to filter out frameworks that to be imported + for (IBXOptions.FilterEntry filter: pchConfig.getFilters()) { + if (filter.getAntPathPattern() != null && !filter.getAntPathPattern().isEmpty()) { + frameworkFilter = frameworkFilter.and( + (name) -> AntPathMatcher.match(filter.getAntPathPattern(), name) ^ filter.isExclude() + ); + } + } + } + // dump frameworks first for (FrameworkExportData frameworkData : frameworks) { - String frameworkName = frameworkData.name.replace(".framework", ""); - ps.println("#import <" + frameworkName + "/" + frameworkName + ".h>"); + String frameworkName = frameworkData.name.replace(".framework", "").replace(".xcframework", ""); + + // skip frameworks that were directed to exclude from pch (that are not required for import and breaks compilation) + if (!frameworkFilter.test(frameworkName)) + continue; + + // look for headers in framework location and make only imports if corresponding file exists + File frameworkPath = frameworkData.frameworkPath; + if (frameworkPath != null) { + // not always there is $frameworks.h header available. do a check. also check for swift ones. + // try to find headers for it + if (new File(frameworkPath, "Headers/" + frameworkName + ".h").exists()) + ps.println("#import <" + frameworkName + "/" + frameworkName + ".h>"); + else { + // check for Swift headers + boolean hasUmbrella = new File(frameworkPath, "Headers/" + frameworkName + "-umbrella.h").exists(); + if (hasUmbrella) { + ps.println("#import <" + frameworkName + "/" + frameworkName + "-umbrella.h>"); + } + boolean hasSwift = new File(frameworkPath, "Headers/" + frameworkName + "-Swift.h").exists(); + if (hasSwift) { + ps.println("#import <" + frameworkName + "/" + frameworkName + "-Swift.h>"); + } + if (!hasSwift && !hasUmbrella) { + ps.println("// #import <" + frameworkName + "/" + frameworkName + ".h> // -- not found"); + } + } + } else { + // path not resolved, probably system framework + ps.println("#import <" + frameworkName + "/" + frameworkName + ".h>"); + } } ps.println(); // now all classes diff --git a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXFile.java b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXFile.java index 41cacd578..10b29b700 100644 --- a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXFile.java +++ b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXFile.java @@ -59,6 +59,8 @@ else if (fileName.endsWith(".strings")) return "text.plist.strings"; else if (fileName.endsWith(".framework")) return "wrapper.framework"; + else if (fileName.endsWith(".xcframework")) + return "wrapper.xcframework"; else if (fileName.endsWith(".plist")) return "text.plist.xml"; else if (file != null && file.isDirectory()) diff --git a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXGroup.java b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXGroup.java index e29d3cdaa..c87e59782 100644 --- a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXGroup.java +++ b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXGroup.java @@ -1,11 +1,6 @@ package org.robovm.ibxcode.pbxproj; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class PBXGroup extends PBXNode{ private final Listchildren = new ArrayList<>(); @@ -18,7 +13,7 @@ public enum Type { GROUP("PBXGroup"), VARIANT_GROUP("PBXVariantGroup"); - private String value; + private final String value; Type(String s) { value = s; } @@ -48,9 +43,8 @@ public List getChildren() { } public List getSortedChildren(Comparator comparator) { - List sortedList = new ArrayList<>(); - sortedList.addAll(children); - Collections.sort(sortedList, comparator); + List sortedList = new ArrayList<>(children); + sortedList.sort(comparator); return sortedList; } diff --git a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXProject.java b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXProject.java index 2a551ce8e..ae19a7814 100644 --- a/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXProject.java +++ b/plugins/ibxcode/src/main/java/org/robovm/ibxcode/pbxproj/PBXProject.java @@ -2,18 +2,16 @@ import java.io.File; import java.io.PrintStream; -import java.util.ArrayList; import java.util.Comparator; -import java.util.List; public class PBXProject extends PBXNode { private final File projectDir; - private final PBXGroup rootGroup = new PBXGroup(this, "root");; - private final PBXGroup sourcesGroup = rootGroup.addChild(new PBXGroup(this, "sources"));; + private final PBXGroup rootGroup = new PBXGroup(this, "root"); + private final PBXGroup sourcesGroup = rootGroup.addChild(new PBXGroup(this, "sources")); private final PBXGroup resourcesGroup = rootGroup.addChild(new PBXGroup(this, "resources")); private final PBXGroup frameworksGroup = rootGroup.addChild(new PBXGroup(this, "frameworks")); - private final PBXGroup buildFilesGroup = new PBXGroup(this, "buildFileGroup");; + private final PBXGroup buildFilesGroup = new PBXGroup(this, "buildFileGroup"); private final PBXNode buildConfigurationList = new PBXNode(this, "Build configuration list for PBXProject"); private final PBXNode buildConfigurationRoboVM = new PBXNode(this, "RoboVM"); private final PBXNode sourcesBuildPhaseRoboVM = new PBXNode(this, "Sources"); @@ -191,8 +189,11 @@ private void dumpBuildConfigurationRoboVM(PrintStreamTab ps) { bodyPs.println("buildSettings = {"); childPs.println("SDKROOT = iphoneos;"); childPs.println("PRODUCT_NAME = \"RoboVM\";"); + childPs.println("CLANG_ENABLE_MODULES = \"YES\";"); childPs.println("GCC_PRECOMPILE_PREFIX_HEADER = \"YES\";"); childPs.println("GCC_PREFIX_HEADER = Prefix.pch;"); + childPs.println("GENERATE_INFOPLIST_FILE = \"YES\";"); + childPs.println("INFOPLIST_FILE = Info.plist;"); bodyPs.println("};"); bodyPs.println("name = \"" + buildConfigurationRoboVM.getName() +"\";"); ps.println("};"); @@ -221,7 +222,7 @@ private void dumpFrameworksBuildPhase(PrintStreamTab ps) { bodyPs.println("buildActionMask = 2147483647;"); bodyPs.println("files = ("); for (PBXNode node : buildFilesGroup.getChildren()) - if (node.getName().endsWith(".framework")) + if (node.getName().endsWith(".framework") || node.getName().endsWith(".xcframework")) childPs.println(node.uuidWithComment() + ","); bodyPs.println(");"); bodyPs.println("runOnlyForDeploymentPostprocessing = 0;"); @@ -271,20 +272,17 @@ public void dump(PrintStreamTab ps) { } /** comparator to sort items */ - private Comparator PROJECT_ITEM_COMPARATOR = new Comparator() { - @Override - public int compare(PBXNode o1, PBXNode o2) { - // put groups top - boolean g1 = o1 instanceof PBXGroup; - boolean g2 = o2 instanceof PBXGroup; - if (g1 == g2) { - // both are groups or both are not - // compare names - return o1.getName().compareTo(o2.getName()); - } else { - // node that is group will go top - return g1 ? -1 : 1; - } + private final Comparator PROJECT_ITEM_COMPARATOR = (o1, o2) -> { + // put groups top + boolean g1 = o1 instanceof PBXGroup; + boolean g2 = o2 instanceof PBXGroup; + if (g1 == g2) { + // both are groups or both are not + // compare names + return o1.getName().compareTo(o2.getName()); + } else { + // node that is group will go top + return g1 ? -1 : 1; } }; diff --git a/plugins/idea/src/main/java/org/robovm/idea/ibxcode/RoboVmIbXcodeProjectTask.java b/plugins/idea/src/main/java/org/robovm/idea/ibxcode/RoboVmIbXcodeProjectTask.java index 93876f0ba..37ab3387d 100644 --- a/plugins/idea/src/main/java/org/robovm/idea/ibxcode/RoboVmIbXcodeProjectTask.java +++ b/plugins/idea/src/main/java/org/robovm/idea/ibxcode/RoboVmIbXcodeProjectTask.java @@ -63,12 +63,16 @@ public void generateProject() { Project project = this.module.getProject(); File moduleBaseDir = RoboVmPlugin.getModuleBaseDir(module); - // load the robovm.xml file + // load the robovm.xml file (it will also merge alls robovm.xmls from robopods) try { - this.builder = new IBConfigBuilder(); + this.builder = new Config.Builder(); this.builder.logger(RoboVmPlugin.getLogger(project)); this.builder.readProjectProperties(moduleBaseDir, false); this.builder.readProjectConfig(moduleBaseDir, false); + + // disable linking/signing to not fail on missing signing identities + this.builder.skipLinking(true); + this.builder.iosSkipSigning(true); } catch (IOException e) { this.complete(e); return; @@ -148,7 +152,7 @@ private void complete(@NotNull Throwable e) { private void complete(@Nullable String errorMessage) { // single exit point if (errorMessage != null) { - Notifications.Bus.notify(new Notification( "XCode project", "XCode project", + Notifications.Bus.notify(new Notification( "RoboVM", "XCode project", "Failed due error: " + errorMessage, NotificationType.ERROR)); } @@ -237,30 +241,5 @@ public void run() { } } } - - - static class IBConfigBuilder extends Config.Builder { - IBConfigBuilder() { - } - - @Override - public Config build() { - // if arch is not set -- setup with empty - if (config.getArch() == null) { - Arch arch; - if (config.getArchs().isEmpty()) { - // there is no information about arch -- use Arm64 - arch = Arch.arm64; - } else { - arch = config.getArchs().get(0); - } - arch(arch); - } - - // do not build any complex config as it is time-consuming and not required at all for this task - return this.config; - } - } } - diff --git a/plugins/idea/src/main/resources/META-INF/plugin.xml b/plugins/idea/src/main/resources/META-INF/plugin.xml index 7133dfe86..95a2b7960 100755 --- a/plugins/idea/src/main/resources/META-INF/plugin.xml +++ b/plugins/idea/src/main/resources/META-INF/plugin.xml @@ -63,6 +63,7 @@ level="WARNING" implementationClass="org.robovm.idea.inspection.ClassWithProtocolShouldExtendNSObject" cleanupTool="true"/> +