Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -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"'
23 changes: 0 additions & 23 deletions .github/workflows/build_nix.yml

This file was deleted.

23 changes: 0 additions & 23 deletions .github/workflows/build_osx.yml

This file was deleted.

28 changes: 0 additions & 28 deletions .github/workflows/build_win.yml

This file was deleted.

17 changes: 17 additions & 0 deletions .sublime-project
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"folders" :
[
{
"path" : "."
}
],
"settings" :
{
"ClangFormat" :
{
"binary" : "clang-format",
"format_on_save" : true,
"style" : "file"
}
}
}
3 changes: 3 additions & 0 deletions .sublime-project.sublime-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"project": ".sublime-project",
}
9 changes: 8 additions & 1 deletion mkn.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: .}}
168 changes: 78 additions & 90 deletions mod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <cstdint>
#include <unordered_set>
#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 <string> // for basic_string, string
#include <vector> // for vector
#include <stdlib.h> // for exit
#include <stdexcept>

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<kul::cli::EnvVar> 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<kul::cli::EnvVar>("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<std::string> 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<std::string> 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

Expand Down
Loading
Loading