2222 '.' .join (str (n ) for n in sys .version_info [:3 ]))
2323 sys .exit (error )
2424
25+ import os
2526from pathlib import Path
2627import shutil
28+ import subprocess
2729from zipfile import ZipFile
2830
2931from setuptools import setup , find_packages , Extension
4244else :
4345 del sdist .sdist .make_release_tree
4446
47+ from distutils .errors import CompileError
4548from distutils .dist import Distribution
4649
4750import setupext
6467 ]
6568
6669
70+ # From https://bugs.python.org/issue26689
71+ def has_flag (self , flagname ):
72+ """Return whether a flag name is supported on the specified compiler."""
73+ import tempfile
74+ with tempfile .NamedTemporaryFile ('w' , suffix = '.cpp' ) as f :
75+ f .write ('int main (int argc, char **argv) { return 0; }' )
76+ try :
77+ self .compile ([f .name ], extra_postargs = [flagname ])
78+ except CompileError :
79+ return False
80+ return True
81+
82+
6783class NoopTestCommand (TestCommand ):
6884 def __init__ (self , dist ):
6985 print ("Matplotlib does not support running tests with "
@@ -79,15 +95,85 @@ def finalize_options(self):
7995 ]
8096 super ().finalize_options ()
8197
98+ def add_optimization_flags (self ):
99+ """
100+ Add optional optimization flags to extension.
101+
102+ This adds flags for LTO and hidden visibility to both compiled
103+ extensions, and to the environment variables so that vendored libraries
104+ will also use them. If the compiler does not support these flags, then
105+ none are added.
106+ """
107+
108+ env = os .environ .copy ()
109+ if sys .platform == 'win32' :
110+ return env
111+
112+ cppflags = []
113+ if 'CPPFLAGS' in os .environ :
114+ cppflags .append (os .environ ['CPPFLAGS' ])
115+ cxxflags = []
116+ if 'CXXFLAGS' in os .environ :
117+ cxxflags .append (os .environ ['CXXFLAGS' ])
118+ ldflags = []
119+ if 'LDFLAGS' in os .environ :
120+ ldflags .append (os .environ ['LDFLAGS' ])
121+
122+ if has_flag (self .compiler , '-fvisibility=hidden' ):
123+ for ext in self .extensions :
124+ ext .extra_compile_args .append ('-fvisibility=hidden' )
125+ cppflags .append ('-fvisibility=hidden' )
126+ if has_flag (self .compiler , '-fvisibility-inlines-hidden' ):
127+ for ext in self .extensions :
128+ if self .compiler .detect_language (ext .sources ) != 'cpp' :
129+ continue
130+ ext .extra_compile_args .append ('-fvisibility-inlines-hidden' )
131+ cxxflags .append ('-fvisibility-inlines-hidden' )
132+ ranlib = 'RANLIB' in env
133+ if not ranlib and self .compiler .compiler_type == 'unix' :
134+ try :
135+ result = subprocess .run (self .compiler .compiler +
136+ ['--version' ],
137+ stdout = subprocess .PIPE ,
138+ stderr = subprocess .STDOUT ,
139+ universal_newlines = True )
140+ except Exception as e :
141+ pass
142+ else :
143+ version = result .stdout .lower ()
144+ if 'gcc' in version :
145+ ranlib = shutil .which ('gcc-ranlib' )
146+ elif 'clang' in version :
147+ if sys .platform == 'darwin' :
148+ ranlib = True
149+ else :
150+ ranlib = shutil .which ('llvm-ranlib' )
151+ if ranlib and has_flag (self .compiler , '-flto' ):
152+ for ext in self .extensions :
153+ ext .extra_compile_args .append ('-flto' )
154+ cppflags .append ('-flto' )
155+ ldflags .append ('-flto' )
156+ # Needed so FreeType static library doesn't lose its LTO objects.
157+ if isinstance (ranlib , str ):
158+ env ['RANLIB' ] = ranlib
159+
160+ env ['CPPFLAGS' ] = ' ' .join (cppflags )
161+ env ['CXXFLAGS' ] = ' ' .join (cxxflags )
162+ env ['LDFLAGS' ] = ' ' .join (ldflags )
163+
164+ return env
165+
82166 def build_extensions (self ):
83167 # Remove the -Wstrict-prototypes option, it's not valid for C++. Fixed
84168 # in Py3.7 as bpo-5755.
85169 try :
86170 self .compiler .compiler_so .remove ('-Wstrict-prototypes' )
87171 except (ValueError , AttributeError ):
88172 pass
173+
174+ env = self .add_optimization_flags ()
89175 for package in good_packages :
90- package .do_custom_build ()
176+ package .do_custom_build (env )
91177 return super ().build_extensions ()
92178
93179
0 commit comments