* 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.
*/
#ifndef GE_COMPILER_GRAPH_FUSION_PASS_PYTHON_PASS_BRIDGE_LOADER_HELPER_H_
#define GE_COMPILER_GRAPH_FUSION_PASS_PYTHON_PASS_BRIDGE_LOADER_HELPER_H_
#include <cstdint>
#include <string>
#include "ge/ge_api_error_codes.h"
#include "python_pass_artifact_selector.h"
#include "python_pass_bridge_c_api.h"
namespace ge {
namespace fusion {
namespace python_pass_bridge_loader {
struct LoadedBridgeCandidate {
void *handle{nullptr};
const PythonFusionPassBridgeApi *api{nullptr};
std::string real_path;
};
struct BridgeLoadDependencies {
using RealPathFn = std::string (*)(const char *path);
using OpenLibraryFn = void *(*)(const char *path, int flags);
using CloseLibraryFn = int (*)(void *handle);
using LookupSymbolFn = void *(*)(void *handle, const char *symbol);
using ResolveRuntimeKeyFn = python_pass_artifact::PythonRuntimeKey (*)();
RealPathFn real_path{nullptr};
OpenLibraryFn open_library{nullptr};
CloseLibraryFn close_library{nullptr};
LookupSymbolFn lookup_symbol{nullptr};
ResolveRuntimeKeyFn resolve_runtime_key{nullptr};
const char *api_symbol{nullptr};
uint32_t expected_abi{0U};
int open_flags{0};
};
enum class BridgeLoadStatus {
kSuccess,
kInvalidDependency,
kInvalidPath,
kOpenFailed,
kRuntimeMismatch,
kMissingApiSymbol,
kInvalidApi,
kSetArtifactConfigFailed,
};
inline const char *BridgeLoadStatusToString(const BridgeLoadStatus status) {
switch (status) {
case BridgeLoadStatus::kSuccess:
return "success";
case BridgeLoadStatus::kInvalidDependency:
return "invalid dependency";
case BridgeLoadStatus::kInvalidPath:
return "invalid path";
case BridgeLoadStatus::kOpenFailed:
return "open failed";
case BridgeLoadStatus::kRuntimeMismatch:
return "runtime mismatch";
case BridgeLoadStatus::kMissingApiSymbol:
return "missing api symbol";
case BridgeLoadStatus::kInvalidApi:
return "invalid api";
case BridgeLoadStatus::kSetArtifactConfigFailed:
return "set artifact config failed";
default:
return "unknown";
}
}
inline std::string BuildBridgeLoadErrorSuffix(const BridgeLoadStatus status, const char *open_error) {
if ((status != BridgeLoadStatus::kOpenFailed) || (open_error == nullptr) || (open_error[0] == '\0')) {
return "";
}
return std::string(", dlerror[") + open_error + "]";
}
inline std::string FirstLine(const std::string &content) {
const auto pos = content.find('\n');
return (pos == std::string::npos) ? content : content.substr(0U, pos);
}
inline std::string SecondLine(const std::string &content) {
const auto first_end = content.find('\n');
if (first_end == std::string::npos) {
return "";
}
const auto second_end = content.find('\n', first_end + 1U);
if (second_end == std::string::npos) {
return content.substr(first_end + 1U);
}
return content.substr(first_end + 1U, second_end - first_end - 1U);
}
inline bool IsRuntimeKeyCompatible(const python_pass_artifact::PythonRuntimeKey &expected_key,
const python_pass_artifact::PythonRuntimeKey &loaded_key) {
return expected_key.python_tag.empty() || loaded_key.python_tag.empty() ||
(loaded_key.python_tag == expected_key.python_tag);
}
inline bool IsBridgeApiValid(const PythonFusionPassBridgeApi *api, const uint32_t expected_abi) {
return (api != nullptr) && (api->abi_version == expected_abi) &&
(api->set_artifact_config != nullptr) && (api->register_passes != nullptr) &&
(api->reset_bridge_state != nullptr) && (api->shutdown_bridge != nullptr);
}
inline PythonFusionPassBridgeArtifactConfig BuildArtifactConfig(
const python_pass_artifact::BridgeLibraryCandidate &candidate) {
return PythonFusionPassBridgeArtifactConfig{
candidate.artifact_root.empty() ? nullptr : candidate.artifact_root.c_str(),
candidate.native_module_path.empty() ? nullptr : candidate.native_module_path.c_str(),
};
}
inline bool IsBridgeLoadDependenciesValid(const BridgeLoadDependencies &deps) {
return (deps.real_path != nullptr) && (deps.open_library != nullptr) && (deps.close_library != nullptr) &&
(deps.lookup_symbol != nullptr) && (deps.resolve_runtime_key != nullptr) && (deps.api_symbol != nullptr);
}
inline void CloseLibraryQuietly(const BridgeLoadDependencies &deps, void *handle) {
if ((handle != nullptr) && (deps.close_library != nullptr)) {
(void)deps.close_library(handle);
}
}
inline BridgeLoadStatus TryLoadBridgeCandidate(
const python_pass_artifact::PythonRuntimeKey &expected_key,
const python_pass_artifact::BridgeLibraryCandidate &candidate,
const BridgeLoadDependencies &deps,
LoadedBridgeCandidate &loaded_bridge) {
loaded_bridge = LoadedBridgeCandidate {};
if (!IsBridgeLoadDependenciesValid(deps)) {
return BridgeLoadStatus::kInvalidDependency;
}
const auto real_path = deps.real_path(candidate.bridge_path.c_str());
if (real_path.empty()) {
return BridgeLoadStatus::kInvalidPath;
}
void *handle = deps.open_library(real_path.c_str(), deps.open_flags);
if (handle == nullptr) {
return BridgeLoadStatus::kOpenFailed;
}
const auto loaded_key = deps.resolve_runtime_key();
if (!IsRuntimeKeyCompatible(expected_key, loaded_key)) {
CloseLibraryQuietly(deps, handle);
return BridgeLoadStatus::kRuntimeMismatch;
}
using GetApiFn = const PythonFusionPassBridgeApi *(*)();
auto *get_api = reinterpret_cast<GetApiFn>(deps.lookup_symbol(handle, deps.api_symbol));
if (get_api == nullptr) {
CloseLibraryQuietly(deps, handle);
return BridgeLoadStatus::kMissingApiSymbol;
}
const auto *api = get_api();
if (!IsBridgeApiValid(api, deps.expected_abi)) {
CloseLibraryQuietly(deps, handle);
return BridgeLoadStatus::kInvalidApi;
}
const auto artifact_config = BuildArtifactConfig(candidate);
if (api->set_artifact_config(&artifact_config) != SUCCESS) {
CloseLibraryQuietly(deps, handle);
return BridgeLoadStatus::kSetArtifactConfigFailed;
}
loaded_bridge.handle = handle;
loaded_bridge.api = api;
loaded_bridge.real_path = real_path;
return BridgeLoadStatus::kSuccess;
}
}
}
}
#endif