| // 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 |