commit 14dfb3e69257ce4271215a163eed8428ed99678a Author: Pavel Kirilin Date: Mon Sep 8 14:17:51 2025 +0200 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54b02da --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +*.so diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..7a5c4ff --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,300 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pyrtest" +version = "0.1.0" +dependencies = [ + "bindgen", + "pkg-config", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f12e463 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "pyrtest" +version = "0.1.0" +edition = "2024" + +[lib] +crate-type = ["dylib"] +name = 'pyrtest' + +[dependencies] + +[build-dependencies] +bindgen = "0.72.1" +pkg-config = "0.3.32" diff --git a/README.md b/README.md new file mode 100644 index 0000000..3fc395a --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Python lib from scratch + + +``` +cargo build +cp target/debug/*.so . +python -c 'import libpyrtest; print(libpyrtest.shit("fuck"))' +``` diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..cb984a8 --- /dev/null +++ b/build.rs @@ -0,0 +1,45 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + // Trying to find python3 + let lib = pkg_config::probe_library("python3").expect("Python3 is not available for linking"); + + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + let mut bindings_builder = bindgen::Builder::default() + // The input header we would like to generate + // bindings for. + .header("csrc/wrapper.h") + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .blocklist_var("FP_INT_UPWARD") + .blocklist_var("FP_NORMAL") + .blocklist_var("FP_SUBNORMAL") + .blocklist_var("FP_INFINITE") + .blocklist_var("FP_INT_TONEAREST") + .blocklist_var("FP_INT_TONEARESTFROMZERO") + .blocklist_var("FP_INT_TOWARDZERO") + .blocklist_var("FP_NAN") + .blocklist_var("FP_ZERO") + .blocklist_var("FP_INT_DOWNWARD"); + // Finish the builder and generate the bindings. + for path in lib.include_paths { + let Some(lib_path) = path.as_path().to_str() else { + continue; + }; + bindings_builder = bindings_builder.clang_arg(format!("-I{}", lib_path)); + } + let bindings = bindings_builder + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/csrc/wrapper.h b/csrc/wrapper.h new file mode 100644 index 0000000..576fc6d --- /dev/null +++ b/csrc/wrapper.h @@ -0,0 +1 @@ +#include diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a8828ad --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,87 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(improper_ctypes)] + +use std::ffi::CStr; + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + +pub const PyObject_HEAD_INIT: PyObject = PyObject { + __bindgen_anon_1: _object__bindgen_ty_1 { ob_refcnt: 1 }, + ob_type: std::ptr::null_mut(), +}; + +pub const PyModuleDef_HEAD_INIT: PyModuleDef_Base = PyModuleDef_Base { + ob_base: PyObject_HEAD_INIT, + m_init: None, + m_index: 0, + m_copy: std::ptr::null_mut(), +}; + +pub fn safe_shit_func(data: &str) -> usize { + return data.len(); +} + +unsafe extern "C" fn py_shit_func(_mod_self: *mut PyObject, args: *mut PyObject) -> *mut PyObject { + let mut ptr = std::ptr::null(); + let parsed = unsafe { PyArg_ParseTuple(args, c"s".as_ptr(), &mut ptr) }; + if parsed == 0 { + return std::ptr::null::() as *mut _; + } + let Ok(read_arg) = unsafe { CStr::from_ptr(ptr) }.to_str() else { + unsafe { PyErr_SetString(PyExc_RuntimeError, c"Not an UTF-8 string".as_ptr()) }; + return std::ptr::null::() as *mut _; + }; + let ret = safe_shit_func(read_arg); + return unsafe { PyLong_FromSize_t(ret) }; +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyInit_libpyrtest() -> *mut PyObject { + let slots = vec![ + PyModuleDef_Slot { + slot: Py_mod_multiple_interpreters as i32, + value: 2 as *mut std::ffi::c_void, + }, + PyModuleDef_Slot { + slot: 0, + value: std::ptr::null_mut(), + }, + ] + .into_boxed_slice(); + let slots_ptr: *mut PyModuleDef_Slot = Box::into_raw(slots) as *mut _; + + let methods: Box<[PyMethodDef]> = vec![ + PyMethodDef { + ml_name: c"shit".as_ptr(), + ml_meth: Some(py_shit_func), + ml_flags: METH_VARARGS as i32, + ml_doc: c"Shit function for you all fools".as_ptr(), + }, + PyMethodDef { + ml_name: std::ptr::null(), + ml_meth: None, + ml_flags: 0, + ml_doc: std::ptr::null(), + }, + ] + .into_boxed_slice(); + let methods_ptr: *mut _ = Box::into_raw(methods) as *mut _; + + let my_mod = PyModuleDef { + m_base: PyModuleDef_HEAD_INIT, + m_name: c"libpyrstest".as_ptr(), + m_doc: c"My cool rust module".as_ptr(), + m_size: 0, + m_methods: methods_ptr, + m_slots: slots_ptr, + m_traverse: None, + m_clear: None, + m_free: None, + }; + let raw_mod = Box::into_raw(Box::new(my_mod)); + return unsafe { PyModuleDef_Init(raw_mod) }; +}