* 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 BASE_COMMON_PYTHON_RUNTIME_PYTHON_BRIDGE_LOADER_UTILS_H_
#define BASE_COMMON_PYTHON_RUNTIME_PYTHON_BRIDGE_LOADER_UTILS_H_
#include <dlfcn.h>
#include <cstdint>
#include <string>
#include "common/python_runtime/python_artifact_utils.h"
namespace ge {
namespace python_bridge_loader {
constexpr uint32_t kBridgeLoadSuccess = 0U;
template <typename BridgeApiT>
struct LoadedBridgeCandidate {
void *handle{nullptr};
const BridgeApiT *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_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 + "]";
}
template <typename ArtifactConfigT>
inline ArtifactConfigT BuildArtifactConfig(const python_artifact::BridgeLibraryCandidate &candidate) {
return ArtifactConfigT{
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);
}
}
template <typename BridgeApiT, typename ArtifactConfigT>
BridgeLoadStatus TryLoadBridgeCandidate(const python_artifact::PythonRuntimeKey &expected_key,
const python_artifact::BridgeLibraryCandidate &candidate,
const BridgeLoadDependencies &deps,
bool (*is_api_valid)(const BridgeApiT *api, uint32_t expected_abi),
LoadedBridgeCandidate<BridgeApiT> &loaded_bridge) {
loaded_bridge = LoadedBridgeCandidate<BridgeApiT>{};
if (!IsBridgeLoadDependenciesValid(deps) || (is_api_valid == nullptr)) {
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 (!python_artifact::IsRuntimeKeyCompatible(expected_key, loaded_key)) {
CloseLibraryQuietly(deps, handle);
return BridgeLoadStatus::kRuntimeMismatch;
}
using GetApiFn = const BridgeApiT *(*)();
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 (!is_api_valid(api, deps.expected_abi)) {
CloseLibraryQuietly(deps, handle);
return BridgeLoadStatus::kInvalidApi;
}
const auto artifact_config = BuildArtifactConfig<ArtifactConfigT>(candidate);
if (api->set_artifact_config(&artifact_config) != kBridgeLoadSuccess) {
CloseLibraryQuietly(deps, handle);
return BridgeLoadStatus::kSetArtifactConfigFailed;
}
loaded_bridge.handle = handle;
loaded_bridge.api = api;
loaded_bridge.real_path = real_path;
return BridgeLoadStatus::kSuccess;
}
}
}
#endif