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 ce3932a..0a8a856 100644 --- a/mod.cpp +++ b/mod.cpp @@ -28,109 +28,97 @@ 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 basic_string, string +#include // for vector +#include // for exit +#include + +namespace YAML { +class Node; +} namespace mkn { namespace python3 { -class ModuleMaker : public maiken::Module { - private: +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) - const bool config_expected = 0; + dir = kul::Dir(HOME); + if (!dir) KEXCEPT(kul::Exception, "$PYTHON3_HOME does not exist"); #else - const bool config_expected = 1; + dir = kul::Dir("bin", HOME); + if (!dir) KEXCEPT(kul::Exception, "$PYTHON3_HOME/bin does not exist"); #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; -#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()) { -#if defined(_WIN32) - bin = mkn::kul::Dir(HOME); - if (!bin) 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"); -#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()); - }; -#if defined(_WIN32) - pyconfig_found = false; // doesn't exist on windows (generally) -#else - pyconfig_found = mkn::kul::env::WHICH(PY3_CONFIG.c_str()); + 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 - 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; - - 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); + + 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(); + } 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 +} + +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"); }