From 6da08c65394df3f32d4cd19c01cddab2bbcb45a1 Mon Sep 17 00:00:00 2001 From: deegan Date: Mon, 2 Feb 2026 15:19:09 +0100 Subject: [PATCH] wip --- mod.cpp | 421 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 255 insertions(+), 166 deletions(-) diff --git a/mod.cpp b/mod.cpp index c8dab21..b156a99 100644 --- a/mod.cpp +++ b/mod.cpp @@ -28,62 +28,34 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include +#include "maiken/module/init.hpp" // IWYU pragma: keep -#include "maiken/module/init.hpp" -#include "mkn/kul/string.hpp" +#include "maiken/app.hpp" // for Application +#include "maiken/compiler.hpp" // for CompilationInfo, Mode + +#include "mkn/kul/os.hpp" // for Dir, WHICH, PushDir +#include "mkn/kul/cli.hpp" // for EnvVar, EnvVarMode +#include "mkn/kul/env.hpp" // for GET, SET +#include "mkn/kul/log.hpp" // for KERR +#include "mkn/kul/defs.hpp" // for MKN_KUL_PUBLISH +#include "mkn/kul/proc.hpp" // for Process, ProcessCapture, AProcess +#include "mkn/kul/yaml.hpp" // for NodeValidator, Validator +#include "maiken/project.hpp" // for Project +#include "mkn/kul/except.hpp" // for Exception, KEXCEPT, KTHROW +#include "mkn/kul/string.hpp" // for String + +#include // for shared_ptr, make_shared +#include // for basic_string, string +#include // for vector +#include // for exit +#include // for exception namespace mkn { namespace lang { class Python3Module : public maiken::Module { - private: -#if defined(_WIN32) - bool const config_expected = 0; -#else - bool const config_expected = 1; -#endif - bool pyconfig_found = 0; - std::string HOME, PY = "python3", PYTHON, PY_CONFIG = "python-config", - PY3_CONFIG = "python3-config", PATH = kul::env::GET("PATH"); - kul::Dir bin; - std::shared_ptr path_var; - - protected: - static std::vector MajMin(std::string const& PY) { - std::vector version(2); - - for (auto const& idx : {0, 1}) { - kul::Process p(PY); - kul::ProcessCapture pc(p); - std::string print{"\"import sys; print(sys.version_info[" + std::to_string(idx) + "])\""}; - p << "-c" << print; - p.start(); - - auto out = kul::String::LINES(pc.outs())[0]; - kul::String::TRIM(out); - - version[idx] = kul::String::UINT16(out); - } - - return version; - } - - static void VALIDATE_NODE(YAML::Node const& node) { - using namespace kul::yaml; - Validator({ - NodeValidator("args"), - NodeValidator("delete"), - NodeValidator("with"), - NodeValidator("min"), - }) - .validate(node); - } - public: void init(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) override { - bool finally = 0; if (!kul::env::WHICH(PY.c_str())) PY = "python"; PYTHON = kul::env::GET("PYTHON"); if (!PYTHON.empty()) PY = PYTHON; @@ -105,78 +77,22 @@ class Python3Module : public maiken::Module { kul::env::SET(path_var->name(), path_var->toString().c_str()); p.var(path_var->name(), path_var->toString()); }; - pyconfig_found = kul::env::WHICH(PY3_CONFIG.c_str()); - if (!pyconfig_found) { - pyconfig_found = kul::env::WHICH(PY_CONFIG.c_str()); - PY3_CONFIG = PY_CONFIG; - } - try { - if (!pyconfig_found && config_expected) { - finally = 1; - KEXCEPT(kul::Exception, "python-config does not exist on path"); - } - p << "-c" - << "\"import sys; print(sys.version_info[0])\""; - p.start(); - } catch (kul::Exception const& e) { - KERR << e.stack(); - } catch (std::exception const& e) { - KERR << e.what(); - } catch (...) { - KERR << "UNKNOWN ERROR CAUGHT"; - } - if (finally) exit(2); } void compile(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) override { VALIDATE_NODE(node); - kul::os::PushDir pushd(a.project().dir()); + + auto const include = py_include(); + KLOG(INF) << include; std::vector incs; - try { - if (pyconfig_found) { - kul::Process p(PY3_CONFIG); - kul::ProcessCapture pc(p); - p << "--includes"; - if (path_var) p.var(path_var->name(), path_var->toString()); - p.start(); - auto outs(pc.outs()); - outs.pop_back(); - for (auto inc : kul::cli::asArgs(outs)) { - if (inc.find("-I") == 0) inc = inc.substr(2); - incs.push_back(inc); - } - } else { - kul::Dir dInc; - if (path_var) { - dInc = kul::Dir("include", bin.parent()); - if (!dInc) dInc = kul::Dir("include", kul::File(kul::env::WHERE(PY.c_str())).dir()); - } else { - dInc = kul::Dir("include", kul::File(kul::env::WHERE(PY.c_str())).dir()); - } - if (!dInc) - KEXCEPT(kul::Exception, "$PYTHON3_HOME/include does not exist") - << kul::os::EOL() << dInc.path(); - incs.push_back(dInc.real()); - } - } catch (kul::Exception const& e) { - KERR << e.stack(); - } catch (std::exception const& e) { - KERR << e.what(); - } catch (...) { - KERR << "UNKNOWN ERROR CAUGHT"; - } + incs.push_back(include); try { if (node["with"]) { for (auto const with : kul::cli::asArgs(node["with"].Scalar())) { std::stringstream import; import << "\"import " << with << "; print(" << with << ".get_include())\""; - kul::Process p(PY); - kul::ProcessCapture pc(p); - p << "-c" << import.str(); - if (path_var) p.var(path_var->name(), path_var->toString()); - p.start(); - auto outs(pc.outs()); + auto outs = pyexec_for_string(import.str()); outs.pop_back(); #if defined(_WIN32) outs.pop_back(); @@ -200,75 +116,248 @@ class Python3Module : public maiken::Module { } } - std::string prefix() const { - kul::Process p(PY3_CONFIG); - kul::ProcessCapture pc(p); - p << "--prefix"; - p.start(); - auto ret = pc.outs(); - ret.pop_back(); // new line - return ret; - }; + // void compile(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) override + // { + // VALIDATE_NODE(node); + // kul::os::PushDir pushd(a.project().dir()); + // std::vector incs; + // try { + // if (pyconfig_found) { + // kul::Process p(PY3_CONFIG); + // kul::ProcessCapture pc(p); + // p << "--includes"; + // if (path_var) p.var(path_var->name(), path_var->toString()); + // p.start(); + // auto outs(pc.outs()); + // outs.pop_back(); + // for (auto inc : kul::cli::asArgs(outs)) { + // if (inc.find("-I") == 0) inc = inc.substr(2); + // incs.push_back(inc); + // } + // } else { + // kul::Dir dInc; + // if (path_var) { + // dInc = kul::Dir("include", bin.parent()); + // if (!dInc) dInc = kul::Dir("include", kul::File(kul::env::WHERE(PY.c_str())).dir()); + // } else { + // dInc = kul::Dir("include", kul::File(kul::env::WHERE(PY.c_str())).dir()); + // } + // if (!dInc) + // KEXCEPT(kul::Exception, "$PYTHON3_HOME/include does not exist") + // << kul::os::EOL() << dInc.path(); + // incs.push_back(dInc.real()); + // } + // } catch (kul::Exception const& e) { + // KERR << e.stack(); + // } catch (std::exception const& e) { + // KERR << e.what(); + // } catch (...) { + // KERR << "UNKNOWN ERROR CAUGHT"; + // } + + // try { + // if (node["with"]) { + // for (auto const with : kul::cli::asArgs(node["with"].Scalar())) { + // std::stringstream import; + // import << "\"import " << with << "; print(" << with << ".get_include())\""; + // kul::Process p(PY); + // kul::ProcessCapture pc(p); + // p << "-c" << import.str(); + // if (path_var) p.var(path_var->name(), path_var->toString()); + // p.start(); + // auto outs(pc.outs()); + // outs.pop_back(); + // #if defined(_WIN32) + // outs.pop_back(); + // #endif + // incs.push_back(outs); + // } + // } + // for (auto const inc : incs) { + // kul::Dir req_include(inc); + // if (req_include) { + // a.addInclude(req_include.real()); + // for (auto* rep : a.revendencies()) rep->addInclude(req_include.real()); + // } + // } + // } catch (kul::Exception const& e) { + // KERR << e.stack(); + // } catch (std::exception const& e) { + // KERR << e.what(); + // } catch (...) { + // KERR << "UNKNOWN ERROR CAUGHT"; + // } + // } void link(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) override { VALIDATE_NODE(node); - if (pyconfig_found) { - auto version = MajMin(PY); - kul::os::PushDir pushd(a.project().dir()); - kul::Process p(PY3_CONFIG); - kul::ProcessCapture pc(p); - p << "--ldflags"; + auto const embed = kul::String::BOOL(kul::env::GET("MKN_PYTHON_LIB_EMBED", "0")); + + auto linker = py_cflags(); + auto const libpath = py_libdir(); + std::cout << __FILE__ << " " << __LINE__ << " " << libpath << std::endl; + auto const prefx = py_prefix(); + KLOG(INF) << prefx; + if (prefx.size()) + if (auto const lib = kul::Dir(kul::Dir::JOIN(prefx, "lib"))) { + if (auto const needle = std::string{"-L" + lib.real()}; + linker.find(needle) != std::string::npos) { + kul::String::REPLACE_ALL(linker, needle + " ", ""); + a.addLibpath(lib.real()); + } + } + + if (embed) { + auto const lib = py_libname(); + KLOG(INF) << lib; + a.addLib(lib); + } + + if (a.mode() != maiken::compiler::Mode::STAT) a.prependLinkString(linker); + } + + // void link(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) override { + // VALIDATE_NODE(node); + // if (pyconfig_found) { + // auto version = MajMin(PY); + + // kul::os::PushDir pushd(a.project().dir()); + // kul::Process p(PY3_CONFIG); + // kul::ProcessCapture pc(p); + // p << "--ldflags"; + + // if (path_var) p.var(path_var->name(), path_var->toString()); + + // auto const embed = kul::String::BOOL(kul::env::GET("MKN_PYTHON_LIB_EMBED", "0")); + // if (embed) p << "--embed"; + + // p.start(); + // std::string linker(pc.outs()); + // linker.pop_back(); + // auto const prefx = prefix(); + + // if (prefx.size()) + // if (auto const lib = kul::Dir(kul::Dir::JOIN(prefx, "lib"))) { + // if (auto const needle = std::string{"-L" + lib.real()}; + // linker.find(needle) != std::string::npos) { + // kul::String::REPLACE_ALL(linker, needle + " ", ""); + // a.addLibpath(lib.real()); + // } + // } + + // if (embed) + // for (auto bit : kul::String::SPLIT(linker, " ")) { + // kul::String::REPLACE_ALL(bit, " ", ""); + // if (bit.find("-l") == 0) { + // auto const lib = bit.substr(2); + // kul::String::REPLACE_ALL(linker, bit + " ", ""); + // a.addLib(lib); + // } + // } - if (path_var) p.var(path_var->name(), path_var->toString()); + // if (node["delete"]) { + // kul::String::REPLACE_ALL(linker, " ", " "); + // for (auto const del : kul::String::SPLIT(node["delete"].Scalar(), " ")) + // kul::String::REPLACE_ALL(linker, del, ""); + // kul::String::REPLACE_ALL(linker, " ", " "); + // } + // if (a.mode() != maiken::compiler::Mode::STAT) a.prependLinkString(linker); + // } else { + // kul::Dir dPath; + // if (path_var) { + // #if defined(_WIN32) + // dPath = kul::Dir("libs", bin); + // #endif + // } else { + // dPath = kul::Dir("libs", kul::File(kul::env::WHERE(PY.c_str())).dir()); + // } + // if (!dPath) KEXCEPT(kul::Exception, "$PYTHON3_HOME/libs does not exist"); + // a.addLibpath(dPath.real()); + // } + // } - auto const embed = kul::String::BOOL(kul::env::GET("MKN_PYTHON_LIB_EMBED", "0")); - if (embed) p << "--embed"; + private: + std::string pyexec_for_string(std::string const& cmd) const { + mkn::kul::Process p(PY); + mkn::kul::ProcessCapture pc(p); + p << "-c" << cmd; + + KLOG(INF) << p.toString(); + // try { + p.start(); + KLOG(INF) << "FINE " << pc.outs(); + return pc.outs(); + // } catch (mkn::kul::proc::ExitException const& e) { + // KLOG(INF) << pc.outs(); + // KLOG(INF) << pc.errs(); + // KLOG(INF) << e.what(); + // } + + return "FAIL"; + } + std::string py_include() const { + // return pyexec_for_string("\"import sysconfig; + // print('-I'+sysconfig.get_paths()['include'])\""); import sysconfig; + // print('-I'+sysconfig.get_paths()['include']) + return pyexec_for_string("\"import sysconfig; print('-I'+sysconfig.get_paths()['include']) \""); + } + + std::string py_cflags() const { + return pyexec_for_string( + "\"import sysconfig; print(sysconfig.get_config_var(\'CFLAGS\') or \'\')\""); + } + + std::string py_libdir() const { + return pyexec_for_string("\"import sysconfig; print(sysconfig.get_config_var('LIBDIR'))\""); + } + + std::string py_libname() const { + return pyexec_for_string( + "\"import sysconfig; lib=sysconfig.get_config_var('LDLIBRARY');" + "print(lib[3:-3] if lib.startswith('lib') and lib.endswith('.so') else lib)\""); + } + std::string py_prefix() const { + return pyexec_for_string("\"import sysconfig; print(sysconfig.get_config_var('prefix'))\""); + } + + static std::vector MajMin(std::string const& PY) { + std::vector version(2); + for (auto const& idx : {0, 1}) { + kul::Process p(PY); + kul::ProcessCapture pc(p); + std::string print{"\"import sys; print(sys.version_info[" + std::to_string(idx) + "])\""}; + p << "-c" << print; p.start(); - std::string linker(pc.outs()); - linker.pop_back(); - auto const prefx = prefix(); - - if (prefx.size()) - if (auto const lib = kul::Dir(kul::Dir::JOIN(prefx, "lib"))) { - if (auto const needle = std::string{"-L" + lib.real()}; - linker.find(needle) != std::string::npos) { - kul::String::REPLACE_ALL(linker, needle + " ", ""); - a.addLibpath(lib.real()); - } - } - if (embed) - for (auto bit : kul::String::SPLIT(linker, " ")) { - kul::String::REPLACE_ALL(bit, " ", ""); - if (bit.find("-l") == 0) { - auto const lib = bit.substr(2); - kul::String::REPLACE_ALL(linker, bit + " ", ""); - a.addLib(lib); - } - } + auto out = kul::String::LINES(pc.outs())[0]; + kul::String::TRIM(out); - if (node["delete"]) { - kul::String::REPLACE_ALL(linker, " ", " "); - for (auto const del : kul::String::SPLIT(node["delete"].Scalar(), " ")) - kul::String::REPLACE_ALL(linker, del, ""); - kul::String::REPLACE_ALL(linker, " ", " "); - } - if (a.mode() != maiken::compiler::Mode::STAT) a.prependLinkString(linker); - } else { - kul::Dir dPath; - if (path_var) { -#if defined(_WIN32) - dPath = kul::Dir("libs", bin); -#endif - } else { - dPath = kul::Dir("libs", kul::File(kul::env::WHERE(PY.c_str())).dir()); - } - if (!dPath) KEXCEPT(kul::Exception, "$PYTHON3_HOME/libs does not exist"); - a.addLibpath(dPath.real()); + version[idx] = kul::String::UINT16(out); } + + return version; } + + static void VALIDATE_NODE(YAML::Node const& node) { + using namespace kul::yaml; + Validator({ + NodeValidator("args"), + NodeValidator("delete"), + NodeValidator("with"), + NodeValidator("min"), + }) + .validate(node); + } + + std::string HOME; + std::string PY = "python3"; + std::string PYTHON; + std::string PATH = kul::env::GET("PATH"); + + kul::Dir bin; + std::shared_ptr path_var; }; } // namespace lang } // namespace mkn