From d8f3ddecde30dc1f8b75856551567974d8be4aeb Mon Sep 17 00:00:00 2001
From: Stefan Bruens <stefan.bruens@rwth-aachen.de>
Date: Fri, 28 Jun 2024 00:01:49 -0700
Subject: [PATCH] Import https://github.com/pybind/pybind11_protobuf/pull/162:

* Add the missing definitions for building the tests when using the CMake build.

Actually running the tests is left for another PR (see #162 for difficulties encountered):

* https://github.com/pybind/pybind11_protobuf/pull/162#issuecomment-2170849829

Manual import. The Google-internal repo is the source of truth for pybind11_protobuf. Sorry we didn't get to automating imports from GitHub PRs.

PiperOrigin-RevId: 647572543
---
 CMakeLists.txt                         | 77 +++++++++++++++-----
 cmake/dependencies/CMakeLists.txt      | 62 ----------------
 pybind11_protobuf/tests/CMakeLists.txt | 97 ++++++++++++++++++++++++++
 3 files changed, 156 insertions(+), 80 deletions(-)
 delete mode 100644 cmake/dependencies/CMakeLists.txt
 create mode 100644 pybind11_protobuf/tests/CMakeLists.txt

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 26dce5c..2139dc0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,7 +16,13 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 # ============================================================================
 # Options
 
-option(BUILD_TESTS "Build tests." OFF)
+option(USE_SYSTEM_ABSEIL "Force usage of system provided abseil-cpp" OFF)
+option(USE_SYSTEM_PROTOBUF "Force usage of system provided Protobuf" OFF)
+option(USE_SYSTEM_PYBIND "Force usage of system provided pybind11" OFF)
+
+# ============================================================================
+# Testing
+include(CTest)
 
 # ============================================================================
 # Find Python
@@ -26,22 +32,53 @@ find_package(Python COMPONENTS Interpreter Development)
 # ============================================================================
 # Build dependencies
 
-set(_absl_repository "https://github.com/abseil/abseil-cpp.git")
-set(_absl_version 20230125)
-set(_absl_tag 20230125.3)
-find_package(absl ${_absl_version} QUIET)
-
-set(_protobuf_repository "https://github.com/protocolbuffers/protobuf.git")
-set(_protobuf_version 3.23.3)
-set(_protobuf_tag v23.3)
-find_package(Protobuf ${_protobuf_version} QUIET)
-
-set(_pybind11_repository "https://github.com/pybind/pybind11.git")
-set(_pybind11_version 2.11.1)
-set(_pybind11_tag v2.11.1)
-find_package(pybind11 ${_pybind11_version} QUIET)
+if(USE_SYSTEM_ABSEIL)
+  # Version omitted, as absl only allows EXACT version matches
+  set(_absl_package_args REQUIRED)
+else()
+  set(_absl_package_args 20230125)
+endif()
+if(USE_SYSTEM_PROTOBUF)
+  set(_protobuf_package_args 4.23.3 REQUIRED)
+else()
+  set(_protobuf_package_args 4.23.3)
+endif()
+if(USE_SYSTEM_PYBIND)
+  set(_pybind11_package_args 2.11.1 REQUIRED)
+else()
+  set(_pybind11_package_args 2.11.1)
+endif()
 
-add_subdirectory(cmake/dependencies dependencies)
+set(ABSL_PROPAGATE_CXX_STD ON)
+set(ABSL_ENABLE_INSTALL ON)
+
+include(FetchContent)
+FetchContent_Declare(
+  absl
+  GIT_REPOSITORY "https://github.com/abseil/abseil-cpp.git"
+  GIT_TAG 20230125.3
+  FIND_PACKAGE_ARGS ${_absl_package_args} NAMES absl)
+
+# cmake-format: off
+FetchContent_Declare(
+  Protobuf
+  GIT_REPOSITORY "https://github.com/protocolbuffers/protobuf.git"
+  GIT_TAG v23.3
+  GIT_SUBMODULES ""
+  FIND_PACKAGE_ARGS ${_protobuf_package_args} NAMES protobuf)
+set(protobuf_BUILD_TESTS OFF CACHE INTERNAL "")
+# cmake-format: on
+
+FetchContent_Declare(
+  pybind11
+  GIT_REPOSITORY "https://github.com/pybind/pybind11.git"
+  GIT_TAG v2.11.1
+  FIND_PACKAGE_ARGS ${_pybind11_package_args} NAMES pybind11)
+
+message(CHECK_START "Checking for external dependencies")
+list(APPEND CMAKE_MESSAGE_INDENT "  ")
+FetchContent_MakeAvailable(absl Protobuf pybind11)
+list(POP_BACK CMAKE_MESSAGE_INDENT)
 
 # ============================================================================
 # pybind11_proto_utils pybind11 extension module
@@ -60,7 +97,7 @@ target_include_directories(
 # ============================================================================
 # pybind11_native_proto_caster shared library
 add_library(
-  pybind11_native_proto_caster SHARED
+  pybind11_native_proto_caster STATIC
   # bazel: pybind_library: native_proto_caster
   pybind11_protobuf/native_proto_caster.h
   # bazel: pybind_library: enum_type_caster
@@ -89,7 +126,7 @@ target_include_directories(
 # ============================================================================
 # pybind11_wrapped_proto_caster shared library
 add_library(
-  pybind11_wrapped_proto_caster SHARED
+  pybind11_wrapped_proto_caster STATIC
   # bazel: pybind_library: wrapped_proto_caster
   pybind11_protobuf/wrapped_proto_caster.h
   # bazel: pybind_library: proto_cast_util
@@ -113,6 +150,10 @@ target_include_directories(
   PRIVATE ${PROJECT_SOURCE_DIR} ${protobuf_INCLUDE_DIRS} ${protobuf_SOURCE_DIR}
           ${pybind11_INCLUDE_DIRS})
 
+if(BUILD_TESTING)
+  add_subdirectory(pybind11_protobuf/tests)
+endif()
+
 # bazel equivs. checklist
 #
 # bazel: pybind_library: enum_type_caster - enum_type_caster.h
diff --git a/cmake/dependencies/CMakeLists.txt b/cmake/dependencies/CMakeLists.txt
deleted file mode 100644
index 111b34f..0000000
--- a/cmake/dependencies/CMakeLists.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-include(FetchContent)
-
-# ============================================================================
-# Declare all dependencies first
-
-if(NOT absl_FOUND)
-  set(ABSL_PROPAGATE_CXX_STD ON)
-  set(ABSL_ENABLE_INSTALL ON)
-  FetchContent_Declare(
-    absl
-    GIT_REPOSITORY ${_absl_repository}
-    GIT_TAG ${_absl_tag})
-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(NOT Protobuf_FOUND)
-  set(protobuf_BUILD_TESTS
-      OFF
-      CACHE INTERNAL "")
-  FetchContent_Declare(
-    Protobuf
-    GIT_REPOSITORY ${_protobuf_repository}
-    GIT_TAG ${_protobuf_tag}
-    GIT_SUBMODULES "")
-endif()
-
-if(NOT pybind11_FOUND)
-  set(PYBIND11_TEST OFF)
-  FetchContent_Declare(
-    pybind11
-    GIT_REPOSITORY ${_pybind11_repository}
-    GIT_TAG ${_pybind11_tag})
-endif()
-
-# ============================================================================
-# Make dependencies avaialble
-
-if(NOT absl_FOUND)
-  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(NOT Protobuf_FOUND)
-  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(NOT pybind11_FOUND)
-  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/pybind11_protobuf/tests/CMakeLists.txt b/pybind11_protobuf/tests/CMakeLists.txt
new file mode 100644
index 0000000..6a9cfc0
--- /dev/null
+++ b/pybind11_protobuf/tests/CMakeLists.txt
@@ -0,0 +1,97 @@
+#
+# Evaluate if Protobuf uses the system package, otherwise explicitly include the
+# required macro
+#
+FetchContent_GetProperties(Protobuf SOURCE_DIR Protobuf_SOURCE_DIR)
+if(Protobuf_SOURCE_DIR)
+  # Use macros from content made available by FetchContent
+  include(${Protobuf_SOURCE_DIR}/cmake/protobuf-generate.cmake)
+endif()
+
+# cmake-format: off
+function(generate_cc_proto protoname)
+  # Generate C++ files (.pb.h, .pb.cc)
+  #
+  add_library(${protoname}_cc_proto OBJECT)
+  target_include_directories(${protoname}_cc_proto
+    PRIVATE $<TARGET_PROPERTY:protobuf::libprotobuf,INCLUDE_DIRECTORIES>
+            $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>)
+  protobuf_generate(
+    TARGET ${protoname}_cc_proto
+    PROTOS ${CMAKE_SOURCE_DIR}/pybind11_protobuf/tests/${protoname}.proto
+    IMPORT_DIRS ${CMAKE_SOURCE_DIR}
+    PROTOC_OUT_DIR ${CMAKE_BINARY_DIR})
+endfunction()
+
+function(generate_py_proto protoname)
+  # Generate Python files (_pb2.py)
+  #
+  add_custom_target(${protoname}_py_pb2 ALL)
+  protobuf_generate(
+    TARGET ${protoname}_py_pb2
+    LANGUAGE PYTHON
+    PROTOS ${CMAKE_SOURCE_DIR}/pybind11_protobuf/tests/${protoname}.proto
+    IMPORT_DIRS ${CMAKE_SOURCE_DIR}
+    PROTOC_OUT_DIR ${CMAKE_BINARY_DIR})
+endfunction()
+# cmake-format: on
+
+generate_cc_proto("test")
+generate_cc_proto("extension")
+generate_cc_proto("extension_nest_repeated")
+generate_cc_proto("extension_in_other_file_in_deps")
+generate_cc_proto("extension_in_other_file")
+generate_cc_proto("we-love-dashes")
+
+generate_py_proto("test")
+generate_py_proto("extension")
+generate_py_proto("extension_nest_repeated")
+generate_py_proto("extension_in_other_file_in_deps")
+generate_py_proto("extension_in_other_file")
+
+function(generate_extension modulename deps)
+  pybind11_add_module(${modulename}_module ${modulename}_module.cc)
+  add_dependencies(${modulename}_module ${deps})
+  target_include_directories(${modulename}_module #
+                             PRIVATE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})
+  target_link_libraries(${modulename}_module #
+                        PRIVATE protobuf::libprotobuf ${deps})
+endfunction()
+
+generate_extension(proto_enum "test_cc_proto")
+generate_extension(dynamic_message "pybind11_native_proto_caster")
+generate_extension(
+  extension #
+  "extension_in_other_file_in_deps_cc_proto;extension_nest_repeated_cc_proto;test_cc_proto;extension_cc_proto;pybind11_native_proto_caster"
+)
+generate_extension(message "test_cc_proto;pybind11_native_proto_caster")
+generate_extension(pass_by "test_cc_proto;pybind11_native_proto_caster")
+generate_extension(pass_proto2_message "pybind11_native_proto_caster")
+generate_extension(wrapped_proto "test_cc_proto;pybind11_wrapped_proto_caster")
+generate_extension(thread "test_cc_proto;pybind11_native_proto_caster")
+generate_extension(regression_wrappers "pybind11_native_proto_caster")
+generate_extension(we_love_dashes_cc_only #
+                   "we-love-dashes_cc_proto;pybind11_native_proto_caster")
+
+function(add_py_test testname)
+  add_test(NAME ${testname}_test
+           COMMAND ${Python_EXECUTABLE}
+                   ${CMAKE_CURRENT_SOURCE_DIR}/${testname}_test.py)
+  set_property(TEST ${testname}_test #
+               PROPERTY ENVIRONMENT "PYTHONPATH=${CMAKE_BINARY_DIR}")
+endfunction()
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/compare.py
+     DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+
+add_py_test(proto_enum)
+add_py_test(dynamic_message)
+add_py_test(extension)
+# FIXME What is the difference to the "extension_test"?
+# add_py_test(extension_disallow_unknown_fields)
+add_py_test(message)
+add_py_test(pass_by)
+add_py_test(wrapped_proto_module)
+add_py_test(thread_module)
+add_py_test(regression_wrappers)
+add_py_test(we_love_dashes_cc_only)