Skip to content

Commit 4b06006

Browse files
committed
Hide symbols in compiled extension where possible.
Note that using `__attribute__((visibility("default")))` on individual functions is the recommended way to expose things (e.g., for module _init), but the way `PyMODINIT_FUNC` is defined does not allow that to be used. Instead, use `#pragma`s to toggle the visibility setting.
1 parent 8373989 commit 4b06006

File tree

12 files changed

+79
-5
lines changed

12 files changed

+79
-5
lines changed

setup.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
'.'.join(str(n) for n in sys.version_info[:3]))
2323
sys.exit(error)
2424

25+
import os
2526
from pathlib import Path
2627
import shutil
2728
from zipfile import ZipFile
@@ -42,6 +43,7 @@
4243
else:
4344
del sdist.sdist.make_release_tree
4445

46+
from distutils.errors import CompileError
4547
from distutils.dist import Distribution
4648

4749
import setupext
@@ -64,6 +66,19 @@
6466
]
6567

6668

69+
# From https://bugs.python.org/issue26689
70+
def has_flag(self, flagname):
71+
"""Return whether a flag name is supported on the specified compiler."""
72+
import tempfile
73+
with tempfile.NamedTemporaryFile('w', suffix='.cpp') as f:
74+
f.write('int main (int argc, char **argv) { return 0; }')
75+
try:
76+
self.compile([f.name], extra_postargs=[flagname])
77+
except CompileError:
78+
return False
79+
return True
80+
81+
6782
class NoopTestCommand(TestCommand):
6883
def __init__(self, dist):
6984
print("Matplotlib does not support running tests with "
@@ -79,15 +94,35 @@ def finalize_options(self):
7994
]
8095
super().finalize_options()
8196

97+
def add_optional_flags(self):
98+
env = os.environ.copy()
99+
if sys.platform == 'win32':
100+
return env
101+
102+
cppflags = []
103+
if 'CPPFLAGS' in os.environ:
104+
cppflags.append(os.environ['CPPFLAGS'])
105+
106+
if has_flag(self.compiler, '-fvisibility=hidden'):
107+
for ext in self.extensions:
108+
ext.extra_compile_args.append('-fvisibility=hidden')
109+
cppflags.append('-fvisibility=hidden')
110+
111+
env['CPPFLAGS'] = ' '.join(cppflags)
112+
113+
return env
114+
82115
def build_extensions(self):
83116
# Remove the -Wstrict-prototypes option, it's not valid for C++. Fixed
84117
# in Py3.7 as bpo-5755.
85118
try:
86119
self.compiler.compiler_so.remove('-Wstrict-prototypes')
87120
except (ValueError, AttributeError):
88121
pass
122+
123+
env = self.add_optional_flags()
89124
for package in good_packages:
90-
package.do_custom_build()
125+
package.do_custom_build(env)
91126
return super().build_extensions()
92127

93128

setupext.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ def get_extensions(self):
262262
"""
263263
return []
264264

265-
def do_custom_build(self):
265+
def do_custom_build(self, env):
266266
"""
267267
If a package needs to do extra custom things, such as building a
268268
third-party library, before building an extension, it should
@@ -538,7 +538,7 @@ def add_flags(self, ext):
538538
0, str(src_path / 'objs' / '.libs' / libfreetype))
539539
ext.define_macros.append(('FREETYPE_BUILD_TYPE', 'local'))
540540

541-
def do_custom_build(self):
541+
def do_custom_build(self, env):
542542
# We're using a system freetype
543543
if options.get('system_freetype'):
544544
return
@@ -586,8 +586,7 @@ def do_custom_build(self):
586586

587587
print(f"Building freetype in {src_path}")
588588
if sys.platform != 'win32': # compilation on non-windows
589-
env = {**os.environ,
590-
"CFLAGS": "{} -fPIC".format(os.environ.get("CFLAGS", ""))}
589+
env = {**env, "CFLAGS": "{} -fPIC".format(env.get("CFLAGS", ""))}
591590
subprocess.check_call(
592591
["./configure", "--with-zlib=no", "--with-bzip2=no",
593592
"--with-png=no", "--with-harfbuzz=no"],

src/_backend_agg_wrapper.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,8 @@ static struct PyModuleDef moduledef = {
672672
NULL
673673
};
674674

675+
#pragma GCC visibility push(default)
676+
675677
PyMODINIT_FUNC PyInit__backend_agg(void)
676678
{
677679
PyObject *m;
@@ -694,3 +696,5 @@ PyMODINIT_FUNC PyInit__backend_agg(void)
694696

695697
return m;
696698
}
699+
700+
#pragma GCC visibility pop

src/_contour_wrapper.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ static struct PyModuleDef moduledef = {
164164
NULL
165165
};
166166

167+
#pragma GCC visibility push(default)
168+
167169
PyMODINIT_FUNC PyInit__contour(void)
168170
{
169171
PyObject *m;
@@ -182,3 +184,5 @@ PyMODINIT_FUNC PyInit__contour(void)
182184

183185
return m;
184186
}
187+
188+
#pragma GCC visibility pop

src/_image_wrapper.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,8 @@ static struct PyModuleDef moduledef = {
456456
NULL
457457
};
458458

459+
#pragma GCC visibility push(default)
460+
459461
PyMODINIT_FUNC PyInit__image(void)
460462
{
461463
PyObject *m;
@@ -491,3 +493,5 @@ PyMODINIT_FUNC PyInit__image(void)
491493

492494
return m;
493495
}
496+
497+
#pragma GCC visibility pop

src/_macosx.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,6 +2531,8 @@ static void context_cleanup(const void* info)
25312531
NULL
25322532
};
25332533

2534+
#pragma GCC visibility push(default)
2535+
25342536
PyObject* PyInit__macosx(void)
25352537
{
25362538
PyObject *module;
@@ -2556,3 +2558,5 @@ static void context_cleanup(const void* info)
25562558

25572559
return module;
25582560
}
2561+
2562+
#pragma GCC visibility pop

src/_path_wrapper.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,8 @@ static struct PyModuleDef moduledef = {
853853
NULL
854854
};
855855

856+
#pragma GCC visibility push(default)
857+
856858
PyMODINIT_FUNC PyInit__path(void)
857859
{
858860
PyObject *m;
@@ -866,3 +868,5 @@ PyMODINIT_FUNC PyInit__path(void)
866868

867869
return m;
868870
}
871+
872+
#pragma GCC visibility pop

src/_tkagg.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ static PyModuleDef _tkagg_module = {
226226
PyModuleDef_HEAD_INIT, "_tkagg", "", -1, functions, NULL, NULL, NULL, NULL
227227
};
228228

229+
#pragma GCC visibility push(default)
230+
229231
PyMODINIT_FUNC PyInit__tkagg(void)
230232
{
231233
load_tkinter_funcs();
@@ -240,3 +242,5 @@ PyMODINIT_FUNC PyInit__tkagg(void)
240242
}
241243
return PyModule_Create(&_tkagg_module);
242244
}
245+
246+
#pragma GCC visibility pop

src/_ttconv.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ static PyModuleDef ttconv_module = {
276276
NULL, NULL, NULL, NULL
277277
};
278278

279+
#pragma GCC visibility push(default)
280+
279281
PyMODINIT_FUNC
280282
PyInit_ttconv(void)
281283
{
@@ -285,3 +287,5 @@ PyInit_ttconv(void)
285287

286288
return m;
287289
}
290+
291+
#pragma GCC visibility pop

src/ft2font_wrapper.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,8 @@ static struct PyModuleDef moduledef = {
16321632
NULL
16331633
};
16341634

1635+
#pragma GCC visibility push(default)
1636+
16351637
PyMODINIT_FUNC PyInit_ft2font(void)
16361638
{
16371639
PyObject *m;
@@ -1722,3 +1724,5 @@ PyMODINIT_FUNC PyInit_ft2font(void)
17221724

17231725
return m;
17241726
}
1727+
1728+
#pragma GCC visibility pop

0 commit comments

Comments
 (0)