Skip to content

Commit 97aa54f

Browse files
committed
Compile with hidden visibility always; set via cmake property rather than compiler flag
This updates the compilation to always apply hidden visibility to resolve the issues with default visibility causing problems under debug compilations. Moreover using the cmake property makes it easier for a caller to override if absolutely needed for some reason. For `pybind11_add_module` we use cmake to set the property; for the targets, we append to compilation option to non-MSVC compilers.
1 parent a859dd6 commit 97aa54f

File tree

5 files changed

+63
-31
lines changed

5 files changed

+63
-31
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ if(NOT (CMAKE_VERSION VERSION_LESS 3.0)) # CMake >= 3.0
9191
$<BUILD_INTERFACE:${PYTHON_INCLUDE_DIRS}>
9292
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
9393
target_compile_options(pybind11 INTERFACE $<BUILD_INTERFACE:${PYBIND11_CPP_STANDARD}>)
94+
if(NOT MSVC)
95+
target_compile_options(pybind11 INTERFACE -fvisibility=hidden)
96+
endif()
9497

9598
add_library(module INTERFACE)
9699
add_library(pybind11::module ALIAS module)

docs/advanced/misc.rst

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -135,22 +135,16 @@ has been executed:
135135
136136
Naturally, both methods will fail when there are cyclic dependencies.
137137

138-
Note that compiling code which has its default symbol visibility set to
139-
*hidden* (e.g. via the command line flag ``-fvisibility=hidden`` on GCC/Clang) can interfere with the
140-
ability to access types defined in another extension module. Workarounds
141-
include changing the global symbol visibility (not recommended, because it will
142-
lead unnecessarily large binaries) or manually exporting types that are
143-
accessed by multiple extension modules:
138+
Note that pybind11 code compiled with hidden-by-default symbol visibility (e.g.
139+
via the command line flag ``-fvisibility=hidden`` on GCC/Clang), which is
140+
required proper pybind11 functionality, can interfere with the ability to
141+
access types defined in another extension module. Working around this requires
142+
manually exporting types that are accessed by multiple extension modules;
143+
pybind11 provides a macro to do just this:
144144

145145
.. code-block:: cpp
146146
147-
#ifdef _WIN32
148-
# define EXPORT_TYPE __declspec(dllexport)
149-
#else
150-
# define EXPORT_TYPE __attribute__ ((visibility("default")))
151-
#endif
152-
153-
class EXPORT_TYPE Dog : public Animal {
147+
class PYBIND11_EXPORT Dog : public Animal {
154148
...
155149
};
156150

docs/compiling.rst

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,15 @@ removes this target from the default build (see CMake docs for details).
7474

7575
Since pybind11 is a template library, ``pybind11_add_module`` adds compiler
7676
flags to ensure high quality code generation without bloat arising from long
77-
symbol names and duplication of code in different translation units. The
78-
additional flags enable LTO (Link Time Optimization), set default visibility
79-
to *hidden* and strip unneeded symbols. See the :ref:`FAQ entry <faq:symhidden>`
80-
for a more detailed explanation. These optimizations are never applied in
81-
``Debug`` mode. If ``NO_EXTRAS`` is given, they will always be disabled, even
82-
in ``Release`` mode. However, this will result in code bloat and is generally
83-
not recommended.
77+
symbol names and duplication of code in different translation units. It
78+
sets default visibility to *hidden*, which is required for some pybind11
79+
features and functionality when attempting to load multiple pybind11 modules
80+
compiled under different pybind11 versions. It also adds additional flags
81+
enabling LTO (Link Time Optimization) and strip unneeded symbols. See the
82+
:ref:`FAQ entry <faq:symhidden>` for a more detailed explanation. These
83+
latter optimizations are never applied in ``Debug`` mode. If ``NO_EXTRAS`` is
84+
given, they will always be disabled, even in ``Release`` mode. However, this
85+
will result in code bloat and is generally not recommended.
8486

8587
As stated above, LTO is enabled by default. Some newer compilers also support
8688
different flavors of LTO such as `ThinLTO`_. Setting ``THIN_LTO`` will cause
@@ -181,9 +183,8 @@ to an independently constructed (through ``add_library``, not
181183
flags (i.e. this is up to you).
182184

183185
These include Link Time Optimization (``-flto`` on GCC/Clang/ICPC, ``/GL``
184-
and ``/LTCG`` on Visual Studio). Default-hidden symbols on GCC/Clang/ICPC
185-
(``-fvisibility=hidden``) and .OBJ files with many sections on Visual Studio
186-
(``/bigobj``). The :ref:`FAQ <faq:symhidden>` contains an
186+
and ``/LTCG`` on Visual Studio) and .OBJ files with many sections on Visual
187+
Studio (``/bigobj``). The :ref:`FAQ <faq:symhidden>` contains an
187188
explanation on why these are needed.
188189

189190
Embedding the Python interpreter

docs/faq.rst

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,33 @@ specifying a larger value, e.g. ``-ftemplate-depth=1024`` on GCC/Clang. The
151151
culprit is generally the generation of function signatures at compile time
152152
using C++14 template metaprogramming.
153153

154+
.. _`faq:hidden_visibility`:
155+
156+
"‘SomeClass’ declared with greater visibility than the type of its field ‘SomeClass::member’ [-Wattributes]"
157+
============================================================================================================
158+
159+
This error typically indicates that you are compiling without the required
160+
``-fvisibility`` flag. pybind11 code internally forces hidden visibility on
161+
all internal code, but if non-hidden (and thus *exported*) code attempts to
162+
include a pybind type (for example, ``py::object`` or ``py::list``) you can run
163+
into this warning.
164+
165+
To avoid it, make sure you are specifying ``-fvisibility=hidden`` when
166+
compiling pybind code.
167+
168+
As to why ``-fvisibility=hidden`` is necessary, because pybind modules could
169+
have been compiled under different versions of pybind itself, it is also
170+
important that the symbols defined in one module do not clash with the
171+
potentially-incompatible symbols defined in another. While Python extension
172+
modules are usually loaded with localized symbols (under POSIX systems
173+
typically using ``dlopen`` with the ``RTLD_LOCAL`` flag), this Python default
174+
can be changed, but even if it isn't it is not always enough to guarantee
175+
complete independence of the symbols involved when not using
176+
``-fvisibility=hidden``.
177+
178+
Additionally, ``-fvisiblity=hidden`` can deliver considerably binary size
179+
savings. (See the following section for more details).
180+
154181

155182
.. _`faq:symhidden`:
156183

@@ -192,11 +219,14 @@ world. So we'll generally only want to export symbols for those functions which
192219
are actually called from the outside.
193220

194221
This can be achieved by specifying the parameter ``-fvisibility=hidden`` to GCC
195-
and Clang, which sets the default symbol visibility to *hidden*. It's best to
196-
do this only for release builds, since the symbol names can be helpful in
197-
debugging sessions. On Visual Studio, symbols are already hidden by default, so
198-
nothing needs to be done there. Needless to say, this has a tremendous impact
199-
on the final binary size of the resulting extension library.
222+
and Clang, which sets the default symbol visibility to *hidden*, which has a
223+
tremendous impact on the final binary size of the resulting extension library.
224+
(On Visual Studio, symbols are already hidden by default, so nothing needs to
225+
be done there.)
226+
227+
In addition to decreasing binary size, ``-fvisibility=hidden`` also avoids
228+
potential serious issues when loading multiple modules and is required for
229+
proper pybind operation. See the previous FAQ entry for more details.
200230

201231
Another aspect that can require a fair bit of code are function signature
202232
descriptions. pybind11 automatically generates human-readable function

tools/pybind11Tools.cmake

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ function(pybind11_add_module target_name)
139139
set_target_properties(${target_name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}")
140140
set_target_properties(${target_name} PROPERTIES SUFFIX "${PYTHON_MODULE_EXTENSION}")
141141

142+
# -fvisibility=hidden is required to allow multiple modules compiled against
143+
# different pybind versions to work properly, and for some features (e.g.
144+
# py::module_local). We force it on everything inside the `pybind11`
145+
# namespace; also turning it on for a pybind module compilation here avoids
146+
# potential warnings or issues from having mixed hidden/non-hidden types.
147+
set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden")
148+
142149
if(WIN32 OR CYGWIN)
143150
# Link against the Python shared library on Windows
144151
target_link_libraries(${target_name} PRIVATE ${PYTHON_LIBRARIES})
@@ -175,9 +182,6 @@ function(pybind11_add_module target_name)
175182
_pybind11_add_lto_flags(${target_name} ${ARG_THIN_LTO})
176183

177184
if (NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug)
178-
# Set the default symbol visibility to hidden (very important to obtain small binaries)
179-
target_compile_options(${target_name} PRIVATE "-fvisibility=hidden")
180-
181185
# Strip unnecessary sections of the binary on Linux/Mac OS
182186
if(CMAKE_STRIP)
183187
if(APPLE)

0 commit comments

Comments
 (0)