* Copyright (c) 2026 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "kernel_compilation_workspace.h"
#include "ascendc_tool_log.h"
#include "file_utils.h"
#include <boost/filesystem.hpp>
#include <cerrno>
#include <cstring>
#include <fstream>
#include <map>
#include <sstream>
namespace ascendc {
namespace aclrtc {
namespace {
namespace fs = boost::filesystem;
bool ReadSourceFileContents(const fs::path& sourceFilePath, std::string& sourceFileContents)
{
std::ifstream inputStream;
if (!FileUtils::OpenRegularFileForRead(sourceFilePath.string(), inputStream)) {
return false;
}
std::ostringstream sourceFileContentsStream;
sourceFileContentsStream << inputStream.rdbuf();
if (inputStream.bad()) {
const int readError = errno;
ASCENDLOGE(
"Failed to read source patch file: path=%s errno=%d message=%s", sourceFilePath.c_str(), readError,
std::strerror(readError));
return false;
}
sourceFileContents = sourceFileContentsStream.str();
return true;
}
bool ReplaceAllSourceTemplateOccurrences(
std::string& sourceFileContents, const std::string& sourceTemplateText, const std::string& replacementText)
{
bool replacedAtLeastOnce = false;
size_t searchPosition = 0U;
while ((searchPosition = sourceFileContents.find(sourceTemplateText, searchPosition)) != std::string::npos) {
sourceFileContents.replace(searchPosition, sourceTemplateText.size(), replacementText);
searchPosition += replacementText.size();
replacedAtLeastOnce = true;
}
return replacedAtLeastOnce;
}
}
KernelCompilationWorkspace::KernelCompilationWorkspace(fs::path worktreePath, WorktreeRetentionPolicy retentionPolicy)
: retentionPolicy_(retentionPolicy)
{
if (!worktreePath.empty()) {
(void)worktreeCleanupGuard_.RegisterDirectoryForCleanup(worktreePath.string());
}
if (retentionPolicy_ == WorktreeRetentionPolicy::RetainAfterCompilation) {
worktreeCleanupGuard_.PreserveDirectory();
}
}
fs::path KernelCompilationWorkspace::GetWorktreePath() const
{
return fs::path(worktreeCleanupGuard_.GetDirectoryPath());
}
aclError KernelCompilationWorkspace::CreateOutputDirectoriesAndApplySourcePatches(
const KernelCompilationPlan& compilationPlan) const
{
for (const fs::path& outputDirectoryPath : compilationPlan.requiredOutputDirectoryPaths) {
if (!FileUtils::CreateDirectories(outputDirectoryPath.string())) {
return ACLRTC_ERROR_FAILURE;
}
}
std::map<fs::path, std::vector<const KernelSourcePatch*>> patchesByFile;
for (const KernelSourcePatch& sourcePatch : compilationPlan.sourcePatches) {
patchesByFile[sourcePatch.targetFilePath].push_back(&sourcePatch);
}
for (const auto& filePatches : patchesByFile) {
std::string patchedSourceText;
if (!ReadSourceFileContents(filePatches.first, patchedSourceText)) {
return ACLRTC_ERROR_FAILURE;
}
for (size_t patchIndex = 0U; patchIndex < filePatches.second.size(); ++patchIndex) {
const KernelSourcePatch* sourcePatch = filePatches.second[patchIndex];
if (!ReplaceAllSourceTemplateOccurrences(
patchedSourceText, sourcePatch->templateText, sourcePatch->replacementText)) {
ASCENDLOGE(
"Source patch template was not found: path=%s patch_index=%zu; regenerate the JIT resource "
"from matching source files",
filePatches.first.c_str(), patchIndex);
return ACLRTC_ERROR_FAILURE;
}
}
if (!FileUtils::WriteTextFileAtomically(filePatches.first.string(), patchedSourceText)) {
return ACLRTC_ERROR_FAILURE;
}
}
return ACLRTC_SUCCESS;
}
aclError KernelCompilationWorkspace::CleanupWorktreeBeforeElfPublication()
{
if (worktreeCleanupGuard_.GetDirectoryPath().empty()) {
return ACLRTC_SUCCESS;
}
if (retentionPolicy_ == WorktreeRetentionPolicy::RetainAfterCompilation) {
return ACLRTC_SUCCESS;
}
const std::string worktreePath = worktreeCleanupGuard_.GetDirectoryPath();
if (!worktreeCleanupGuard_.RemoveDirectory()) {
ASCENDLOGE(
"Failed to clean resource worktree before publishing ELF: path=%s; ensure the path is removable and retry",
worktreePath.c_str());
return ACLRTC_ERROR_FAILURE;
}
return ACLRTC_SUCCESS;
}
}
}