1
0
blueloveTH 2 жил өмнө
parent
commit
a06a8918ce

+ 1 - 1
CMakeLists.txt

@@ -20,7 +20,7 @@ endif()
 if(MSVC)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR- /EHsc /utf-8 /O2")
 else()
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fexceptions -O2")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fexceptions -O2 -ldl")
 endif()
 
 option(PK_EXPORT_C_API "Export C API" ON)

+ 2 - 2
amalgamate.py

@@ -6,11 +6,11 @@ with open("include/pocketpy/opcodes.h", "rt", encoding='utf-8') as f:
 	OPCODES_TEXT = '\n' + f.read() + '\n'
 
 pipeline = [
-	["config.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
+	["config.h", "export.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
 	["obj.h", "dict.h", "codeobject.h", "frame.h"],
 	["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
 	["_generated.h", "cffi.h", "bindings.h", "iter.h", "base64.h", "random.h", "re.h", "linalg.h", "easing.h", "io.h"],
-	["export.h", "pocketpy.h"]
+	["pocketpy.h"]
 ]
 
 copied = set()

+ 1 - 1
build.sh

@@ -1,3 +1,3 @@
 python3 prebuild.py
 SRC=$(find src/ -name "*.cpp")
-clang++ -std=c++17 -fno-rtti -O2 -stdlib=libc++ -Wfatal-errors -o pocketpy src2/main.cpp $SRC -Iinclude
+clang++ -std=c++17 -fno-rtti -O2 -stdlib=libc++ -Wfatal-errors -o pocketpy src2/main.cpp $SRC -Iinclude -ldl

+ 6 - 0
include/pocketpy/bindings.h

@@ -122,4 +122,10 @@ struct OpaquePointer{
                 return VAR(self->get_##NAME()); \
             }));
 
+#define PK_REGISTER_CONSTRUCTOR(T, T0)  \
+        vm->bind_constructor<2>(type, [](VM* vm, ArgsView args){ \
+            void* p = CAST(void*, args[0]); \
+            return VAR_T(T, (T0*)p);    \
+        });
+
 }   // namespace pkpy

+ 30 - 21
include/pocketpy/common.h

@@ -23,6 +23,7 @@
 #define PK_VERSION				"1.0.9"
 
 #include "config.h"
+#include "export.h"
 
 /*******************************************************************************/
 #if PK_ENABLE_STD_FUNCTION
@@ -34,7 +35,7 @@
 #define THREAD_LOCAL thread_local
 #include <mutex>
 
-struct GIL {
+struct PK_EXPORT GIL {
 	inline static std::mutex _mutex;
     explicit GIL() { _mutex.lock(); }
     ~GIL() { _mutex.unlock(); }
@@ -58,7 +59,7 @@ template <size_t T>
 struct NumberTraits;
 
 template <>
-struct NumberTraits<4> {
+struct PK_EXPORT NumberTraits<4> {
 	using int_t = int32_t;
 	using float_t = float;
 
@@ -73,7 +74,7 @@ struct NumberTraits<4> {
 };
 
 template <>
-struct NumberTraits<8> {
+struct PK_EXPORT NumberTraits<8> {
 	using int_t = int64_t;
 	using float_t = double;
 
@@ -95,13 +96,13 @@ static_assert(sizeof(i64) == sizeof(void*));
 static_assert(sizeof(f64) == sizeof(void*));
 static_assert(std::numeric_limits<f64>::is_iec559);
 
-struct Dummy { };
-struct DummyInstance { };
-struct DummyModule { };
-struct NoReturn { };
-struct Discarded { };
+struct PK_EXPORT Dummy { };
+struct PK_EXPORT DummyInstance { };
+struct PK_EXPORT DummyModule { };
+struct PK_EXPORT NoReturn { };
+struct PK_EXPORT Discarded { };
 
-struct Type {
+struct PK_EXPORT Type {
 	int index;
 	Type(): index(-1) {}
 	Type(int index): index(index) {}
@@ -124,30 +125,32 @@ struct Type {
 
 struct PyObject;
 #define PK_BITS(p) (reinterpret_cast<i64>(p))
-inline bool is_tagged(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) != 0b00; }
-inline bool is_int(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b01; }
-inline bool is_float(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b10; }
-inline bool is_special(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b11; }
+PK_EXPORT inline bool is_tagged(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) != 0b00; }
+PK_EXPORT inline bool is_int(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b01; }
+PK_EXPORT inline bool is_float(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b10; }
+PK_EXPORT inline bool is_special(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b11; }
 
-inline bool is_both_int_or_float(PyObject* a, PyObject* b) noexcept {
+PK_EXPORT inline bool is_both_int_or_float(PyObject* a, PyObject* b) noexcept {
     return is_tagged(a) && is_tagged(b);
 }
 
-inline bool is_both_int(PyObject* a, PyObject* b) noexcept {
+PK_EXPORT inline bool is_both_int(PyObject* a, PyObject* b) noexcept {
     return is_int(a) && is_int(b);
 }
 
-inline bool is_both_float(PyObject* a, PyObject* b) noexcept {
+PK_EXPORT inline bool is_both_float(PyObject* a, PyObject* b) noexcept {
 	return is_float(a) && is_float(b);
 }
 
 // special singals, is_tagged() for them is true
-inline PyObject* const PY_NULL = (PyObject*)0b000011;		// tagged null
-inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
-inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
+PK_EXPORT inline PyObject* const PY_NULL = (PyObject*)0b000011;		// tagged null
+PK_EXPORT inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
+PK_EXPORT inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
 
 #define ADD_MODULE_PLACEHOLDER(name) namespace pkpy { inline void add_module_##name(void* vm) { (void)vm; } }
 
+} // namespace pkpy
+
 #ifdef _WIN32
 
 #ifndef WIN32_LEAN_AND_MEAN
@@ -159,6 +162,12 @@ inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
 #endif
 
 #include <Windows.h>
-#endif
+#elif __unix__
+
+#include <dlfcn.h>
+
+#elif __EMSCRIPTEN__
+
+#include <emscripten.h>
 
-} // namespace pkpy
+#endif

+ 2 - 2
include/pocketpy/export.h

@@ -6,9 +6,9 @@
 #include <emscripten.h>
 #define PK_EXPORT EMSCRIPTEN_KEEPALIVE
 #else
-#define PK_EXPORT __attribute__((visibility("default"))) __attribute__((used))
+#define PK_EXPORT __attribute__((visibility("default")))
 #endif
 
-#define PK_LEGACY_EXPORT PK_EXPORT inline
+#define PK_INLINE_EXPORT PK_EXPORT inline
 
 #endif

+ 11 - 12
include/pocketpy/pocketpy.h

@@ -10,7 +10,6 @@
 #include "easing.h"
 #include "io.h"
 #include "_generated.h"
-#include "export.h"
 #include "vm.h"
 #include "re.h"
 #include "random.h"
@@ -99,17 +98,17 @@ void add_module_gc(VM* vm);
 
 /*************************GLOBAL NAMESPACE*************************/
 extern "C" {
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     void pkpy_free(void* p){
         free(p);
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     void pkpy_vm_exec(pkpy::VM* vm, const char* source){
         vm->exec(source, "main.py", pkpy::EXEC_MODE);
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     void pkpy_vm_exec_2(pkpy::VM* vm, const char* source, const char* filename, int mode, const char* module){
         pkpy::PyObject* mod;
         if(module == nullptr) mod = vm->_main;
@@ -120,7 +119,7 @@ extern "C" {
         vm->exec(source, filename, (pkpy::CompileMode)mode, mod);
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     void pkpy_vm_compile(pkpy::VM* vm, const char* source, const char* filename, int mode, bool* ok, char** res){
         try{
             pkpy::CodeObject_ code = vm->compile(source, filename, (pkpy::CompileMode)mode);
@@ -138,39 +137,39 @@ extern "C" {
         }
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     pkpy::REPL* pkpy_new_repl(pkpy::VM* vm){
         pkpy::REPL* p = new pkpy::REPL(vm);
         return p;
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     bool pkpy_repl_input(pkpy::REPL* r, const char* line){
         return r->input(line);
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     void pkpy_vm_add_module(pkpy::VM* vm, const char* name, const char* source){
         vm->_lazy_modules[name] = source;
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     pkpy::VM* pkpy_new_vm(bool enable_os=true){
         pkpy::VM* p = new pkpy::VM(enable_os);
         return p;
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     void pkpy_delete_vm(pkpy::VM* vm){
         delete vm;
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     void pkpy_delete_repl(pkpy::REPL* repl){
         delete repl;
     }
 
-    PK_LEGACY_EXPORT
+    PK_INLINE_EXPORT
     void pkpy_vm_gc_on_delete(pkpy::VM* vm, void (*f)(pkpy::VM *, pkpy::PyObject *)){
         vm->heap._gc_on_delete = f;
     }

+ 45 - 1
src/pocketpy.cpp

@@ -2,6 +2,38 @@
 
 namespace pkpy{
 
+using dylib_entry_t = PyObject*(*)(VM*, const char*);
+
+#if PK_ENABLE_OS
+
+#if _WIN32
+static dylib_entry_t load_dylib(const char* path){
+    std::error_code ec;
+    auto p = std::filesystem::absolute(path, ec);
+    if(ec) return nullptr;
+    HMODULE handle = LoadLibraryA(p.c_str());
+    if(!handle) return nullptr;
+    return (dylib_entry_t)GetProcAddress(handle, "platform_module__init__");
+}
+#else
+static dylib_entry_t load_dylib(const char* path){
+    std::error_code ec;
+    auto p = std::filesystem::absolute(path, ec);
+    if(ec) return nullptr;
+    void* handle = dlopen(p.c_str(), RTLD_LAZY);
+    if(!handle) return nullptr;
+    return (dylib_entry_t)dlsym(handle, "platform_module__init__");
+}
+#endif
+
+#else
+static dylib_entry_t load_dylib(const char* path){
+    PK_UNUSED(path);
+    return nullptr;
+}
+#endif
+
+
 void init_builtins(VM* _vm) {
 #define BIND_NUM_ARITH_OPT(name, op)                                                                    \
     _vm->bind##name(_vm->tp_int, [](VM* vm, PyObject* lhs, PyObject* rhs) {                             \
@@ -106,7 +138,19 @@ void init_builtins(VM* _vm) {
     });
 
     _vm->bind_builtin_func<1>("__import__", [](VM* vm, ArgsView args) {
-        return vm->py_import(CAST(Str&, args[0]));
+        const Str& name = CAST(Str&, args[0]);
+        auto dot = name.sv().find_first_of(".");
+        if(dot != std::string_view::npos){
+            auto ext = name.sv().substr(dot);
+            if(ext == ".so" || ext == ".dll" || ext == ".dylib" || ext == ".pyd"){
+                dylib_entry_t entry = load_dylib(name.c_str());
+                if(!entry){
+                    vm->_error("ImportError", "cannot load dynamic library: " + name.escape());
+                }
+                return entry(vm, PK_VERSION);
+            }
+        }
+        return vm->py_import(name);
     });
 
     _vm->bind_builtin_func<2>("divmod", [](VM* vm, ArgsView args) {

+ 0 - 0
tests/dylib/build.bat


+ 2 - 0
tests/dylib/build.sh

@@ -0,0 +1,2 @@
+SRC=$(find ../../src/ -name "*.cpp")
+clang++ -std=c++17 -fno-rtti -O2 -stdlib=libc++ -Wfatal-errors -o libtest.so test.cpp -I../../include -fPIC -shared

+ 6 - 0
tests/dylib/main.py

@@ -0,0 +1,6 @@
+import os
+
+print(os.getcwd())
+test = __import__('libtest.so')
+
+test.hello()

+ 18 - 0
tests/dylib/test.cpp

@@ -0,0 +1,18 @@
+#include "pocketpy.h"
+
+using namespace pkpy;
+
+extern "C" {
+    PK_EXPORT
+    PyObject* platform_module__init__(VM* vm, const char* version){
+        PyObject* mod = vm->new_module("test");
+        vm->_stdout(vm, "Hello from dylib!\n");
+
+        vm->bind(mod, "hello()", [](VM* vm, ArgsView args){
+            vm->_stdout(vm, "Hello from dylib!\n");
+            return vm->None;
+        });
+        return mod;
+    }
+
+}