diff --git a/cpp/cmake/TargetSettings.cmake b/cpp/cmake/TargetSettings.cmake index 47573b12..9a2ebfab 100644 --- a/cpp/cmake/TargetSettings.cmake +++ b/cpp/cmake/TargetSettings.cmake @@ -138,7 +138,8 @@ set(WEDPR_TRANSPORT_SDK_TARGET wedpr-transport-sdk) # ==== the swig wrapper ===== set(WEDPR_PYTHON_TRANSPORT "wedpr_python_transport") -set(WEDPR_PYTHON_TRANSPORT_DIR ${PROJECT_BINARY_DIR}/python/${WEDPR_PYTHON_TRANSPORT}) +set(WEDPR_PYTHON_TRANSPORT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/python/generated/${WEDPR_PYTHON_TRANSPORT}) +set(WEDPR_PYTHON_TRANSPORT_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/wedpr-transport/sdk-wrapper/python/bindings/libs) set(WEDPR_JAVA_TRANSPORT "wedpr_java_transport_jni") set(WEDPR_JAVA_TRANSPORT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/java/generated/${WEDPR_JAVA_TRANSPORT}) diff --git a/cpp/cmake/python.cmake b/cpp/cmake/python.cmake index 8adbf35d..e941adfb 100644 --- a/cpp/cmake/python.cmake +++ b/cpp/cmake/python.cmake @@ -19,7 +19,13 @@ if(UNIX AND NOT APPLE) endif() # Find Python 3 -find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module) +find_package(Python REQUIRED COMPONENTS Interpreter Development) +message("Python_FOUND:${Python_FOUND}") +message("Python_VERSION:${Python_VERSION}") +message("Python_Development_FOUND:${Python_Development_FOUND}") +message("Python_LIBRARIES:${Python_LIBRARIES}") +message("Python_INCLUDE_DIRS:${Python_INCLUDE_DIRS}") + list(APPEND CMAKE_SWIG_FLAGS "-py3" "-DPY3") function(search_python_module) diff --git a/cpp/wedpr-transport/sdk-wrapper/python/CMakeLists.txt b/cpp/wedpr-transport/sdk-wrapper/python/CMakeLists.txt index f925ec3a..d787ea89 100644 --- a/cpp/wedpr-transport/sdk-wrapper/python/CMakeLists.txt +++ b/cpp/wedpr-transport/sdk-wrapper/python/CMakeLists.txt @@ -1,54 +1,49 @@ -file(GLOB_RECURSE SRCS *.i) -set_source_files_properties(${SRCS} PROPERTIES CPLUSPLUS ON) +option(AUTO_GENERATE "Auto generate the targes" OFF) +if(AUTO_GENERATE) + file(GLOB_RECURSE SRCS *.i) + set_source_files_properties(${SRCS} PROPERTIES CPLUSPLUS ON) -swig_add_library( - ${WEDPR_PYTHON_TRANSPORT} - TYPE MODULE - LANGUAGE python - OUTPUT_DIR ${WEDPR_PYTHON_TRANSPORT_DIR} - SOURCES ${SRCS} -) - -message("#### Python3_INCLUDE_DIRS: ${Python3_INCLUDE_DIRS}") -target_include_directories( - ${WEDPR_PYTHON_TRANSPORT} - PRIVATE - ../include - ${Python3_INCLUDE_DIRS} - ) -set_property(TARGET ${WEDPR_PYTHON_TRANSPORT} PROPERTY SWIG_USE_TARGET_INCLUDE_DIRECTORIES ON) + file(MAKE_DIRECTORY ${WEDPR_PYTHON_TRANSPORT_DIR}) + file(MAKE_DIRECTORY ${WEDPR_PYTHON_TRANSPORT_LIB_DIR}) + + swig_add_library( + ${WEDPR_PYTHON_TRANSPORT} + TYPE MODULE + LANGUAGE python + OUTPUT_DIR ${WEDPR_PYTHON_TRANSPORT_DIR} + SOURCES ${SRCS} + ) + set_property(TARGET ${WEDPR_PYTHON_TRANSPORT} PROPERTY SWIG_USE_TARGET_INCLUDE_DIRECTORIES ON) +else() + file(GLOB_RECURSE SRCS src/*.cxx) + add_library(${WEDPR_PYTHON_TRANSPORT} SHARED ${SRCS}) +endif() + +target_include_directories(${WEDPR_PYTHON_TRANSPORT} PRIVATE ${Python_INCLUDE_DIRS}) # note: macOS is APPLE and also UNIX ! if(APPLE) set_property(TARGET ${WEDPR_PYTHON_TRANSPORT} APPEND PROPERTY LINK_FLAGS "-flat_namespace -undefined suppress" ) - set_target_properties(${WEDPR_PYTHON_TRANSPORT} PROPERTIES - SUFFIX ".so" - INSTALL_RPATH "@loader_path;@loader_path/../../${WEDPR_PYTHON_TRANSPORT}/.libs" + set_target_properties(${WEDPR_PYTHON_TRANSPORT} PROPERTIES + INSTALL_RPATH "@loader_path;@loader_path/../../${WEDPR_PYTHON_TRANSPORT}/.libs" ) elseif(UNIX) set_target_properties(${WEDPR_PYTHON_TRANSPORT} PROPERTIES INSTALL_RPATH "$ORIGIN:$ORIGIN/../../${WEDPR_PYTHON_TRANSPORT}/.libs" ) endif() -target_link_libraries(${WEDPR_PYTHON_TRANSPORT} PRIVATE ${WEDPR_TRANSPORT_SDK_TARGET}) - -SET(LIBRARY_OUTPUT_PATH ${WEDPR_PYTHON_TRANSPORT_DIR}/) - # Variable PYTHON_LIBRARIES can contains keyword `optimized` # which won't be interpreted inside a generator expression. # i.e. we can't use: $<$:${PYTHON_LIBRARIES}> # see: https://cmake.org/cmake/help/git-stage/command/target_link_libraries.html#command:target_link_libraries if(MSVC) target_link_libraries(${WEDPR_PYTHON_TRANSPORT} PRIVATE ${Python3_LIBRARIES}) +else() + target_link_libraries(${WEDPR_PYTHON_TRANSPORT} PRIVATE ${WEDPR_TRANSPORT_SDK_TARGET} ${Python_LIBRARIES}) endif() - -# Configure setup.py and copy to output directory -file(GENERATE OUTPUT ${WEDPR_PYTHON_TRANSPORT_DIR}/__init__.py CONTENT "__version__ = \"${PYTHON_TOOLKIT_VERSION}\"\n") -set(SETUP_PY_IN ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in) -set(SETUP_PY_OUT ${WEDPR_PYTHON_TRANSPORT_DIR}/setup.py) -configure_file(${SETUP_PY_IN} ${SETUP_PY_OUT}) +SET(LIBRARY_OUTPUT_PATH ${WEDPR_PYTHON_TRANSPORT_LIB_DIR}) message(STATUS "CMAKE_INSTALL_INCLUDEDIR => ${CMAKE_INSTALL_INCLUDEDIR}") message(STATUS "CMAKE_CURRENT_SOURCE_DIR => ${CMAKE_CURRENT_SOURCE_DIR}") \ No newline at end of file diff --git a/cpp/wedpr-transport/sdk-wrapper/python/bindings/setup.py b/cpp/wedpr-transport/sdk-wrapper/python/bindings/setup.py new file mode 100644 index 00000000..a5ca07ca --- /dev/null +++ b/cpp/wedpr-transport/sdk-wrapper/python/bindings/setup.py @@ -0,0 +1,62 @@ +import sys + +from setuptools import find_packages, setup +from setuptools.command.bdist_egg import bdist_egg + + +class bdist_egg_disabled(bdist_egg): + """Disabled version of bdist_egg + + Prevents setup.py install from performing setuptools' default easy_install, + which it should never ever do. + """ + + def run(self): + sys.exit( + "Aborting implicit building of eggs. Use `pip install .` to install from source." + ) + + +setup_args = dict( + name='wedpr-python-gateway-sdk', + packages=find_packages(), + version="1.0.0-rc1", + description="wedpr-python-gateway-sdk: The gateway sdk for WeDPR", + long_description_content_type="text/markdown", + author="Jupyter Development Team", + author_email="wedpr@webank.com", + url="https://github.com/WeBankBlockchain/WeDPR-Component", + license="Apache-2.0", + platforms="Linux, Mac OS X", + keywords=['Interactive', 'Interpreter', 'Shell', 'Web'], + python_requires=">=3.8", + include_package_data=True, + classifiers=[ + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: Apache License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + ], +) + +setup_args['cmdclass'] = { + 'bdist_egg': bdist_egg if 'bdist_egg' in sys.argv else bdist_egg_disabled, +} + +setup_args['install_requires'] = install_requires = [] +with open('requirements.txt') as f: + for line in f.readlines(): + req = line.strip() + if not req or req.startswith(('-e', '#')): + continue + install_requires.append(req) + + +def main(): + setup(**setup_args) + + +if __name__ == '__main__': + main() diff --git a/cpp/wedpr-transport/sdk-wrapper/python/bindings/transport/__init__.py b/cpp/wedpr-transport/sdk-wrapper/python/bindings/transport/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cpp/wedpr-transport/sdk-wrapper/python/bindings/utils/__init__.py b/cpp/wedpr-transport/sdk-wrapper/python/bindings/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cpp/wedpr-transport/sdk-wrapper/python/bindings/utils/lib_loader.py b/cpp/wedpr-transport/sdk-wrapper/python/bindings/utils/lib_loader.py new file mode 100644 index 00000000..dbc9a78b --- /dev/null +++ b/cpp/wedpr-transport/sdk-wrapper/python/bindings/utils/lib_loader.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- + +import platform +import os +from enum import Enum +import sys +import ctypes + + +class OSType(Enum): + MACOS_X64 = 1 + MACOS_ARM64 = 2 + WINDOWS = 3 + LINUX_X64 = 4 + LINUX_ARM64 = 5 + + +class ArchType(Enum): + ARM64 = 1 + X86_64 = 2 + + +class LibLoader: + # the library information + TRANSPORT_LIB_PATH = "libs" + TRANSPORT_LIB_NAME = "wedpr_python_transport" + LIB_PREFIX = "lib" + MACOS_LIB_POSTFIX = "dylib" + WINDOWS_LIB_POSTFIX = "dll" + LINUX_LIB_PORSTFIX = "so" + # the OS name + MACOS_OS = "darwin" + WINDOWS_OS = "windows" + LINUX_OS = "linux" + + AARCH64 = "aarch64" + ARM64 = "arm64" + X86_64 = "x86_64" + + @staticmethod + def get_arch_type(): + arch_type = platform.machine().lower() + if LibLoader.AARCH64 in arch_type or LibLoader.ARM64 in arch_type: + return ArchType.ARM64 + if LibLoader.X86_64 in arch_type: + return ArchType.X86_64 + raise Exception(f"Unsupported arch type: {arch_type}") + + @staticmethod + def get_os_type(): + os_type = platform.system().lower() + arch_type = LibLoader.get_arch_type() + if LibLoader.MACOS_OS in os_type: + if arch_type == ArchType.ARM64: + return OSType.MACOS_ARM64 + else: + return OSType.MACOS_X64 + if LibLoader.LINUX_OS in os_type: + if arch_type == ArchType.ARM64: + return OSType.LINUX_ARM64 + else: + return OSType.LINUX_X64 + if LibLoader.WINDOWS_OS in os_type: + return OSType.WINDOWS + raise Exception(f"Unsupported os {os_type}, arch: {arch_type}") + + @staticmethod + def get_lib_name(): + os_type = LibLoader.get_os_type() + if os_type == OSType.WINDOWS: + return "{}{}.{}".format(LibLoader.LIB_PREFIX, LibLoader.TRANSPORT_LIB_NAME, LibLoader.WINDOWS_LIB_POSTFIX) + if os_type == OSType.MACOS_ARM64: + return "{}{}-arm64.{}".format(LibLoader.LIB_PREFIX, LibLoader.TRANSPORT_LIB_NAME, LibLoader.MACOS_LIB_POSTFIX) + if os_type == OSType.MACOS_X64: + return "{}{}.{}".format(LibLoader.LIB_PREFIX, LibLoader.TRANSPORT_LIB_NAME, LibLoader.MACOS_LIB_POSTFIX) + if os_type == OSType.LINUX_ARM64: + return "{}{}.{}-arm64".format(LibLoader.LIB_PREFIX, LibLoader.TRANSPORT_LIB_NAME, LibLoader.LINUX_LIB_PORSTFIX) + if os_type == OSType.LINUX_X64: + return "{}{}.{}".format(LibLoader.LIB_PREFIX, LibLoader.TRANSPORT_LIB_NAME, LibLoader.LINUX_LIB_PORSTFIX) + raise Exception( + f"get_lib_name failed for not support the os_type: {os_type}") + + @staticmethod + def load_lib(): + lib_path = os.path.join( + LibLoader.TRANSPORT_LIB_PATH, LibLoader.get_lib_name()) + print(f"#### lib_path: {lib_path}") + lib = ctypes.cdll.LoadLibrary(lib_path) + return lib diff --git a/cpp/wedpr-transport/sdk-wrapper/python/bindings/utils/tests/test_lib_loader.py b/cpp/wedpr-transport/sdk-wrapper/python/bindings/utils/tests/test_lib_loader.py new file mode 100644 index 00000000..2f287a85 --- /dev/null +++ b/cpp/wedpr-transport/sdk-wrapper/python/bindings/utils/tests/test_lib_loader.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +import unittest + + +class TestLibLoader(unittest.TestCase): + def test_load_lib(self): + from utils.lib_loader import LibLoader + _wedpr_python_transport = LibLoader.load_lib() + + +if __name__ == '__main__': + unittest.main() diff --git a/cpp/wedpr-transport/sdk-wrapper/python/setup.py.in b/cpp/wedpr-transport/sdk-wrapper/python/setup.py.in deleted file mode 100644 index b2ec003f..00000000 --- a/cpp/wedpr-transport/sdk-wrapper/python/setup.py.in +++ /dev/null @@ -1,35 +0,0 @@ -import setuptools.command.install -import shutil -from distutils.sysconfig import get_python_lib - - -class CompiledLibInstall(setuptools.command.install.install): - """ - Specialized install to install to python libs - """ - - def run(self): - """ - Run method called by setup - :return: - """ - # Get filenames from CMake variable - filenames = '${PYTHON_INSTALL_FILES}'.split(';') - - # Directory to install to - install_dir = get_python_lib() - - # Install files - [shutil.copy(filename, install_dir) for filename in filenames] - - -if __name__ == '__main__': - setuptools.setup( - name='wedpr-python-transport', - version='1.0.0-rc1', - packages=['wedpr-python-transport'], - license='Apache License 2.0', - author='wedpr', - author_email='wedpr@webank.com', - cmdclass={'install': CompiledLibInstall} - ) diff --git a/cpp/wedpr-transport/sdk-wrapper/python/swig/wedpr_python_transport.i b/cpp/wedpr-transport/sdk-wrapper/python/swig/wedpr_python_transport.i index 16515cba..60e4f350 100644 --- a/cpp/wedpr-transport/sdk-wrapper/python/swig/wedpr_python_transport.i +++ b/cpp/wedpr-transport/sdk-wrapper/python/swig/wedpr_python_transport.i @@ -1,4 +1,11 @@ -%module wedpr_python_transport +%define MODULEIMPORT +" +from utils.lib_loader import LibLoader +_wedpr_python_transport = LibLoader.load_lib() +" +%enddef + +%module(moduleimport=MODULEIMPORT) wedpr_python_transport %include %include @@ -7,43 +14,157 @@ %include +// shared_ptr definition %shared_ptr(ppc::front::FrontConfig); +%shared_ptr(ppc::front::IFront); +%shared_ptr(ppc::front::IFrontClient); +// the callbacks +%shared_ptr(ppc::front::ErrorCallback); +%shared_ptr(ppc::front::MessageDispatcherHandler); +%shared_ptr(ppc::front::IMessageHandler); +%shared_ptr(ppc::front::GetPeersInfoHandler); + +%shared_ptr(ppc::gateway::IGateway); %shared_ptr(bcos::Error); +%shared_ptr(bcos::bytes); %shared_ptr(ppc::protocol::Message); -%shared_ptr(ppc::protocol::MessageOptionalHeader) +%shared_ptr(ppc::protocol::MessageOptionalHeader); +%shared_ptr(ppc::protocol::MessageHeader); +%shared_ptr(ppc::protocol::MessagePayload); +%shared_ptr(ppc::protocol::MessageBuilder); +%shared_ptr(ppc::protocol::MessageHeaderBuilder); +%shared_ptr(ppc::protocol::MessagePayloadBuilder); +%shared_ptr(ppc::protocol::MessageOptionalHeaderBuilder); +%shared_ptr(ppc::protocol::GrpcConfig); %shared_ptr(ppc::sdk::Transport); %{ #define SWIG_FILE_WITH_INIT +#include +#include #include #include "wedpr-transport/sdk/src/TransportBuilder.h" #include "wedpr-transport/sdk/src/Transport.h" +#include "ppc-framework/libwrapper/Buffer.h" #include "ppc-framework/front/IFront.h" #include "ppc-framework/protocol/RouteType.h" #include "ppc-framework/front/FrontConfig.h" +#include "ppc-framework/protocol/GrpcConfig.h" #include +#include "ppc-framework/protocol/EndPoint.h" +#include "ppc-framework/protocol/Message.h" +#include "ppc-framework/protocol/MessagePayload.h" %} +namespace ppc::sdk{ + class Transport; + class TransportBuilder; +} + +namespace ppc::gateway{ + class IGateway; +} + +namespace ppc::protocol{ + class Message; + class MessageHeader; + class MessagePayload; + class MessageOptionalHeader; + class MessageBuilder; + class MessageHeaderBuilder; + class MessagePayloadBuilder; + class MessageOptionalHeaderBuilder; + class EndPoint; + class GrpcConfig; + class RouteType; +} namespace ppc::front{ class FrontConfig; class IFront; + class IFrontClient; class FrontImpl; class FrontBuilderImpl; - class RouteType; class GatewayEndPoint; + class ErrorCallback; + class MessageDispatcherHandler; + class IMessageHandler; + class SendResponseHandler; } -namespace ppc::sdk{ - class Transport; - class TransportBuilder; +namespace std{ + class vector; } -%template(SharedFrontConfig) std::shared_ptr; +namespace bcos{ + using byte = uint8_t; + using bytes = std::vector; + class Error; +} + +// define shared_ptr objects %template(SharedBcosError) std::shared_ptr; + +%template(SharedFrontConfig) std::shared_ptr; +%template(SharedGrpcConfig) std::shared_ptr; + +%template(SharedFront) std::shared_ptr; +%template(SharedFrontClient) std::shared_ptr; + +%template(SharedErrorCallback) std::shared_ptr; +%template(SharedMessageDispatcherHandler) std::shared_ptr; +%template(SharedIMessageHandler) std::shared_ptr; +%template(SharedGetPeersInfoHandler) std::shared_ptr; + +%template(SharedGateway) std::shared_ptr; + %template(SharedMessage) std::shared_ptr; +%template(SharedMessageHeader) std::shared_ptr; +%template(SharedMessagePayload) std::shared_ptr; %template(SharedRouteInfo) std::shared_ptr; -%template(SharedTransport) std::shared_ptr; + +%template(SharedMessageBuilder) std::shared_ptr; +%template(SharedMessageHeaderBuilder) std::shared_ptr; +%template(SharedMessagePayloadBuilder) std::shared_ptr; +%template(SharedRouteInfoBuilder) std::shared_ptr; + +%template(ubytes) std::vector; +%template(ibytes) std::vector; + +/// callbacks +%feature("director") ppc::front::ErrorCallback; +%feature("director") ppc::front::MessageDispatcherHandler; +%feature("director") ppc::front::IMessageHandler; +%feature("director") ppc::front::GetPeersInfoHandler; + +// the method no need to wrapper +%ignore ppc::sdk::TransportBuilder::build; +%ignore ppc::front::IFront::onReceiveMessage; +%ignore ppc::front::IFront::asyncSendMessage; +%ignore ppc::front::IFront::asyncGetAgencies; +%ignore ppc::front::IFront::registerTopicHandler; +%ignore ppc::front::IFront::registerMessageHandler; +%ignore ppc::front::IFront::asyncSendResponse; +%ignore ppc::front::IFront::populateErrorCallback; +%ignore ppc::front::IFront::populateMessageDispatcherCallback; +%ignore ppc::front::IFront::populateMsgCallback; + +/* +///// tests /// +%inline { +} +///// tests /// +*/ + +// define the interface should been exposed +%include "bcos-utilities/Error.h" +%include "ppc-framework/libwrapper/Buffer.h" +%include "ppc-framework/front/FrontConfig.h" +%include "ppc-framework/protocol/EndPoint.h" +%include "ppc-framework/protocol/GrpcConfig.h" +%include "ppc-framework/protocol/Message.h" +%include "ppc-framework/protocol/MessagePayload.h" + +%include "ppc-framework/front/IFront.h" %include "wedpr-transport/sdk/src/TransportBuilder.h" -%include "wedpr-transport/sdk/src/Transport.h" -%include "ppc-framework/front/IFront.h" \ No newline at end of file +%include "wedpr-transport/sdk/src/Transport.h" \ No newline at end of file