diff --git a/.gitignore b/.gitignore index d33a5917..c59d8f10 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,5 @@ pocketpy.lib APPS build -pocketpy.dSYM \ No newline at end of file +pocketpy.dSYM +main diff --git a/CMakeLists.txt b/CMakeLists.txt index cdffae6c..61f8c4b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,31 +26,25 @@ else() endif() endif() -option(PK_EXPORT_C_API "Export C API" ON) +option(PK_EXPORT_CXX_API "Export C++ API" OFF) include_directories(${CMAKE_CURRENT_LIST_DIR}/include) -if(PK_EXPORT_C_API) - message(STATUS "Exporting C API") - include_directories(${CMAKE_CURRENT_LIST_DIR}/c_bindings) - set(PK_LIB_CPP ${CMAKE_CURRENT_LIST_DIR}/c_bindings/pocketpy_c.cpp) -else() - set(PK_LIB_CPP ${CMAKE_CURRENT_LIST_DIR}/src2/lib.cpp) -endif() - aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src POCKETPY_SRC) option(PK_BUILD_SHARED_LIB "Build shared library" OFF) option(PK_BUILD_STATIC_LIB "Build static library" OFF) -set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +if (PK_EXPORT_CXX_API) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() if(PK_BUILD_SHARED_LIB) - add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC} ${PK_LIB_CPP}) + add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC}) elseif(PK_BUILD_STATIC_LIB) - add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC} ${PK_LIB_CPP}) + add_library(${PROJECT_NAME} STATIC ${POCKETPY_SRC}) else() - add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC} ${PK_LIB_CPP}) + add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC}) set(PROJECT_EXE_NAME main) add_executable(${PROJECT_EXE_NAME} src2/main.cpp) target_link_libraries(${PROJECT_EXE_NAME} ${PROJECT_NAME}) diff --git a/amalgamate.py b/amalgamate.py index 9cb58f25..96e5e62f 100644 --- a/amalgamate.py +++ b/amalgamate.py @@ -10,7 +10,7 @@ pipeline = [ ["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"], - ["pocketpy.h"] + ["pocketpy.h", "pocketpy_c.h"] ] copied = set() @@ -88,28 +88,12 @@ if sys.platform in ['linux', 'darwin']: print("amalgamated/pocketpy.h") -content = [] -for i in ["include/pocketpy/export.h", "c_bindings/pocketpy_c.h", "c_bindings/pocketpy_c.cpp"]: - with open(i, "rt", encoding='utf-8') as g: - content.append(g.read()) - -with open("amalgamated/pocketpy.cpp", "wt", encoding='utf-8') as f: - content = '\n\n'.join(content) - content = content.replace('#include "pocketpy/export.h"', '') - content = content.replace('#include "pocketpy_c.h"', '') - f.write(content) - - shutil.copy("amalgamated/pocketpy.h", "plugins/flutter/src/pocketpy.h") -shutil.copy("amalgamated/pocketpy.cpp", "plugins/flutter/src/pocketpy.cpp") - shutil.copy("amalgamated/pocketpy.h", "plugins/macos/pocketpy/pocketpy.h") -shutil.copy("amalgamated/pocketpy.cpp", "plugins/macos/pocketpy/pocketpy.cpp") # unity plugin unity_ios_root = 'plugins/unity/PocketPyUnityPlugin/Assets/PocketPython/Plugins/iOS' if os.path.exists(unity_ios_root): shutil.copy("amalgamated/pocketpy.h", unity_ios_root) - shutil.copy("amalgamated/pocketpy.cpp", unity_ios_root) diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index 4d83561b..c0b6fab6 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -149,26 +149,4 @@ 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 -#define WIN32_LEAN_AND_MEAN -#endif - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include - -#elif __EMSCRIPTEN__ - -#include - -#elif __unix__ - -#include - -#endif \ No newline at end of file +} // namespace pkpy \ No newline at end of file diff --git a/include/pocketpy/export.h b/include/pocketpy/export.h index 2877b7ef..de3ab192 100644 --- a/include/pocketpy/export.h +++ b/include/pocketpy/export.h @@ -9,11 +9,27 @@ #define PK_EXPORT __attribute__((visibility("default"))) #endif -#define PK_INLINE_EXPORT PK_EXPORT inline - #endif -#ifdef PK_SHARED_MODULE -#undef PK_INLINE_EXPORT -#define PK_INLINE_EXPORT inline + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN #endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include + +#elif __EMSCRIPTEN__ + +#include + +#elif __unix__ + +#include + +#endif \ No newline at end of file diff --git a/include/pocketpy/memory.h b/include/pocketpy/memory.h index 51d54d17..54a1a905 100644 --- a/include/pocketpy/memory.h +++ b/include/pocketpy/memory.h @@ -246,8 +246,8 @@ struct MemoryPool{ } }; -PK_EXPORT inline MemoryPool<64> pool64; -PK_EXPORT inline MemoryPool<128> pool128; +inline MemoryPool<64> pool64; +inline MemoryPool<128> pool128; template struct shared_ptr { diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 1f4ca685..8674d7f0 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -94,83 +94,4 @@ void add_module_dis(VM* vm); void add_module_traceback(VM* vm); void add_module_gc(VM* vm); -} // namespace pkpy - -/*************************GLOBAL NAMESPACE*************************/ -extern "C" { - PK_INLINE_EXPORT - void pkpy_free(void* p){ - free(p); - } - - PK_INLINE_EXPORT - void pkpy_vm_exec(pkpy::VM* vm, const char* source){ - vm->exec(source, "main.py", pkpy::EXEC_MODE); - } - - 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; - else{ - mod = vm->_modules.try_get(module); - if(mod == nullptr) return; - } - vm->exec(source, filename, (pkpy::CompileMode)mode, mod); - } - - 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); - *res = code->serialize(vm).c_str_dup(); - *ok = true; - }catch(pkpy::Exception& e){ - *ok = false; - *res = e.summary().c_str_dup(); - }catch(std::exception& e){ - *ok = false; - *res = strdup(e.what()); - }catch(...){ - *ok = false; - *res = strdup("unknown error"); - } - } - - PK_INLINE_EXPORT - pkpy::REPL* pkpy_new_repl(pkpy::VM* vm){ - pkpy::REPL* p = new pkpy::REPL(vm); - return p; - } - - PK_INLINE_EXPORT - bool pkpy_repl_input(pkpy::REPL* r, const char* line){ - return r->input(line); - } - - PK_INLINE_EXPORT - void pkpy_vm_add_module(pkpy::VM* vm, const char* name, const char* source){ - vm->_lazy_modules[name] = source; - } - - PK_INLINE_EXPORT - pkpy::VM* pkpy_new_vm(bool enable_os=true){ - pkpy::VM* p = new pkpy::VM(enable_os); - return p; - } - - PK_INLINE_EXPORT - void pkpy_delete_vm(pkpy::VM* vm){ - delete vm; - } - - PK_INLINE_EXPORT - void pkpy_delete_repl(pkpy::REPL* repl){ - delete repl; - } - - PK_INLINE_EXPORT - void pkpy_vm_gc_on_delete(pkpy::VM* vm, void (*f)(pkpy::VM *, pkpy::PyObject *)){ - vm->heap._gc_on_delete = f; - } -} +} // namespace pkpy \ No newline at end of file diff --git a/c_bindings/pocketpy_c.h b/include/pocketpy/pocketpy_c.h similarity index 84% rename from c_bindings/pocketpy_c.h rename to include/pocketpy/pocketpy_c.h index 697364b2..3c725d4c 100644 --- a/c_bindings/pocketpy_c.h +++ b/include/pocketpy/pocketpy_c.h @@ -8,7 +8,7 @@ extern "C" { #include #include -#include "pocketpy/export.h" +#include "export.h" typedef struct pkpy_vm_handle pkpy_vm; @@ -119,4 +119,41 @@ PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source); } #endif + +/*************************GLOBAL NAMESPACE*************************/ +extern "C" { + PK_EXPORT + void pkpy_free(void* p); + + PK_EXPORT + void pkpy_vm_exec(void* vm, const char* source); + + PK_EXPORT + void pkpy_vm_exec_2(void* vm, const char* source, const char* filename, int mode, const char* module); + + PK_EXPORT + void pkpy_vm_compile(void* vm, const char* source, const char* filename, int mode, bool* ok, char** res); + + PK_EXPORT + void* pkpy_new_repl(void* vm); + + PK_EXPORT + bool pkpy_repl_input(void* r, const char* line); + + PK_EXPORT + void pkpy_vm_add_module(void* vm, const char* name, const char* source); + + PK_EXPORT + void* pkpy_new_vm(bool enable_os=true); + + PK_EXPORT + void pkpy_delete_vm(void* vm); + + PK_EXPORT + void pkpy_delete_repl(void* repl); +} + + + + #endif diff --git a/include/pocketpy/repl.h b/include/pocketpy/repl.h index 399efa14..4c02083a 100644 --- a/include/pocketpy/repl.h +++ b/include/pocketpy/repl.h @@ -4,9 +4,7 @@ #include "vm.h" namespace pkpy{ - -std::string platform_getline(bool* eof=nullptr); - + class REPL { protected: int need_more_lines = 0; diff --git a/include/pocketpy_c.h b/include/pocketpy_c.h new file mode 100644 index 00000000..9e662f8e --- /dev/null +++ b/include/pocketpy_c.h @@ -0,0 +1,3 @@ +#pragma once + +#include "pocketpy/pocketpy_c.h" \ No newline at end of file diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index b9d368a9..90bcb94f 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -11,7 +11,29 @@ 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((LPCSTR)p.c_str()); + HMODULE handle = LoadLibraryA((LPCSTR)"test.dll"); + // get last error + // Get the last error code + SetErrorMode(SEM_FAILCRITICALERRORS); + DWORD errorCode = GetLastError(); + + // Convert the error code to text + LPSTR errorMessage = nullptr; + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&errorMessage, + 0, + nullptr + ); + + // Print the error message to stdout + printf("%lu: %s\n", errorCode, errorMessage); + + // Free the message buffer + LocalFree(errorMessage); if(!handle) return nullptr; return (dylib_entry_t)GetProcAddress(handle, "platform_module__init__"); } diff --git a/c_bindings/pocketpy_c.cpp b/src/pocketpy_c.cpp similarity index 89% rename from c_bindings/pocketpy_c.cpp rename to src/pocketpy_c.cpp index c0f821e0..c9d23d78 100644 --- a/c_bindings/pocketpy_c.cpp +++ b/src/pocketpy_c.cpp @@ -552,3 +552,67 @@ bool pkpy_eval(pkpy_vm* vm_handle, const char* code) { ERRHANDLER_CLOSE return true; } + +/*****************************************************************/ + + void pkpy_free(void* p){ + free(p); + } + + void pkpy_vm_exec(void* vm, const char* source){ + ((VM*)vm)->exec(source, "main.py", EXEC_MODE); + } + + void pkpy_vm_exec_2(void* vm_, const char* source, const char* filename, int mode, const char* module){ + VM* vm = (VM*)vm_; + PyObject* mod; + if(module == nullptr) mod = vm->_main; + else{ + mod = vm->_modules.try_get(module); + if(mod == nullptr) return; + } + vm->exec(source, filename, (CompileMode)mode, mod); + } + + void pkpy_vm_compile(void* vm_, const char* source, const char* filename, int mode, bool* ok, char** res){ + VM* vm = (VM*)vm_; + try{ + CodeObject_ code = vm->compile(source, filename, (CompileMode)mode); + *res = code->serialize(vm).c_str_dup(); + *ok = true; + }catch(Exception& e){ + *ok = false; + *res = e.summary().c_str_dup(); + }catch(std::exception& e){ + *ok = false; + *res = strdup(e.what()); + }catch(...){ + *ok = false; + *res = strdup("unknown error"); + } + } + + void* pkpy_new_repl(void* vm){ + return new REPL((VM*)vm); + } + + bool pkpy_repl_input(void* r, const char* line){ + return ((REPL*)r)->input(line); + } + + void pkpy_vm_add_module(void* vm, const char* name, const char* source){ + ((VM*)vm)->_lazy_modules[name] = source; + } + + void* pkpy_new_vm(bool enable_os){ + void* p = new VM(enable_os); + return p; + } + + void pkpy_delete_vm(void* vm){ + delete (VM*)vm; + } + + void pkpy_delete_repl(void* repl){ + delete (REPL*)repl; + } \ No newline at end of file diff --git a/src/repl.cpp b/src/repl.cpp index e82184c0..815f98c3 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -1,39 +1,6 @@ #include "pocketpy/repl.h" namespace pkpy { - -#ifdef _WIN32 - -std::string platform_getline(bool* eof){ - HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); - std::wstringstream wss; - WCHAR buf; - DWORD read; - while (ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') { - if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z - wss << buf; - } - std::wstring wideInput = wss.str(); - int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL); - std::string output; - output.resize(length); - WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL); - if(!output.empty() && output.back() == '\r') output.pop_back(); - return output; -} - -#else - -std::string platform_getline(bool* eof){ - std::string line; - if(!std::getline(std::cin, line)){ - if(eof) *eof = true; - } - return line; -} - -#endif - REPL::REPL(VM* vm) : vm(vm){ vm->_stdout(vm, "pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") "); vm->_stdout(vm, fmt("[", sizeof(void*)*8, " bit]" "\n")); diff --git a/src2/lib.cpp b/src2/lib.cpp deleted file mode 100644 index a11446e0..00000000 --- a/src2/lib.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pocketpy.h" \ No newline at end of file diff --git a/src2/main.cpp b/src2/main.cpp index 1e3b8cad..b9ff855d 100644 --- a/src2/main.cpp +++ b/src2/main.cpp @@ -1,33 +1,72 @@ #include #include +#include -#include "pocketpy.h" +#include "pocketpy_c.h" -std::string f_input(){ - return pkpy::platform_getline(); + +#ifdef _WIN32 + +void pkpy_platform_getline(char* buffer, int size, bool* eof){ + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + std::wstringstream wss; + WCHAR buf; + DWORD read; + while (ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') { + if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z + wss << buf; + } + std::wstring wideInput = wss.str(); + int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL); + std::string output; + output.resize(length); + WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL); + if(!output.empty() && output.back() == '\r') output.pop_back(); + + size = std::min(size-1, output.size()); + for(int i=0; i(size-1, output.size()); + for(int i=0; ibuiltins, "input() -> str", &f_input); + void* vm = pkpy_new_vm(); + // pkpy::_bind(vm, vm->builtins, "input() -> str", &f_input); if(argc == 1){ - pkpy::REPL* repl = pkpy_new_repl(vm); + void* repl = pkpy_new_repl(vm); bool need_more_lines = false; while(true){ - vm->_stdout(vm, need_more_lines ? "... " : ">>> "); + std::cout << (need_more_lines ? "... " : ">>> "); bool eof = false; - std::string line = pkpy::platform_getline(&eof); + pkpy_platform_getline(buffer, 1024, &eof); if(eof) break; - need_more_lines = pkpy_repl_input(repl, line.c_str()); + need_more_lines = pkpy_repl_input(repl, buffer); } pkpy_delete_vm(vm); return 0; @@ -54,10 +93,10 @@ int main(int argc, char** argv){ // set parent path as cwd std::filesystem::current_path(filepath.parent_path()); - pkpy::PyObject* ret = nullptr; - ret = vm->exec(src.c_str(), filepath.filename().string(), pkpy::EXEC_MODE); + pkpy_vm_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL); pkpy_delete_vm(vm); - return ret != nullptr ? 0 : 1; + // return ret != nullptr ? 0 : 1; + return 0; } __HELP: diff --git a/tests/dylib/test.cpp b/tests/dylib/test.cpp index 29d2ce4c..1bda2734 100644 --- a/tests/dylib/test.cpp +++ b/tests/dylib/test.cpp @@ -1,4 +1,3 @@ -#define PK_SHARED_MODULE #include "pocketpy.h" using namespace pkpy; @@ -15,15 +14,4 @@ extern "C" { }); return mod; } - -#if _WIN32 -BOOL WINAPI DllMain( - HINSTANCE hinstDLL, // handle to DLL module - DWORD fdwReason, // reason for calling function - LPVOID lpvReserved ) // reserved -{ - return TRUE; // Successful DLL_PROCESS_ATTACH. -} -#endif - } \ No newline at end of file