From 60c8a5c50fd98d8ae3f5deb424978649ca8ff1e5 Mon Sep 17 00:00:00 2001 From: blissful Date: Sat, 11 May 2024 20:34:20 -0400 Subject: [PATCH] poc --- .gitignore | 14 ++++++++++++-- Makefile | 5 ++++- flake.nix | 42 ++++++++++++++++++++++++------------------ pyproject.toml | 3 +++ rose/ffi.py | 16 ++++++++++++++++ rose_cli/__main__.py | 4 ++++ rose_zig/build.zig | 14 ++++++++++++++ rose_zig/src/ffi.zig | 17 +++++++++++++++++ rose_zig/src/rose.zig | 5 +++++ 9 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 rose/ffi.py create mode 100644 rose_zig/build.zig create mode 100644 rose_zig/src/ffi.zig create mode 100644 rose_zig/src/rose.zig diff --git a/.gitignore b/.gitignore index 1a5ad33..09723b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,19 @@ +# Testing +db.sqlite3 + +# Nix +result +# Python .direnv __pycache__ .ruff_cache .mypy_cache .coverage .coverage.* -result -db.sqlite3 htmlcov + +# Zig +*.so +*.so.o +zig-cache +zig-out diff --git a/Makefile b/Makefile index 0b7a74e..6cae435 100644 --- a/Makefile +++ b/Makefile @@ -24,4 +24,7 @@ lint: ruff check --fix . prettier --write . -.PHONY: check test typecheck lintcheck lint +clean: + git clean -xdf + +.PHONY: check test typecheck lintcheck lint clean diff --git a/flake.nix b/flake.nix index 7bde02b..4ba5f51 100644 --- a/flake.nix +++ b/flake.nix @@ -26,8 +26,9 @@ }; doCheck = false; }; - prod-deps = with python.pkgs; [ + prod-py-deps = with python.pkgs; [ appdirs + cffi click jinja2 llfuse @@ -38,7 +39,7 @@ uuid6-python watchdog ]; - dev-deps = with python.pkgs; [ + dev-py-deps = with python.pkgs; [ mypy pytest pytest-timeout @@ -46,14 +47,7 @@ pytest-xdist snapshottest ]; - zig-pkgs = with pkgs; [ - zig - zls - ]; - dev-cli = pkgs.writeShellScriptBin "rose" '' - cd $ROSE_ROOT - python -m rose_cli "$@" - ''; + version = nixpkgs.lib.strings.removeSuffix "\n" (builtins.readFile ./rose/.version); in { devShells.default = pkgs.mkShell { @@ -70,25 +64,37 @@ buildInputs = [ (pkgs.buildEnv { name = "rose-devshell"; - paths = with pkgs; ([ - (python.withPackages (_: prod-deps ++ dev-deps)) + paths = with pkgs; [ + (python.withPackages (_: prod-py-deps ++ dev-py-deps)) ruff - dev-cli nodePackages.pyright nodePackages.prettier - ] ++ zig-pkgs); + zig + zls + ]; }) ]; }; packages = rec { - rose = python.pkgs.buildPythonPackage { + rose-zig = pkgs.stdenv.mkDerivation { + pname = "rose"; + version = version; + src = ./rose_zig; + nativeBuildInputs = [ pkgs.zig.hook ]; + }; + # TODO: Split up into multiple packages. + rose-py = python.pkgs.buildPythonPackage { pname = "rose"; - version = nixpkgs.lib.strings.removeSuffix "\n" (builtins.readFile ./rose/.version); + version = version; src = ./.; - propagatedBuildInputs = prod-deps; + propagatedBuildInputs = prod-py-deps ++ [ rose-zig ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; + postInstall = '' + wrapProgram $out/bin/rose \ + --prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath [ rose-zig ]}" + ''; doCheck = false; }; - default = rose; }; }); } diff --git a/pyproject.toml b/pyproject.toml index e3e984d..859a262 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,9 @@ ignore_missing_imports = true [[tool.mypy.overrides]] module = "snapshottest" ignore_missing_imports = true +[[tool.mypy.overrides]] +module = "cffi" +ignore_missing_imports = true [tool.pytest.ini_options] addopts = [ diff --git a/rose/ffi.py b/rose/ffi.py new file mode 100644 index 0000000..86e38c5 --- /dev/null +++ b/rose/ffi.py @@ -0,0 +1,16 @@ +# type: ignore +from cffi import FFI + +ffi = FFI() + +lib = ffi.dlopen("rose") + +ffi.cdef(""" + void free_str(void *str); + + char *getRelease(); +""") + + +def get_release() -> str: + return ffi.string(ffi.gc(lib.getRelease(), lib.free_str)).decode("utf-8") diff --git a/rose_cli/__main__.py b/rose_cli/__main__.py index 38acd1e..8bd7f50 100644 --- a/rose_cli/__main__.py +++ b/rose_cli/__main__.py @@ -7,6 +7,10 @@ def main() -> None: from rose import RoseExpectedError + from rose.ffi import get_release + + print(get_release()) + exit(0) try: cli() diff --git a/rose_zig/build.zig b/rose_zig/build.zig new file mode 100644 index 0000000..08d4b5b --- /dev/null +++ b/rose_zig/build.zig @@ -0,0 +1,14 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const libroseffi = b.addSharedLibrary(.{ + .name = "rose", + .root_source_file = .{ .path = "src/ffi.zig" }, + .target = target, + .optimize = optimize, + }); + b.installArtifact(libroseffi); +} diff --git a/rose_zig/src/ffi.zig b/rose_zig/src/ffi.zig new file mode 100644 index 0000000..d838260 --- /dev/null +++ b/rose_zig/src/ffi.zig @@ -0,0 +1,17 @@ +const std = @import("std"); +const rose = @import("rose.zig"); + +var gpa = std.heap.GeneralPurposeAllocator(.{}){}; +const allocator = gpa.allocator(); + +export fn getRelease() [*:0]const u8 { + const message = rose.getRelease(allocator) catch |err| switch (err) { + error.OutOfMemory => @panic("Out of memory"), + }; + return message.ptr; +} + +export fn free_str(str: [*:0]const u8) void { + const len = std.mem.len(str); + allocator.free(str[0 .. len + 1]); +} diff --git a/rose_zig/src/rose.zig b/rose_zig/src/rose.zig new file mode 100644 index 0000000..9a0b023 --- /dev/null +++ b/rose_zig/src/rose.zig @@ -0,0 +1,5 @@ +const std = @import("std"); + +pub fn getRelease(allocator: std.mem.Allocator) ![:0]const u8 { + return try allocator.dupeZ(u8, "hello"); +}