Shamrock 2025.10.0
Astrophysical Code
Loading...
Searching...
No Matches
locate_pylib.cpp
Go to the documentation of this file.
1// -------------------------------------------------------//
2//
3// SHAMROCK code for hydrodynamics
4// Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me>
5// SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1
6// Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information
7//
8// -------------------------------------------------------//
9
17#include "shambase/print.hpp"
18#include "shambase/string.hpp"
20#include "shamcmdopt/env.hpp"
21#include <pybind11/embed.h>
22#include <pybind11/stl.h>
23#include <filesystem>
24#include <optional>
25#include <string>
26#include <vector>
27
28// env var to set the path to the pylib
29std::optional<std::string> pylib_path_env_var = shamcmdopt::getenv_str("SHAMROCK_PYLIB_PATH");
30
32extern const char *configure_time_pylib_paths();
33
34std::vector<std::string> configure_time_pylib_paths_str() {
35 return shambase::split_str(std::string(configure_time_pylib_paths()), std::string(";"));
36}
37
38namespace shambindings {
39
40 std::optional<std::string> get_binary_path() {
41
42 // first try /proc/self/exe
43 try {
44 return std::filesystem::read_symlink("/proc/self/exe");
45 } catch (const std::filesystem::filesystem_error &e) {
46 return std::nullopt;
47 }
48
49 // then try sys.executable from python because why not XD
50 try {
51 py::module_ sys = py::module_::import("sys");
52 std::string executable = sys.attr("executable").cast<std::string>();
53 return executable;
54 } catch (const std::exception &e) {
55 return std::nullopt;
56 }
57 }
58
59 std::optional<std::string> is_path_valid_pylib(const std::string &path) {
60 std::filesystem::path path_fs(path);
61 if (!std::filesystem::exists(path_fs)) {
62 return "does not exist";
63 }
64 if (!std::filesystem::is_directory(path_fs)) {
65 return "is not a directory";
66 }
67
68 // it should contain shamrock folder
69 if (!std::filesystem::exists(path_fs / "shamrock")) {
70 return "does not contain shamrock folder";
71 }
72
73 // it should be a directory
74 if (!std::filesystem::is_directory(path_fs / "shamrock")) {
75 return "shamrock folder is not a directory";
76 }
77
78 // it should contain shamrock/__init__.py
79 if (!std::filesystem::exists(path_fs / "shamrock" / "__init__.py")) {
80 return "shamrock/__init__.py does not exist";
81 }
82
83 return std::nullopt;
84 }
85
86 std::vector<std::string> get_site_packages() {
87 py::module_ site = py::module_::import("site");
88 auto site_packages = site.attr("getsitepackages")();
89 return site_packages.cast<std::vector<std::string>>();
90 }
91
92 std::string locate_pylib_path(bool do_print) {
93
94 auto get_binary_dir = []() -> std::filesystem::path {
95 auto bpath = get_binary_path();
96 if (bpath.has_value()) {
97 return std::filesystem::path(bpath.value()).parent_path();
98 }
99 return std::filesystem::path(".");
100 };
101
102 // Get the path to the current binary
103 std::filesystem::path binary_dir = get_binary_dir();
104
105 std::filesystem::path pyshamrock_path_relative1 = binary_dir / ".." / "pylib";
106 std::filesystem::path pyshamrock_path_relative2 = binary_dir / ".." / "src" / "pylib";
107
108 std::vector<std::string> possible_paths = {};
109
110 for (const auto &path : get_site_packages()) {
111 possible_paths.push_back(path);
112 }
113
114 possible_paths.push_back("pylib");
115 possible_paths.push_back(pyshamrock_path_relative1);
116 possible_paths.push_back(pyshamrock_path_relative2);
117
118 for (const auto &path : configure_time_pylib_paths_str()) {
119 possible_paths.push_back(path);
120 }
121
122 if (pylib_path_env_var.has_value()) {
123 if (do_print) {
124 shambase::println("using pylib path from env var: " + pylib_path_env_var.value());
125 }
126 possible_paths = {pylib_path_env_var.value()};
127 }
128
129 if (do_print) {
130 shambase::println("possible pylib paths (search order) : ");
131 for (const auto &path : possible_paths) {
132 shambase::println(" " + path);
133 }
134 }
135
136 std::optional<std::string> ret = std::nullopt;
137
138 for (const auto &path : possible_paths) {
139 auto err = is_path_valid_pylib(path);
140 if (err.has_value()) {
141 // shambase::println("pylib path " + path + " is not valid: " + err.value());
142 } else {
143 ret = path;
144 break;
145 }
146 }
147
148 if (ret.has_value()) {
149 if (do_print) {
150 shambase::println("using pylib path : " + ret.value());
151 }
152 return ret.value();
153 }
154
155 shambase::println("pylib path was not found ... Something might be broken");
156
157 return "";
158 };
159
160} // namespace shambindings
const char * configure_time_pylib_paths()
Path to shamrock utils lib supplied at configure time.
void println(std::string_view sv)
Prints a string to the console followed by a newline.
Definition print.cpp:37
std::vector< std::string > split_str(std::string s, std::string delimiter)
Splits a string into a vector of substrings according to a delimiter.
Definition string.hpp:290
std::optional< std::string > getenv_str(const char *env_var)
Get the content of the environment variable if it exist.
Definition env.cpp:24
void err(std::string module_name, Types... var2)
Prints a log message with multiple arguments.
Definition logs.hpp:133