feat: setup.py redesign and helpers (#2433)

* feat: setup.py redesign and helpers

* refactor: simpler design with two outputs

* refactor: helper file update and Windows support

* fix: review points from @YannickJadoul

* refactor: fixes to naming and more docs

* feat: more customization points

* feat: add entry point pybind11-config

* refactor: Try Extension-focused method

* refactor: rename alt/inplace to global

* fix: allow usage with git modules, better docs

* feat: global as an extra (@YannickJadoul's suggestion)

* feat: single version location

* fix: remove the requirement that setuptools must be imported first

* fix: some review points from @wjacob

* fix: use .in, add procedure to docs

* refactor: avoid monkeypatch copy

* docs: minor typos corrected

* fix: minor points from @YannickJadoul

* fix: typo on Windows C++ mode

* fix: MSVC 15 update 3+ have c++14 flag

See <https://docs.microsoft.com/en-us/cpp/build/reference/std-specify-language-standard-version?view=vs-2019>

* docs: discuss making SDists by hand

* ci: use pep517.build instead of manual setup.py

* refactor: more comments from @YannickJadoul

* docs: updates from @ktbarrett

* fix: change to newly recommended tool instead of pep517.build

This was intended as a proof of concept; build seems to be the correct replacement.

See https://github.com/pypa/pep517/pull/83

* docs: updates from @wjakob

* refactor: dual version locations

* docs: typo spotted by @wjakob
diff --git a/tools/pybind11Common.cmake b/tools/pybind11Common.cmake
index 96e958e..26a1e04 100644
--- a/tools/pybind11Common.cmake
+++ b/tools/pybind11Common.cmake
@@ -300,7 +300,7 @@
 # ---------------------- pybind11_strip -----------------------------
 
 function(pybind11_strip target_name)
-  # Strip unnecessary sections of the binary on Linux/Mac OS
+  # Strip unnecessary sections of the binary on Linux/macOS
   if(CMAKE_STRIP)
     if(APPLE)
       set(x_opt -x)
diff --git a/tools/pybind11NewTools.cmake b/tools/pybind11NewTools.cmake
index 812ec09..27eb4d9 100644
--- a/tools/pybind11NewTools.cmake
+++ b/tools/pybind11NewTools.cmake
@@ -197,7 +197,7 @@
   endif()
 
   if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
-    # Strip unnecessary sections of the binary on Linux/Mac OS
+    # Strip unnecessary sections of the binary on Linux/macOS
     pybind11_strip(${target_name})
   endif()
 
diff --git a/tools/pyproject.toml b/tools/pyproject.toml
new file mode 100644
index 0000000..9787c3b
--- /dev/null
+++ b/tools/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools", "wheel"]
+build-backend = "setuptools.build_meta"
diff --git a/tools/setup_global.py.in b/tools/setup_global.py.in
new file mode 100644
index 0000000..3325cd0
--- /dev/null
+++ b/tools/setup_global.py.in
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Setup script for pybind11-global (in the sdist or in tools/setup_global.py in the repository)
+# This package is targeted for easy use from CMake.
+
+import contextlib
+import glob
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+
+# Setuptools has to be before distutils
+from setuptools import setup
+
+from distutils.command.install_headers import install_headers
+
+class InstallHeadersNested(install_headers):
+    def run(self):
+        headers = self.distribution.headers or []
+        for header in headers:
+            # Remove pybind11/include/
+            short_header = header.split("/", 2)[-1]
+
+            dst = os.path.join(self.install_dir, os.path.dirname(short_header))
+            self.mkpath(dst)
+            (out, _) = self.copy_file(header, dst)
+            self.outfiles.append(out)
+
+
+main_headers = glob.glob("pybind11/include/pybind11/*.h")
+detail_headers = glob.glob("pybind11/include/pybind11/detail/*.h")
+cmake_files = glob.glob("pybind11/share/cmake/pybind11/*.cmake")
+headers = main_headers + detail_headers
+
+cmdclass = {"install_headers": InstallHeadersNested}
+$extra_cmd
+
+setup(
+    name="pybind11_global",
+    version="$version",
+    packages=[],
+    headers=headers,
+    data_files=[
+        ("share/cmake/pybind11", cmake_files),
+        ("include/pybind11", main_headers),
+        ("include/pybind11/detail", detail_headers),
+    ],
+    cmdclass=cmdclass,
+)
diff --git a/tools/setup_main.py.in b/tools/setup_main.py.in
new file mode 100644
index 0000000..c859c1f
--- /dev/null
+++ b/tools/setup_main.py.in
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Setup script (in the sdist or in tools/setup_main.py in the repository)
+
+from setuptools import setup
+
+cmdclass = {}
+$extra_cmd
+
+setup(
+    name="pybind11",
+    version="$version",
+    download_url='https://github.com/pybind/pybind11/tarball/v$version',
+    packages=[
+        "pybind11",
+        "pybind11.include.pybind11",
+        "pybind11.include.pybind11.detail",
+        "pybind11.share.cmake.pybind11",
+    ],
+    package_data={
+        "pybind11.include.pybind11": ["*.h"],
+        "pybind11.include.pybind11.detail": ["*.h"],
+        "pybind11.share.cmake.pybind11": ["*.cmake"],
+    },
+    extras_require={
+        "global": ["pybind11_global==$version"]
+        },
+    entry_points={
+        "console_scripts": [
+             "pybind11-config = pybind11.__main__:main",
+        ]
+    },
+    cmdclass=cmdclass
+)