Skip to content

Commit dffd1b2

Browse files
committed
Use autolinking to pull in compatibility libraries.
Many build systems that support Swift don't use swiftc to drive the linker. To make things easier for these build systems, also use autolinking to pull in the needed compatibility libraries. This is less ideal than letting the driver add it at link time, since individual compile jobs don't know whether they're building an executable or not. Introduce a `-disable-autolink-runtime-compatibility` flag, which build systems that do drive the linker with swiftc can pass to avoid autolinking. rdar://problem/50057445
1 parent b794cf0 commit dffd1b2

File tree

13 files changed

+156
-50
lines changed

13 files changed

+156
-50
lines changed

cmake/modules/SwiftSource.cmake

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,10 @@ function(_compile_swift_files
253253
list(APPEND swift_flags "-module-name" "${SWIFTFILE_MODULE_NAME}")
254254
endif()
255255

256-
# Force swift 5 mode for Standard Library.
256+
# Force swift 5 mode for Standard Library and overlays.
257257
if (SWIFTFILE_IS_STDLIB)
258258
list(APPEND swift_flags "-swift-version" "5")
259259
endif()
260-
261-
# Force swift 4 compatibility mode for overlays.
262260
if (SWIFTFILE_IS_SDK_OVERLAY)
263261
list(APPEND swift_flags "-swift-version" "5")
264262
endif()
@@ -267,6 +265,12 @@ function(_compile_swift_files
267265
list(APPEND swift_flags "-autolink-force-load")
268266
endif()
269267

268+
# Don't need to link runtime compatibility libraries for older runtimes
269+
# into the new runtime.
270+
if (SWIFTFILE_IS_STDLIB OR SWIFTFILE_IS_SDK_OVERLAY)
271+
list(APPEND swift_flags "-runtime-compatibility-version" "none")
272+
endif()
273+
270274
if (SWIFTFILE_IS_STDLIB_CORE OR SWIFTFILE_IS_SDK_OVERLAY)
271275
list(APPEND swift_flags "-warn-swift3-objc-inference-complete")
272276
endif()

include/swift/AST/IRGenOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
// FIXME: This include is just for llvm::SanitizerCoverageOptions. We should
2727
// split the header upstream so we don't include so much.
2828
#include "llvm/Transforms/Instrumentation.h"
29+
#include "llvm/Support/VersionTuple.h"
2930
#include <string>
3031
#include <vector>
3132

@@ -224,6 +225,9 @@ class IRGenOptions {
224225
};
225226

226227
TypeInfoDumpFilter TypeInfoFilter;
228+
229+
/// Pull in runtime compatibility shim libraries by autolinking.
230+
Optional<llvm::VersionTuple> AutolinkRuntimeCompatibilityLibraryVersion;
227231

228232
IRGenOptions()
229233
: DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssembly),

include/swift/Basic/Platform.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
namespace llvm {
2121
class Triple;
22+
class VersionTuple;
2223
}
2324

2425
namespace swift {
@@ -85,6 +86,12 @@ namespace swift {
8586
/// The input triple should already be "normalized" in the sense that
8687
/// llvm::Triple::normalize() would not affect it.
8788
llvm::Triple getTargetSpecificModuleTriple(const llvm::Triple &triple);
89+
90+
91+
/// Get the Swift runtime version to deploy back to, given a deployment target expressed as an
92+
/// LLVM target triple.
93+
Optional<llvm::VersionTuple>
94+
getSwiftRuntimeCompatibilityVersionForTarget(const llvm::Triple &Triple);
8895
} // end namespace swift
8996

9097
#endif // SWIFT_BASIC_PLATFORM_H

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,4 +892,9 @@ def vfsoverlay_EQ : Joined<["-"], "vfsoverlay=">,
892892
def runtime_compatibility_version : Separate<["-"], "runtime-compatibility-version">,
893893
Flags<[FrontendOption]>,
894894
HelpText<"Link compatibility library for Swift runtime version, or 'none'">;
895+
896+
def disable_autolinking_runtime_compatibility : Flag<["-"], "disable-autolinking-runtime-compatibility">,
897+
Flags<[FrontendOption]>,
898+
HelpText<"Do not use autolinking for runtime compatibility libraries">;
899+
895900
include "FrontendOptions.td"

lib/Basic/Platform.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/ADT/StringExtras.h"
1515
#include "llvm/ADT/StringSwitch.h"
1616
#include "llvm/ADT/Triple.h"
17+
#include "llvm/Support/VersionTuple.h"
1718

1819
using namespace swift;
1920

@@ -313,3 +314,37 @@ llvm::Triple swift::getTargetSpecificModuleTriple(const llvm::Triple &triple) {
313314
return triple;
314315
}
315316

317+
Optional<llvm::VersionTuple>
318+
swift::getSwiftRuntimeCompatibilityVersionForTarget(const llvm::Triple &Triple){
319+
unsigned Major, Minor, Micro;
320+
321+
if (Triple.isMacOSX()) {
322+
Triple.getMacOSXVersion(Major, Minor, Micro);
323+
if (Major == 10) {
324+
if (Minor <= 14) {
325+
return llvm::VersionTuple(5, 0);
326+
} else {
327+
return None;
328+
}
329+
} else {
330+
return None;
331+
}
332+
} else if (Triple.isiOS()) { // includes tvOS
333+
Triple.getiOSVersion(Major, Minor, Micro);
334+
if (Major <= 12) {
335+
return llvm::VersionTuple(5, 0);
336+
} else {
337+
return None;
338+
}
339+
} else if (Triple.isWatchOS()) {
340+
Triple.getWatchOSVersion(Major, Minor, Micro);
341+
if (Major <= 5) {
342+
return llvm::VersionTuple(5, 0);
343+
} else {
344+
return None;
345+
}
346+
} else {
347+
return None;
348+
}
349+
}
350+

lib/Driver/DarwinToolChains.cpp

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "llvm/Support/Path.h"
3434
#include "llvm/Support/Process.h"
3535
#include "llvm/Support/Program.h"
36+
#include "llvm/Support/VersionTuple.h"
3637

3738
using namespace swift;
3839
using namespace swift::driver;
@@ -221,42 +222,6 @@ static bool wantsObjCRuntime(const llvm::Triple &triple) {
221222
llvm_unreachable("unknown Darwin OS");
222223
}
223224

224-
/// Return the earliest backward deployment compatibility version we need to
225-
/// link in for the given target triple, if any.
226-
static Optional<std::pair<unsigned, unsigned>>
227-
getSwiftRuntimeCompatibilityVersionForTarget(const llvm::Triple &Triple) {
228-
unsigned Major, Minor, Micro;
229-
230-
if (Triple.isMacOSX()) {
231-
Triple.getMacOSXVersion(Major, Minor, Micro);
232-
if (Major == 10) {
233-
if (Minor <= 14) {
234-
return std::make_pair(5u, 0u);
235-
} else {
236-
return None;
237-
}
238-
} else {
239-
return None;
240-
}
241-
} else if (Triple.isiOS()) { // includes tvOS
242-
Triple.getiOSVersion(Major, Minor, Micro);
243-
if (Major <= 12) {
244-
return std::make_pair(5u, 0u);
245-
} else {
246-
return None;
247-
}
248-
} else if (Triple.isWatchOS()) {
249-
Triple.getWatchOSVersion(Major, Minor, Micro);
250-
if (Major <= 5) {
251-
return std::make_pair(5u, 0u);
252-
} else {
253-
return None;
254-
}
255-
} else {
256-
return None;
257-
}
258-
}
259-
260225
ToolChain::InvocationInfo
261226
toolchains::Darwin::constructInvocation(const LinkJobAction &job,
262227
const JobContext &context) const
@@ -431,12 +396,13 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job,
431396

432397
// Link compatibility libraries, if we're deploying back to OSes that
433398
// have an older Swift runtime.
434-
Optional<std::pair<unsigned, unsigned>> runtimeCompatibilityVersion;
399+
Optional<llvm::VersionTuple> runtimeCompatibilityVersion;
435400

436401
if (context.Args.hasArg(options::OPT_runtime_compatibility_version)) {
437-
auto value = context.Args.getLastArgValue(options::OPT_runtime_compatibility_version);
402+
auto value = context.Args.getLastArgValue(
403+
options::OPT_runtime_compatibility_version);
438404
if (value.equals("5.0")) {
439-
runtimeCompatibilityVersion = std::make_pair(5u, 0u);
405+
runtimeCompatibilityVersion = llvm::VersionTuple(5, 0);
440406
} else if (value.equals("none")) {
441407
runtimeCompatibilityVersion = None;
442408
} else {
@@ -448,7 +414,7 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job,
448414
}
449415

450416
if (runtimeCompatibilityVersion) {
451-
if (*runtimeCompatibilityVersion <= std::make_pair(5u, 0u)) {
417+
if (*runtimeCompatibilityVersion <= llvm::VersionTuple(5, 0)) {
452418
// Swift 5.0 compatibility library
453419
SmallString<128> BackDeployLib;
454420
BackDeployLib.append(RuntimeLibPath);

lib/Driver/ToolChains.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,17 @@ ToolChain::constructInvocation(const CompileJobAction &job,
433433
Arguments.push_back("-debug-info-store-invocation");
434434
}
435435

436+
if (context.Args.hasArg(
437+
options::OPT_disable_autolinking_runtime_compatibility)) {
438+
Arguments.push_back("-disable-autolinking-runtime-compatibility");
439+
}
440+
441+
if (auto arg = context.Args.getLastArg(
442+
options::OPT_runtime_compatibility_version)) {
443+
Arguments.push_back("-runtime-compatibility-version");
444+
Arguments.push_back(arg->getValue());
445+
}
446+
436447
return II;
437448
}
438449

lib/Frontend/CompilerInvocation.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,30 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
11581158
A->getAsString(Args), A->getValue());
11591159
}
11601160
}
1161+
1162+
// Autolink runtime compatibility libraries, if asked to.
1163+
if (!Args.hasArg(options::OPT_disable_autolinking_runtime_compatibility)) {
1164+
Optional<llvm::VersionTuple> runtimeCompatibilityVersion;
1165+
1166+
if (auto versionArg = Args.getLastArg(
1167+
options::OPT_runtime_compatibility_version)) {
1168+
auto version = StringRef(versionArg->getValue());
1169+
if (version.equals("none")) {
1170+
runtimeCompatibilityVersion = None;
1171+
} else if (version.equals("5.0")) {
1172+
runtimeCompatibilityVersion = llvm::VersionTuple(5, 0);
1173+
} else {
1174+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
1175+
versionArg->getAsString(Args), version);
1176+
}
1177+
} else {
1178+
runtimeCompatibilityVersion =
1179+
getSwiftRuntimeCompatibilityVersionForTarget(Triple);
1180+
}
1181+
1182+
Opts.AutolinkRuntimeCompatibilityLibraryVersion =
1183+
runtimeCompatibilityVersion;
1184+
}
11611185

11621186
return false;
11631187
}

lib/IRGen/GenDecl.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,26 @@ void IRGenModule::emitSourceFile(SourceFile &SF) {
445445

446446
if (ObjCInterop)
447447
this->addLinkLibrary(LinkLibrary("objc", LibraryKind::Library));
448+
449+
// FIXME: It'd be better to have the driver invocation or build system that
450+
// executes the linker introduce these compatibility libraries, since at
451+
// that point we know whether we're building an executable, which is the only
452+
// place where the compatibility libraries take effect. For the benefit of
453+
// build systems that build Swift code, but don't use Swift to drive
454+
// the linker, we can also use autolinking to pull in the compatibility
455+
// libraries. This may however cause the library to get pulled in in
456+
// situations where it isn't useful, such as for dylibs, though this is
457+
// harmless aside from code size.
458+
if (!IRGen.Opts.UseJIT) {
459+
if (auto compatibilityVersion
460+
= IRGen.Opts.AutolinkRuntimeCompatibilityLibraryVersion) {
461+
if (*compatibilityVersion <= llvm::VersionTuple(5, 0)) {
462+
this->addLinkLibrary(LinkLibrary("swiftCompatibility50",
463+
LibraryKind::Library,
464+
/*forceLoad*/ true));
465+
}
466+
}
467+
}
448468
}
449469

450470
/// Collect elements of an already-existing global list with the given

stdlib/public/Compatibility50/Overrides.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,8 @@ __attribute__((used, section("__DATA,__swift_hooks"))) = {
3131
.version = 0,
3232
.conformsToProtocol = swift50override_conformsToProtocol,
3333
};
34+
35+
// Allow this library to get force-loaded by autolinking
36+
__attribute__((weak, visibility("hidden")))
37+
extern "C"
38+
char _swift_FORCE_LOAD_$_swiftCompatibility50 = 0;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// REQUIRES: OS=macosx
2+
3+
// Doesn't autolink compatibility library because autolinking is disabled
4+
// RUN: %target-swift-frontend -target x86_64-apple-macosx10.9 -disable-autolinking-runtime-compatibility -emit-ir -parse-stdlib %s | %FileCheck -check-prefix=NO-FORCE-LOAD %s
5+
// RUN: %target-swift-frontend -runtime-compatibility-version 5.0 -disable-autolinking-runtime-compatibility -emit-ir -parse-stdlib %s | %FileCheck -check-prefix=NO-FORCE-LOAD %s
6+
7+
// Doesn't autolink compatibility library because runtime compatibility library is disabled
8+
// RUN: %target-swift-frontend -runtime-compatibility-version none -emit-ir -parse-stdlib %s | %FileCheck -check-prefix=NO-FORCE-LOAD %s
9+
10+
// Doesn't autolink compatibility library because target OS doesn't need it
11+
// RUN: %target-swift-frontend -target x86_64-apple-macosx10.24 -emit-ir -parse-stdlib %s | %FileCheck -check-prefix=NO-FORCE-LOAD %s
12+
13+
// Autolinks because compatibility library was explicitly asked for
14+
// RUN: %target-swift-frontend -runtime-compatibility-version 5.0 -emit-ir -parse-stdlib %s | %FileCheck -check-prefix=FORCE-LOAD %s
15+
// RUN: %target-swift-frontend -target x86_64-apple-macosx10.24 -runtime-compatibility-version 5.0 -emit-ir -parse-stdlib %s | %FileCheck -check-prefix=FORCE-LOAD %s
16+
17+
public func foo() {}
18+
19+
// NO-FORCE-LOAD-NOT: FORCE_LOAD
20+
// NO-FORCE-LOAD-NOT: !{!"-lswiftCompatibility50"}
21+
22+
// FORCE-LOAD: declare {{.*}} @"_swift_FORCE_LOAD_$_swiftCompatibility50"
23+
24+
// FORCE-LOAD-DAG: [[AUTOLINK_SWIFT_COMPAT:![0-9]+]] = !{!"-lswiftCompatibility50"}
25+
// FORCE-LOAD-DAG: !llvm.linker.options = !{{{.*}}[[AUTOLINK_SWIFT_COMPAT]]{{[,}]}}

test/IRGen/unused.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck -check-prefix CHECK -check-prefix NEGATIVE -check-prefix CHECK-%target-object-format %s
1+
// RUN: %target-swift-frontend -runtime-compatibility-version none -primary-file %s -emit-ir | %FileCheck -check-prefix CHECK -check-prefix NEGATIVE -check-prefix CHECK-%target-object-format %s
22

33
// REQUIRES: CPU=x86_64
44

test/Serialization/autolinking.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-swift-frontend -emit-module -parse-stdlib -o %t -module-name someModule -module-link-name module %S/../Inputs/empty.swift
3-
// RUN: %target-swift-frontend -emit-ir -lmagic %s -I %t > %t/out.txt
3+
// RUN: %target-swift-frontend -runtime-compatibility-version none -emit-ir -lmagic %s -I %t > %t/out.txt
44
// RUN: %FileCheck %s < %t/out.txt
55
// RUN: %FileCheck -check-prefix=NO-FORCE-LOAD %s < %t/out.txt
66

77
// RUN: %empty-directory(%t/someModule.framework/Modules/someModule.swiftmodule)
88
// RUN: mv %t/someModule.swiftmodule %t/someModule.framework/Modules/someModule.swiftmodule/%target-swiftmodule-name
9-
// RUN: %target-swift-frontend -emit-ir -lmagic %s -F %t > %t/framework.txt
9+
// RUN: %target-swift-frontend -runtime-compatibility-version none -emit-ir -lmagic %s -F %t > %t/framework.txt
1010
// RUN: %FileCheck -check-prefix=FRAMEWORK %s < %t/framework.txt
1111
// RUN: %FileCheck -check-prefix=NO-FORCE-LOAD %s < %t/framework.txt
1212

1313
// RUN: %target-swift-frontend -emit-module -parse-stdlib -o %t -module-name someModule -module-link-name module %S/../Inputs/empty.swift -autolink-force-load
14-
// RUN: %target-swift-frontend -emit-ir -lmagic %s -I %t > %t/force-load.txt
14+
// RUN: %target-swift-frontend -runtime-compatibility-version none -emit-ir -lmagic %s -I %t > %t/force-load.txt
1515
// RUN: %FileCheck %s < %t/force-load.txt
1616
// RUN: %FileCheck -check-prefix FORCE-LOAD-CLIENT -check-prefix FORCE-LOAD-CLIENT-%target-object-format %s < %t/force-load.txt
1717

18-
// RUN: %target-swift-frontend -emit-ir -parse-stdlib -module-name someModule -module-link-name module %S/../Inputs/empty.swift | %FileCheck --check-prefix=NO-FORCE-LOAD %s
19-
// RUN: %target-swift-frontend -emit-ir -parse-stdlib -module-name someModule -module-link-name module %S/../Inputs/empty.swift -autolink-force-load | %FileCheck --check-prefix=FORCE-LOAD %s
20-
// RUN: %target-swift-frontend -emit-ir -parse-stdlib -module-name someModule -module-link-name 0module %S/../Inputs/empty.swift -autolink-force-load | %FileCheck --check-prefix=FORCE-LOAD-HEX %s
18+
// RUN: %target-swift-frontend -runtime-compatibility-version none -emit-ir -parse-stdlib -module-name someModule -module-link-name module %S/../Inputs/empty.swift | %FileCheck --check-prefix=NO-FORCE-LOAD %s
19+
// RUN: %target-swift-frontend -runtime-compatibility-version none -emit-ir -parse-stdlib -module-name someModule -module-link-name module %S/../Inputs/empty.swift -autolink-force-load | %FileCheck --check-prefix=FORCE-LOAD %s
20+
// RUN: %target-swift-frontend -runtime-compatibility-version none -emit-ir -parse-stdlib -module-name someModule -module-link-name 0module %S/../Inputs/empty.swift -autolink-force-load | %FileCheck --check-prefix=FORCE-LOAD-HEX %s
2121

2222
// Linux uses a different autolinking mechanism, based on
2323
// swift-autolink-extract. This file tests the Darwin mechanism.

0 commit comments

Comments
 (0)