From d6db77ad71c35277659285407d62f2bbfcd353cf Mon Sep 17 00:00:00 2001 From: deegan Date: Mon, 2 Feb 2026 15:20:18 +0100 Subject: [PATCH 1/2] wip --- mod.cpp | 103 ++++++++++++++++++++------------------------------------ 1 file changed, 37 insertions(+), 66 deletions(-) diff --git a/mod.cpp b/mod.cpp index ce3932a..da55a6e 100644 --- a/mod.cpp +++ b/mod.cpp @@ -28,36 +28,35 @@ 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 "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/defs.hpp" // for MKN_KUL_PUBLISH +#include "mkn/kul/proc.hpp" // for Process, ProcessCapture, AProcess +#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 + +namespace YAML { +class Node; +} namespace mkn { namespace python3 { class ModuleMaker : public maiken::Module { - private: -#if defined(_WIN32) - const bool config_expected = 0; -#else - const bool config_expected = 1; -#endif - bool pyconfig_found = 0; - std::string HOME, PY = "python3", PYTHON, PY_CONFIG = "python-config", - PY3_CONFIG = "python3-config", PATH = mkn::kul::env::GET("PATH"); - mkn::kul::Dir bin; - std::shared_ptr path_var; - - protected: - static void VALIDATE_NODE(YAML::Node const& node) { - using namespace mkn::kul::yaml; - Validator({NodeValidator("args")}).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 = mkn::kul::env::GET("PYTHON"); if (!PYTHON.empty()) PY = PYTHON; @@ -80,56 +79,28 @@ class ModuleMaker : public maiken::Module { mkn::kul::env::SET(path_var->name(), path_var->toString().c_str()); p.var(path_var->name(), path_var->toString()); }; -#if defined(_WIN32) - pyconfig_found = false; // doesn't exist on windows (generally) -#else - pyconfig_found = mkn::kul::env::WHICH(PY3_CONFIG.c_str()); -#endif - if (!pyconfig_found) { - pyconfig_found = mkn::kul::env::WHICH(PY_CONFIG.c_str()); - PY3_CONFIG = PY_CONFIG; - } - try { - p << "-c" - << "\"import sys; print(sys.version_info[0])\""; - p.start(); - if (!pyconfig_found && config_expected) { - finally = 1; - KEXCEPT(kul::Exception, "python-config does not exist on path"); - } - } catch (mkn::kul::Exception const& e) { - KERR << e.stack(); - } catch (std::exception const& e) { - KERR << e.what(); - } catch (...) { - KERR << "UNKNOWN ERROR CAUGHT"; - } - if (finally) exit(2); - using namespace mkn::kul::cli; + auto const extension = + pyexec_for_string("\"import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))\""); - std::string extension; - if (pyconfig_found) { - mkn::kul::os::PushDir pushd(a.project().dir()); - mkn::kul::Process p(PY3_CONFIG); - mkn::kul::ProcessCapture pc(p); - p << "--extension-suffix"; - if (path_var) p.var(path_var->name(), path_var->toString()); - p.start(); - extension = pc.outs(); - } else { - mkn::kul::Process p(PY); - mkn::kul::ProcessCapture pc(p); - p << "-c" - << "\"import sysconfig; " - "print(sysconfig.get_config_var('EXT_SUFFIX'))\""; - p.start(); - extension = pc.outs(); - } a.m_cInfo.lib_ext = mkn::kul::String::LINES(extension)[0]; // drop EOL a.m_cInfo.lib_prefix = ""; a.mode(maiken::compiler::Mode::SHAR); } + + private: + std::string pyexec_for_string(std::string const& cmd) { + mkn::kul::Process p(PY); + mkn::kul::ProcessCapture pc(p); + p << "-c" << cmd; + p.start(); + return pc.outs(); + } + + std::string HOME, PY = "python3", PYTHON, PY_CONFIG = "python-config", + PY3_CONFIG = "python3-config", PATH = mkn::kul::env::GET("PATH"); + mkn::kul::Dir bin; + std::shared_ptr path_var; }; } // namespace python3 } // namespace mkn From 2903791136387c4af6c4bc01657cf0f837587e05 Mon Sep 17 00:00:00 2001 From: PhilipDeegan Date: Sat, 4 Apr 2026 17:39:46 +0200 Subject: [PATCH 2/2] ++ --- .github/workflows/build.yml | 91 ++++++++++++++++++++++++++++ .github/workflows/build_nix.yml | 23 ------- .github/workflows/build_osx.yml | 23 ------- .github/workflows/build_win.yml | 28 --------- .sublime-project | 17 ++++++ .sublime-project.sublime-workspace | 3 + mkn.yaml | 9 ++- mod.cpp | 97 ++++++++++++++++++------------ test.cpp | 13 ++-- test_module.cpp | 12 ++++ 10 files changed, 195 insertions(+), 121 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 create mode 100644 test_module.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..11cc812 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,91 @@ +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 + strategy: + fail-fast: false + max-parallel: 4 + matrix: + python-version: ['3.14'] + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + architecture: x64 + + - env: + MKN_LIB_LINK_LIB: 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 -dtOa "-std=c++20 -fPIC" -p test_module + python3 -c "import test_module as tm; tm.lol()" + + macos: + runs-on: macos-latest + strategy: + fail-fast: false + max-parallel: 4 + matrix: + python-version: ['3.14'] + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + architecture: x64 + + - env: + MKN_LIB_LINK_LIB: 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" + + windows: + runs-on: windows-latest + strategy: + fail-fast: false + max-parallel: 4 + matrix: + python-version: ['3.14'] + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + architecture: x64 + + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64 + + - env: + 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 84f50e3..0000000 --- a/.github/workflows/build_nix.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: ubuntu-latest - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - run: uname -a - - - 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_nix - chmod +x mkn - KLOG=2 ./mkn clean build run -dtOa "-std=c++17 -fPIC" diff --git a/.github/workflows/build_osx.yml b/.github/workflows/build_osx.yml deleted file mode 100644 index 8021099..0000000 --- a/.github/workflows/build_osx.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: macos-latest - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - runs-on: macos-latest - steps: - - uses: actions/checkout@v4 - - - run: uname -a - - - 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" 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/mkn.yaml b/mkn.yaml index f4c8351..24c87b9 100644 --- a/mkn.yaml +++ b/mkn.yaml @@ -21,6 +21,13 @@ profile: dep: mkn&${maiken_location}(${maiken_scm})[lib] main: test.cpp +- name: test_module + dep: lang.pybind11 + src: test_module.cpp + mod: python3.module lang.python3 + out: test_module + install: . + - name: format mod: | - clang.format{init{style: google, paths: .}} + clang.format{init{style: file, paths: .}} diff --git a/mod.cpp b/mod.cpp index da55a6e..0a8a856 100644 --- a/mod.cpp +++ b/mod.cpp @@ -42,10 +42,10 @@ 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 exit +#include namespace YAML { class Node; @@ -54,54 +54,71 @@ class Node; namespace mkn { namespace python3 { -class ModuleMaker : 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 = mkn::kul::env::GET("PYTHON"); - if (!PYTHON.empty()) PY = PYTHON; -#if defined(_WIN32) - if (PY.rfind(".exe") == std::string::npos) PY += ".exe"; -#endif - mkn::kul::Process p(PY); - mkn::kul::ProcessCapture pc(p); - HOME = mkn::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 = mkn::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 = mkn::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(), mkn::kul::cli::EnvVarMode::PREP); - mkn::kul::env::SET(path_var->name(), path_var->toString().c_str()); - p.var(path_var->name(), path_var->toString()); - }; - - auto const extension = - pyexec_for_string("\"import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))\""); - - a.m_cInfo.lib_ext = mkn::kul::String::LINES(extension)[0]; // drop EOL - a.m_cInfo.lib_prefix = ""; - a.mode(maiken::compiler::Mode::SHAR); } - private: - std::string pyexec_for_string(std::string const& cmd) { - mkn::kul::Process p(PY); - mkn::kul::ProcessCapture pc(p); - p << "-c" << cmd; + 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 + + throw std::runtime_error("Could not find python!"); +} + +kul::cli::EnvVar python3_path_var(kul::File const& exe) { + return {"PATH", exe.dir().real(), kul::cli::EnvVarMode::PREP}; +} + +static inline kul::File const python_exe = find_python3(); + +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()); + + try { p.start(); - return pc.outs(); + } catch (kul::proc::ExitException const& ex) { + KLOG(ERR) << pc.outs(); + KLOG(ERR) << pc.errs(); + KERR << ex; + throw; } + return kul::String::LINES(pc.outs())[0]; // DROP EOL +} - std::string HOME, PY = "python3", PYTHON, PY_CONFIG = "python-config", - PY3_CONFIG = "python3-config", PATH = mkn::kul::env::GET("PATH"); - mkn::kul::Dir bin; - std::shared_ptr path_var; +class ModuleMaker : public maiken::Module { + public: + void init(maiken::Application& a, YAML::Node const& /*node*/) KTHROW(std::exception) override; }; + +void ModuleMaker::init(maiken::Application& a, YAML::Node const& /*node*/) KTHROW(std::exception) { + auto const cmd = "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))"; + a.m_cInfo.lib_ext = pyexec_for_string(cmd); + a.m_cInfo.lib_prefix = ""; + a.mode(maiken::compiler::Mode::SHAR); +} + } // namespace python3 } // namespace mkn diff --git a/test.cpp b/test.cpp index ebdb642..603069d 100644 --- a/test.cpp +++ b/test.cpp @@ -5,13 +5,14 @@ #include "mkn/kul/signal.hpp" #include "mkn/kul/yaml.hpp" -const std::string yArgs = ""; +std::string const yArgs = ""; -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { + KOUT(NON) << __FILE__; mkn::kul::Signal sig; try { YAML::Node node = mkn::kul::yaml::String(yArgs).root(); - char *argv2[2] = {argv[0], (char *)"-O"}; + char* argv2[2] = {argv[0], (char*)"-O"}; auto app = (maiken::Application::CREATE(2, argv2))[0]; auto loader(maiken::ModuleLoader::LOAD(*app)); loader->module()->init(*app, node); @@ -19,11 +20,11 @@ int main(int argc, char *argv[]) { loader->module()->link(*app, node); loader->module()->pack(*app, node); loader->unload(); - for (const auto inc : app->includes()) KLOG(INF) << inc.first; - } catch (const mkn::kul::Exception &e) { + for (auto const inc : app->includes()) KLOG(INF) << inc.first; + } catch (mkn::kul::Exception const& e) { KLOG(ERR) << e.what(); return 2; - } catch (const std::exception &e) { + } catch (std::exception const& e) { KERR << e.what(); return 3; } catch (...) { diff --git a/test_module.cpp b/test_module.cpp new file mode 100644 index 0000000..96fb384 --- /dev/null +++ b/test_module.cpp @@ -0,0 +1,12 @@ + + +// #include +#include +// #include +// #include + +#include + +void lol() { std::cout << "lol" << std::endl; } + +PYBIND11_MODULE(test_module, m, pybind11::mod_gil_not_used()) { m.def("lol", lol, "lol"); }