Repository: pybind/pybind11 (language: python)

Issue:
[BUG]: strdup cannot be found on Cygwin
### Required prerequisites

- [X] Make sure you've read the [documentation](https://pybind11.readthedocs.io). Your issue may be addressed there.
- [X] Search the [issue tracker](https://github.com/pybind/pybind11/issues) and [Discussions](https:/pybind/pybind11/discussions) to verify that this hasn't already been reported. +1 or comment there if it has.
- [ ] Consider asking first in the [Gitter chat room](https://gitter.im/pybind/Lobby) or in a [Discussion](https:/pybind/pybind11/discussions/new).

### What version (or hash if on master) of pybind11 are you using?

2.11.1

### Problem description

On our [test builds with Cygwin](https://github.com/matplotlib/matplotlib/actions/runs/6823134200/job/18556454531), some newly added pybind11 code is no longer compiling due to `strdup`:
```
  ccache c++ -Isrc/_c_internal_utils.cpython-39-x86_64-cygwin.dll.p -Isrc -I../../src -I/usr/include/python3.9 -I/usr/local/lib/python3.9/site-packages/pybind11/include -fvisibility=hidden -fvisibility-inlines-hidden -flto=auto -fdiagnostics-color=always -DNDEBUG -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -std=c++17 -O3 -DPY_ARRAY_UNIQUE_SYMBOL=MPL__c_internal_utils_ARRAY_API -MD -MQ src/_c_internal_utils.cpython-39-x86_64-cygwin.dll.p/_c_internal_utils.cpp.o -MF src/_c_internal_utils.cpython-39-x86_64-cygwin.dll.p/_c_internal_utils.cpp.o.d -o src/_c_internal_utils.cpython-39-x86_64-cygwin.dll.p/_c_internal_utils.cpp.o -c ../../src/_c_internal_utils.cpp
  In file included from ../../src/_c_internal_utils.cpp:9:
  /usr/local/lib/python3.9/site-packages/pybind11/include/pybind11/pybind11.h: In member function 'char* pybind11::cpp_function::strdup_guard::operator()(const char*)':
  /usr/local/lib/python3.9/site-packages/pybind11/include/pybind11/pybind11.h:331:23: error: 'strdup' was not declared in this scope; did you mean 'strcmp'?
    331 |             auto *t = PYBIND11_COMPAT_STRDUP(s);
        |                       ^~~~~~
        |                       strcmp
  In file included from ../../src/_c_internal_utils.cpp:9:
  /usr/local/lib/python3.9/site-packages/pybind11/include/pybind11/pybind11.h: In member function 'void pybind11::cpp_function::initialize_generic(pybind11::cpp_function::unique_function_record&&, const char*, const std::type_info* const*, pybind11::size_t)':
  /usr/local/lib/python3.9/site-packages/pybind11/include/pybind11/pybind11.h:617:46: error: 'strdup' was not declared in this scope; did you mean 'strcmp'?
    617 |             = signatures.empty() ? nullptr : PYBIND11_COMPAT_STRDUP(signatures.c_str());
        |                                              ^~~~~~
        |                                              strcmp
  In file included from ../../src/_c_internal_utils.cpp:9:
  /usr/local/lib/python3.9/site-packages/pybind11/include/pybind11/pybind11.h: In member function 'pybind11::class_<type_, options>& pybind11::class_<type_, options>::def_property_static(const char*, const pybind11::cpp_function&, const pybind11::cpp_function&, const Extra& ...)':
  /usr/local/lib/python3.9/site-packages/pybind11/include/pybind11/pybind11.h:1789:33: error: there are no arguments to 'strdup' that depend on a template parameter, so a declaration of 'strdup' must be available [-fpermissive]
   1789 |                 rec_fget->doc = PYBIND11_COMPAT_STRDUP(rec_fget->doc);
        |                                 ^~~~~~
  /usr/local/lib/python3.9/site-packages/pybind11/include/pybind11/pybind11.h:1789:33: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
  /usr/local/lib/python3.9/site-packages/pybind11/include/pybind11/pybind11.h:1797:33: error: there are no arguments to 'strdup' that depend on a template parameter, so a declaration of 'strdup' must be available [-fpermissive]
   1797 |                 rec_fset->doc = PYBIND11_COMPAT_STRDUP(rec_fset->doc);
        |                                 ^~~~~~
```

Unfortunately, the compiler backtrace only seems to [point to the `#include` line](https://github.com/matplotlib/matplotlib/blob/main/src/_c_internal_utils.cpp#L9), so I'm sure what exact code triggers this.

### Reproducible example code

_No response_

### Is this a regression? Put the last known working version here if it is.

Not a regression


Discussion / hints:
https://github.com/pybind/pybind11/blob/39e65e10d05bfdc80413a6290bdae3391f0f93d7/include/pybind11/pybind11.h#L116-L120

My best guess (with no windows box handy to test it on) is that Cygwin also requires the `_strdup` version, but does not define `_MSC_VER`, and so that condition may be able to be expanded to e.g. `#if defined(_MSC_VER) || defined(__CYGWIN__)` (got the `__CYGWIN__` based off of another part of the codebase).

The other option would be the inverse, that it _is_ getting `_strdup` and needs `strdup` (and thus `&& !`), but based on the error message not having an `_`, I think the former is more likely.
Cygwin /usr/include/string.h:
```C
#if __MISC_VISIBLE || __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 4
char 	*strdup (const char *) __malloc_like __result_use_check;
#endif
```

Cygwin /usr/include/python3.9/pyconfig.h:
```C
/* Define to activate features from IEEE Stds 1003.1-2008 */
#define _POSIX_C_SOURCE 200809L
```
Maybe a `#include <Python.h>` is missing somewhere?  Per [the python C-API documentation](https://docs.python.org/3/c-api/intro.html#include-files):
> Since Python may define some pre-processor definitions which affect the standard headers on some systems, you must include Python.h before any standard headers are included.

Given [the first pybind11 example in the documentation](https://pybind11.readthedocs.io/en/latest/basics.html#creating-bindings-for-a-simple-function) is
```C++
#include <pybind11/pybind11.h>

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

    m.def("add", &add, "A function that adds two numbers");
}
```
either the docs need to change to have `#include <Python.h>` before the pybind11 include, or `include/pybind11/pybind11.h` needs to have `#include <Python.h> on line 13 or so.

This was the cause of scipy/scipy#17925, which was fixed in scipy/scipy#18049
Chasing includes: the first include in `pybind11/pybind11.h` is `detail/class.h`, which first includes `../attr.h`, which in turn first includes `detail/common.h`
https://github.com/pybind/pybind11/blob/8b48ff878c168b51fe5ef7b8c728815b9e1a9857/include/pybind11/detail/common.h#L226-L233
are the two actual included files before `Python.h` on line 274.  This does not seem to be a problem on the pybind side.

On the other hand, matplotlib's `src/_c_internal_utils.cpp` opens with `#include <stdexcept>`.  matplotlib/matplotlib#27821 describes one way to fix this; alternately, moving the `stdexcept` include after the pybind11 include should also work.
Closed by matplotlib/matplotlib#27821?
This could do with a documentation note at least? I don't think it's mentioned anywhere that `pybind11.h` should be first (or at least that it includes `Python.h` and has the same requirements as it does).
[`doc/limitations.rst`](https://github.com/pybind/pybind11/blob/master/docs/limitations.rst) or [`doc/basics.rst`](https://github.com/pybind/pybind11/blob/master/docs/basics.rst#header-and-namespace-conventions) look like decent places for such a warning.  Do the maintainers have a preference on which place the warning goes?

Fix patch:
diff --git a/docs/advanced/cast/stl.rst b/docs/advanced/cast/stl.rst
index 03d49b2950..42b85532d8 100644
--- a/docs/advanced/cast/stl.rst
+++ b/docs/advanced/cast/stl.rst
@@ -162,7 +162,7 @@ the declaration
 
 .. code-block:: cpp
 
-    PYBIND11_MAKE_OPAQUE(std::vector<int>);
+    PYBIND11_MAKE_OPAQUE(std::vector<int>)
 
 before any binding code (e.g. invocations to ``class_::def()``, etc.). This
 macro must be specified at the top level (and outside of any namespaces), since
@@ -207,8 +207,8 @@ The following example showcases usage of :file:`pybind11/stl_bind.h`:
     // Don't forget this
     #include <pybind11/stl_bind.h>
 
-    PYBIND11_MAKE_OPAQUE(std::vector<int>);
-    PYBIND11_MAKE_OPAQUE(std::map<std::string, double>);
+    PYBIND11_MAKE_OPAQUE(std::vector<int>)
+    PYBIND11_MAKE_OPAQUE(std::map<std::string, double>)
 
     // ...
 
diff --git a/docs/advanced/smart_ptrs.rst b/docs/advanced/smart_ptrs.rst
index 6f004a5971..e2e9f3f37f 100644
--- a/docs/advanced/smart_ptrs.rst
+++ b/docs/advanced/smart_ptrs.rst
@@ -131,7 +131,7 @@ top namespace level before any binding code:
 
 .. code-block:: cpp
 
-    PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
+    PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>)
 
 The first argument of :func:`PYBIND11_DECLARE_HOLDER_TYPE` should be a
 placeholder name that is used as a template parameter of the second argument.
@@ -143,7 +143,7 @@ by default. Specify
 
 .. code-block:: cpp
 
-    PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true);
+    PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>, true)
 
 if ``SmartPtr<T>`` can always be initialized from a ``T*`` pointer without the
 risk of inconsistencies (such as multiple independent ``SmartPtr`` instances
@@ -161,7 +161,7 @@ specialized:
 .. code-block:: cpp
 
     // Always needed for custom holder types
-    PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>);
+    PYBIND11_DECLARE_HOLDER_TYPE(T, SmartPtr<T>)
 
     // Only needed if the type's `.get()` goes by another name
     namespace PYBIND11_NAMESPACE { namespace detail {
diff --git a/docs/basics.rst b/docs/basics.rst
index e9b24c7fa7..cd97c100ec 100644
--- a/docs/basics.rst
+++ b/docs/basics.rst
@@ -78,6 +78,13 @@ For brevity, all code examples assume that the following two lines are present:
 
     namespace py = pybind11;
 
+.. note::
+
+    ``pybind11/pybind11.h`` includes ``Python.h``, as such it must be the first file
+    included in any source file or header for `the same reasons as Python.h`_.
+
+.. _`the same reasons as Python.h`: https://docs.python.org/3/extending/extending.html#a-simple-example
+
 Some features may require additional headers, but those will be specified as needed.
 
 .. _simple_example:
diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h
index 4d2cc70a5b..c75e8ab212 100644
--- a/include/pybind11/detail/common.h
+++ b/include/pybind11/detail/common.h
@@ -479,6 +479,8 @@ PYBIND11_WARNING_POP
         }
 
 \endrst */
+PYBIND11_WARNING_PUSH
+PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
 #define PYBIND11_MODULE(name, variable, ...)                                                      \
     static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name)            \
         PYBIND11_MAYBE_UNUSED;                                                                    \
@@ -499,6 +501,7 @@ PYBIND11_WARNING_POP
         PYBIND11_CATCH_INIT_EXCEPTIONS                                                            \
     }                                                                                             \
     void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable))
+PYBIND11_WARNING_POP
 
 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
 


Test patch:
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 450b96dfa8..99843ee4f2 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -400,6 +400,9 @@ function(pybind11_enable_warnings target_name)
               -Wdeprecated
               -Wundef
               -Wnon-virtual-dtor)
+    if(DEFINED CMAKE_CXX_STANDARD AND NOT CMAKE_CXX_STANDARD VERSION_LESS 20)
+      target_compile_options(${target_name} PRIVATE -Wpedantic)
+    endif()
   endif()
 
   if(PYBIND11_WERROR)
diff --git a/tests/local_bindings.h b/tests/local_bindings.h
index 01d2785353..dea1813108 100644
--- a/tests/local_bindings.h
+++ b/tests/local_bindings.h
@@ -56,13 +56,13 @@ class LocalSimpleException : public std::exception {
     std::string message = "";
 };
 
-PYBIND11_MAKE_OPAQUE(LocalVec);
-PYBIND11_MAKE_OPAQUE(LocalVec2);
-PYBIND11_MAKE_OPAQUE(LocalMap);
-PYBIND11_MAKE_OPAQUE(NonLocalVec);
-// PYBIND11_MAKE_OPAQUE(NonLocalVec2); // same type as LocalVec2
-PYBIND11_MAKE_OPAQUE(NonLocalMap);
-PYBIND11_MAKE_OPAQUE(NonLocalMap2);
+PYBIND11_MAKE_OPAQUE(LocalVec)
+PYBIND11_MAKE_OPAQUE(LocalVec2)
+PYBIND11_MAKE_OPAQUE(LocalMap)
+PYBIND11_MAKE_OPAQUE(NonLocalVec)
+// PYBIND11_MAKE_OPAQUE(NonLocalVec2) // same type as LocalVec2
+PYBIND11_MAKE_OPAQUE(NonLocalMap)
+PYBIND11_MAKE_OPAQUE(NonLocalMap2)
 
 // Simple bindings (used with the above):
 template <typename T, int Adjust = 0, typename... Args>
@@ -70,7 +70,7 @@ py::class_<T> bind_local(Args &&...args) {
     return py::class_<T>(std::forward<Args>(args)...).def(py::init<int>()).def("get", [](T &i) {
         return i.i + Adjust;
     });
-};
+}
 
 // Simulate a foreign library base class (to match the example in the docs):
 namespace pets {
diff --git a/tests/test_callbacks.cpp b/tests/test_callbacks.cpp
index 2fd05dec72..e303e76567 100644
--- a/tests/test_callbacks.cpp
+++ b/tests/test_callbacks.cpp
@@ -148,7 +148,7 @@ TEST_SUBMODULE(callbacks, m) {
     m.def("dummy_function2", [](int i, int j) { return i + j; });
     m.def(
         "roundtrip",
-        [](std::function<int(int)> f, bool expect_none = false) {
+        [](std::function<int(int)> f, bool expect_none) {
             if (expect_none && f) {
                 throw std::runtime_error("Expected None to be converted to empty std::function");
             }
diff --git a/tests/test_eigen_matrix.cpp b/tests/test_eigen_matrix.cpp
index 21261bfc2f..cb8e8c6259 100644
--- a/tests/test_eigen_matrix.cpp
+++ b/tests/test_eigen_matrix.cpp
@@ -55,7 +55,7 @@ void reset_refs() {
 }
 
 // Returns element 2,1 from a matrix (used to test copy/nocopy)
-double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); };
+double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); }
 
 // Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
 // reference is referencing rows/columns correctly).
@@ -76,7 +76,7 @@ struct CustomOperatorNew {
     Eigen::Matrix4d a = Eigen::Matrix4d::Zero();
     Eigen::Matrix4d b = Eigen::Matrix4d::Identity();
 
-    EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
+    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
 };
 
 TEST_SUBMODULE(eigen_matrix, m) {
diff --git a/tests/test_opaque_types.cpp b/tests/test_opaque_types.cpp
index 154d0a8d31..da3866cd00 100644
--- a/tests/test_opaque_types.cpp
+++ b/tests/test_opaque_types.cpp
@@ -18,7 +18,7 @@
 // This also deliberately doesn't use the below StringList type alias to test
 // that MAKE_OPAQUE can handle a type containing a `,`.  (The `std::allocator`
 // bit is just the default `std::vector` allocator).
-PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
+PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>)
 
 using StringList = std::vector<std::string, std::allocator<std::string>>;
 
diff --git a/tests/test_sequences_and_iterators.cpp b/tests/test_sequences_and_iterators.cpp
index 4a1d37f4de..c997b73001 100644
--- a/tests/test_sequences_and_iterators.cpp
+++ b/tests/test_sequences_and_iterators.cpp
@@ -86,8 +86,8 @@ class NonCopyableInt {
 };
 using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;
 
-PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>);
-PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);
+PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>)
+PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>)
 
 template <typename PythonType>
 py::list test_random_access_iterator(PythonType x) {
diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp
index 496073b3c1..4ab43953f1 100644
--- a/tests/test_smart_ptr.cpp
+++ b/tests/test_smart_ptr.cpp
@@ -11,6 +11,9 @@
 #include "object.h"
 #include "pybind11_tests.h"
 
+// This breaks on PYBIND11_DECLARE_HOLDER_TYPE
+PYBIND11_WARNING_DISABLE_GCC("-Wpedantic")
+
 namespace {
 
 // This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
@@ -279,13 +282,13 @@ struct holder_helper<ref<T>> {
 } // namespace PYBIND11_NAMESPACE
 
 // Make pybind aware of the ref-counted wrapper type (s):
-PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true);
+PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true)
 // The following is not required anymore for std::shared_ptr, but it should compile without error:
-PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
-PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
-PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
-PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>);
-PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>);
+PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)
+PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>)
+PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>)
+PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>)
+PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>)
 
 TEST_SUBMODULE(smart_ptr, m) {
     // Please do not interleave `struct` and `class` definitions with bindings code,
diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp
index 6240524a09..dd93d51d0a 100644
--- a/tests/test_stl.cpp
+++ b/tests/test_stl.cpp
@@ -59,7 +59,7 @@ struct visit_helper<boost::variant> {
 } // namespace PYBIND11_NAMESPACE
 #endif
 
-PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
+PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>)
 
 /// Issue #528: templated constructor
 struct TplCtorClass {
diff --git a/tests/test_tagbased_polymorphic.cpp b/tests/test_tagbased_polymorphic.cpp
index 24b49021b4..13e5ed3198 100644
--- a/tests/test_tagbased_polymorphic.cpp
+++ b/tests/test_tagbased_polymorphic.cpp
@@ -145,4 +145,4 @@ TEST_SUBMODULE(tagbased_polymorphic, m) {
         .def(py::init<std::string>())
         .def("purr", &Panther::purr);
     m.def("create_zoo", &create_zoo);
-};
+}
diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp
index 93b136ad3c..a6164eb81d 100644
--- a/tests/test_virtual_functions.cpp
+++ b/tests/test_virtual_functions.cpp
@@ -589,4 +589,4 @@ void initialize_inherited_virtuals(py::module_ &m) {
     // Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
     m.def("test_gil", &test_gil);
     m.def("test_gil_from_thread", &test_gil_from_thread);
-};
+}