This commit is contained in:
blueloveTH 2024-09-22 21:12:31 +08:00
parent 4001f53e10
commit 275f958cfc
21 changed files with 71 additions and 113 deletions

View File

@ -1,17 +1,13 @@
cmake_minimum_required(VERSION 3.10)
project(numpy_bindings)
project(numpy)
# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Add pocketpy as a subdirectory
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../.." "${CMAKE_CURRENT_BINARY_DIR}/pocketpy")
# Include pybind11 and numpy
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include")
include_directories("${CMAKE_CURRENT_LIST_DIR}/../../include")
include_directories("${CMAKE_CURRENT_LIST_DIR}/include")
# Control xtensor warnings (OFF by default)
option(SHOW_XTENSOR_WARNINGS "Show warnings from xtensor" OFF)
@ -32,14 +28,17 @@ if(NOT SHOW_XTENSOR_WARNINGS)
endif()
# Add numpy source and test files
file (GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../src/numpy.cpp")
file (GLOB TESTS "${CMAKE_CURRENT_SOURCE_DIR}/test_numpy.cpp")
file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.cpp)
# Create numpy executables
add_executable(numpy_bindings ${TESTS} ${SOURCES})
# Create numpy dynamic library
add_library(${PROJECT_NAME} SHARED ${SOURCES})
# Set VS debugger working directory (if relevant)
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY CMAKE_CURRENT_LIST_DIR)
# Define PY_DYNAMIC_MODULE for numpy
target_compile_definitions(${PROJECT_NAME} PRIVATE PY_DYNAMIC_MODULE)
# Link numpy with pocketpy
target_link_libraries(${PROJECT_NAME} PRIVATE pocketpy)
target_link_libraries(
${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/../..//build/Release/pocketpy.lib
)

View File

@ -1,49 +1,6 @@
# numpy
# How to build
### How to run **numpy** module programs with **gsoc-2024-dev** [pybind11](https://github.com/pocketpy/gsoc-2024-dev/tree/main/pybind11)
1. Prepare the python code file with the numpy operations you want to run. \
\
For example : let's try out numpy [arange](https://numpy.org/doc/stable/reference/generated/numpy.arange.html) function in `test_numpy.py`
```py
import numpy_bindings as np
def test_arange(n):
a = np.arange(n)
print(a.sum())
test_arange(100)
```
2. Read the script and execute it in `test_numpy.cpp`.
```cpp
#include <pybind11/embed.h>
#include <fstream>
#include <sstream>
#include <string>
namespace py = pybind11;
using namespace pybind11;
int main() {
py::scoped_interpreter guard{};
std::ifstream file("test_numpy.py");
std::stringstream buffer;
buffer << file.rdbuf();
std::string script = buffer.str();
py::exec(script);
return 0;
}
```
3. Build the project at root to generate the executable at `build/gsoc2024`.
```sh
cmake -B build
cmake --build build
```
4. Now run the executable to get the output.
```sh
|base| gsoc-2024-dev ±|main ✗|→ build/gsoc2024
4950
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
```

View File

@ -2869,7 +2869,7 @@ void array_creation_registry(py::module_& m) {
}
PYBIND11_EMBEDDED_MODULE(numpy_bindings, m) {
PYBIND11_MODULE(numpy, m) {
m.doc() = "Python bindings for pkpy::numpy::ndarray using pybind11";
m.attr("bool_") = "bool";

View File

@ -3,8 +3,12 @@
// clang-format off
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
//define something for Windows (32-bit and 64-bit, this part is common)
#define PK_EXPORT __declspec(dllexport)
// define something for Windows (32-bit and 64-bit, this part is common)
#ifdef PY_DYNAMIC_MODULE
#define PK_EXPORT __declspec(dllimport)
#else
#define PK_EXPORT __declspec(dllexport)
#endif
#define PY_SYS_PLATFORM 0
#define PY_SYS_PLATFORM_STRING "win32"
#elif __EMSCRIPTEN__

View File

@ -14,7 +14,6 @@
// 4. stack balance guanrantee
// 5. stack effect of each opcode
// 6. py_TypeInfo
// 7. Direct assignment of py_NIL, py_True, py_False, py_None. They are slow.
typedef struct VM {
Frame* top_frame;

View File

@ -70,15 +70,6 @@ typedef bool (*py_CFunction)(int argc, py_StackRef argv) PY_RAISE PY_RETURN;
/// + `SINGLE_MODE`: for REPL or jupyter notebook execution.
enum py_CompileMode { EXEC_MODE, EVAL_MODE, SINGLE_MODE };
/// A shorthand for `True`.
PK_EXPORT extern py_GlobalRef py_True;
/// A shorthand for `False`.
PK_EXPORT extern py_GlobalRef py_False;
/// A shorthand for `None`.
PK_EXPORT extern py_GlobalRef py_None;
/// A shorthand for `nil`. `nil` is not a valid python object.
PK_EXPORT extern py_GlobalRef py_NIL;
/************* Global Setup *************/
/// Initialize pocketpy and the default VM.
@ -145,6 +136,15 @@ PK_EXPORT void py_newlocals(py_OutRef);
/************* Values Creation *************/
/// A shorthand for `True`.
PK_EXPORT py_GlobalRef py_True();
/// A shorthand for `False`.
PK_EXPORT py_GlobalRef py_False();
/// A shorthand for `None`.
PK_EXPORT py_GlobalRef py_None();
/// A shorthand for `nil`. `nil` is not a valid python object.
PK_EXPORT py_GlobalRef py_NIL();
/// Create an `int` object.
PK_EXPORT void py_newint(py_OutRef, py_i64);
/// Create a `float` object.

View File

@ -51,14 +51,14 @@ class none : public object {
PKBIND_TYPE_IMPL(object, none, tp_NoneType);
// note: none is global instance, so we use ref_t.
none() : object(py_None, ref_t{}) {}
none() : object(py_None(), ref_t{}) {}
};
class bool_ : public object {
PKBIND_TYPE_IMPL(object, bool_, tp_bool);
// same as none, bool is a singleton.
bool_(bool value) : object(value ? py_True : py_False, ref_t{}) {}
bool_(bool value) : object(value ? py_True() : py_False(), ref_t{}) {}
explicit operator bool () { return py_tobool(ptr()); }
};

View File

@ -22,7 +22,10 @@ int load_module_from_dll_desktop_only(const char* path) PY_RAISE PY_RETURN {
if(dll == NULL) return 0;
py_module_initialize_t f_init = (py_module_initialize_t)dlsym(dll, f_init_name);
#endif
if(f_init == NULL) return 0;
if(f_init == NULL) {
RuntimeError("%s() not found in '%s'", f_init_name, path);
return -1;
}
bool success = f_init();
if(!success) return -1;
return 1;

View File

@ -52,23 +52,23 @@ static void py_TypeInfo__ctor(py_TypeInfo* self,
};
self->module = module;
self->annotations = *py_NIL;
self->annotations = *py_NIL();
}
void VM__ctor(VM* self) {
self->top_frame = NULL;
ModuleDict__ctor(&self->modules, NULL, *py_NIL);
ModuleDict__ctor(&self->modules, NULL, *py_NIL());
TypeList__ctor(&self->types);
self->builtins = *py_NIL;
self->main = *py_NIL;
self->builtins = *py_NIL();
self->main = *py_NIL();
self->callbacks.importfile = pk_default_importfile;
self->callbacks.print = pk_default_print;
self->last_retval = *py_NIL;
self->curr_exception = *py_NIL;
self->last_retval = *py_NIL();
self->curr_exception = *py_NIL();
self->is_curr_exc_handled = false;
self->ctx = NULL;
@ -329,7 +329,7 @@ py_Type pk_newtype(const char* name,
if(base_ti && base_ti->is_sealed) {
c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name));
}
py_TypeInfo__ctor(ti, py_name(name), index, base, base_ti, module ? *module : *py_NIL);
py_TypeInfo__ctor(ti, py_name(name), index, base, base_ti, module ? *module : *py_NIL());
if(!dtor && base) dtor = base_ti->dtor;
ti->dtor = dtor;
ti->is_python = is_python;

View File

@ -106,7 +106,7 @@ static bool array2d_get(int argc, py_Ref argv) {
PY_CHECK_ARG_TYPE(1, tp_int);
PY_CHECK_ARG_TYPE(2, tp_int);
if(argc == 3) {
default_ = py_None;
default_ = py_None();
} else if(argc == 4) {
default_ = py_arg(3);
} else {

View File

@ -21,9 +21,9 @@ static bool json_dumps(int argc, py_Ref argv) {
void pk__add_module_json() {
py_Ref mod = py_newmodule("json");
py_setdict(mod, py_name("null"), py_None);
py_setdict(mod, py_name("true"), py_True);
py_setdict(mod, py_name("false"), py_False);
py_setdict(mod, py_name("null"), py_None());
py_setdict(mod, py_name("true"), py_True());
py_setdict(mod, py_name("false"), py_False());
py_bindfunc(mod, "loads", json_loads);
py_bindfunc(mod, "dumps", json_dumps);

View File

@ -162,7 +162,7 @@ void CodeObject__dtor(CodeObject* self) {
void Function__ctor(Function* self, FuncDecl_ decl, py_TValue* module) {
PK_INCREF(decl);
self->decl = decl;
self->module = module ? *module : *py_NIL;
self->module = module ? *module : *py_NIL();
self->clazz = NULL;
self->closure = NULL;
self->cfunc = NULL;

View File

@ -11,13 +11,9 @@
VM* pk_current_vm;
py_GlobalRef py_True;
py_GlobalRef py_False;
py_GlobalRef py_None;
py_GlobalRef py_NIL;
static VM pk_default_vm;
static VM* pk_all_vm[16];
static py_TValue _True, _False, _None, _NIL;
void py_initialize() {
if(pk_current_vm){
@ -30,18 +26,18 @@ void py_initialize() {
pk_current_vm = pk_all_vm[0] = &pk_default_vm;
// initialize some convenient references
static py_TValue _True, _False, _None, _NIL;
py_newbool(&_True, true);
py_newbool(&_False, false);
py_newnone(&_None);
py_newnil(&_NIL);
py_True = &_True;
py_False = &_False;
py_None = &_None;
py_NIL = &_NIL;
VM__ctor(&pk_default_vm);
}
py_GlobalRef py_True() { return &_True; }
py_GlobalRef py_False() { return &_False; }
py_GlobalRef py_None() { return &_None; }
py_GlobalRef py_NIL() { return &_NIL; }
void py_finalize() {
for(int i = 1; i < 16; i++) {
VM* vm = pk_all_vm[i];
@ -169,7 +165,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
py_Ref cls_var = py_tpfindmagic(py_totype(self), name);
if(cls_var) {
self[0] = *cls_var;
self[1] = *py_NIL;
self[1] = *py_NIL();
return true;
}
return false;
@ -197,7 +193,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
}
case tp_staticmethod:
self[0] = *py_getslot(cls_var, 0);
self[1] = *py_NIL;
self[1] = *py_NIL();
break;
case tp_classmethod:
self[0] = *py_getslot(cls_var, 0);

View File

@ -676,11 +676,11 @@ py_TValue pk_builtins__register() {
// some patches
py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
*py_tpgetmagic(tp_NoneType, __hash__) = *py_None;
*py_tpgetmagic(tp_NoneType, __hash__) = *py_None();
py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__);
*py_tpgetmagic(tp_ellipsis, __hash__) = *py_None;
*py_tpgetmagic(tp_ellipsis, __hash__) = *py_None();
py_bindmagic(tp_NotImplementedType, __repr__, NotImplementedType__repr__);
*py_tpgetmagic(tp_NotImplementedType, __hash__) = *py_None;
*py_tpgetmagic(tp_NotImplementedType, __hash__) = *py_None();
return *builtins;
}

View File

@ -389,7 +389,7 @@ static bool dict_update(int argc, py_Ref argv) {
static bool dict_get(int argc, py_Ref argv) {
Dict* self = py_touserdata(argv);
if(argc > 3) return TypeError("get() takes at most 3 arguments (%d given)", argc);
py_Ref default_val = argc == 3 ? py_arg(2) : py_None;
py_Ref default_val = argc == 3 ? py_arg(2) : py_None();
DictEntry* entry;
if(!Dict__try_get(self, py_arg(1), &entry)) return false;
*py_retval() = entry ? entry->val : *default_val;
@ -399,7 +399,7 @@ static bool dict_get(int argc, py_Ref argv) {
static bool dict_pop(int argc, py_Ref argv) {
Dict* self = py_touserdata(argv);
if(argc < 2 || argc > 3) return TypeError("pop() takes 1 or 2 arguments (%d given)", argc - 1);
py_Ref default_val = argc == 3 ? py_arg(2) : py_None;
py_Ref default_val = argc == 3 ? py_arg(2) : py_None();
int res = Dict__pop(self, py_arg(1));
if(res == -1) return false;
if(res == 0) { py_assign(py_retval(), default_val); }
@ -482,7 +482,7 @@ py_Type pk_dict__register() {
py_bindmethod(type, "keys", dict_keys);
py_bindmethod(type, "values", dict_values);
py_setdict(py_tpobject(type), __hash__, py_None);
py_setdict(py_tpobject(type), __hash__, py_None());
return type;
}

View File

@ -134,8 +134,8 @@ bool py_matchexc(py_Type type) {
void py_clearexc(py_StackRef p0) {
VM* vm = pk_current_vm;
vm->last_retval = *py_NIL;
vm->curr_exception = *py_NIL;
vm->last_retval = *py_NIL();
vm->curr_exception = *py_NIL();
vm->is_curr_exc_handled = false;
/* Don't clear this, because StopIteration() may corrupt the class defination */

View File

@ -444,6 +444,6 @@ py_Type pk_list__register() {
py_bind(py_tpobject(type), "sort(self, key=None, reverse=False)", list_sort);
py_setdict(py_tpobject(type), __hash__, py_None);
py_setdict(py_tpobject(type), __hash__, py_None());
return type;
}

View File

@ -8,7 +8,7 @@ static bool property__new__(int argc, py_Ref argv) {
py_newobject(py_retval(), tp_property, 2, 0);
if(argc == 1 + 1) {
py_setslot(py_retval(), 0, py_arg(1));
py_setslot(py_retval(), 1, py_None);
py_setslot(py_retval(), 1, py_None());
} else if(argc == 1 + 2) {
py_setslot(py_retval(), 0, py_arg(1));
py_setslot(py_retval(), 1, py_arg(2));

View File

@ -100,7 +100,7 @@ py_Type pk_slice__register() {
py_bindmagic(type, __eq__, slice__eq__);
py_bindmagic(type, __ne__, slice__ne__);
py_setdict(py_tpobject(type), __hash__, py_None);
py_setdict(py_tpobject(type), __hash__, py_None());
py_bindproperty(type, "start", slice_start, NULL);
py_bindproperty(type, "stop", slice_stop, NULL);

View File

@ -30,7 +30,7 @@ void py_setdict(py_Ref self, py_Name name, py_Ref val) {
}
py_ItemRef py_emplacedict(py_Ref self, py_Name name){
py_setdict(self, name, py_NIL);
py_setdict(self, name, py_NIL());
return py_getdict(self, name);
}

View File

@ -67,7 +67,7 @@ void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFu
if(setter) {
py_newnativefunc(py_getslot(&tmp, 1), setter);
} else {
py_setslot(&tmp, 1, py_None);
py_setslot(&tmp, 1, py_None());
}
py_setdict(py_tpobject(type), py_name(name), &tmp);
}