diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 39c1e65..c5838e5 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -1,9 +1,8 @@ name: pre-commit on: + workflow_dispatch: pull_request: - push: - branches: [main] jobs: pre-commit: diff --git a/.github/workflows/ubuntu-build.yml b/.github/workflows/ubuntu-build.yml new file mode 100644 index 0000000..9285e72 --- /dev/null +++ b/.github/workflows/ubuntu-build.yml @@ -0,0 +1,45 @@ +name: ubuntu-build + +on: + workflow_dispatch: + pull_request: + +concurrency: + group: ci-${{github.workflow}}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-22.04 + name: ubuntu-build + steps: + - name: Show env + run: env + + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Build Dependencies + shell: bash + run: | + sudo apt update && sudo apt install --no-install-recommends -y \ + cmake \ + make + + - name: Show Python version and platform info + run: | + python --version + python -m platform + + - name: Show CMake version + run: cmake --version + + - name: CMake Configure + shell: bash + run: | + cmake -S . -B build -DCMAKE_VERBOSE_MAKEFILE=ON + + - name: CMake Build + shell: bash + run: | + cmake --build build -j$(nproc) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9424d86 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,166 @@ +cmake_minimum_required(VERSION 3.18) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +project(pybind11_protobuf) + +if(MSVC) + set(CMAKE_CXX_STANDARD 20) +else() + set(CMAKE_CXX_STANDARD 17) +endif() +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_CXX_FLAGS + "-fPIC" + CACHE INTERNAL "") + +# ============================================================================ +# Options + +option(BUILD_absl "Build the abseil-cpp dependency Library" ON) +message(STATUS "Build abseil-cpp: ${BUILD_absl}") + +option(BUILD_protobuf "Build the Protobuf dependency Library" ON) +message(STATUS "Build protobuf: ${BUILD_protobuf}") + +option(BUILD_pybind11 "Build the pybind11 dependency Library" ON) +message(STATUS "Python: Build pybind11: ${BUILD_pybind11}") + +# ============================================================================ +# Find Python + +find_package(Python COMPONENTS Interpreter Development) + +# ============================================================================ +# Build dependencies + +add_subdirectory(cmake/dependencies dependencies) + +include(deps) + +include(CMakeFindDependencyMacro) +include(FindProtobuf) +if(NOT protobuf_FOUND + AND NOT PROTOBUF_FOUND + AND NOT TARGET protobuf::libprotobuf) + if(BUILD_protobuf) + find_dependency(protobuf CONFIG REQUIRED) + endif() +endif() + +# ============================================================================ +# Debug messages for find_package + +# message("pybind11_FOUND: ${pybind11_FOUND}") message("pybind11_VERSION: +# ${pybind11_VERSION}") message("pybind11_VERSION_TYPE: +# ${pybind11_VERSION_TYPE}") message("pybind11_INCLUDE_DIRS: +# ${pybind11_INCLUDE_DIRS}") message("pybind11_INCLUDE_DIR: +# ${pybind11_INCLUDE_DIR}") message("pybind11_DEFINITIONS: +# ${pybind11_DEFINITIONS}") message("pybind11_LIBRARIES: ${pybind11_LIBRARIES}") + +# message("Python_FOUND: ${Python_FOUND}") message("Python_VERSION: +# ${Python_VERSION}") message("Python_INCLUDE_DIRS: ${Python_INCLUDE_DIRS}") +# message("Python_LIBRARIES: ${Python_LIBRARIES}") + +# message("protobuf_FOUND: ${protobuf_FOUND}") message("protobuf_VERSION: +# ${protobuf_VERSION}") message("protobuf_INCLUDE_DIRS: +# ${protobuf_INCLUDE_DIRS}") message("protobuf_SOURCE_DIR: +# ${protobuf_SOURCE_DIR}") message("protobuf_LIBRARIES: ${protobuf_LIBRARIES}") + +# ============================================================================ +# pybind11_proto_utils pybind11 extension module +pybind11_add_module( + pybind11_proto_utils MODULE pybind11_protobuf/proto_utils.cc + pybind11_protobuf/proto_utils.h) + +target_link_libraries( + pybind11_proto_utils PRIVATE absl::strings protobuf::libprotobuf + ${Python_LIBRARIES}) + +target_include_directories( + pybind11_proto_utils PRIVATE ${PROJECT_SOURCE_DIR} ${protobuf_INCLUDE_DIRS} + ${protobuf_SOURCE_DIR} ${pybind11_INCLUDE_DIRS}) + +# ============================================================================ +# pybind11_native_proto_caster shared library +add_library( + pybind11_native_proto_caster SHARED + # bazel: pybind_library: native_proto_caster + pybind11_protobuf/native_proto_caster.h + # bazel: pybind_library: enum_type_caster + pybind11_protobuf/enum_type_caster.h + # bazel: pybind_library: proto_cast_util + pybind11_protobuf/proto_cast_util.cc + pybind11_protobuf/proto_cast_util.h + pybind11_protobuf/proto_caster_impl.h + # bazel: cc_library::check_unknown_fields + pybind11_protobuf/check_unknown_fields.cc + pybind11_protobuf/check_unknown_fields.h) + +target_link_libraries( + pybind11_native_proto_caster + absl::flat_hash_map + absl::flat_hash_set + absl::hash + absl::strings + absl::optional + protobuf::libprotobuf + pybind11::pybind11 + ${Python_LIBRARIES}) + +target_include_directories( + pybind11_native_proto_caster + PRIVATE ${PROJECT_SOURCE_DIR} ${protobuf_INCLUDE_DIRS} ${protobuf_SOURCE_DIR} + ${pybind11_INCLUDE_DIRS}) + +# ============================================================================ +# pybind11_wrapped_proto_caster shared library +add_library( + pybind11_wrapped_proto_caster SHARED + # bazel: pybind_library: wrapped_proto_caster + pybind11_protobuf/wrapped_proto_caster.h + # bazel: pybind_library: proto_cast_util + pybind11_protobuf/proto_cast_util.cc + pybind11_protobuf/proto_cast_util.h + pybind11_protobuf/proto_caster_impl.h + # bazel: cc_library: check_unknown_fields + pybind11_protobuf/check_unknown_fields.cc + pybind11_protobuf/check_unknown_fields.h) + +target_link_libraries( + pybind11_wrapped_proto_caster + absl::flat_hash_map + absl::flat_hash_set + absl::hash + absl::strings + absl::optional + protobuf::libprotobuf + pybind11::pybind11 + ${Python_LIBRARIES}) + +target_include_directories( + pybind11_wrapped_proto_caster + PRIVATE ${PROJECT_SOURCE_DIR} ${protobuf_INCLUDE_DIRS} ${protobuf_SOURCE_DIR} + ${pybind11_INCLUDE_DIRS}) + +# TODO set defines PYBIND11_PROTOBUF_ENABLE_PYPROTO_API see: bazel: +# pybind_library: proto_cast_util + +# bazel equivs. checklist +# +# bazel: pybind_library: enum_type_caster - enum_type_caster.h +# +# bazel: pybind_library: native_proto_caster - native_proto_caster.h +# +# check_unknown_fields enum_type_caster proto_cast_util +# +# bazel: pybind_library: proto_cast_util - proto_cast_util.cc - +# proto_cast_util.h - proto_caster_impl.h +# +# check_unknown_fields +# +# bazel: pybind_library: wrapped_proto_caster - wrapped_proto_caster.h +# +# proto_cast_util +# diff --git a/cmake/dependencies/CMakeLists.txt b/cmake/dependencies/CMakeLists.txt new file mode 100644 index 0000000..ea302c9 --- /dev/null +++ b/cmake/dependencies/CMakeLists.txt @@ -0,0 +1,60 @@ +include(FetchContent) + +# ============================================================================ +# Declare all dependencies first + +if(BUILD_absl) + FetchContent_Declare( + absl + GIT_REPOSITORY "https://github.com/abseil/abseil-cpp.git" + GIT_TAG "20220623.1") +endif() + +# https://stackoverflow.com/questions/63309544/cmake-protobuf-external-to-application-code +# https://cmake.org/cmake/help/latest/policy/CMP0077.html +# https://gitlab.kitware.com/cmake/cmake/-/merge_requests/7565/diffs +if(BUILD_protobuf) + set(protobuf_BUILD_TESTS + OFF + CACHE INTERNAL "") + FetchContent_Declare( + protobuf + GIT_REPOSITORY "https://github.com/protocolbuffers/protobuf.git" + GIT_TAG "v21.5" + GIT_SUBMODULES "") +endif() + +if(BUILD_pybind11) + set(PYBIND11_TEST OFF) + FetchContent_Declare( + pybind11 + GIT_REPOSITORY "https://github.com/pybind/pybind11.git" + GIT_TAG "v2.10.1") +endif() + +# ============================================================================ +# Make dependencies avaialble + +if(BUILD_absl) + message(CHECK_START "Fetching Abseil-cpp") + list(APPEND CMAKE_MESSAGE_INDENT " ") + FetchContent_MakeAvailable(absl) + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_PASS "fetched") +endif() + +if(BUILD_protobuf) + message(CHECK_START "Fetching protobuf") + list(APPEND CMAKE_MESSAGE_INDENT " ") + FetchContent_MakeAvailable(protobuf) + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_PASS "fetched") +endif() + +if(BUILD_pybind11) + message(CHECK_START "Fetching pybind11") + list(APPEND CMAKE_MESSAGE_INDENT " ") + FetchContent_MakeAvailable(pybind11) + list(POP_BACK CMAKE_MESSAGE_INDENT) + message(CHECK_PASS "fetched") +endif() diff --git a/cmake/deps.cmake b/cmake/deps.cmake new file mode 100644 index 0000000..5db89a7 --- /dev/null +++ b/cmake/deps.cmake @@ -0,0 +1,11 @@ +if(NOT BUILD_absl) + find_package(absl REQUIRED) +endif() + +if(NOT BUILD_protobuf) + find_package(protobuf REQUIRED) +endif() + +if(NOT BUILD_pybind11) + find_package(pybind11 REQUIRED) +endif() diff --git a/pybind11_protobuf/tests/CMakeLists.txt b/pybind11_protobuf/tests/CMakeLists.txt new file mode 100644 index 0000000..afca562 --- /dev/null +++ b/pybind11_protobuf/tests/CMakeLists.txt @@ -0,0 +1,33 @@ +# ============================================================================ +# tests +# ============================================================================ + +# ============================================================================ +# generate protobuf bindings + +set(Protobuf_IMPORT_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}/../../..;${Protobuf_IMPORT_DIRS}") + +protobuf_generate_cpp( + PROTO_SRCS PROTO_HDRS + # extension.proto + test.proto) + +protobuf_generate_python( + PROTO_PYS + # extension.proto + test.proto) + +# ============================================================================ +# adding a custom target forces CMake to generate the bindings + +add_custom_target(pybind11_test_proto_cpp ALL DEPENDS ${PROTO_SRCS} + ${PROTO_HDRS}) +add_custom_target(pybind11_test_proto_python ALL DEPENDS ${PROTO_PYS}) + +# ============================================================================ +# generate protobuf library + +add_library(pybind11_test_proto ${PROTO_SRCS} ${PROTO_HDR}) + +target_include_directories(pybind11_test_proto PUBLIC ${Protobuf_INCLUDE_DIR})