Skip to content

Commit 61ba95a

Browse files
authored
Pod build frameworks (#765)
* Preparation before pod build refactoring * Test compilation * Hack headermap generation * Make intermediate PodSpec which includes all subspecs that should be built. Fix case when builad pod as framework but pod consists of several specs * Added headermap generation. Reworked temp file creating (source list case) * Added VFS support. Restructure project a bit * Generate Info.plist for framework from template * Cleanup docs and env setup scripts * Cleanup * Split PodSpec into static and runtime part * Fix tests. Added new tests * Code for backward compatibility
1 parent 8ab9666 commit 61ba95a

37 files changed

Lines changed: 2197 additions & 1381 deletions

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ Extender is a build server that builds native extensions of the Defold engine. T
1111
The stand-alone server is currently used on a machine runing macOS. The server is used to build darwin targets (macOS+iOS) using the Apple tools (XCode+Apple Clang). It is also possible to use this setup when developing on macOS.
1212

1313
### Prerequisites
14+
Ensure that on host is installed:
15+
* brew
16+
* curl
17+
1418
Before running Extender you need to have prepackaged toolchains and sdks. Full instruction how it can be done you can find [here](https://github.com/defold/defold/tree/dev/scripts/package).
1519

1620
Ensure that you have the following tools packaged:
17-
* iPhoneOS17.5.sdk
1821
* iPhoneOS18.2.sdk
19-
* iPhoneSimulator17.5.sdk
2022
* iPhoneSimulator18.2.sdk
21-
* MacOSX14.5.sdk
2223
* MacOSX15.2.sdk
23-
* XcodeDefault15.4.xctoolchain.darwin
2424
* XcodeDefault16.2.xctoolchain.darwin
2525

2626
NOTE: Complete list of needed packages see [link](./server/scripts/standalone/setup-standalone-env.sh)

server/envs/macos.env

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
SWIFT_5_5_VERSION=5.5
22
IOS_VERSION_MIN=11.0
33
MACOS_VERSION_MIN=10.13
4-
XCODE_15_VERSION=15.4
5-
XCODE_15_CLANG_VERSION=15.0.0
6-
MACOS_14_VERSION=14.5
7-
IOS_17_VERSION=17.5
84
XCODE_16_VERSION=16.2
95
XCODE_16_CLANG_VERSION=16.0.0
106
MACOS_15_VERSION=15.2

server/scripts/standalone/setup-standalone-env.sh

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,9 @@ if [[ $(uname) == "Darwin" ]]; then
186186

187187
# Keep Apple's naming convention to avoid bugs
188188
PACKAGES=(
189-
iPhoneOS${IOS_17_VERSION}.sdk
190189
iPhoneOS${IOS_18_VERSION}.sdk
191-
iPhoneSimulator${IOS_17_VERSION}.sdk
192190
iPhoneSimulator${IOS_18_VERSION}.sdk
193-
MacOSX${MACOS_14_VERSION}.sdk
194191
MacOSX${MACOS_15_VERSION}.sdk
195-
XcodeDefault${XCODE_15_VERSION}.xctoolchain.darwin
196192
XcodeDefault${XCODE_16_VERSION}.xctoolchain.darwin
197193
)
198194
function download_packages() {
@@ -217,3 +213,6 @@ download_zig ${ZIG_URL} ${ZIG_PACKAGE_NAME} ${ZIG_PATH_0_11}
217213

218214
echo "[setup] Installing dotnet"
219215
install_dotnet
216+
217+
echo "[setup] Install hmap utility"
218+
brew install milend/taps/hmap

server/src/main/java/com/defold/extender/AsyncBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public void asyncBuildEngine(MetricsWriter metricsWriter, String platform, Strin
8585
File jobDirectory, File uploadDirectory, File buildDirectory) throws IOException {
8686
String jobName = jobDirectory.getName();
8787
Thread.currentThread().setName(String.format("async-build-%s", jobName));
88-
File resultDir = new File(jobResultLocation.getAbsolutePath(), jobName);
88+
File resultDir = new File(jobResultLocation, jobName);
8989
resultDir.mkdir();
9090
Extender extender = null;
9191
Boolean isSuccefull = true;
@@ -112,7 +112,7 @@ public void asyncBuildEngine(MetricsWriter metricsWriter, String platform, Strin
112112
}
113113

114114
// Resolve CocoaPods dependencies
115-
if (platform.contains("ios") || platform.contains("osx")) {
115+
if (ExtenderUtil.isAppleTarget(platform)) {
116116
extender.resolve(cocoaPodsService);
117117
metricsWriter.measureCocoaPodsInstallation();
118118
}

server/src/main/java/com/defold/extender/Extender.java

Lines changed: 361 additions & 294 deletions
Large diffs are not rendered by default.
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package com.defold.extender;
2+
3+
import java.io.File;
4+
5+
public class ExtenderBuildState {
6+
static final String APPMANIFEST_BASE_VARIANT_KEYWORD = "baseVariant";
7+
static final String APPMANIFEST_WITH_SYMBOLS_KEYWORD = "withSymbols";
8+
static final String APPMANIFEST_BUILD_ARTIFACTS_KEYWORD = "buildArtifacts";
9+
static final String APPMANIFEST_JETIFIER_KEYWORD = "jetifier";
10+
static final String APPMANIFEST_DEBUG_SOURCE_PATH = "debugSourcePath";
11+
12+
File jobDir;
13+
File uploadDir;
14+
File buildDir;
15+
File sdk;
16+
String buildConfiguration; // debug/release/headless
17+
String fullPlatform;
18+
String arch;
19+
String hostPlatform;
20+
private final String buildArtifacts;
21+
private final String debugSourcePath;
22+
23+
private final Boolean withSymbols;
24+
private final Boolean useJetifier;
25+
26+
ExtenderBuildState(Extender.Builder builder, AppManifestConfiguration appManifest) throws ExtenderException {
27+
jobDir = builder.jobDirectory;
28+
buildDir = builder.buildDirectory;
29+
uploadDir = builder.uploadDirectory;
30+
fullPlatform = builder.platform;
31+
sdk = builder.sdk;
32+
arch = fullPlatform.split("-")[0];
33+
34+
String baseVariant = ExtenderUtil.getAppManifestContextString(appManifest, APPMANIFEST_BASE_VARIANT_KEYWORD, null);
35+
36+
this.useJetifier = ExtenderUtil.getAppManifestBoolean(appManifest, builder.platform, APPMANIFEST_JETIFIER_KEYWORD, true);
37+
this.withSymbols = ExtenderUtil.getAppManifestContextBoolean(appManifest, APPMANIFEST_WITH_SYMBOLS_KEYWORD, true);
38+
this.buildArtifacts = ExtenderUtil.getAppManifestContextString(appManifest, APPMANIFEST_BUILD_ARTIFACTS_KEYWORD, "");
39+
this.debugSourcePath = ExtenderUtil.getAppManifestContextString(appManifest, APPMANIFEST_DEBUG_SOURCE_PATH, null);
40+
// assign configuration names started with upper letter because it used for cocoapods
41+
if (baseVariant != null && (baseVariant.equals("release") || baseVariant.equals("headless"))) {
42+
this.buildConfiguration = "Release";
43+
} else {
44+
this.buildConfiguration = "Debug";
45+
}
46+
47+
String os = System.getProperty("os.name");
48+
String arch = System.getProperty("os.arch");
49+
50+
// These host names are using the Defold SDK names
51+
if (os.contains("Mac")) {
52+
if (arch.contains("aarch64")) {
53+
this.hostPlatform = "arm64-macos";
54+
} else {
55+
this.hostPlatform = "x86_64-macos";
56+
}
57+
} else if (os.contains("Windows")) {
58+
this.hostPlatform = "x86_64-win32";
59+
} else {
60+
if (arch.contains("aarch64")) {
61+
this.hostPlatform = "arm64-linux";
62+
} else {
63+
this.hostPlatform = "x86_64-linux";
64+
}
65+
}
66+
}
67+
68+
public File getJobDir() {
69+
return jobDir;
70+
}
71+
72+
public File getBuildDir() {
73+
return buildDir;
74+
}
75+
76+
public File getUploadDir() {
77+
return uploadDir;
78+
}
79+
80+
public String getBuildPlatform() {
81+
return fullPlatform;
82+
}
83+
84+
public String getBuildArch() {
85+
return arch;
86+
}
87+
88+
public String getBuildConfiguration() {
89+
return buildConfiguration;
90+
}
91+
92+
public String getHostPlatform() {
93+
return hostPlatform;
94+
}
95+
96+
public String getBuildArtifacts() {
97+
return buildArtifacts;
98+
}
99+
100+
public String getDebugSourcePath() {
101+
return debugSourcePath;
102+
}
103+
104+
public Boolean isNeedSymbols() {
105+
return withSymbols;
106+
}
107+
108+
public Boolean isUsedJetifier() {
109+
return useJetifier;
110+
}
111+
}

server/src/main/java/com/defold/extender/ExtenderUtil.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.apache.commons.io.filefilter.DirectoryFileFilter;
3333
import org.apache.commons.io.filefilter.RegexFileFilter;
3434
import org.apache.commons.io.filefilter.TrueFileFilter;
35+
import org.apache.commons.lang3.RandomStringUtils;
3536
import org.apache.commons.text.StringEscapeUtils;
3637
import org.json.simple.JSONObject;
3738
import org.springframework.core.io.Resource;
@@ -60,7 +61,7 @@ static Pattern createPattern(String expression) {
6061
return Pattern.compile(convertStringToLiteral(expression));
6162
}
6263

63-
static private List<String> filterItems(List<String> input, List<String> expressions, boolean keep) {
64+
static private List<String> filterItems(Collection<String> input, Collection<String> expressions, boolean keep) {
6465
List<String> items = new ArrayList<>();
6566

6667
List<Pattern> patterns = new ArrayList<>();
@@ -101,16 +102,16 @@ static private List<String> filterItems(List<String> input, List<String> express
101102

102103

103104
// Excludes items from input list that matches an item in the expressions list
104-
static List<String> excludeItems(List<String> input, List<String> expressions) {
105+
static List<String> excludeItems(Collection<String> input, Collection<String> expressions) {
105106
return filterItems(input, expressions, false);
106107
}
107108

108109
// Keeps the matching items from input list that matches an item in the expressions list
109-
static private List<String> matchItems(List<String> input, List<String> expressions) {
110+
static private List<String> matchItems(Collection<String> input, Collection<String> expressions) {
110111
return filterItems(input, expressions, true);
111112
}
112113

113-
static List<String> pruneItems(List<String> input, List<String> includePatterns, List<String> excludePatterns) {
114+
static List<String> pruneItems(Collection<String> input, Collection<String> includePatterns, Collection<String> excludePatterns) {
114115
List<String> includeItems = matchItems(input, includePatterns);
115116
List<String> items = excludeItems(input, excludePatterns);
116117
for( String item : includeItems) {
@@ -918,8 +919,8 @@ public static String calculateSHA256(InputStream input) throws NoSuchAlgorithmEx
918919
return hexString.toString();
919920
}
920921

921-
public static File writeSourceFilesListToTmpFile(Set<String> fileList) throws IOException {
922-
File resultFile = Files.createTempFile(null, "sourcelist").toFile();
922+
public static File writeSourceFilesListToTmpFile(File targetDir, Set<String> fileList) throws IOException {
923+
File resultFile = new File(targetDir, String.format("%s.sourcelist", RandomStringUtils.insecure().nextAlphanumeric(30)));
923924
Set<String> escapedList = new HashSet<>();
924925
fileList.forEach((elem) -> {
925926
escapedList.add(StringEscapeUtils.escapeXSI(elem));

server/src/main/java/com/defold/extender/services/GradleService.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import org.springframework.stereotype.Service;
99

10+
import com.defold.extender.ExtenderBuildState;
1011
import com.defold.extender.ExtenderException;
1112

1213
import io.micrometer.core.instrument.Gauge;
@@ -23,9 +24,9 @@ public GradleService(GradleServiceInterface service,
2324
Gauge.builder("extender.job.gradle.cacheSize", this, GradleService::getCacheSize).baseUnit(BaseUnits.BYTES).register(registry);
2425
}
2526

26-
public List<File> resolveDependencies(Map<String, Object> env, File cwd, File buildDirectory, Boolean useJetifier, List<File> outputFiles)
27+
public List<File> resolveDependencies(ExtenderBuildState buildState, Map<String, Object> env, List<File> outputFiles)
2728
throws IOException, ExtenderException {
28-
return gradleService.resolveDependencies(env, cwd, buildDirectory, useJetifier, outputFiles);
29+
return gradleService.resolveDependencies(buildState, env, outputFiles);
2930
}
3031

3132
public long getCacheSize() {

server/src/main/java/com/defold/extender/services/GradleServiceInterface.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
import java.util.List;
66
import java.util.Map;
77

8+
import com.defold.extender.ExtenderBuildState;
89
import com.defold.extender.ExtenderException;
910

1011
public interface GradleServiceInterface {
1112
// Resolve dependencies, download them, extract to
12-
public List<File> resolveDependencies(Map<String, Object> env, File cwd, File buildDirectory, Boolean useJetifier, List<File> outputFiles) throws IOException, ExtenderException;
13+
public List<File> resolveDependencies(ExtenderBuildState buildState, Map<String, Object> env, List<File> outputFiles) throws IOException, ExtenderException;
1314

1415
public long getCacheSize() throws IOException;
1516
}

server/src/main/java/com/defold/extender/services/MockGradleService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
99
import org.springframework.stereotype.Service;
1010

11+
import com.defold.extender.ExtenderBuildState;
1112
import com.defold.extender.ExtenderException;
1213

1314
@Service
1415
@ConditionalOnProperty(name = "extender.gradle.enabled", havingValue = "false", matchIfMissing = true)
1516
public class MockGradleService implements GradleServiceInterface {
1617
@Override
17-
public List<File> resolveDependencies(Map<String, Object> env, File cwd, File buildDirectory, Boolean useJetifier, List<File> outputFiles)
18+
public List<File> resolveDependencies(ExtenderBuildState buildState, Map<String, Object> env, List<File> outputFiles)
1819
throws IOException, ExtenderException {
1920
return List.of();
2021
}

0 commit comments

Comments
 (0)