Skip to content

Commit 0771f1e

Browse files
authored
Merge pull request #37211 from compnerd/windows-static-linking
IRGen: support static linking on Windows
2 parents d974373 + 8da2c37 commit 0771f1e

17 files changed

+128
-7
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,10 @@ class alignas(1 << DeclAlignInBits) Decl {
588588
HasAnyUnavailableValues : 1
589589
);
590590

591-
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1,
591+
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1,
592+
/// If the module is compiled as static library.
593+
StaticLibrary : 1,
594+
592595
/// If the module was or is being compiled with `-enable-testing`.
593596
TestingEnabled : 1,
594597

include/swift/AST/Module.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,14 @@ class ModuleDecl : public DeclContext, public TypeDecl {
424424
DebugClient = R;
425425
}
426426

427+
/// Returns true if this module is compiled as static library.
428+
bool isStaticLibrary() const {
429+
return Bits.ModuleDecl.StaticLibrary;
430+
}
431+
void setStaticLibrary(bool isStatic = true) {
432+
Bits.ModuleDecl.StaticLibrary = isStatic;
433+
}
434+
427435
/// Returns true if this module was or is being compiled for testing.
428436
bool isTestingEnabled() const {
429437
return Bits.ModuleDecl.TestingEnabled;

include/swift/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ class FrontendOptions {
314314
/// skip nodes entirely, depending on the errors involved.
315315
bool AllowModuleWithCompilerErrors = false;
316316

317+
/// True if the "-static" option is set.
318+
bool Static = false;
319+
317320
/// The different modes for validating TBD against the LLVM IR.
318321
enum class TBDValidationMode {
319322
Default, ///< Do the default validation for the current platform.

include/swift/Serialization/SerializationOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ namespace swift {
136136
bool SerializeOptionsForDebugging = false;
137137
bool IsSIB = false;
138138
bool DisableCrossModuleIncrementalInfo = false;
139+
bool StaticLibrary = false;
139140
};
140141

141142
} // end namespace swift

include/swift/Serialization/Validation.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class ExtendedValidationInfo {
9898
struct {
9999
unsigned ArePrivateImportsEnabled : 1;
100100
unsigned IsSIB : 1;
101+
unsigned IsStaticLibrary: 1;
101102
unsigned IsTestable : 1;
102103
unsigned ResilienceStrategy : 2;
103104
unsigned IsImplicitDynamicEnabled : 1;
@@ -131,6 +132,10 @@ class ExtendedValidationInfo {
131132
void setImplicitDynamicEnabled(bool val) {
132133
Bits.IsImplicitDynamicEnabled = val;
133134
}
135+
bool isStaticLibrary() const { return Bits.IsStaticLibrary; }
136+
void setIsStaticLibrary(bool val) {
137+
Bits.IsStaticLibrary = val;
138+
}
134139
bool isTestable() const { return Bits.IsTestable; }
135140
void setIsTestable(bool val) {
136141
Bits.IsTestable = val;

lib/AST/Module.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx,
475475

476476
setAccess(AccessLevel::Public);
477477

478+
Bits.ModuleDecl.StaticLibrary = 0;
478479
Bits.ModuleDecl.TestingEnabled = 0;
479480
Bits.ModuleDecl.FailedToLoad = 0;
480481
Bits.ModuleDecl.RawResilienceStrategy = 0;

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ bool ArgsToFrontendOptionsConverter::convert(
258258

259259
Opts.SkipInheritedDocs = Args.hasArg(OPT_skip_inherited_docs);
260260

261+
Opts.Static = Args.hasArg(OPT_static);
262+
261263
return false;
262264
}
263265

lib/Frontend/Frontend.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ SerializationOptions CompilerInvocation::computeSerializationOptions(
182182
serializationOpts.DisableCrossModuleIncrementalInfo =
183183
opts.DisableCrossModuleIncrementalBuild;
184184

185+
serializationOpts.StaticLibrary = opts.Static;
186+
185187
return serializationOpts;
186188
}
187189

lib/IRGen/GenDecl.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,7 +2030,7 @@ void irgen::updateLinkageForDefinition(IRGenModule &IGM,
20302030
bool isKnownLocal = entity.isAlwaysSharedLinkage();
20312031
if (const auto *DC = entity.getDeclContextForEmission())
20322032
if (const auto *MD = DC->getParentModule())
2033-
isKnownLocal = IGM.getSwiftModule() == MD;
2033+
isKnownLocal = IGM.getSwiftModule() == MD || MD->isStaticLibrary();
20342034

20352035
auto IRL =
20362036
getIRLinkage(linkInfo, entity.getLinkage(ForDefinition),
@@ -2059,7 +2059,7 @@ LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo,
20592059
bool isKnownLocal = entity.isAlwaysSharedLinkage();
20602060
if (const auto *DC = entity.getDeclContextForEmission())
20612061
if (const auto *MD = DC->getParentModule())
2062-
isKnownLocal = MD == swiftModule;
2062+
isKnownLocal = MD == swiftModule || MD->isStaticLibrary();
20632063

20642064
entity.mangle(result.Name);
20652065
bool weakImported = entity.isWeakImported(swiftModule);
@@ -2074,6 +2074,8 @@ LinkInfo LinkInfo::get(const UniversalLinkageInfo &linkInfo, StringRef name,
20742074
bool isWeakImported) {
20752075
LinkInfo result;
20762076

2077+
// TODO(compnerd) handle this properly
2078+
20772079
result.Name += name;
20782080
result.IRL = getIRLinkage(linkInfo, linkage, isDefinition, isWeakImported);
20792081
result.ForDefinition = isDefinition;

lib/IRGen/GenProto.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,9 +1117,15 @@ class DirectConformanceInfo : public ConformanceInfo {
11171117

11181118
llvm::Constant *tryGetConstantTable(IRGenModule &IGM,
11191119
CanType conformingType) const override {
1120-
if (IGM.getOptions().LazyInitializeProtocolConformances &&
1121-
RootConformance->getDeclContext()->getParentModule() != IGM.getSwiftModule())
1122-
return nullptr;
1120+
if (IGM.getOptions().LazyInitializeProtocolConformances) {
1121+
const auto *MD = RootConformance->getDeclContext()->getParentModule();
1122+
// If the protocol conformance is defined in the current module or the
1123+
// module will be statically linked, then we can statically initialize the
1124+
// conformance as we know that the protocol conformance is guaranteed to
1125+
// be present.
1126+
if (!(MD == IGM.getSwiftModule() || MD->isStaticLibrary()))
1127+
return nullptr;
1128+
}
11231129
return IGM.getAddrOfWitnessTable(RootConformance);
11241130
}
11251131
};

lib/Serialization/ModuleFile.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,11 @@ class ModuleFile
461461
return Core->Bits.IsTestable;
462462
}
463463

464+
/// Whether this module is compiled as static library.
465+
bool isStaticLibrary() const {
466+
return Core->Bits.IsStaticLibrary;
467+
}
468+
464469
/// Whether the module is resilient. ('-enable-library-evolution')
465470
ResilienceStrategy getResilienceStrategy() const {
466471
return ResilienceStrategy(Core->Bits.ResilienceStrategy);

lib/Serialization/ModuleFileSharedCore.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
131131
options_block::IsSIBLayout::readRecord(scratch, IsSIB);
132132
extendedInfo.setIsSIB(IsSIB);
133133
break;
134+
case options_block::IS_STATIC_LIBRARY:
135+
extendedInfo.setIsStaticLibrary(true);
136+
break;
134137
case options_block::IS_TESTABLE:
135138
extendedInfo.setIsTestable(true);
136139
break;
@@ -1180,6 +1183,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
11801183
UserModuleVersion = info.userModuleVersion;
11811184
Bits.ArePrivateImportsEnabled = extInfo.arePrivateImportsEnabled();
11821185
Bits.IsSIB = extInfo.isSIB();
1186+
Bits.IsStaticLibrary = extInfo.isStaticLibrary();
11831187
Bits.IsTestable = extInfo.isTestable();
11841188
Bits.ResilienceStrategy = unsigned(extInfo.getResilienceStrategy());
11851189
Bits.IsImplicitDynamicEnabled = extInfo.isImplicitDynamicEnabled();

lib/Serialization/ModuleFileSharedCore.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,9 @@ class ModuleFileSharedCore {
326326
/// Whether this module file is actually a .sib file.
327327
unsigned IsSIB: 1;
328328

329+
/// Whether this module is compiled as static library.
330+
unsigned IsStaticLibrary: 1;
331+
329332
/// Whether this module file is compiled with '-enable-testing'.
330333
unsigned IsTestable : 1;
331334

lib/Serialization/ModuleFormat.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5656
/// describe what change you made. The content of this comment isn't important;
5757
/// it just ensures a conflict if two people change the module format.
5858
/// Don't worry about adhering to the 80-column limit for this line.
59-
const uint16_t SWIFTMODULE_VERSION_MINOR = 612; // add user-defined module version
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 613; // isStaticLibrary option
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///
@@ -788,6 +788,7 @@ namespace options_block {
788788
SDK_PATH = 1,
789789
XCC,
790790
IS_SIB,
791+
IS_STATIC_LIBRARY,
791792
IS_TESTABLE,
792793
RESILIENCE_STRATEGY,
793794
ARE_PRIVATE_IMPORTS_ENABLED,
@@ -811,6 +812,10 @@ namespace options_block {
811812
BCFixed<1> // Is this an intermediate file?
812813
>;
813814

815+
using IsStaticLibraryLayout = BCRecordLayout<
816+
IS_STATIC_LIBRARY
817+
>;
818+
814819
using IsTestableLayout = BCRecordLayout<
815820
IS_TESTABLE
816821
>;

lib/Serialization/Serialization.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,11 @@ void Serializer::writeHeader(const SerializationOptions &options) {
981981
options_block::IsSIBLayout IsSIB(Out);
982982
IsSIB.emit(ScratchRecord, options.IsSIB);
983983

984+
if (options.StaticLibrary) {
985+
options_block::IsStaticLibraryLayout IsStaticLibrary(Out);
986+
IsStaticLibrary.emit(ScratchRecord);
987+
}
988+
984989
if (M->isTestingEnabled()) {
985990
options_block::IsTestableLayout IsTestable(Out);
986991
IsTestable.emit(ScratchRecord);

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
722722

723723
// We've loaded the file. Now try to bring it into the AST.
724724
fileUnit = new (Ctx) SerializedASTFile(M, *loadedModuleFile);
725+
M.setStaticLibrary(loadedModuleFile->isStaticLibrary());
725726
if (loadedModuleFile->isTestable())
726727
M.setTestingEnabled();
727728
if (loadedModuleFile->arePrivateImportsEnabled())

test/IRGen/windows-linking.swift

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -static -emit-module -emit-module-path %t/module.swiftmodule -module-name module -DMODULE %s
3+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -S -emit-ir %s -module-name main -o - -I%t | %FileCheck %s -check-prefix CHECK-STATIC
4+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -emit-module -emit-module-path %t/module.swiftmodule -module-name module -DMODULE %s
5+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -S -emit-ir %s -module-name main -o - -I%t | %FileCheck %s -check-prefix CHECK-SHARED
6+
7+
#if MODULE
8+
9+
public struct S {}
10+
public var value: S {
11+
S()
12+
}
13+
14+
public func f(_ s: S) {}
15+
16+
public protocol P {
17+
}
18+
19+
public enum E: P {
20+
}
21+
22+
#else
23+
24+
import module
25+
26+
protocol Q: P {
27+
}
28+
29+
extension E: Q {
30+
}
31+
32+
@main
33+
struct Entry {
34+
public static func main() {
35+
f(value)
36+
}
37+
}
38+
39+
#endif
40+
41+
42+
// Ensure that static linking does not mark the entries as being indirected
43+
// through the IAT.
44+
45+
// CHECK-STATIC: @"$s6module1EO4main1QADWP" = hidden constant [2 x i8*] [
46+
// CHECK-STATIC-SAME: i8* bitcast (%swift.protocol_conformance_descriptor* @"$s6module1EO4main1QADMc" to i8*),
47+
// CHECK-STATIC-SAME: i8* bitcast (i8** @"$s6module1EOAA1PAAWP" to i8*)
48+
// CHECK-STATIC-SAME: ]
49+
50+
// CHECK-STATIC: declare swiftcc void @"$s6module5valueAA1SVvg"()
51+
52+
// CHECK-STATIC: declare swiftcc void @"$s6module1fyyAA1SVF"()
53+
54+
55+
// Ensure that shared linking does mark the functions as being indirected
56+
// through the IAT.
57+
58+
// CHECK-SHARED: @"$s6module1EO4main1QADWP" = hidden constant [2 x i8*] [
59+
// CHECK-SHARED-SAME: i8* bitcast (%swift.protocol_conformance_descriptor* @"$s6module1EO4main1QADMc" to i8*),
60+
// CHECK-SHARED-SAME: i8* null
61+
// CHECK-SHARED-SAME: ]
62+
63+
// CHECK-SHARED: declare dllimport swiftcc void @"$s6module5valueAA1SVvg"()
64+
65+
// CHECK-SHARED: declare dllimport swiftcc void @"$s6module1fyyAA1SVF"()

0 commit comments

Comments
 (0)