blob: b763830da3d65b528b1c0c7ab90da89500947a6d [file] [log] [blame]
// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "compiler/plugins/target/LLVMCPU/LinkerTool.h"
#include "iree/compiler/Utils/StringUtils.h"
#include "iree/compiler/Utils/ToolUtils.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Process.h"
#define DEBUG_TYPE "iree-tools"
namespace mlir::iree_compiler::IREE::HAL {
// static
Artifact Artifact::fromFile(StringRef path) { return {path.str(), nullptr}; }
// static
Artifact Artifact::createTemporary(StringRef prefix, StringRef suffix) {
auto sanitizedPrefix = sanitizeFileName(prefix);
auto sanitizedSuffix = sanitizeFileName(suffix);
llvm::SmallString<32> filePath;
if (std::error_code error = llvm::sys::fs::createTemporaryFile(
sanitizedPrefix, sanitizedSuffix, filePath)) {
llvm::errs() << "failed to generate temporary file: " << error.message();
return {};
}
std::error_code error;
auto file = std::make_unique<llvm::ToolOutputFile>(filePath, error,
llvm::sys::fs::OF_None);
if (error) {
llvm::errs() << "failed to open temporary file '" << filePath
<< "': " << error.message();
return {};
}
return {filePath.str().str(), std::move(file)};
}
// static
Artifact Artifact::createVariant(StringRef basePath, StringRef suffix) {
SmallString<32> filePath(basePath);
llvm::sys::path::replace_extension(filePath, suffix);
std::error_code error;
auto file = std::make_unique<llvm::ToolOutputFile>(filePath, error,
llvm::sys::fs::OF_Append);
if (error) {
llvm::errs() << "failed to open temporary file '" << filePath
<< "': " << error.message();
return {};
}
return {filePath.str().str(), std::move(file)};
}
void Artifact::keep() const {
if (outputFile)
outputFile->keep();
}
std::optional<std::vector<int8_t>> Artifact::read() const {
auto fileData = llvm::MemoryBuffer::getFile(path);
if (!fileData) {
llvm::errs() << "failed to load library output file '" << path << "'";
return std::nullopt;
}
auto sourceBuffer = fileData.get()->getBuffer();
std::vector<int8_t> resultBuffer(sourceBuffer.size());
std::memcpy(resultBuffer.data(), sourceBuffer.data(), sourceBuffer.size());
return resultBuffer;
}
bool Artifact::readInto(raw_ostream &targetStream) const {
// NOTE: we could make this much more efficient if we read in the file a
// chunk at a time and piped it along to targetStream. I couldn't find
// anything in LLVM that did this, for some crazy reason, but since we are
// dealing with binaries that can be 10+MB here it'd be nice if we could avoid
// reading them all into memory.
auto fileData = llvm::MemoryBuffer::getFile(path);
if (!fileData) {
llvm::errs() << "failed to load library output file '" << path << "'";
return false;
}
auto sourceBuffer = fileData.get()->getBuffer();
targetStream.write(sourceBuffer.data(), sourceBuffer.size());
return true;
}
void Artifact::close() { outputFile->os().close(); }
void Artifacts::keepAllFiles() {
libraryFile.keep();
debugFile.keep();
for (auto &file : otherFiles) {
file.keep();
}
}
std::string LinkerTool::getSystemToolPath() const {
// Always use the --iree-llvmcpu-system-linker-path flag when specified as
// it's explicitly telling us what to use.
if (!targetOptions.systemLinkerPath.empty()) {
return targetOptions.systemLinkerPath;
}
// Allow users to override the automatic search with an environment variable.
char *linkerPath = std::getenv("IREE_LLVM_SYSTEM_LINKER_PATH");
if (linkerPath) {
return std::string(linkerPath);
}
// Fallback to other searches as specified by the LinkerTool implementation.
return "";
}
LogicalResult LinkerTool::runLinkCommand(std::string commandLine,
StringRef env) {
LLVM_DEBUG(llvm::dbgs() << "Running linker command:\n"
<< env << " " << commandLine << "\n");
if (!env.empty()) {
#if defined(_WIN32)
commandLine = ("set " + env + " && " + commandLine).str();
#else
commandLine = (env + " " + commandLine).str();
#endif // _WIN32
} else {
commandLine = escapeCommandLineComponent(commandLine);
}
int exitCode = system(commandLine.c_str());
if (exitCode == 0)
return success();
llvm::errs() << "Linking failed; escaped command line returned exit code "
<< exitCode << ":\n\n"
<< commandLine << "\n\n";
return failure();
}
} // namespace mlir::iree_compiler::IREE::HAL