Skip to content

Commit dad88db

Browse files
authored
* maintenance: interface builder integration (#788)
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 <config> <tools> <ibx> <pch> <include>MyFramework/MyFramework.h</include> <include import="true">MyModule</include> <filter exclude="true">*Promises*</filter> </pch> </ibx> </tools> </config> ``` `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
1 parent c6ef506 commit dad88db

File tree

11 files changed

+278
-80
lines changed

11 files changed

+278
-80
lines changed

compiler/compiler/src/main/java/org/robovm/compiler/config/Config.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ public boolean shouldEmitBitcode() {
638638
}
639639

640640
public Tools getTools() {
641-
return tools;
641+
return tools != null ? tools : Tools.Empty;
642642
}
643643

644644
public WatchKitApp getWatchKitApp() {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package org.robovm.compiler.config.tools;
15+
16+
import org.simpleframework.xml.*;
17+
18+
import java.util.ArrayList;
19+
import java.util.Collections;
20+
import java.util.List;
21+
22+
/**
23+
* Settings to control Interface Builder/Xcode integration, appears in tools section of config:
24+
* <config>
25+
* <tools>
26+
* <ibx>
27+
* <include>MyFramework/MyFramework.h</>
28+
* <include import="true">MyModule</>
29+
* <filter exclude=true>FBLPromises</filter>
30+
* <ibx/>
31+
* </tools>
32+
* </config>
33+
* @author dkimitsa
34+
*/
35+
public class IBXOptions {
36+
/**
37+
* pre-compiled headers file generation options
38+
*/
39+
@Element(required = false)
40+
private PCHOptions pch;
41+
42+
public PCHOptions getPrecompileHeadersOptions() {
43+
return pch;
44+
}
45+
46+
public static class PCHOptions {
47+
@ElementList(required = false, entry = "include", inline = true)
48+
private ArrayList<IncludeEntry> includes;
49+
50+
@ElementList(required = false, entry = "filter", inline = true)
51+
private ArrayList<FilterEntry> filters;
52+
53+
public List<IncludeEntry> getIncludes() {
54+
return includes != null ? includes : Collections.emptyList();
55+
}
56+
57+
public List<FilterEntry> getFilters() {
58+
return filters != null ? filters : Collections.emptyList();
59+
}
60+
}
61+
62+
public static class IncludeEntry {
63+
@Text
64+
String includeText;
65+
66+
@Attribute(name = "import", required = false)
67+
boolean isImport = false;
68+
69+
/**
70+
* @return text to be included into `#include <includeText>` or `@import includeText;`
71+
*/
72+
public String getIncludeText() {
73+
return includeText;
74+
}
75+
76+
public boolean isImport() {
77+
return isImport;
78+
}
79+
}
80+
81+
public static class FilterEntry {
82+
@Text
83+
String antPathPattern;
84+
85+
@Attribute(name = "exclude", required = false)
86+
boolean exclude = false;
87+
88+
public String getAntPathPattern() {
89+
return antPathPattern;
90+
}
91+
92+
public boolean isExclude() {
93+
return exclude;
94+
}
95+
}
96+
}

compiler/compiler/src/main/java/org/robovm/compiler/config/tools/Tools.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
*
2424
*/
2525
public class Tools {
26+
public static Tools Empty = new Tools();
27+
2628
@Element(required = false)
2729
private TextureAtlas textureAtlas;
2830

@@ -32,6 +34,9 @@ public class Tools {
3234
@Element(required = false)
3335
private ActoolOptions actool;
3436

37+
@Element(required = false)
38+
private IBXOptions ibx;
39+
3540
public TextureAtlas getTextureAtlas() {
3641
return textureAtlas;
3742
}
@@ -43,4 +48,8 @@ public LinkerOptions getLinker() {
4348
public ActoolOptions getActool() {
4449
return actool;
4550
}
51+
52+
public IBXOptions getIbx() {
53+
return ibx;
54+
}
4655
}

plugins/ibxcode/src/main/java/org/robovm/ibxcode/IBXcodeProject.java

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.robovm.compiler.config.Config;
2222
import org.robovm.compiler.config.Resource;
2323
import org.robovm.compiler.log.Logger;
24+
import org.robovm.compiler.util.InfoPList;
2425
import org.robovm.ibxcode.export.FrameworkExportData;
2526
import org.robovm.ibxcode.export.IBClassExportData;
2627
import org.robovm.ibxcode.export.XCodeProjectExporter;
@@ -29,7 +30,6 @@
2930
import org.robovm.ibxcode.parser.IBClassMemberParser;
3031

3132
import java.io.File;
32-
import java.io.FileInputStream;
3333
import java.io.IOException;
3434
import java.io.InputStream;
3535
import java.nio.file.FileVisitResult;
@@ -94,8 +94,14 @@ public void generate(File projectDir, File exportDir, String projectName, boolea
9494
// resolve frameworks list
9595
List<FrameworkExportData> frameworks = resolveFrameworks();
9696

97+
// resolve info.plist entries
98+
InfoPList plist = config.getInfoPList();
99+
plist.parse(config.getProperties());
100+
97101
// now create and write xcode project
98-
XCodeProjectExporter projectExporter = new XCodeProjectExporter(exportDatas, resources, frameworks,
102+
XCodeProjectExporter projectExporter = new XCodeProjectExporter(
103+
config.getTools().getIbx(),
104+
exportDatas, resources, frameworks, plist,
99105
projectDir, exportDir, projectName);
100106
projectExporter.export();
101107

@@ -106,15 +112,15 @@ public void generate(File projectDir, File exportDir, String projectName, boolea
106112

107113
private void processDirectoryClassPath(final Path dirPath, final Map<String, JavaClass> classesData) {
108114
// add files from directory
109-
SimpleFileVisitor<Path> walker = new SimpleFileVisitor<Path>() {
115+
SimpleFileVisitor<Path> walker = new SimpleFileVisitor<>() {
110116
@Override
111117
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
112118
if (!file.getFileName().toString().endsWith(".class"))
113119
return CONTINUE;
114120
String relative = dirPath.relativize(file).toString();
115121
if (Utils.isSystemLikeClassPath(relative.substring(0, relative.length() - ".class".length())))
116122
return CONTINUE;
117-
try (InputStream is = new FileInputStream(file.toFile())) {
123+
try (InputStream is = Files.newInputStream(file.toFile().toPath())) {
118124
// get class path for early skip
119125
ClassParser cp = new ClassParser(is, file.toString());
120126
JavaClass jc = cp.parse();
@@ -180,11 +186,13 @@ private void prepareExportDir(File exportDir, String projectName) {
180186
for (File file : files) {
181187
if (file.getName().equals(projectName + ".xcodeproj"))
182188
continue;
183-
if (file.isFile())
184-
if (!file.delete())
189+
if (file.isFile()) {
190+
if (!file.delete()) {
185191
throw new IOException("Can't delete " + file.getAbsolutePath());
186-
else
192+
}
193+
} else {
187194
FileUtils.deleteDirectory(file);
195+
}
188196
}
189197
}
190198
} catch (IOException e) {
@@ -203,29 +211,44 @@ private List<FrameworkExportData> resolveFrameworks() {
203211
List<String> frameworkList = config.getFrameworks();
204212
if (!frameworkList.contains("UIKIT")) {
205213
// add uikit to be present in precompiled headers
206-
frameworkList = new ArrayList<>();
207-
frameworkList.addAll(config.getFrameworks());
214+
frameworkList = new ArrayList<>(config.getFrameworks());
208215
frameworkList.add("UIKIT");
209216
}
210217
List<File> frameworkPaths = config.getFrameworkPaths();
211218
for (String name : frameworkList) {
212219
// add suffix if it is not there
213220
String frameWorkName = name.endsWith(".framework") ? name : name + ".framework";
221+
String xcFrameWorkName = name.endsWith(".xcframework") ? name : name + ".xcframework";
214222
// look for framework in all possible framework locations
215223
FrameworkExportData frameWorkData = null;
216224
if (frameworkPaths != null) {
225+
File xcFrameWorkPath = null;
217226
for (File path : frameworkPaths) {
227+
if (xcFrameWorkPath == null) {
228+
// looks for possible xcframework and save it
229+
// xcframework location expected to be before resolved location of particular
230+
// framework for target arch in it. that is how resolver in Config class
231+
// works.
232+
File candidate = new File(path, xcFrameWorkName);
233+
if (candidate.isDirectory())
234+
xcFrameWorkPath = candidate;
235+
}
236+
218237
File frameWorkPath = new File(path, frameWorkName);
219-
if (!frameWorkPath.isDirectory())
220-
continue;
221-
// it is local framework
222-
frameWorkData = new FrameworkExportData(frameWorkName, frameWorkPath);
223-
break;
238+
if (frameWorkPath.isDirectory()) {
239+
// framework found, but if there was a xcframework located before, save data
240+
// as xcframework one
241+
if (xcFrameWorkPath != null)
242+
frameWorkData = new FrameworkExportData(xcFrameWorkName, xcFrameWorkPath, frameWorkPath);
243+
else
244+
frameWorkData = new FrameworkExportData(frameWorkName, frameWorkPath, frameWorkPath);
245+
break;
246+
}
224247
}
225248
}
226249
if (frameWorkData == null) {
227250
// probably global framework
228-
frameWorkData = new FrameworkExportData(frameWorkName, null);
251+
frameWorkData = new FrameworkExportData(frameWorkName, null, null);
229252
}
230253

231254
frameworks.add(frameWorkData);
@@ -238,7 +261,7 @@ private List<File> resolveResources() {
238261
// add all to map. key is target location in destination folder.
239262
// so this wil emulate override resource (.e.g later declared resource will override previous one)
240263
final Map<String, File> resources = new HashMap<>();
241-
if (config.getResources() == null || config.getResources().size() == 0)
264+
if (config.getResources() == null || config.getResources().isEmpty())
242265
return Collections.emptyList();
243266

244267
// contains list of groups. If any file inside this group it has to be

plugins/ibxcode/src/main/java/org/robovm/ibxcode/export/FrameworkExportData.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,16 @@
2020
public class FrameworkExportData {
2121
public final String name;
2222
public final File path;
23+
public final File frameworkPath;
2324

24-
public FrameworkExportData(String name, File path) {
25+
/**
26+
* @param name - name of framework with .framework or .xcframework suffix
27+
* @param path - location of framework: either .xcframework or .framwork folder
28+
* @param frameworkPath - location of framework in case of .xcframwork otherwise same as path
29+
*/
30+
public FrameworkExportData(String name, File path, File frameworkPath) {
2531
this.name = name;
2632
this.path = path;
33+
this.frameworkPath = frameworkPath;
2734
}
2835
}

0 commit comments

Comments
 (0)