mirror of
https://github.com/github/codeql.git
synced 2026-05-05 05:35:13 +02:00
Swift: remove VFS related code
This commit is contained in:
@@ -1,341 +0,0 @@
|
||||
#include "swift/extractor/SwiftOutputRewrite.h"
|
||||
#include "swift/extractor/SwiftExtractorConfiguration.h"
|
||||
#include "swift/extractor/TargetTrapFile.h"
|
||||
|
||||
#include <llvm/ADT/SmallString.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/Path.h>
|
||||
#include <swift/Basic/OutputFileMap.h>
|
||||
#include <swift/Basic/Platform.h>
|
||||
#include <unistd.h>
|
||||
#include <unordered_set>
|
||||
#include <optional>
|
||||
#include <iostream>
|
||||
|
||||
// Creates a copy of the output file map and updates remapping table in place
|
||||
// It does not change the original map file as it is depended upon by the original compiler
|
||||
// Returns path to the newly created output file map on success, or None in a case of failure
|
||||
static std::optional<std::string> rewriteOutputFileMap(
|
||||
const codeql::SwiftExtractorConfiguration& config,
|
||||
const std::string& outputFileMapPath,
|
||||
const std::vector<std::string>& inputs,
|
||||
std::unordered_map<std::string, std::string>& remapping) {
|
||||
auto newMapPath = config.getTempArtifactDir() + '/' + outputFileMapPath;
|
||||
|
||||
// TODO: do not assume absolute path for the second parameter
|
||||
auto outputMapOrError = swift::OutputFileMap::loadFromPath(outputFileMapPath, "");
|
||||
if (!outputMapOrError) {
|
||||
std::cerr << "Cannot load output map: '" << outputFileMapPath << "'\n";
|
||||
return std::nullopt;
|
||||
}
|
||||
auto oldOutputMap = outputMapOrError.get();
|
||||
swift::OutputFileMap newOutputMap;
|
||||
std::vector<llvm::StringRef> keys;
|
||||
for (auto& key : inputs) {
|
||||
auto oldMap = oldOutputMap.getOutputMapForInput(key);
|
||||
if (!oldMap) {
|
||||
continue;
|
||||
}
|
||||
keys.push_back(key);
|
||||
auto& newMap = newOutputMap.getOrCreateOutputMapForInput(key);
|
||||
newMap.copyFrom(*oldMap);
|
||||
for (auto& entry : newMap) {
|
||||
auto oldPath = entry.getSecond();
|
||||
auto newPath = config.getTempArtifactDir() + '/' + oldPath;
|
||||
entry.getSecond() = newPath;
|
||||
remapping[oldPath] = newPath;
|
||||
}
|
||||
}
|
||||
std::error_code ec;
|
||||
llvm::SmallString<PATH_MAX> filepath(newMapPath);
|
||||
llvm::StringRef parent = llvm::sys::path::parent_path(filepath);
|
||||
if (std::error_code ec = llvm::sys::fs::create_directories(parent)) {
|
||||
std::cerr << "Cannot create relocated output map dir: '" << parent.str()
|
||||
<< "': " << ec.message() << "\n";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
llvm::raw_fd_ostream fd(newMapPath, ec, llvm::sys::fs::OF_None);
|
||||
newOutputMap.write(fd, keys);
|
||||
return newMapPath;
|
||||
}
|
||||
|
||||
// This is an Xcode-specific workaround to produce alias names for an existing .swiftmodule file.
|
||||
// In the case of Xcode, it calls the Swift compiler and asks it to produce a Swift module.
|
||||
// Once it's done, Xcode moves the .swiftmodule file in another location, and the location is
|
||||
// rather arbitrary. Here are examples of such locations:
|
||||
// Original file produced by the frontend:
|
||||
// DerivedData/<Project>/Build/Intermediates.noindex/<Project>.build/<BuiltType>-<Target>/<Project>.build/Objects-normal/<Arch>/<ModuleName>.swiftmodule
|
||||
// where:
|
||||
// Project: name of a project, target, or scheme
|
||||
// BuildType: Debug, Release, etc.
|
||||
// Target: macOS, iphoneos, appletvsimulator, etc.
|
||||
// Arch: arm64, x86_64, etc.
|
||||
//
|
||||
// So far we observed that Xcode can move the module into different locations, and it's not
|
||||
// entirely clear how to deduce the destination from the context available for the extractor.
|
||||
// 1. First case:
|
||||
// DerivedData/<Project>/Build/Products/<BuiltType>-<Target>/<ModuleName>.swiftmodule/<Arch>.swiftmodule
|
||||
// DerivedData/<Project>/Build/Products/<BuiltType>-<Target>/<ModuleName>.swiftmodule/<Triple>.swiftmodule
|
||||
// 2. Second case:
|
||||
// DerivedData/<Project>/Build/Products/<BuiltType>-<Target>/<ModuleName>/<ModuleName>.swiftmodule/<Arch>.swiftmodule
|
||||
// DerivedData/<Project>/Build/Products/<BuiltType>-<Target>/<ModuleName>/<ModuleName>.swiftmodule/<Triple>.swiftmodule
|
||||
// 2. Third case:
|
||||
// DerivedData/<Project>/Build/Products/<BuiltType>-<Target>/<ModuleName>/<ModuleName>.framework/Modules/<ModuleName>.swiftmodule/<Arch>.swiftmodule
|
||||
// DerivedData/<Project>/Build/Products/<BuiltType>-<Target>/<ModuleName>/<ModuleName>.framework/Modules/<ModuleName>.swiftmodule/<Triple>.swiftmodule
|
||||
// The <Triple> here is a normalized target triple (e.g. arm64-apple-iphoneos15.4 ->
|
||||
// arm64-apple-iphoneos).
|
||||
//
|
||||
// This method constructs those aliases for a module only if it comes from Xcode, which is detected
|
||||
// by the presence of an `Intermediates.noindex` directory in the module path.
|
||||
//
|
||||
// In the case of the Swift Package Manager (`swift build`) this is not needed.
|
||||
static std::vector<std::string> computeModuleAliases(llvm::StringRef modulePath,
|
||||
const std::string& targetTriple) {
|
||||
if (modulePath.empty()) {
|
||||
return {};
|
||||
}
|
||||
if (!modulePath.endswith(".swiftmodule")) {
|
||||
return {};
|
||||
}
|
||||
// Deconstructing the Xcode generated path
|
||||
//
|
||||
// clang-format off
|
||||
// intermediatesDirIndex destinationDir (2) arch(5)
|
||||
// DerivedData/FooBar/Build/Intermediates.noindex/FooBar.build/Debug-iphonesimulator/FooBar.build/Objects-normal/x86_64/FooBar.swiftmodule
|
||||
// clang-format on
|
||||
llvm::SmallVector<llvm::StringRef> chunks;
|
||||
modulePath.split(chunks, '/');
|
||||
size_t intermediatesDirIndex = 0;
|
||||
for (size_t i = 0; i < chunks.size(); i++) {
|
||||
if (chunks[i] == "Intermediates.noindex") {
|
||||
intermediatesDirIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Not built by Xcode, skipping
|
||||
if (intermediatesDirIndex == 0) {
|
||||
return {};
|
||||
}
|
||||
size_t destinationDirIndex = intermediatesDirIndex + 2;
|
||||
size_t archIndex = intermediatesDirIndex + 5;
|
||||
if (archIndex >= chunks.size()) {
|
||||
return {};
|
||||
}
|
||||
// e.g. Debug-iphoneos, Release-iphonesimulator, etc.
|
||||
auto destinationDir = chunks[destinationDirIndex].str();
|
||||
auto arch = chunks[archIndex].str();
|
||||
auto moduleNameWithExt = chunks.back();
|
||||
auto moduleName = moduleNameWithExt.substr(0, moduleNameWithExt.find_last_of('.'));
|
||||
std::string relocatedModulePath = chunks[0].str();
|
||||
for (size_t i = 1; i < intermediatesDirIndex; i++) {
|
||||
relocatedModulePath += '/' + chunks[i].str();
|
||||
}
|
||||
relocatedModulePath += "/Products/";
|
||||
relocatedModulePath += destinationDir + '/';
|
||||
|
||||
// clang-format off
|
||||
std::vector<std::string> moduleLocations = {
|
||||
// First case
|
||||
relocatedModulePath + moduleNameWithExt.str() + '/',
|
||||
// Second case
|
||||
relocatedModulePath + moduleName.str() + '/' + moduleNameWithExt.str() + '/',
|
||||
// Third case
|
||||
relocatedModulePath + moduleName.str() + '/' + moduleName.str() + ".framework/Modules/" + moduleNameWithExt.str() + '/',
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
std::vector<std::string> archs({arch});
|
||||
if (!targetTriple.empty()) {
|
||||
llvm::Triple triple(targetTriple);
|
||||
archs.push_back(swift::getTargetSpecificModuleTriple(triple).normalize());
|
||||
}
|
||||
|
||||
std::vector<std::string> aliases;
|
||||
for (auto& location : moduleLocations) {
|
||||
for (auto& a : archs) {
|
||||
aliases.push_back(location + a + ".swiftmodule");
|
||||
}
|
||||
}
|
||||
|
||||
return aliases;
|
||||
}
|
||||
|
||||
namespace codeql {
|
||||
|
||||
std::unordered_map<std::string, std::string> rewriteOutputsInPlace(
|
||||
const SwiftExtractorConfiguration& config,
|
||||
std::vector<std::string>& CLIArgs) {
|
||||
std::unordered_map<std::string, std::string> remapping;
|
||||
|
||||
// TODO: handle filelists?
|
||||
const std::unordered_set<std::string> pathRewriteOptions({
|
||||
"-emit-dependencies-path",
|
||||
"-emit-module-path",
|
||||
"-emit-module-doc-path",
|
||||
"-emit-module-source-info-path",
|
||||
"-emit-objc-header-path",
|
||||
"-emit-reference-dependencies-path",
|
||||
"-index-store-path",
|
||||
"-module-cache-path",
|
||||
"-o",
|
||||
"-pch-output-dir",
|
||||
"-serialize-diagnostics-path",
|
||||
});
|
||||
|
||||
std::unordered_set<std::string> outputFileMaps(
|
||||
{"-supplementary-output-file-map", "-output-file-map"});
|
||||
|
||||
std::vector<size_t> outputFileMapIndexes;
|
||||
std::vector<std::string> maybeInput;
|
||||
std::string targetTriple;
|
||||
|
||||
std::vector<std::string> newLocations;
|
||||
for (size_t i = 0; i < CLIArgs.size(); i++) {
|
||||
if (pathRewriteOptions.count(CLIArgs[i])) {
|
||||
auto oldPath = CLIArgs[i + 1];
|
||||
auto newPath = config.getTempArtifactDir() + '/' + oldPath;
|
||||
CLIArgs[++i] = newPath;
|
||||
newLocations.push_back(newPath);
|
||||
|
||||
remapping[oldPath] = newPath;
|
||||
} else if (outputFileMaps.count(CLIArgs[i])) {
|
||||
// collect output map indexes for further rewriting and skip the following argument
|
||||
// We don't patch the map in place as we need to collect all the input files first
|
||||
outputFileMapIndexes.push_back(++i);
|
||||
} else if (CLIArgs[i] == "-target") {
|
||||
targetTriple = CLIArgs[++i];
|
||||
} else if (CLIArgs[i][0] != '-') {
|
||||
// TODO: add support for input file lists?
|
||||
// We need to collect input file names to later use them to extract information from the
|
||||
// output file maps.
|
||||
maybeInput.push_back(CLIArgs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto index : outputFileMapIndexes) {
|
||||
auto oldPath = CLIArgs[index];
|
||||
auto maybeNewPath = rewriteOutputFileMap(config, oldPath, maybeInput, remapping);
|
||||
if (maybeNewPath) {
|
||||
auto newPath = maybeNewPath.value();
|
||||
CLIArgs[index] = newPath;
|
||||
remapping[oldPath] = newPath;
|
||||
}
|
||||
}
|
||||
|
||||
// This doesn't really belong here, but we've got Xcode...
|
||||
for (const auto& [oldPath, newPath] : remapping) {
|
||||
llvm::StringRef path(oldPath);
|
||||
auto aliases = computeModuleAliases(path, targetTriple);
|
||||
for (auto& alias : aliases) {
|
||||
remapping[alias] = newPath;
|
||||
}
|
||||
}
|
||||
|
||||
return remapping;
|
||||
}
|
||||
|
||||
void ensureDirectoriesForNewPathsExist(
|
||||
const std::unordered_map<std::string, std::string>& remapping) {
|
||||
for (auto& [_, newPath] : remapping) {
|
||||
llvm::SmallString<PATH_MAX> filepath(newPath);
|
||||
llvm::StringRef parent = llvm::sys::path::parent_path(filepath);
|
||||
if (std::error_code ec = llvm::sys::fs::create_directories(parent)) {
|
||||
std::cerr << "Cannot create redirected directory: " << ec.message() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void storeRemappingForVFS(const SwiftExtractorConfiguration& config,
|
||||
const std::unordered_map<std::string, std::string>& remapping) {
|
||||
// Only create remapping for the .swiftmodule files
|
||||
std::unordered_map<std::string, std::string> modules;
|
||||
for (const auto& [oldPath, newPath] : remapping) {
|
||||
if (llvm::StringRef(oldPath).endswith(".swiftmodule")) {
|
||||
modules.emplace(oldPath, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (modules.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::error_code ec = llvm::sys::fs::create_directories(config.getTempVFSDir())) {
|
||||
std::cerr << "Cannot create temp VFS directory: " << ec.message() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::error_code ec = llvm::sys::fs::create_directories(config.getVFSDir())) {
|
||||
std::cerr << "Cannot create VFS directory: " << ec.message() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Constructing the VFS yaml file in a temp folder so that the other process doesn't read it
|
||||
// while it is not complete
|
||||
// TODO: Pick a more robust way to not collide with files from other processes
|
||||
auto tempVfsPath = config.getTempVFSDir() + '/' + std::to_string(getpid()) + "-vfs.yaml";
|
||||
std::error_code ec;
|
||||
llvm::raw_fd_ostream fd(tempVfsPath, ec, llvm::sys::fs::OF_None);
|
||||
if (ec) {
|
||||
std::cerr << "Cannot create temp VFS file: '" << tempVfsPath << "': " << ec.message() << "\n";
|
||||
return;
|
||||
}
|
||||
// TODO: there must be a better API than this
|
||||
// LLVM expects the version to be 0
|
||||
fd << "{ version: 0,\n";
|
||||
// This tells the FS not to fallback to the physical file system in case the remapped file is not
|
||||
// present
|
||||
fd << " fallthrough: false,\n";
|
||||
fd << " roots: [\n";
|
||||
for (auto& [oldPath, newPath] : modules) {
|
||||
fd << " {\n";
|
||||
fd << " type: 'file',\n";
|
||||
fd << " name: '" << oldPath << "\',\n";
|
||||
fd << " external-contents: '" << newPath << "\'\n";
|
||||
fd << " },\n";
|
||||
}
|
||||
fd << " ]\n";
|
||||
fd << "}\n";
|
||||
|
||||
fd.flush();
|
||||
auto vfsPath = config.getVFSDir() + '/' + std::to_string(getpid()) + "-vfs.yaml";
|
||||
if (std::error_code ec = llvm::sys::fs::rename(tempVfsPath, vfsPath)) {
|
||||
std::cerr << "Cannot move temp VFS file '" << tempVfsPath << "' -> '" << vfsPath
|
||||
<< "': " << ec.message() << "\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> collectVFSFiles(const SwiftExtractorConfiguration& config) {
|
||||
auto vfsDir = config.getVFSDir() + '/';
|
||||
if (!llvm::sys::fs::exists(vfsDir)) {
|
||||
return {};
|
||||
}
|
||||
std::vector<std::string> overlays;
|
||||
std::error_code ec;
|
||||
llvm::sys::fs::directory_iterator it(vfsDir, ec);
|
||||
while (!ec && it != llvm::sys::fs::directory_iterator()) {
|
||||
llvm::StringRef path(it->path());
|
||||
if (path.endswith("vfs.yaml")) {
|
||||
overlays.push_back(path.str());
|
||||
}
|
||||
it.increment(ec);
|
||||
}
|
||||
|
||||
return overlays;
|
||||
}
|
||||
|
||||
void lockOutputSwiftModuleTraps(const SwiftExtractorConfiguration& config,
|
||||
const std::unordered_map<std::string, std::string>& remapping) {
|
||||
for (const auto& [oldPath, newPath] : remapping) {
|
||||
if (llvm::StringRef(oldPath).endswith(".swiftmodule")) {
|
||||
if (auto target = createTargetTrapFile(config, oldPath)) {
|
||||
*target << "// trap file deliberately empty\n"
|
||||
"// this swiftmodule was created during the build, so its entities must have"
|
||||
" been extracted directly from source files";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace codeql
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace codeql {
|
||||
|
||||
struct SwiftExtractorConfiguration;
|
||||
|
||||
// Rewrites all the output CLI args to point to a scratch dir instead of the actual locations.
|
||||
// This is needed to ensure that the artifacts produced by the extractor do not collide with the
|
||||
// artifacts produced by the actual Swift compiler.
|
||||
// Returns the map containing remapping oldpath -> newPath.
|
||||
std::unordered_map<std::string, std::string> rewriteOutputsInPlace(
|
||||
const SwiftExtractorConfiguration& config,
|
||||
std::vector<std::string>& CLIArgs);
|
||||
|
||||
// Create directories for all the redirected new paths as the Swift compiler expects them to exist.
|
||||
void ensureDirectoriesForNewPathsExist(
|
||||
const std::unordered_map<std::string, std::string>& remapping);
|
||||
|
||||
// Stores remapped `.swiftmoduile`s in a YAML file for later consumption by the
|
||||
// llvm::RedirectingFileSystem via Swift's VFSOverlayFiles.
|
||||
void storeRemappingForVFS(const SwiftExtractorConfiguration& config,
|
||||
const std::unordered_map<std::string, std::string>& remapping);
|
||||
|
||||
// Returns a list of VFS YAML files produced by all the extractor processes.
|
||||
// This is separate from storeRemappingForVFS as we also collect files produced by other processes.
|
||||
std::vector<std::string> collectVFSFiles(const SwiftExtractorConfiguration& config);
|
||||
|
||||
// Creates empty trap files for output swiftmodule files
|
||||
void lockOutputSwiftModuleTraps(const SwiftExtractorConfiguration& config,
|
||||
const std::unordered_map<std::string, std::string>& remapping);
|
||||
|
||||
} // namespace codeql
|
||||
@@ -10,7 +10,8 @@
|
||||
#include <swift/FrontendTool/FrontendTool.h>
|
||||
|
||||
#include "swift/extractor/SwiftExtractor.h"
|
||||
#include "swift/extractor/SwiftOutputRewrite.h"
|
||||
#include "swift/extractor/TargetTrapFile.h"
|
||||
#include "swift/extractor/remapping/SwiftOutputRewrite.h"
|
||||
#include "swift/extractor/remapping/SwiftOpenInterception.h"
|
||||
|
||||
using namespace std::string_literals;
|
||||
@@ -37,6 +38,20 @@ static std::string getenv_or(const char* envvar, const std::string& def) {
|
||||
return def;
|
||||
}
|
||||
|
||||
static void lockOutputSwiftModuleTraps(
|
||||
const codeql::SwiftExtractorConfiguration& config,
|
||||
const std::unordered_map<std::string, std::string>& remapping) {
|
||||
for (const auto& [oldPath, newPath] : remapping) {
|
||||
if (llvm::StringRef(oldPath).endswith(".swiftmodule")) {
|
||||
if (auto target = codeql::createTargetTrapFile(config, oldPath)) {
|
||||
*target << "// trap file deliberately empty\n"
|
||||
"// this swiftmodule was created during the build, so its entities must have"
|
||||
" been extracted directly from source files";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc == 1) {
|
||||
// TODO: print usage
|
||||
@@ -60,10 +75,10 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
configuration.patchedFrontendOptions = configuration.frontendOptions;
|
||||
|
||||
auto remapping =
|
||||
codeql::rewriteOutputsInPlace(configuration, configuration.patchedFrontendOptions);
|
||||
auto remapping = codeql::rewriteOutputsInPlace(configuration.getTempArtifactDir(),
|
||||
configuration.patchedFrontendOptions);
|
||||
codeql::ensureDirectoriesForNewPathsExist(remapping);
|
||||
codeql::lockOutputSwiftModuleTraps(configuration, remapping);
|
||||
lockOutputSwiftModuleTraps(configuration, remapping);
|
||||
|
||||
std::vector<const char*> args;
|
||||
for (auto& arg : configuration.patchedFrontendOptions) {
|
||||
|
||||
@@ -2,7 +2,7 @@ load("//swift:rules.bzl", "swift_cc_library")
|
||||
|
||||
swift_cc_library(
|
||||
name = "remapping",
|
||||
srcs = select({
|
||||
srcs = ['SwiftOutputRewrite.cpp'] + select({
|
||||
"@platforms//os:linux": [
|
||||
"SwiftOpenInterception.Linux.cpp",
|
||||
],
|
||||
|
||||
137
swift/extractor/remapping/SwiftOutputRewrite.cpp
Normal file
137
swift/extractor/remapping/SwiftOutputRewrite.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "swift/extractor/remapping/SwiftOutputRewrite.h"
|
||||
|
||||
#include <llvm/ADT/SmallString.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/Path.h>
|
||||
#include <swift/Basic/OutputFileMap.h>
|
||||
#include <swift/Basic/Platform.h>
|
||||
#include <unistd.h>
|
||||
#include <unordered_set>
|
||||
#include <optional>
|
||||
#include <iostream>
|
||||
|
||||
// Creates a copy of the output file map and updates remapping table in place
|
||||
// It does not change the original map file as it is depended upon by the original compiler
|
||||
// Returns path to the newly created output file map on success, or None in a case of failure
|
||||
static std::optional<std::string> rewriteOutputFileMap(
|
||||
const std::string& scratchDir,
|
||||
const std::string& outputFileMapPath,
|
||||
const std::vector<std::string>& inputs,
|
||||
std::unordered_map<std::string, std::string>& remapping) {
|
||||
auto newMapPath = scratchDir + '/' + outputFileMapPath;
|
||||
|
||||
// TODO: do not assume absolute path for the second parameter
|
||||
auto outputMapOrError = swift::OutputFileMap::loadFromPath(outputFileMapPath, "");
|
||||
if (!outputMapOrError) {
|
||||
std::cerr << "Cannot load output map: '" << outputFileMapPath << "'\n";
|
||||
return std::nullopt;
|
||||
}
|
||||
auto oldOutputMap = outputMapOrError.get();
|
||||
swift::OutputFileMap newOutputMap;
|
||||
std::vector<llvm::StringRef> keys;
|
||||
for (auto& key : inputs) {
|
||||
auto oldMap = oldOutputMap.getOutputMapForInput(key);
|
||||
if (!oldMap) {
|
||||
continue;
|
||||
}
|
||||
keys.push_back(key);
|
||||
auto& newMap = newOutputMap.getOrCreateOutputMapForInput(key);
|
||||
newMap.copyFrom(*oldMap);
|
||||
for (auto& entry : newMap) {
|
||||
auto oldPath = entry.getSecond();
|
||||
auto newPath = scratchDir + '/' + oldPath;
|
||||
entry.getSecond() = newPath;
|
||||
remapping[oldPath] = newPath;
|
||||
}
|
||||
}
|
||||
std::error_code ec;
|
||||
llvm::SmallString<PATH_MAX> filepath(newMapPath);
|
||||
llvm::StringRef parent = llvm::sys::path::parent_path(filepath);
|
||||
if (std::error_code ec = llvm::sys::fs::create_directories(parent)) {
|
||||
std::cerr << "Cannot create relocated output map dir: '" << parent.str()
|
||||
<< "': " << ec.message() << "\n";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
llvm::raw_fd_ostream fd(newMapPath, ec, llvm::sys::fs::OF_None);
|
||||
newOutputMap.write(fd, keys);
|
||||
return newMapPath;
|
||||
}
|
||||
|
||||
namespace codeql {
|
||||
|
||||
std::unordered_map<std::string, std::string> rewriteOutputsInPlace(
|
||||
const std::string& scratchDir,
|
||||
std::vector<std::string>& CLIArgs) {
|
||||
std::unordered_map<std::string, std::string> remapping;
|
||||
|
||||
// TODO: handle filelists?
|
||||
const std::unordered_set<std::string> pathRewriteOptions({
|
||||
"-emit-dependencies-path",
|
||||
"-emit-module-path",
|
||||
"-emit-module-doc-path",
|
||||
"-emit-module-source-info-path",
|
||||
"-emit-objc-header-path",
|
||||
"-emit-reference-dependencies-path",
|
||||
"-index-store-path",
|
||||
"-module-cache-path",
|
||||
"-o",
|
||||
"-pch-output-dir",
|
||||
"-serialize-diagnostics-path",
|
||||
});
|
||||
|
||||
std::unordered_set<std::string> outputFileMaps(
|
||||
{"-supplementary-output-file-map", "-output-file-map"});
|
||||
|
||||
std::vector<size_t> outputFileMapIndexes;
|
||||
std::vector<std::string> maybeInput;
|
||||
std::string targetTriple;
|
||||
|
||||
std::vector<std::string> newLocations;
|
||||
for (size_t i = 0; i < CLIArgs.size(); i++) {
|
||||
if (pathRewriteOptions.count(CLIArgs[i])) {
|
||||
auto oldPath = CLIArgs[i + 1];
|
||||
auto newPath = scratchDir + '/' + oldPath;
|
||||
CLIArgs[++i] = newPath;
|
||||
newLocations.push_back(newPath);
|
||||
|
||||
remapping[oldPath] = newPath;
|
||||
} else if (outputFileMaps.count(CLIArgs[i])) {
|
||||
// collect output map indexes for further rewriting and skip the following argument
|
||||
// We don't patch the map in place as we need to collect all the input files first
|
||||
outputFileMapIndexes.push_back(++i);
|
||||
} else if (CLIArgs[i] == "-target") {
|
||||
targetTriple = CLIArgs[++i];
|
||||
} else if (CLIArgs[i][0] != '-') {
|
||||
// TODO: add support for input file lists?
|
||||
// We need to collect input file names to later use them to extract information from the
|
||||
// output file maps.
|
||||
maybeInput.push_back(CLIArgs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto index : outputFileMapIndexes) {
|
||||
auto oldPath = CLIArgs[index];
|
||||
auto maybeNewPath = rewriteOutputFileMap(scratchDir, oldPath, maybeInput, remapping);
|
||||
if (maybeNewPath) {
|
||||
auto newPath = maybeNewPath.value();
|
||||
CLIArgs[index] = newPath;
|
||||
remapping[oldPath] = newPath;
|
||||
}
|
||||
}
|
||||
|
||||
return remapping;
|
||||
}
|
||||
|
||||
void ensureDirectoriesForNewPathsExist(
|
||||
const std::unordered_map<std::string, std::string>& remapping) {
|
||||
for (auto& [_, newPath] : remapping) {
|
||||
llvm::SmallString<PATH_MAX> filepath(newPath);
|
||||
llvm::StringRef parent = llvm::sys::path::parent_path(filepath);
|
||||
if (std::error_code ec = llvm::sys::fs::create_directories(parent)) {
|
||||
std::cerr << "Cannot create redirected directory: " << ec.message() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace codeql
|
||||
21
swift/extractor/remapping/SwiftOutputRewrite.h
Normal file
21
swift/extractor/remapping/SwiftOutputRewrite.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace codeql {
|
||||
|
||||
// Rewrites all the output CLI args to point to a scratch dir instead of the actual locations.
|
||||
// This is needed to ensure that the artifacts produced by the extractor do not collide with the
|
||||
// artifacts produced by the actual Swift compiler.
|
||||
// Returns the map containing remapping oldpath -> newPath.
|
||||
std::unordered_map<std::string, std::string> rewriteOutputsInPlace(
|
||||
const std::string& scratchDir,
|
||||
std::vector<std::string>& CLIArgs);
|
||||
|
||||
// Create directories for all the redirected new paths as the Swift compiler expects them to exist.
|
||||
void ensureDirectoriesForNewPathsExist(
|
||||
const std::unordered_map<std::string, std::string>& remapping);
|
||||
|
||||
} // namespace codeql
|
||||
Reference in New Issue
Block a user