14
14
#include " swift/AST/ASTContext.h"
15
15
#include " swift/AST/Decl.h"
16
16
#include " swift/AST/DiagnosticsFrontend.h"
17
+ #include " swift/AST/FileSystem.h"
17
18
#include " swift/AST/Module.h"
18
19
#include " swift/Frontend/Frontend.h"
19
20
#include " swift/Frontend/ParseableInterfaceSupport.h"
@@ -32,6 +33,7 @@ using namespace swift;
32
33
33
34
#define SWIFT_TOOLS_VERSION_KEY " swift-tools-version"
34
35
#define SWIFT_MODULE_FLAGS_KEY " swift-module-flags"
36
+ #define SWIFT_INTERFACE_DEPS_VERSION " swift-interface-deps-version-1"
35
37
36
38
static bool
37
39
extractSwiftInterfaceVersionAndArgs (DiagnosticEngine &Diags,
@@ -100,10 +102,11 @@ std::string getCacheHash(ASTContext &Ctx,
100
102
}
101
103
102
104
void
103
- ParseableInterfaceModuleLoader::configureSubInvocationAndOutputPath (
105
+ ParseableInterfaceModuleLoader::configureSubInvocationAndOutputPaths (
104
106
CompilerInvocation &SubInvocation,
105
107
StringRef InPath,
106
- llvm::SmallString<128 > &OutPath) {
108
+ llvm::SmallString<128 > &OutPath,
109
+ llvm::SmallString<128 > &DepPath) {
107
110
108
111
auto &SearchPathOpts = Ctx.SearchPathOpts ;
109
112
auto &LangOpts = Ctx.LangOpts ;
@@ -125,8 +128,11 @@ ParseableInterfaceModuleLoader::configureSubInvocationAndOutputPath(
125
128
OutPath.append (" -" );
126
129
OutPath.append (getCacheHash (Ctx, SubInvocation, InPath));
127
130
OutPath.append (" ." );
128
- auto Ext = file_types::getExtension (file_types::TY_SwiftModuleFile);
129
- OutPath.append (Ext);
131
+ DepPath = OutPath;
132
+ auto OutExt = file_types::getExtension (file_types::TY_SwiftModuleFile);
133
+ OutPath.append (OutExt);
134
+ auto DepExt = file_types::getExtension (file_types::TY_SwiftParseableInterfaceDeps);
135
+ DepPath.append (DepExt);
130
136
131
137
auto &FEOpts = SubInvocation.getFrontendOptions ();
132
138
FEOpts.RequestedAction = FrontendOptions::ActionType::EmitModuleOnly;
@@ -137,24 +143,67 @@ ParseableInterfaceModuleLoader::configureSubInvocationAndOutputPath(
137
143
FEOpts.InputsAndOutputs .setMainAndSupplementaryOutputs ({MainOut}, {SOPs});
138
144
}
139
145
140
- // FIXME: this needs to be a more extensive up-to-date check.
146
+ // Write the world's simplest dependencies file: a version identifier on
147
+ // a line followed by a list of files, one per line.
148
+ static bool writeSwiftInterfaceDeps (DiagnosticEngine &Diags,
149
+ ArrayRef<std::string> Deps,
150
+ StringRef DepPath) {
151
+ return withOutputFile (Diags, DepPath, [&](llvm::raw_pwrite_stream &out) {
152
+ out << SWIFT_INTERFACE_DEPS_VERSION << ' \n ' ;
153
+ for (auto const &D : Deps) {
154
+ out << D << ' \n ' ;
155
+ }
156
+ return false ;
157
+ });
158
+ }
159
+
160
+ // Check that the output .swiftmodule file is at least as new as all the
161
+ // dependencies it read when it was built last time.
141
162
static bool
142
163
swiftModuleIsUpToDate (clang::vfs::FileSystem &FS,
143
- StringRef InPath, StringRef OutPath) {
144
- if (FS.exists (OutPath)) {
145
- auto InStatus = FS.status (InPath);
146
- auto OutStatus = FS.status (OutPath);
147
- if (InStatus && OutStatus) {
148
- return InStatus.get ().getLastModificationTime () <=
149
- OutStatus.get ().getLastModificationTime ();
164
+ StringRef InPath, StringRef OutPath, StringRef DepPath) {
165
+
166
+ if (!FS.exists (OutPath) || !FS.exists (DepPath))
167
+ return false ;
168
+
169
+ auto OutStatus = FS.status (OutPath);
170
+ if (!OutStatus)
171
+ return false ;
172
+
173
+ auto DepBuf = FS.getBufferForFile (DepPath);
174
+ if (!DepBuf)
175
+ return false ;
176
+
177
+ // Split the deps file into a vector of lines.
178
+ StringRef Deps = DepBuf.get ()->getBuffer ();
179
+ SmallVector<StringRef, 16 > AllDeps;
180
+ Deps.split (AllDeps, ' \n ' , /* MaxSplit=*/ -1 , /* KeepEmpty=*/ false );
181
+
182
+ // First line in vector is a version-string; check it is the expected value.
183
+ if (AllDeps.size () < 1 ||
184
+ AllDeps[0 ] != SWIFT_INTERFACE_DEPS_VERSION) {
185
+ return false ;
186
+ }
187
+
188
+ // Overwrite the version-string entry in the vector with the .swiftinterface
189
+ // input file we're reading, then stat() every entry in the vector and check
190
+ // none are newer than the .swiftmodule (OutStatus).
191
+ AllDeps[0 ] = InPath;
192
+ for (auto In : AllDeps) {
193
+ auto InStatus = FS.status (In);
194
+ if (!InStatus ||
195
+ (InStatus.get ().getLastModificationTime () >
196
+ OutStatus.get ().getLastModificationTime ())) {
197
+ return false ;
150
198
}
151
199
}
152
- return false ;
200
+ return true ;
153
201
}
154
202
155
203
static bool buildSwiftModuleFromSwiftInterface (
156
204
clang::vfs::FileSystem &FS, DiagnosticEngine &Diags,
157
- CompilerInvocation &SubInvocation, StringRef InPath, StringRef OutPath) {
205
+ CompilerInvocation &SubInvocation, StringRef InPath, StringRef OutPath,
206
+ StringRef DepPath) {
158
207
bool SubError = false ;
159
208
bool RunSuccess = llvm::CrashRecoveryContext ().RunSafelyOnThread ([&] {
160
209
@@ -178,6 +227,7 @@ static bool buildSwiftModuleFromSwiftInterface(
178
227
// module-serialization task we're trying to do here.
179
228
LLVM_DEBUG (llvm::dbgs () << " Setting up instance\n " );
180
229
CompilerInstance SubInstance;
230
+ SubInstance.createDependencyTracker (/* TrackSystemDeps=*/ false );
181
231
if (SubInstance.setup (SubInvocation)) {
182
232
SubError = true ;
183
233
return ;
@@ -212,6 +262,12 @@ static bool buildSwiftModuleFromSwiftInterface(
212
262
});
213
263
SILMod->serialize ();
214
264
SubError = Diags.hadAnyError ();
265
+
266
+ if (!SubError) {
267
+ SubError |= writeSwiftInterfaceDeps (
268
+ Diags, SubInstance.getDependencyTracker ()->getDependencies (),
269
+ DepPath);
270
+ }
215
271
});
216
272
return !RunSuccess || SubError;
217
273
}
@@ -227,7 +283,7 @@ std::error_code ParseableInterfaceModuleLoader::openModuleFiles(
227
283
228
284
auto &FS = *Ctx.SourceMgr .getFileSystem ();
229
285
auto &Diags = Ctx.Diags ;
230
- llvm::SmallString<128 > InPath, OutPath;
286
+ llvm::SmallString<128 > InPath, OutPath, DepPath ;
231
287
232
288
// First check to see if the .swiftinterface exists at all. Bail if not.
233
289
InPath = DirName;
@@ -240,12 +296,12 @@ std::error_code ParseableInterfaceModuleLoader::openModuleFiles(
240
296
// Set up a _potential_ sub-invocation to consume the .swiftinterface and emit
241
297
// the .swiftmodule.
242
298
CompilerInvocation SubInvocation;
243
- configureSubInvocationAndOutputPath (SubInvocation, InPath, OutPath);
299
+ configureSubInvocationAndOutputPaths (SubInvocation, InPath, OutPath, DepPath );
244
300
245
301
// Evaluate if we need to run this sub-invocation, and if so run it.
246
- if (!swiftModuleIsUpToDate (FS, InPath, OutPath)) {
302
+ if (!swiftModuleIsUpToDate (FS, InPath, OutPath, DepPath )) {
247
303
if (buildSwiftModuleFromSwiftInterface (FS, Diags, SubInvocation, InPath,
248
- OutPath))
304
+ OutPath, DepPath ))
249
305
return std::make_error_code (std::errc::invalid_argument);
250
306
}
251
307
0 commit comments