Skip to content

Commit 0bd6361

Browse files
authored
Merge pull request #2577 from apple/compiled-manifests-5.1
[5.1] Compile manifests instead of interpreting them
2 parents 331fa5c + 0b23a7e commit 0bd6361

File tree

2 files changed

+58
-33
lines changed

2 files changed

+58
-33
lines changed

Sources/PackageLoading/ManifestLoader.swift

+54-32
Original file line numberDiff line numberDiff line change
@@ -401,31 +401,21 @@ public final class ManifestLoader: ManifestLoaderProtocol {
401401

402402
// Compute the path to runtime we need to load.
403403
let runtimePath = self.runtimePath(for: manifestVersion).pathString
404-
let interpreterFlags = self.interpreterFlags(for: manifestVersion)
404+
let compilerFlags = self.interpreterFlags(for: manifestVersion)
405405

406406
// FIXME: Workaround for the module cache bug that's been haunting Swift CI
407407
// <rdar://problem/48443680>
408408
let moduleCachePath = Process.env["SWIFTPM_MODULECACHE_OVERRIDE"] ?? Process.env["SWIFTPM_TESTS_MODULECACHE"]
409409

410+
let bootstrapArgs = self.bootstrapArgs()
411+
410412
var cmd = [String]()
411-
#if os(macOS)
412-
// If enabled, use sandbox-exec on macOS. This provides some safety against
413-
// arbitrary code execution when parsing manifest files. We only allow
414-
// the permissions which are absolutely necessary for manifest parsing.
415-
if isManifestSandboxEnabled {
416-
let cacheDirs = [
417-
cacheDir,
418-
moduleCachePath.map{ AbsolutePath($0) }
419-
].compactMap{$0}
420-
cmd += ["sandbox-exec", "-p", sandboxProfile(cacheDirs)]
421-
}
422-
#endif
423413
cmd += [resources.swiftCompiler.pathString]
424-
cmd += ["--driver-mode=swift"]
425-
cmd += bootstrapArgs()
414+
cmd += bootstrapArgs.compileFlags
426415
cmd += verbosity.ccArgs
427416
cmd += ["-L", runtimePath, "-lPackageDescription"]
428-
cmd += interpreterFlags
417+
cmd += ["-Xlinker", "-rpath", "-Xlinker", runtimePath]
418+
cmd += compilerFlags
429419
if let moduleCachePath = moduleCachePath {
430420
cmd += ["-module-cache-path", moduleCachePath]
431421
}
@@ -441,25 +431,55 @@ public final class ManifestLoader: ManifestLoaderProtocol {
441431

442432
cmd += [manifestPath.pathString]
443433

444-
// Create and open a temporary file to write json to.
445-
let file = try TemporaryFile()
434+
let tmpDir = try TemporaryDirectory(removeTreeOnDeinit: true)
435+
let compiledManifest = tmpDir.path.appending(component: "manifest")
436+
// Set path to compiled manifest executable.
437+
cmd += ["-o", compiledManifest.pathString]
438+
439+
// Compile the manifest.
440+
let compilerResult = try Process.popen(arguments: cmd)
441+
let compilerOutput = try (compilerResult.utf8Output() + compilerResult.utf8stderrOutput()).spm_chuzzle()
442+
manifestParseResult.compilerOutput = compilerOutput
443+
444+
// Return now if there was an error.
445+
if compilerResult.exitStatus != .terminated(code: 0) {
446+
return
447+
}
448+
446449
// Pass the fd in arguments.
447-
cmd += ["-fileno", "\(file.fileHandle.fileDescriptor)"]
450+
cmd = [compiledManifest.pathString, "-fileno", "1"]
451+
452+
#if os(macOS)
453+
// If enabled, use sandbox-exec on macOS. This provides some safety against
454+
// arbitrary code execution when parsing manifest files. We only allow
455+
// the permissions which are absolutely necessary for manifest parsing.
456+
if isManifestSandboxEnabled {
457+
let cacheDirectories = [
458+
cacheDir,
459+
moduleCachePath.map({ AbsolutePath($0) })
460+
].compactMap({ $0 })
461+
let profile = sandboxProfile(cacheDirectories)
462+
cmd += ["sandbox-exec", "-p", profile]
463+
}
464+
#endif
465+
466+
// Setup the runtime environment for bootstrapping.
467+
var env = Process.env
468+
if !bootstrapArgs.runtimeFlags.isEmpty {
469+
env["LD_LIBRARY_PATH"] = bootstrapArgs.runtimeFlags.joined(separator: ":")
470+
}
448471

449472
// Run the command.
450-
let result = try Process.popen(arguments: cmd)
451-
let output = try (result.utf8Output() + result.utf8stderrOutput()).spm_chuzzle()
452-
manifestParseResult.compilerOutput = output
473+
let runResult = try Process.popen(arguments: cmd, environment: env)
474+
let runOutput = try (runResult.utf8Output() + runResult.utf8stderrOutput()).spm_chuzzle()
453475

454476
// Return now if there was an error.
455-
if result.exitStatus != .terminated(code: 0) {
477+
if runResult.exitStatus != .terminated(code: 0) {
478+
manifestParseResult.errorOutput = runOutput
456479
return
457480
}
458481

459-
guard let json = try localFileSystem.readFileContents(file.path).validDescription else {
460-
throw StringError("the manifest has invalid encoding")
461-
}
462-
manifestParseResult.parsedManifest = json
482+
manifestParseResult.parsedManifest = runOutput
463483
}
464484

465485
var manifestParseResult = ManifestParseResult()
@@ -478,32 +498,34 @@ public final class ManifestLoader: ManifestLoaderProtocol {
478498
}
479499

480500
/// Returns the extra manifest args required during SwiftPM's own bootstrap.
481-
private func bootstrapArgs() -> [String] {
501+
private func bootstrapArgs() -> (compileFlags: [String], runtimeFlags: [String]) {
482502
#if !os(Linux)
483-
return []
503+
return ([], [])
484504
#else
485505
// The Linux bots require extra arguments in order to locate the corelibs.
486506
// We can potentially drop this by installing some stable linux toolchain
487507
// after Swift gets ABI and module stability.
488508
//
489509
// Compute if SwiftPM is bootstrapping.
490510
let env = ProcessInfo.processInfo.environment
491-
guard env.keys.contains("SWIFTPM_BOOTSTRAP") else { return [] }
511+
guard env.keys.contains("SWIFTPM_BOOTSTRAP") else { return ([], []) }
492512
guard let buildPathStr = env["SWIFTPM_BUILD_DIR"], let buildPath = try? AbsolutePath(validating: buildPathStr) else {
493-
return []
513+
return ([], [])
494514
}
495515

496516
// Construct the required search paths relative to the build directory.
497517
let libdir = buildPath.appending(RelativePath(".bootstrap/lib/swift/linux"))
498518
let incdir = libdir.appending(component: "x86_64")
499519
let dispatchIncdir = incdir.appending(component: "dispatch")
500520

501-
return [
521+
let compileFlags = [
502522
"-I\(incdir)",
503523
"-I\(dispatchIncdir)",
504524
"-L\(libdir)",
505525
"-Xcc", "-F\(incdir)",
506526
]
527+
528+
return (compileFlags, [libdir.pathString])
507529
#endif
508530
}
509531

Utilities/bootstrap

+4-1
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,10 @@ def build_llbuild(args):
908908
cmake_cache_path = os.path.join(llbuild_build_dir, "CMakeCache.txt")
909909
if not os.path.isfile(cmake_cache_path) or not args.swiftc_path in open(cmake_cache_path).read():
910910
mkdir_p(llbuild_build_dir)
911-
cmd = ["cmake", "-G", "Ninja", "-DCMAKE_BUILD_TYPE:=Debug", "-DCMAKE_C_COMPILER:=clang", "-DCMAKE_CXX_COMPILER:=clang++", "-DLLBUILD_SUPPORT_BINDINGS:=Swift", "-DSWIFTC_EXECUTABLE:=%s" % (args.swiftc_path), llbuild_source_dir]
911+
swift_flags = ""
912+
if args.sysroot:
913+
swift_flags = "-sdk %s" % args.sysroot
914+
cmd = ["cmake", "-G", "Ninja", "-DCMAKE_BUILD_TYPE:=Debug", "-DCMAKE_C_COMPILER:=clang", "-DCMAKE_CXX_COMPILER:=clang++", "-DLLBUILD_SUPPORT_BINDINGS:=Swift", "-DCMAKE_Swift_FLAGS:=%s" % (swift_flags), "-DSWIFTC_EXECUTABLE:=%s" % (args.swiftc_path), llbuild_source_dir]
912915
subprocess.check_call(cmd, cwd=llbuild_build_dir)
913916

914917
# Build.

0 commit comments

Comments
 (0)