* 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_ARTIFACT_SELECTOR_H_
#define GE_COMPILER_GRAPH_FUSION_PASS_PYTHON_PASS_ARTIFACT_SELECTOR_H_
#include <dirent.h>
#include <sys/utsname.h>
#include <cctype>
#include <cstdint>
#include <cstdlib>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
#include "nlohmann/json.hpp"
namespace ge {
namespace fusion {
namespace python_pass_artifact {
constexpr const char *kArtifactManifestName = "manifest.json";
constexpr const char *kGePackageRelativePath = "python/site-packages/ge";
constexpr const char *kPythonPassArtifactsRelativePath = "passes/python_pass_artifacts";
constexpr const char *kPythonPathEnvName = "PYTHONPATH";
struct BridgeLibraryCandidate {
std::string bridge_path;
std::string artifact_root;
std::string native_module_path;
};
struct PythonPassArtifactSet {
std::string root;
std::string manifest_path;
std::string python_tag;
std::string platform;
uint32_t bridge_abi{0U};
std::string bridge_path;
std::string native_module_path;
};
struct PythonRuntimeKey {
bool has_python_symbols{false};
bool is_initialized{false};
std::string python_tag;
std::string version;
std::string source;
std::string ToString() const {
if (python_tag.empty() && version.empty()) {
return source.empty() ? "unresolved" : source;
}
return "source[" + (source.empty() ? "unknown" : source) + "], python_tag[" +
(python_tag.empty() ? "unknown" : python_tag) + "], initialized[" +
(is_initialized ? "1" : "0") + "], version[" + version + "]";
}
};
inline bool ParseLeadingNumber(const char *&cursor, int &value) {
if ((cursor == nullptr) || (std::isdigit(static_cast<unsigned char>(*cursor)) == 0)) {
return false;
}
int result = 0;
constexpr int base = 10;
while (std::isdigit(static_cast<unsigned char>(*cursor)) != 0) {
result = (result * base) + (static_cast<unsigned char>(*cursor) - static_cast<unsigned char>('0'));
++cursor;
}
value = result;
return true;
}
inline std::string ParsePythonTag(const char *version) {
if (version == nullptr) {
return "";
}
const char *cursor = version;
int major = 0;
int minor = 0;
if (!ParseLeadingNumber(cursor, major) || (*cursor != '.')) {
return "";
}
++cursor;
if (!ParseLeadingNumber(cursor, minor)) {
return "";
}
return "cp" + std::to_string(major) + std::to_string(minor);
}
inline std::string DirName(const std::string &path) {
const auto pos = path.find_last_of('/');
if (pos == std::string::npos) {
return ".";
}
if (pos == 0U) {
return "/";
}
return path.substr(0U, pos);
}
inline std::string BaseName(const std::string &path) {
const auto pos = path.find_last_of('/');
if (pos == std::string::npos) {
return path;
}
return path.substr(pos + 1U);
}
inline std::string JoinPath(const std::string &dir, const std::string &name) {
if (dir.empty()) {
return name;
}
if (dir.back() == '/') {
return dir + name;
}
return dir + "/" + name;
}
inline std::string CurrentPlatformTag() {
struct utsname uts {};
if ((uname(&uts) != 0) || (uts.machine[0] == '\0')) {
return "linux-unknown";
}
return "linux-" + std::string(uts.machine);
}
inline std::string ResolveRealPath(const char *path) {
if ((path == nullptr) || (path[0] == '\0')) {
return "";
}
char *resolved_path = realpath(path, nullptr);
if (resolved_path == nullptr) {
return "";
}
std::string result(resolved_path);
free(resolved_path);
return result;
}
inline bool ReadTextFile(const std::string &file_path, std::string &content) {
const auto real_path = ResolveRealPath(file_path.c_str());
if (real_path.empty()) {
return false;
}
std::ifstream input(real_path);
if (!input.is_open()) {
return false;
}
content.assign(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
return true;
}
inline bool GetJsonString(const nlohmann::json &json_obj, const char *field_name, std::string &value) {
const auto iter = json_obj.find(field_name);
if ((iter == json_obj.end()) || (!iter->is_string())) {
return false;
}
value = iter->get<std::string>();
return !value.empty();
}
inline bool GetJsonUint32(const nlohmann::json &json_obj, const char *field_name, uint32_t &value) {
const auto iter = json_obj.find(field_name);
if ((iter == json_obj.end()) || (!iter->is_number_unsigned())) {
return false;
}
value = iter->get<uint32_t>();
return true;
}
inline bool LoadArtifactManifest(const std::string &manifest_path, PythonPassArtifactSet &artifact) {
std::string manifest_content;
if (!ReadTextFile(manifest_path, manifest_content)) {
return false;
}
nlohmann::json manifest;
try {
manifest = nlohmann::json::parse(manifest_content);
} catch (const nlohmann::json::exception &err) {
(void)err;
return false;
}
const auto real_manifest_path = ResolveRealPath(manifest_path.c_str());
artifact = PythonPassArtifactSet {};
artifact.manifest_path = real_manifest_path;
artifact.root = DirName(real_manifest_path);
std::string bridge_rel_path;
std::string native_rel_path;
if (!GetJsonString(manifest, "python_tag", artifact.python_tag) ||
!GetJsonString(manifest, "platform", artifact.platform) ||
!GetJsonUint32(manifest, "bridge_abi", artifact.bridge_abi)) {
return false;
}
const auto artifact_iter = manifest.find("artifacts");
if ((artifact_iter == manifest.end()) || (!artifact_iter->is_object()) ||
!GetJsonString(*artifact_iter, "bridge", bridge_rel_path) ||
!GetJsonString(*artifact_iter, "native", native_rel_path)) {
return false;
}
artifact.bridge_path = ResolveRealPath(JoinPath(artifact.root, bridge_rel_path).c_str());
artifact.native_module_path = ResolveRealPath(JoinPath(artifact.root, native_rel_path).c_str());
if (artifact.bridge_path.empty() || artifact.native_module_path.empty()) {
return false;
}
return true;
}
inline void AppendManifestCandidatesFromRoot(const std::string &root_path, std::vector<std::string> &manifest_paths) {
const auto real_root = ResolveRealPath(root_path.c_str());
if (real_root.empty()) {
return;
}
const auto root_manifest_path = JoinPath(real_root, kArtifactManifestName);
if (!ResolveRealPath(root_manifest_path.c_str()).empty()) {
manifest_paths.emplace_back(root_manifest_path);
}
DIR *dir = opendir(real_root.c_str());
if (dir == nullptr) {
return;
}
while (true) {
const auto *entry = readdir(dir);
if (entry == nullptr) {
break;
}
const std::string name = entry->d_name;
if ((name == ".") || (name == "..")) {
continue;
}
const auto child_manifest_path = JoinPath(JoinPath(real_root, name), kArtifactManifestName);
if (!ResolveRealPath(child_manifest_path.c_str()).empty()) {
manifest_paths.emplace_back(child_manifest_path);
}
}
(void)closedir(dir);
}
inline void AppendUniquePath(const std::string &path, std::vector<std::string> &paths) {
const auto real_path = ResolveRealPath(path.c_str());
if (real_path.empty()) {
return;
}
for (const auto &existing_path : paths) {
if (existing_path == real_path) {
return;
}
}
paths.emplace_back(real_path);
}
inline void AppendPythonPathGePackageDirCandidate(const std::string &python_path_entry,
std::vector<std::string> &ge_package_dirs) {
if (python_path_entry.empty()) {
return;
}
if (BaseName(python_path_entry) == "ge") {
AppendUniquePath(python_path_entry, ge_package_dirs);
}
AppendUniquePath(JoinPath(python_path_entry, "ge"), ge_package_dirs);
}
inline void AppendPythonPathGePackageDirCandidates(std::vector<std::string> &ge_package_dirs) {
const char *python_path = std::getenv(kPythonPathEnvName);
if ((python_path == nullptr) || (python_path[0] == '\0')) {
return;
}
const std::string paths(python_path);
size_t start = 0U;
while (start <= paths.size()) {
const auto end = paths.find(':', start);
AppendPythonPathGePackageDirCandidate(paths.substr(start, end - start), ge_package_dirs);
if (end == std::string::npos) {
break;
}
start = end + 1U;
}
}
inline std::vector<std::string> BuildGePackageDirCandidates(const std::string &loader_library_path) {
std::vector<std::string> ge_package_dirs;
if (!loader_library_path.empty()) {
const auto lib_dir = DirName(loader_library_path);
const auto install_root = DirName(lib_dir);
AppendUniquePath(JoinPath(install_root, kGePackageRelativePath), ge_package_dirs);
if (BaseName(lib_dir) == "lib64") {
AppendUniquePath(JoinPath(DirName(install_root), kGePackageRelativePath), ge_package_dirs);
}
if (BaseName(lib_dir) == "_capi") {
AppendUniquePath(DirName(lib_dir), ge_package_dirs);
}
if (BaseName(lib_dir) == "ge") {
AppendUniquePath(lib_dir, ge_package_dirs);
}
}
AppendPythonPathGePackageDirCandidates(ge_package_dirs);
return ge_package_dirs;
}
inline std::vector<std::string> BuildArtifactManifestCandidates(const std::string &loader_library_path) {
std::vector<std::string> manifest_paths;
for (const auto &ge_package_dir : BuildGePackageDirCandidates(loader_library_path)) {
AppendManifestCandidatesFromRoot(JoinPath(ge_package_dir, kPythonPassArtifactsRelativePath), manifest_paths);
}
return manifest_paths;
}
inline void AppendMatchedArtifactCandidate(const PythonRuntimeKey &runtime_key, const PythonPassArtifactSet &artifact,
const std::string &platform_tag, const uint32_t expected_bridge_abi,
std::vector<BridgeLibraryCandidate> &candidates) {
if (artifact.python_tag != runtime_key.python_tag) {
return;
}
if (artifact.platform != platform_tag) {
return;
}
if (artifact.bridge_abi != expected_bridge_abi) {
return;
}
candidates.push_back(BridgeLibraryCandidate{
artifact.bridge_path,
artifact.root,
artifact.native_module_path,
});
}
inline std::vector<BridgeLibraryCandidate> BuildPrebuiltBridgeLibraryCandidates(const PythonRuntimeKey &runtime_key,
const std::string &loader_library_path, const uint32_t expected_bridge_abi) {
std::vector<BridgeLibraryCandidate> candidates;
if (runtime_key.python_tag.empty()) {
return candidates;
}
const auto platform_tag = CurrentPlatformTag();
for (const auto &manifest_path : BuildArtifactManifestCandidates(loader_library_path)) {
PythonPassArtifactSet artifact;
if (!LoadArtifactManifest(manifest_path, artifact)) {
continue;
}
AppendMatchedArtifactCandidate(runtime_key, artifact, platform_tag, expected_bridge_abi, candidates);
}
return candidates;
}
inline std::vector<BridgeLibraryCandidate> BuildBridgeLibraryCandidates(const PythonRuntimeKey &runtime_key,
const std::string &loader_library_path, const char *bridge_library_name, const uint32_t expected_bridge_abi) {
std::vector<BridgeLibraryCandidate> candidates =
BuildPrebuiltBridgeLibraryCandidates(runtime_key, loader_library_path, expected_bridge_abi);
if (!loader_library_path.empty()) {
candidates.push_back(BridgeLibraryCandidate{
JoinPath(DirName(loader_library_path), bridge_library_name),
"",
"",
});
}
candidates.push_back(BridgeLibraryCandidate{bridge_library_name, "", ""});
return candidates;
}
}
}
}
#endif