feat: new FindPython support (#2370)

* feat: FindPython support

* refactor: rename to PYBIND11_FINDPYTHON

* docs: Caps fixes

* feat: NOPYTHON mode

* test: check simple call

* docs: add changelog/upgrade guide

* feat: Support Python3 and Python2

* refactor: Use targets in tests

* fix: support CMake 3.4+

* feat: classic search also finds virtual environments

* docs: some updates from @wjakob's review

* fix: wrong name for QUIET mode variable, reported by @skoslowski

* refactor: cleaner output messaging

* fix: support debug Python's in FindPython mode too

* fixup! refactor: cleaner output messaging

* fix: missing pybind11_FOUND and pybind11_INCLUDE_DIR restored to subdir mode

* fix: nicer reporting of Python / PyPy

* fix: out-of-order variable fix

* docs: minor last-minute cleanup
diff --git a/tools/pybind11NewTools.cmake b/tools/pybind11NewTools.cmake
new file mode 100644
index 0000000..2e7a931
--- /dev/null
+++ b/tools/pybind11NewTools.cmake
@@ -0,0 +1,203 @@
+# tools/pybind11NewTools.cmake -- Build system for the pybind11 modules
+#
+# Copyright (c) 2020 Wenzel Jakob <wenzel@inf.ethz.ch> and Henry Schreiner
+#
+# All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+get_property(
+  is_config
+  TARGET pybind11::headers
+  PROPERTY IMPORTED)
+
+if(pybind11_FIND_QUIETLY)
+  set(_pybind11_quiet QUIET)
+endif()
+
+if(CMAKE_VERSION VERSION_LESS 3.12)
+  message(FATAL_ERROR "You cannot use the new FindPython module with CMake < 3.12")
+endif()
+
+if(NOT Python_FOUND
+   AND NOT Python3_FOUND
+   AND NOT Python2_FOUND)
+  if(NOT DEFINED Python_FIND_IMPLEMENTATIONS)
+    set(Python_FIND_IMPLEMENTATIONS CPython PyPy)
+  endif()
+
+  # GitHub Actions like activation
+  if(NOT DEFINED Python_ROOT_DIR AND DEFINED ENV{pythonLocation})
+    set(Python_ROOT_DIR "$ENV{pythonLocation}")
+  endif()
+
+  find_package(Python REQUIRED COMPONENTS Interpreter Development ${_pybind11_quiet})
+
+  # If we are in submodule mode, export the Python targets to global targets.
+  # If this behavior is not desired, FindPython _before_ pybind11.
+  if(NOT is_config)
+    set_property(TARGET Python::Python PROPERTY IMPORTED_GLOBAL TRUE)
+    set_property(TARGET Python::Interpreter PROPERTY IMPORTED_GLOBAL TRUE)
+    if(TARGET Python::Module)
+      set_property(TARGET Python::Module PROPERTY IMPORTED_GLOBAL TRUE)
+    endif()
+  endif()
+endif()
+
+if(Python_FOUND)
+  set(_Python
+      Python
+      CACHE INTERNAL "" FORCE)
+elseif(Python3_FOUND AND NOT Python2_FOUND)
+  set(_Python
+      Python3
+      CACHE INTERNAL "" FORCE)
+elseif(Python2_FOUND AND NOT Python3_FOUND)
+  set(_Python
+      Python2
+      CACHE INTERNAL "" FORCE)
+else()
+  message(AUTHOR_WARNING "Python2 and Python3 both present, pybind11 in "
+                         "PYBIND11_NOPYTHON mode (manually activate to silence warning)")
+  set(_pybind11_nopython ON)
+  return()
+endif()
+
+if(PYBIND11_MASTER_PROJECT)
+  if(${_Python}_INTERPRETER_ID MATCHES "PyPy")
+    message(STATUS "PyPy ${${_Python}_PyPy_VERSION} (Py ${${_Python}_VERSION})")
+  else()
+    message(STATUS "${_Python} ${${_Python}_VERSION}")
+  endif()
+endif()
+
+# Debug check - see https://stackoverflow.com/questions/646518/python-how-to-detect-debug-Interpreter
+execute_process(COMMAND ${_Python}::Python -c "import sys; print(hasattr(sys, 'gettotalrefcount'))"
+                OUTPUT_VARIABLE PYTHON_IS_DEBUG)
+
+# Python debug libraries expose slightly different objects before 3.8
+# https://docs.python.org/3.6/c-api/intro.html#debugging-builds
+# https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib
+if(PYTHON_IS_DEBUG)
+  set_property(
+    TARGET pybind::pybind11
+    APPEND
+    PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
+endif()
+
+# Check on every access - since Python2 and Python3 could have been used - do nothing in that case.
+
+if(DEFINED ${_Python}_INCLUDE_DIRS)
+  set_property(
+    TARGET pybind11::pybind11
+    APPEND
+    PROPERTY INTERFACE_INCLUDE_DIRECTORIES $<BUILD_INTERFACE:${${_Python}_INCLUDE_DIRS}>)
+endif()
+
+if(DEFINED ${_Python}_VERSION AND ${_Python}_VERSION VERSION_LESS 3)
+  set_property(
+    TARGET pybind11::pybind11
+    APPEND
+    PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python2_no_register)
+endif()
+
+# In CMake 3.18+, you can find these separately, so include an if
+if(TARGET ${_Python}::${_Python})
+  set_property(
+    TARGET pybind11::embed
+    APPEND
+    PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::${_Python})
+endif()
+
+# CMake 3.15+ has this
+if(TARGET ${_Python}::Module)
+  set_property(
+    TARGET pybind11::module
+    APPEND
+    PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Module)
+else()
+  set_property(
+    TARGET pybind11::module
+    APPEND
+    PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_link_helper)
+endif()
+
+function(pybind11_add_module target_name)
+  cmake_parse_arguments(PARSE_ARGV 1 ARG "STATIC;SHARED;MODULE;THIN_LTO;NO_EXTRAS" "" "")
+
+  if(ARG_ADD_LIBRARY_STATIC)
+    set(type STATIC)
+  elseif(ARG_ADD_LIBRARY_SHARED)
+    set(type SHARED)
+  else()
+    set(type MODULE)
+  endif()
+
+  if("${_Python}" STREQUAL "Python")
+    python_add_library(${target_name} ${type} WITH_SOABI ${ARG_UNPARSED_ARGUMENTS})
+  elseif("${_Python}" STREQUAL "Python3")
+    python3_add_library(${target_name} ${type} WITH_SOABI ${ARG_UNPARSED_ARGUMENTS})
+  elseif("${_Python}" STREQUAL "Python2")
+    python2_add_library(${target_name} ${type} WITH_SOABI ${ARG_UNPARSED_ARGUMENTS})
+  else()
+    message(FATAL_ERROR "Cannot detect FindPython version: ${_Python}")
+  endif()
+
+  target_link_libraries(${target_name} PRIVATE pybind11::headers)
+
+  if(type STREQUAL "MODULE")
+    target_link_libraries(${target_name} PRIVATE pybind11::module)
+  else()
+    target_link_libraries(${target_name} PRIVATE pybind11::embed)
+  endif()
+
+  if(MSVC)
+    target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
+  endif()
+
+  if(DEFINED ${_Python}_VERSION AND ${_Python}_VERSION VERSION_LESS 3)
+    target_link_libraries(${target_name} PRIVATE pybind11::python2_no_register)
+  endif()
+
+  set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden"
+                                                  CUDA_VISIBILITY_PRESET "hidden")
+
+  if(ARG_NO_EXTRAS)
+    return()
+  endif()
+
+  if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
+    if(ARG_THIN_LTO)
+      target_link_libraries(${target_name} PRIVATE pybind11::thin_lto)
+    else()
+      target_link_libraries(${target_name} PRIVATE pybind11::lto)
+    endif()
+  endif()
+
+  if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
+    # Strip unnecessary sections of the binary on Linux/Mac OS
+    pybind11_strip(${target_name})
+  endif()
+
+  if(MSVC)
+    target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
+  endif()
+endfunction()
+
+function(pybind11_extension name)
+  set_property(TARGET ${name} PROPERTY PREFIX "")
+
+  if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+    set_property(TARGET ${name} PROPERTY SUFFIX ".pyd")
+  endif()
+
+  if(${_Python}_SOABI)
+    get_property(
+      suffix
+      TARGET ${name}
+      PROPERTY SUFFIX)
+    if(NOT suffix)
+      set(suffix "${CMAKE_SHARED_MODULE_SUFFIX}")
+    endif()
+    set_property(TARGET ${name} PROPERTY SUFFIX ".${${_Python}_SOABI}${suffix}")
+  endif()
+endfunction()