4This module provides helpers for C++11+ projects using pybind11.
8Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>, All rights reserved.
10Redistribution and use in source and binary forms, with or without
11modification, are permitted provided that the following conditions are met:
131. Redistributions of source code must retain the above copyright notice, this
14 list of conditions and the following disclaimer.
162. Redistributions
in binary form must reproduce the above copyright notice,
17 this list of conditions
and the following disclaimer
in the documentation
18 and/
or other materials provided
with the distribution.
203. Neither the name of the copyright holder nor the names of its contributors
21 may be used to endorse
or promote products derived
from this software
22 without specific prior written permission.
24THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND
25ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36# IMPORTANT: If you change this file in the pybind11 repo, also review
37# setup_helpers.pyi for matching changes.
39# If you copy this file in, you don't
40# need the .pyi file; it's just an interface file for static type checkers.
54 from setuptools
import Extension
as _Extension
55 from setuptools.command.build_ext
import build_ext
as _build_ext
57 from distutils.command.build_ext
import build_ext
as _build_ext
58 from distutils.extension
import Extension
as _Extension
60import distutils.ccompiler
61import distutils.errors
63WIN = sys.platform.startswith(
"win32")
and "mingw" not in sysconfig.get_platform()
64PY2 = sys.version_info[0] < 3
65MACOS = sys.platform.startswith(
"darwin")
66STD_TMPL =
"/std:c++{}" if WIN
else "-std=c++{}"
78 Build a C++11+ Extension module with pybind11. This automatically adds the
79 recommended flags when you init the extension
and assumes C++ sources - you
80 can further modify the options yourself.
82 The customizations are:
84 * ``/EHsc``
and ``/bigobj`` on Windows
85 * ``stdlib=libc++`` on macOS
86 * ``visibility=hidden``
and ``-g0`` on Unix
88 Finally, you can set ``cxx_std`` via constructor
or afterwards to enable
89 flags
for C++ std,
and a few extra helper flags related to the C++ standard
90 level. It
is _highly_ recommended you either set this,
or use the provided
91 ``build_ext``, which will search
for the highest supported extension
for
92 you
if the ``cxx_std`` property
is not set. Do
not set the ``cxx_std``
93 property more than once,
as flags are added when you set it. Set the
94 property to
None to disable the addition of C++ standard flags.
96 If you want to add pybind11 headers manually,
for example
for an exact
97 git checkout, then set ``include_pybind11=
False``.
99 Warning: do
not use property-based access to the instance on Python 2 -
100 this
is an ugly old-style
class due to Distutils.
107 self.extra_compile_args[:0] = flags
110 self.extra_link_args[:0] = flags
115 cxx_std = kwargs.pop(
"cxx_std", 0)
117 if "language" not in kwargs:
118 kwargs[
"language"] =
"c++"
120 include_pybind11 = kwargs.pop(
"include_pybind11",
True)
124 _Extension.__init__(self, *args, **kwargs)
132 pyinc = pybind11.get_include()
134 if pyinc
not in self.include_dirs:
135 self.include_dirs.append(pyinc)
140 Pybind11Extension.cxx_std.__set__(self, cxx_std)
145 cflags += [
"/EHsc",
"/bigobj"]
147 cflags += [
"-fvisibility=hidden"]
148 env_cflags = os.environ.get(
"CFLAGS",
"")
149 env_cppflags = os.environ.get(
"CPPFLAGS",
"")
150 c_cpp_flags = shlex.split(env_cflags) + shlex.split(env_cppflags)
151 if not any(opt.startswith(
"-g")
for opt
in c_cpp_flags):
154 cflags += [
"-stdlib=libc++"]
155 ldflags += [
"-stdlib=libc++"]
162 The CXX standard level. If set, will add the required flags. If left
163 at 0, it will trigger an automatic search when pybind11's build_ext
164 is used. If
None, will have no effect. Besides just the flags, this
165 may add a register warning/error fix
for Python 2
or macos-min 10.9
174 warnings.warn(
"You cannot safely change the cxx_level after setting it!")
178 if WIN
and level == 11:
186 cflags = [STD_TMPL.format(level)]
189 if MACOS
and "MACOSX_DEPLOYMENT_TARGET" not in os.environ:
195 current_macos =
tuple(int(x)
for x
in platform.mac_ver()[0].split(
".")[:2])
196 desired_macos = (10, 9)
if level < 17
else (10, 14)
197 macos_string =
".".join(
str(x)
for x
in min(current_macos, desired_macos))
198 macosx_min =
"-mmacosx-version-min=" + macos_string
199 cflags += [macosx_min]
200 ldflags += [macosx_min]
206 cflags += [
"/wd5033"]
208 cflags += [
"-Wno-register"]
210 cflags += [
"-Wno-deprecated-register"]
217tmp_chdir_lock = threading.Lock()
218cpp_cache_lock = threading.Lock()
221@contextlib.contextmanager
223 "Prepare and enter a temporary directory, cleanup when done"
229 tmpdir = tempfile.mkdtemp()
234 shutil.rmtree(tmpdir)
240 Return the flag if a flag name
is supported on the
241 specified compiler, otherwise
None (can be used
as a boolean).
242 If multiple flags are passed,
return the first that matches.
246 fname =
"flagcheck.cpp"
247 with open(fname,
"w")
as f:
249 f.write(
"int main (int, char **) { return 0; }")
252 compiler.compile([fname], extra_postargs=[flag])
253 except distutils.errors.CompileError:
264 Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows.
270 global cpp_flag_cache
275 return cpp_flag_cache
277 levels = [17, 14, 11]
280 if has_flag(compiler, STD_TMPL.format(level)):
282 cpp_flag_cache = level
285 msg =
"Unsupported compiler -- at least C++11 support is needed!"
286 raise RuntimeError(msg)
291 Customized build_ext that allows an auto-search for the highest supported
292 C++ level
for Pybind11Extension. This
is only needed
for the auto-search
293 for now,
and is completely optional otherwise.
298 Build extensions, injecting C++ std for Pybind11Extension
if needed.
301 for ext
in self.extensions:
302 if hasattr(ext,
"_cxx_level")
and ext._cxx_level == 0:
308 _build_ext.build_extensions(self)
313 Generate Pybind11Extensions from source files directly located
in a Python
316 ``package_dir`` behaves
as in ``setuptools.setup``. If unset, the Python
317 package root parent
is determined
as the first parent directory that does
318 not contain an ``__init__.py`` file.
322 if package_dir
is None:
323 parent, _ = os.path.split(path)
324 while os.path.exists(os.path.join(parent,
"__init__.py")):
325 parent, _ = os.path.split(parent)
326 relname, _ = os.path.splitext(os.path.relpath(path, parent))
327 qualified_name = relname.replace(os.path.sep,
".")
331 for prefix, parent
in package_dir.items():
332 if path.startswith(parent):
334 relname, _ = os.path.splitext(os.path.relpath(path, parent))
335 qualified_name = relname.replace(os.path.sep,
".")
337 qualified_name = prefix +
"." + qualified_name
341 "path {} is not a child of any of the directories listed "
342 "in 'package_dir' ({})".format(path, package_dir)
349 This will recompile only if the source file changes. It does
not check
350 header files, so a more advanced function
or Ccache
is better
if you have
351 editable header files
in your package.
353 return os.stat(obj).st_mtime < os.stat(src).st_mtime
358 This is the safest but slowest choice (
and is the default) - will always
371 Make a parallel compile function. Inspired by
372 numpy.distutils.ccompiler.CCompiler_compile and cppimport.
374 This takes several arguments that allow you to customize the compile
378 Set an environment variable to control the compilation threads, like
381 0 will automatically multithread,
or 1 will only multithread
if the
384 The limit
for automatic multithreading
if non-zero
386 A function of (obj, src) that returns
True when recompile
is needed. No
387 effect
in isolated mode; use ccache instead, see
388 https://github.com/matplotlib/matplotlib/issues/1507/
399 By default, this assumes all files need to be recompiled. A smarter
400 function can be provided via needs_recompile. If the output has
not yet
401 been generated, the compile will always run,
and this function
is not
405 __slots__ = ("envvar",
"default",
"max",
"_old",
"needs_recompile")
407 def __init__(self, envvar=None, default=0, max=0, needs_recompile=no_recompile):
416 Builds a function object usable as distutils.ccompiler.CCompiler.compile.
419 def compile_function(
432 macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile(
433 output_dir, macros, include_dirs, sources, depends, extra_postargs
435 cc_args = compiler._get_cc_args(pp_opts, debug, extra_preargs)
441 if self.
envvar is not None:
444 def _single_compile(obj):
446 src, ext = build[obj]
451 compiler._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
456 import multiprocessing.synchronize
457 from multiprocessing.pool
import ThreadPool
463 threads = multiprocessing.cpu_count()
464 threads = self.
max if self.
max and self.
max < threads
else threads
465 except NotImplementedError:
469 pool = ThreadPool(threads)
473 for _
in pool.imap_unordered(_single_compile, objects):
483 return compile_function
490 self.
_old.append(distutils.ccompiler.CCompiler.compile)
494 distutils.ccompiler.CCompiler.compile = self.
_old.pop()
CCompilerMethod function(self)
def __init__(self, envvar=None, default=0, max=0, needs_recompile=no_recompile)
def __exit__(self, *args)
def __init__(self, *args, **kwargs)
def _add_ldflags(self, flags)
def _add_cflags(self, flags)
None _add_cflags(self, List[str] flags)
None _add_ldflags(self, List[str] flags)
def build_extensions(self)
bool hasattr(handle obj, handle name)
def no_recompile(obg, src)
def intree_extensions(paths, package_dir=None)
def naive_recompile(obj, src)
def auto_cpp_level(compiler)
def has_flag(compiler, flag)