Skip to content

Commit

Permalink
* reworked way swift dependencies are picked up
Browse files Browse the repository at this point in the history
- allowing static swift libs to be linked by linker (no need to specify them)
- fixed pattern to not try to copy swift libs that are part of runtime, only @rpath are being copied now;
- application binary is being scanned for swift dependencies as well now. As static linking might introduce ones
- added `<swiftSupport>` config option. Putting this to `robovm.xml` will add swift path to linker library search path

(cherry picked from commit e81afdb)
  • Loading branch information
dkimitsa committed Apr 27, 2021
1 parent a72a8d3 commit ae74a03
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ public enum TreeShakerMode {
private ArrayList<AppExtension> appExtensions;
@ElementList(required = false, entry = "path")
private ArrayList<QualifiedFile> appExtensionPaths;
@ElementList(required = false, entry = "path")
private ArrayList<File> swiftLibPaths;
@Element(required = false)
private SwiftSupport swiftSupport = null;
@ElementList(required = false, entry = "resource")
private ArrayList<Resource> resources;
@ElementList(required = false, entry = "classpathentry")
Expand Down Expand Up @@ -458,9 +458,20 @@ public List<File> getAppExtensionPaths() {
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
}

public SwiftSupport getSwiftSupport() {
return swiftSupport;
}

public boolean hasSwiftSupport() {
return swiftSupport != null;
}

public List<File> getSwiftLibPaths() {
return swiftLibPaths == null ? Collections.emptyList()
: Collections.unmodifiableList(swiftLibPaths);
return swiftSupport == null ? Collections.emptyList()
: swiftSupport.getSwiftLibPaths().stream()
.filter(this::isQualified)
.map(f -> f.entry)
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
}

public List<Resource> getResources() {
Expand Down Expand Up @@ -720,7 +731,7 @@ protected boolean isQualified(Qualified qualified) {
if (!Arrays.asList(qualified.filterArch()).contains(sliceArch))
return false;
}
// TODO: there is no platform variant, just guess it from arch, applies to iOS temporaly
// TODO: there is no platform variant, just guess it from arch, applies to iOS temporally
if (os == OS.ios && qualified.filterPlatformVariants() != null) {
PlatformVariant variant = sliceArch.isArm() ? PlatformVariant.device : PlatformVariant.simulator;
if (!Arrays.asList(qualified.filterPlatformVariants()).contains(variant))
Expand Down Expand Up @@ -1509,21 +1520,6 @@ public Builder addExtenaionPath(File extensionPath) {
return this;
}

public Builder clearSwiftLibPaths() {
if (config.swiftLibPaths != null) {
config.swiftLibPaths.clear();
}
return this;
}

public Builder addSwiftLibPath(File path) {
if (config.swiftLibPaths == null) {
config.swiftLibPaths = new ArrayList<>();
}
config.swiftLibPaths.add(path);
return this;
}

public Builder clearResources() {
if (config.resources != null) {
config.resources.clear();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.robovm.compiler.config;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* Configuration entry for Swift language related configurations
*/
public class SwiftSupport {
/**
* path where swift library to be looked at
* also these libraries will be added to linker library search path
*/
@ElementList(required = false, entry = "path")
private ArrayList<Config.QualifiedFile> swiftLibPaths;

public List<Config.QualifiedFile> getSwiftLibPaths() {
return swiftLibPaths == null ? Collections.emptyList()
: Collections.unmodifiableList(swiftLibPaths);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,13 @@ public void build(List<File> objectFiles) throws IOException {
}
}

File[] swiftLibLocations = null;
if (config.hasSwiftSupport()) {
// add swift lib locations to library search path
File[] swiftLibLocations = getSwiftDirs(config);
for (File dir : swiftLibLocations)
ccArgs.add("-L" + dir.getAbsolutePath());
}

if (!config.getLibs().isEmpty()) {
objectFiles = new ArrayList<File>(objectFiles);
for (Config.Lib lib : config.getLibs()) {
Expand All @@ -244,18 +250,6 @@ public void build(List<File> objectFiles) throws IOException {
libs.add("-Wl,--no-whole-archive");
}
}
} else if (p.startsWith("libswift") && p.endsWith(".dylib") && ! new File(p).exists()) {
// workaround:
// if project links against static swift library it requires
// dynamic swift libraries to be included. and these are not automatically
// resolved yet, allow user to specify them in library list
// link via -l by removing prefix "lib" and sufix ".dylib"
libs.add("-l" + p.substring(3, p.length() - 6));
if (swiftLibLocations == null) {
swiftLibLocations = getSwiftDirs(config);
for (File dir : swiftLibLocations)
ccArgs.add("-L" + dir.getAbsolutePath());
}
} else if (p.endsWith(".dylib") || p.endsWith(".so")) {
libs.add(new File(p).getAbsolutePath());
} else {
Expand Down Expand Up @@ -339,7 +333,7 @@ public void processFile(Resource resource, File file, File destDir)
}
}

protected void copyDynamicFrameworks(File destDir) throws IOException {
protected void copyDynamicFrameworks(File destDir, File appExecutable) throws IOException {
final Set<String> swiftLibraries = new HashSet<>();
File frameworksDir = new File(destDir, "Frameworks");

Expand Down Expand Up @@ -392,13 +386,7 @@ public void processFile(Resource resource, File file, File destDir) throws IOExc
// check if this dylib depends on Swift
// and register those libraries to be copied
// to bundle.app/Frameworks
String dependencies = ToolchainUtil.otool(file);
Pattern swiftLibraryPattern = Pattern.compile("libswift.+\\.dylib");
Matcher matcher = swiftLibraryPattern.matcher(dependencies);
while (matcher.find()) {
String library = dependencies.substring(matcher.start(), matcher.end());
swiftLibraries.add(library);
}
getSwiftDependencies(file, swiftLibraries);
}
}
}
Expand All @@ -408,6 +396,9 @@ public void processFile(Resource resource, File file, File destDir) throws IOExc
}
}

// find swift libraries that might be referenced in executable due static linking
getSwiftDependencies(appExecutable, swiftLibraries);

// workaround: check if libs contain reference to swift lib
// if project links against static swift library it requires
// dynamic swift libraries to be included. and these are not automatically
Expand All @@ -425,6 +416,16 @@ public void processFile(Resource resource, File file, File destDir) throws IOExc
}
}

protected void getSwiftDependencies(File file, Collection<String> swiftLibraries) throws IOException {
String dependencies = ToolchainUtil.otool(file);
Pattern swiftLibraryPattern = Pattern.compile("@rpath/(libswift.+\\.dylib)");
Matcher matcher = swiftLibraryPattern.matcher(dependencies);
while (matcher.find()) {
String library = matcher.group(1);
swiftLibraries.add(library);
}
}

protected void copyAppExtensions(File destDir) throws IOException {
File pluginsDir = new File(destDir, "PlugIns");

Expand Down Expand Up @@ -582,8 +583,7 @@ private File[] getSwiftDirs(Config config) throws IOException {
List<File> candidates = new ArrayList<>();
for (File path : configPaths)
candidates.add(new File(path, system));
File[] swiftDirs = candidates.toArray(new File[0]);
return validateSwiftDirs(swiftDirs);
return candidates.toArray(new File[0]);
} else {
return getDefaultSwiftDirs(config);
}
Expand Down Expand Up @@ -622,19 +622,12 @@ private File[] getDefaultSwiftDirs(String system) throws IOException {
if (candidate.exists())
candidates.add(candidate);
}
File[] swiftDirs = candidates.toArray(new File[0]);
return validateSwiftDirs(swiftDirs);
}

private File[] validateSwiftDirs(File[] swiftDirs) throws IOException {
try {
// FIXME: simplest criteria is to check for one of core libs
locateSwiftLib(swiftDirs, "libswiftCore.dylib");
} catch (Throwable ignored) {
throw new IOException("Failed to locate Swift Library directory!");
}
// also add runtime location of swift libs. these will be checked against
// SDK root for .tbd files
candidates.add(new File("/usr/lib/swift"));

return swiftDirs;
return candidates.toArray(new File[0]);
}

protected void copySwiftLibs(Collection<String> swiftLibraries, File targetDir, boolean strip) throws IOException {
Expand All @@ -644,27 +637,22 @@ protected void copySwiftLibs(Collection<String> swiftLibraries, File targetDir,
// e.g. one swiftLib has dependency that is not listed in included framework
// solve this by moving through all swiftLibs and resolve their not listed dependencies
Set<String> libsToResolve = new HashSet<>(swiftLibraries);
Set<String> extendedSwiftLibraries = new HashSet<>(swiftLibraries);
Map<String, File> resolvedLibs = new HashMap<>();
while (!libsToResolve.isEmpty()) {
for (String library : new HashSet<>(libsToResolve)) {
libsToResolve.remove(library);
if (!resolvedLibs.containsKey(library)) {
File swiftLibrary = locateSwiftLib(swiftDirs, library);
resolvedLibs.put(library, swiftLibrary);

File swiftLibrary = locateSwiftLib(swiftDirs, library);
String dependencies = ToolchainUtil.otool(swiftLibrary);
Pattern swiftLibraryPattern = Pattern.compile("libswift.+\\.dylib");
Matcher matcher = swiftLibraryPattern.matcher(dependencies);
while (matcher.find()) {
String lib = dependencies.substring(matcher.start(), matcher.end());
if (extendedSwiftLibraries.add(lib)) {
// new dependency, add it heere
libsToResolve.add(lib);
}
}
getSwiftDependencies(swiftLibrary, libsToResolve);
}
}
}

for (String library : extendedSwiftLibraries) {
File swiftLibrary = locateSwiftLib(swiftDirs, library);
for (Map.Entry<String, File> e : resolvedLibs.entrySet()) {
String library = e.getKey();
File swiftLibrary = e.getValue();
config.getLogger().info("Copying swift lib %s from %s to %s", library, swiftLibrary.getParent(), targetDir);
FileUtils.copyFileToDirectory(swiftLibrary, targetDir);

Expand Down Expand Up @@ -753,10 +741,13 @@ public void archive() throws IOException {
}

protected void doInstall(File installDir, String image, File resourcesDir) throws IOException {
File executable;
if (!config.getTmpDir().equals(installDir) || !image.equals(config.getExecutableName())) {
File destFile = new File(installDir, image);
FileUtils.copyFile(new File(config.getTmpDir(), config.getExecutableName()), destFile);
destFile.setExecutable(true, false);
executable = new File(installDir, image);
FileUtils.copyFile(new File(config.getTmpDir(), config.getExecutableName()), executable);
executable.setExecutable(true, false);
} else {
executable = new File(config.getTmpDir(), config.getExecutableName());
}
for (File f : config.getOsArchDepLibDir().listFiles()) {
if (f.getName().matches(".*\\.(so|dylib)(\\.1)?")) {
Expand All @@ -765,7 +756,7 @@ protected void doInstall(File installDir, String image, File resourcesDir) throw
}
stripArchives(installDir);
copyResources(resourcesDir);
copyDynamicFrameworks(installDir);
copyDynamicFrameworks(installDir, executable);
copyAppExtensions(installDir);
copyWatchApp(installDir);
}
Expand Down

0 comments on commit ae74a03

Please sign in to comment.