From 6da08c65394df3f32d4cd19c01cddab2bbcb45a1 Mon Sep 17 00:00:00 2001 From: deegan Date: Mon, 2 Feb 2026 15:19:09 +0100 Subject: [PATCH 1/2] 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 From cc7b6427b4bc9ff3e34d836296ca356a3c03705c Mon Sep 17 00:00:00 2001 From: PhilipDeegan Date: Sat, 4 Apr 2026 16:50:11 +0200 Subject: [PATCH 2/2] ++ --- .github/workflows/build.yml | 63 +++++ .github/workflows/build_nix.yml | 21 -- .github/workflows/build_osx.yml | 22 -- .github/workflows/build_win.yml | 28 --- .sublime-project | 17 ++ .sublime-project.sublime-workspace | 3 + mod.cpp | 371 ++++++++++------------------- 7 files changed, 205 insertions(+), 320 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/build_nix.yml delete mode 100644 .github/workflows/build_osx.yml delete mode 100644 .github/workflows/build_win.yml create mode 100644 .sublime-project create mode 100644 .sublime-project.sublime-workspace diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..7d8aa76 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,63 @@ +name: build + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + MKN_KUL_GIT_CO: --depth 1 + CURL_GET: curl -fL --retry 3 --retry-delay 2 + PATH_GET: https://github.com/mkn/mkn/releases/download/latest + +jobs: + ubuntu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - env: + MKN_KUL_GIT_CO: --depth 1 + run: | + $CURL_GET -o mkn ${PATH_GET}/mkn_nix + chmod +x mkn + KLOG=2 ./mkn clean build run -dtOa "-std=c++20 -fPIC" + KLOG=2 ./mkn clean build run -dtOp test -a "-std=c++20 -fPIC" + + macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - env: + MKN_LIB_LINK_LIB: 1 + MKN_KUL_GIT_CO: --depth 1 + run: | + $CURL_GET -o mkn ${PATH_GET}/mkn_arm_osx + chmod +x mkn + KLOG=2 ./mkn clean build run -dtOa "-std=c++20 -fPIC" + KLOG=2 ./mkn clean build run -dtOp test -a "-std=c++20 -fPIC" + + windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64 + + - env: + MKN_KUL_GIT_CO: --depth 1 + MKN_CL_PREFERRED: 1 + shell: cmd + run: | # /bin/link interferes with cl/link.exe + bash -c "rm /bin/link" + bash -c '$CURL_GET -o mkn.exe ${PATH_GET}/mkn.exe' + bash -c 'KLOG=2 ./mkn clean build run -dtOa "-EHsc -std:c++20"' + bash -c 'KLOG=2 ./mkn clean build run -dtOp test -a "-EHsc -std:c++20"' diff --git a/.github/workflows/build_nix.yml b/.github/workflows/build_nix.yml deleted file mode 100644 index c221c0b..0000000 --- a/.github/workflows/build_nix.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: ubuntu-latest - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - env: - MKN_KUL_GIT_CO: --depth 1 - run: | - curl -fL --retry 3 --retry-delay 2 -o mkn https://github.com/mkn/mkn/releases/download/latest/mkn_nix - chmod +x mkn - KLOG=2 ./mkn clean build run -dtOa "-std=c++17 -fPIC" - KLOG=2 ./mkn clean build run -dtOp test -a "-std=c++17 -fPIC" diff --git a/.github/workflows/build_osx.yml b/.github/workflows/build_osx.yml deleted file mode 100644 index ca68153..0000000 --- a/.github/workflows/build_osx.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: macos-latest - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - - env: - MKN_LIB_LINK_LIB: 1 - MKN_KUL_GIT_CO: --depth 1 - run: | - curl -fL --retry 3 --retry-delay 2 -o mkn https://github.com/mkn/mkn/releases/download/latest/mkn_arm_osx - chmod +x mkn - KLOG=2 ./mkn clean build run -dtOa "-std=c++17 -fPIC" - KLOG=2 ./mkn clean build run -dtOp test -a "-std=c++17 -fPIC" diff --git a/.github/workflows/build_win.yml b/.github/workflows/build_win.yml deleted file mode 100644 index 84347fa..0000000 --- a/.github/workflows/build_win.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: windows-latest - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - # setup MSVC compiler - - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: amd64 - - - env: - MKN_KUL_GIT_CO: --depth 1 - MKN_CL_PREFERRED: 1 - shell: cmd - run: | # /bin/link interferes with cl/link.exe - bash -c "rm /bin/link" - bash -c 'curl -Lo mkn.exe https://github.com/mkn/mkn/releases/download/latest/mkn.exe' - bash -c 'KLOG=2 ./mkn clean build run -dtOa "-EHsc -std:c++17"' - bash -c 'KLOG=2 ./mkn clean build run -dtOp test -a "-EHsc -std:c++17"' diff --git a/.sublime-project b/.sublime-project new file mode 100644 index 0000000..aaf0487 --- /dev/null +++ b/.sublime-project @@ -0,0 +1,17 @@ +{ + "folders" : + [ + { + "path" : "." + } + ], + "settings" : + { + "ClangFormat" : + { + "binary" : "clang-format", + "format_on_save" : true, + "style" : "file" + } + } +} \ No newline at end of file diff --git a/.sublime-project.sublime-workspace b/.sublime-project.sublime-workspace new file mode 100644 index 0000000..99d4cf8 --- /dev/null +++ b/.sublime-project.sublime-workspace @@ -0,0 +1,3 @@ +{ + "project": ".sublime-project", +} diff --git a/mod.cpp b/mod.cpp index b156a99..c534a43 100644 --- a/mod.cpp +++ b/mod.cpp @@ -44,281 +44,102 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #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 stringstream #include // for exit #include // for exception +#include // for exception namespace mkn { namespace lang { -class Python3Module : public maiken::Module { - public: - void init(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) override { - if (!kul::env::WHICH(PY.c_str())) PY = "python"; - PYTHON = kul::env::GET("PYTHON"); - if (!PYTHON.empty()) PY = PYTHON; -#if defined(_WIN32) - if (PY.rfind(".exe") == std::string::npos) PY += ".exe"; -#endif - kul::Process p(PY); - kul::ProcessCapture pc(p); - HOME = kul::env::GET("PYTHON3_HOME"); - if (!HOME.empty()) { +kul::File find_python3() KTHROW(std::exception) { + std::string const HOME = kul::env::GET("PYTHON3_HOME"); + + kul::Dir dir; + if (!HOME.empty()) { #if defined(_WIN32) - bin = kul::Dir(HOME); - if (!bin) KEXCEPT(kul::Exception, "$PYTHON3_HOME does not exist"); + dir = kul::Dir(HOME); + if (!dir) KEXCEPT(kul::Exception, "$PYTHON3_HOME does not exist"); #else - bin = kul::Dir("bin", HOME); - if (!bin) KEXCEPT(kul::Exception, "$PYTHON3_HOME/bin does not exist"); + dir = kul::Dir("bin", HOME); + if (!dir) KEXCEPT(kul::Exception, "$PYTHON3_HOME/bin does not exist"); #endif - path_var = std::make_shared("PATH", bin.real(), kul::cli::EnvVarMode::PREP); - kul::env::SET(path_var->name(), path_var->toString().c_str()); - p.var(path_var->name(), path_var->toString()); - }; } - void compile(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) override { - VALIDATE_NODE(node); - - auto const include = py_include(); - KLOG(INF) << include; - std::vector incs; - 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())\""; - auto outs = pyexec_for_string(import.str()); - outs.pop_back(); -#if defined(_WIN32) - outs.pop_back(); + std::vector bins{"python3", "python"}; + for (auto const& bin : bins) + if (kul::env::WHICH(bin.c_str())) + return dir ? kul::File{bin, dir} : kul::env::WHERE(bin.c_str()); + +#if defined(_WIN32) // or fallback + std::vector exes{"python3.exe", "python.exe"}; + for (auto const& bin : exes) + if (kul::env::WHICH(bin.c_str())) + return dir ? kul::File{bin, dir} : kul::env::WHERE(bin.c_str()); #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 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); - - 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()); - } - } + throw std::runtime_error("Could not find python!"); +} - if (embed) { - auto const lib = py_libname(); - KLOG(INF) << lib; - a.addLib(lib); - } +kul::cli::EnvVar python3_path_var(kul::File const& exe) { + return {"PATH", exe.dir().real(), kul::cli::EnvVarMode::PREP}; +} - if (a.mode() != maiken::compiler::Mode::STAT) a.prependLinkString(linker); - } +kul::File find_python_set_env() { + auto const python_exe = find_python3(); + // if (!python_exe) throw std::runtime_error("Could not find python!"); + // auto const path_var = python3_path_var(python_exe); + // kul::env::SET(path_var.name(), path_var.toString().c_str()); + return python_exe; +} - // 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 (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()); - // } - // } +static inline kul::File const python_exe = find_python_set_env(); - private: - std::string pyexec_for_string(std::string const& cmd) const { - mkn::kul::Process p(PY); - mkn::kul::ProcessCapture pc(p); - p << "-c" << cmd; +std::string pyexec_for_string(std::string const& cmd) { + auto const path_var = python3_path_var(python_exe); + kul::Process p(python_exe.real()); + kul::ProcessCapture pc(p); + p << "-c" << ("\"" + cmd + "\""); + p.var(path_var.name(), path_var.toString()); - KLOG(INF) << p.toString(); - // try { + 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"; + } catch (kul::proc::ExitException const& ex) { + KLOG(ERR) << pc.outs(); + KLOG(ERR) << pc.errs(); + KERR << ex; + throw; } - 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']) \""); + return kul::String::LINES(pc.outs())[0]; // DROP EOL +} + +class Python3Module : public maiken::Module { + public: + void compile(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) override; + void link(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) override; + + private: + auto py_include() const { + return pyexec_for_string("import sysconfig; print(sysconfig.get_paths()['include'])"); } std::string py_cflags() const { - return pyexec_for_string( - "\"import sysconfig; print(sysconfig.get_config_var(\'CFLAGS\') or \'\')\""); + 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'))\""); + 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)\""); + "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'))\""); + return pyexec_for_string("import sysconfig; print(sysconfig.get_config_var('prefix'))"); } static std::vector MajMin(std::string const& PY) { @@ -327,7 +148,7 @@ class Python3Module : public maiken::Module { 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) + "])\""}; + std::string print{"import sys; print(sys.version_info[" + std::to_string(idx) + "])"}; p << "-c" << print; p.start(); @@ -350,15 +171,67 @@ class Python3Module : public maiken::Module { }) .validate(node); } +}; + +void Python3Module::compile(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) { + VALIDATE_NODE(node); + + std::vector incs{py_include()}; + + try { + if (node["with"]) { + for (auto const& with : kul::cli::asArgs(node["with"].Scalar())) { + // std::stringstream import; + auto const import = std::string{"import "} + with + "; print(" + with + ".get_include())"; + // auto outs = pyexec_for_string(import); + // outs.pop_back(); + // #if defined(_WIN32) + // outs.pop_back(); + // #endif + incs.push_back(pyexec_for_string(import)); + } + } + 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()); + } else + throw std::runtime_error("include doesn't exist: " + req_include.real()); + } + } catch (kul::Exception const& e) { + KERR << e.stack(); + } catch (std::exception const& e) { + KERR << e.what(); + } catch (...) { + KERR << "UNKNOWN ERROR CAUGHT"; + } +} - std::string HOME; - std::string PY = "python3"; - std::string PYTHON; - std::string PATH = kul::env::GET("PATH"); +void Python3Module::link(maiken::Application& a, YAML::Node const& node) KTHROW(std::exception) { + VALIDATE_NODE(node); + + auto const embed = kul::String::BOOL(kul::env::GET("MKN_PYTHON_LIB_EMBED", "0")); + + auto linker = py_cflags(); + auto const libpath = py_libdir(); + auto const prefx = py_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) a.addLib(py_libname()); + + if (a.mode() != maiken::compiler::Mode::STAT) a.prependLinkString(linker); +} - kul::Dir bin; - std::shared_ptr path_var; -}; } // namespace lang } // namespace mkn