def run(self): cmd = self.reinitialize_command("build_ext") cmd.inplace = True cmd.enable_xpyb = self.enable_xpyb cmd.force = self.force cmd.ensure_finalized() cmd.run() import cairo tests_dir = os.path.join("tests", "cmodule") ext = Extension( name='tests.cmod', sources=[ os.path.join(tests_dir, "cmodule.c"), os.path.join(tests_dir, "cmodulelib.c"), ], include_dirs=[ tests_dir, cairo.get_include(), ], depends=[ os.path.join(tests_dir, "cmodulelib.h"), os.path.join(cairo.get_include(), "pycairo.h"), ], define_macros=[("PY_SSIZE_T_CLEAN", None)], ) compiler = new_compiler() customize_compiler(compiler) add_ext_cflags(ext, compiler) if compiler.compiler_type == "msvc": ext.libraries += ['cairo'] else: pkg_config_version_check('cairo', CAIRO_VERSION_REQUIRED) ext.include_dirs += pkg_config_parse('--cflags-only-I', 'cairo') ext.library_dirs += pkg_config_parse('--libs-only-L', 'cairo') ext.libraries += pkg_config_parse('--libs-only-l', 'cairo') dist = Distribution({"ext_modules": [ext]}) build_cmd = dist.get_command_obj("build") build_cmd.build_base = os.path.join(self.build_base, "pycairo_tests") build_cmd.ensure_finalized() cmd = dist.get_command_obj("build_ext") cmd.inplace = True cmd.force = self.force cmd.ensure_finalized() cmd.run()
def install(): if _mapnik_is_installed(): click.secho("Mapnik already installed!", fg='green') return environ['PYCAIRO'] = "true" with Path("libs/python-mapnik"): import subprocess #child = subprocess.call(['python', 'setup.py', 'clean']) #if child != 0: # sys.exit(-1) import cairo include_path = '--include-dirs=' + cairo.get_include() child = subprocess.call( [sys.executable, 'setup.py', 'build_ext', include_path]) if child != 0: sys.exit(-1) child = subprocess.call(['python', 'setup.py', 'install']) if child != 0: sys.exit(-1) # following seems not to work in debian 9 #dist = run_setup('setup.py') #dist.run_command('clean') #dist.run_command('install') click.secho("Mapnik installed successfully!", fg='green')
def link_pycairo_header(): """ # When pycairo is installed via pip rather than apt, it's header pycairo.h or # py3cairo.h in location like /usr/local/lib/python2.7/dist-packages/cairo/include # rather than /usr/include/pycairo for python-cairo-dev and pkg-config cannot find it. # Thus we have to add the path by hand. # See also: https://github.com/pygobject/pycairo/pull/96/files # # In addition the Python2/3 header file name differs: pycairo.h vs py3cairo.h. # The Cython code depends on one name and cannot change it dynamically. # As a hack we symlink the original header to a local file with constant name. """ import cairo source_dir = cairo.get_include() # Since Cython source depends on pycairo.h and cannot make it conditional, # let's copy the file locally to the same name for any Python as a workaround. source_file = 'py3cairo.h' if sys.version_info[0] == 3 else 'pycairo.h' source_path = os.path.join(source_dir, source_file) target_dir = 'pycairo' target_path = os.path.join(target_dir, 'pycairo.h') if not os.path.exists(target_dir): os.makedirs(target_dir) if os.path.exists(target_path): os.unlink(target_path) os.symlink(source_path, target_path) return target_dir
def find_new_api(): log.info("pycairo: new API") import cairo if cairo.version_info < min_version_info: raise DistutilsSetupError( "pycairo >= %s required, %s found." % (min_version, ".".join(map(str, cairo.version_info)))) if hasattr(cairo, "get_include"): return [cairo.get_include()] log.info("pycairo: no get_include()") return []
def find_new_api(): log.info("pycairo: new API") import cairo if cairo.version_info < min_version_info: raise DistutilsSetupError( "pycairo >= %s required, %s found." % ( min_version, ".".join(map(str, cairo.version_info)))) if hasattr(cairo, "get_include"): return [cairo.get_include()] log.info("pycairo: no get_include()") return []
def build_extensions(self): try: import importlib.metadata as importlib_metadata except ImportError: import importlib_metadata ext, = self.distribution.ext_modules ext.depends += [ "setup.py", *map(str, Path("src").glob("*.h")), *map(str, Path("src").glob("*.cpp")), ] if UNITY_BUILD: ext.sources += ["src/_unity_build.cpp"] else: ext.sources += [*map(str, Path("src").glob("*.cpp"))] ext.sources.remove("src/_unity_build.cpp") ext.language = "c++" # pybind11.get_include() is brittle (pybind #1425). pybind11_include_path = next( path for path in importlib_metadata.files("pybind11") if path.name == "pybind11.h").locate().parents[1] if not (pybind11_include_path / "pybind11/pybind11.h").exists(): # egg-install from setup_requires: # importlib-metadata thinks the headers are at # .eggs/pybind11-VER-TAG.egg/pybind11-VER.data/headers/pybind11.h # but they're actually at # .eggs/pybind11-VER-TAG.egg/pybind11.h # pybind11_include_path is # /<...>/.eggs/pybind11-VER-TAG.egg/pybind11-VER.data # so just create the proper structure there. try: is_egg = (pybind11_include_path.relative_to( Path(__file__).resolve().parent).parts[0] == ".eggs") except ValueError: # Arch Linux ships completely wrong metadata, but the headers # are in the default include paths, so just leave things as is. is_egg = False if is_egg: shutil.rmtree(pybind11_include_path / "pybind11", ignore_errors=True) for file in [*pybind11_include_path.parent.glob("**/*")]: if file.is_dir(): continue dest = (pybind11_include_path / "pybind11" / file.relative_to(pybind11_include_path.parent)) dest.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(file, dest) ext.include_dirs += [pybind11_include_path] tmp_include_dir = Path( self.get_finalized_command("build").build_base, "include") tmp_include_dir.mkdir(parents=True, exist_ok=True) ext.include_dirs += [tmp_include_dir] try: get_pkg_config(f"--atleast-version={MIN_RAQM_VERSION}", "raqm") except (FileNotFoundError, CalledProcessError): (tmp_include_dir / "raqm-version.h").write_text("") # Touch it. with urllib.request.urlopen( f"https://raw.githubusercontent.com/HOST-Oman/libraqm/" f"v{MIN_RAQM_VERSION}/src/raqm.h") as request, \ (tmp_include_dir / "raqm.h").open("wb") as file: file.write(request.read()) if sys.platform == "linux": import cairo get_pkg_config(f"--atleast-version={MIN_CAIRO_VERSION}", "cairo") ext.include_dirs += [cairo.get_include()] ext.extra_compile_args += [ "-std=c++1z", "-fvisibility=hidden", "-flto", "-Wall", "-Wextra", "-Wpedantic", *get_pkg_config("--cflags", "cairo"), ] ext.extra_link_args += ["-flto"] if MANYLINUX: ext.extra_link_args += ["-static-libgcc", "-static-libstdc++"] elif sys.platform == "darwin": import cairo get_pkg_config(f"--atleast-version={MIN_CAIRO_VERSION}", "cairo") ext.include_dirs += [cairo.get_include()] # On OSX<10.14, version-min=10.9 avoids deprecation warning wrt. # libstdc++, but assumes that the build uses non-Xcode-provided # LLVM. # On OSX>=10.14, assume that the build uses the normal toolchain. macosx_min_version = ("10.14" if LooseVersion( platform.mac_ver()[0]) >= "10.14" else "10.9") ext.extra_compile_args += [ "-std=c++1z", "-fvisibility=hidden", "-flto", f"-mmacosx-version-min={macosx_min_version}", *get_pkg_config("--cflags", "cairo"), ] ext.extra_link_args += [ # version-min needs to be repeated to avoid a warning. "-flto", f"-mmacosx-version-min={macosx_min_version}", ] elif sys.platform == "win32": # Windows conda path for FreeType. ext.include_dirs += [Path(sys.prefix, "Library/include")] ext.extra_compile_args += [ "/std:c++17", "/Zc:__cplusplus", "/experimental:preprocessor", "/EHsc", "/D_USE_MATH_DEFINES", "/wd4244", "/wd4267", ] # cf. gcc -Wconversion. ext.libraries += ["psapi", "cairo", "freetype"] # Windows conda path for FreeType -- needs to be str, not Path. ext.library_dirs += [str(Path(sys.prefix, "Library/lib"))] # Workaround https://bugs.llvm.org/show_bug.cgi?id=33222 (clang + # libstdc++ + std::variant = compilation error) and pybind11 #1604 # (-fsized-deallocation). Note that `.compiler.compiler` only exists # for UnixCCompiler. if os.name == "posix": compiler_macros = subprocess.check_output( [*self.compiler.compiler, "-dM", "-E", "-x", "c", "/dev/null"], universal_newlines=True) if "__clang__" in compiler_macros: ext.extra_compile_args += ([ "-stdlib=libc++", "-fsized-deallocation" ]) # Explicitly linking to libc++ is required to avoid picking up # the system C++ library (libstdc++ or an outdated libc++). ext.extra_link_args += ["-lc++"] super().build_extensions() if sys.platform == "win32": for dll in ["cairo.dll", "freetype.dll"]: for path in paths_from_link_libpaths(): if (path / dll).exists(): shutil.copy2(path / dll, Path(self.build_lib, "mplcairo")) break
def test_get_include(): include = cairo.get_include() assert isinstance(include, str) assert os.path.exists(include) assert os.path.isdir(include)
def build_extensions(self): import pybind11 ext, = self.distribution.ext_modules ext.depends += [ "setup.py", *map(str, Path("src").glob("*.h")), *map(str, Path("src").glob("*.cpp")), ] if UNITY_BUILD: ext.sources += ["src/_unity_build.cpp"] else: ext.sources += [*map(str, Path("src").glob("*.cpp"))] ext.sources.remove("src/_unity_build.cpp") ext.include_dirs += [pybind11.get_include()] tmp_include_dir = Path( self.get_finalized_command("build").build_base, "include") tmp_include_dir.mkdir(parents=True, exist_ok=True) # On Arch Linux, the python-pillow (Arch) package # includes a version of ``raqm.h`` that is both invalid # (https://bugs.archlinux.org/task/57492) and now outdated (it is # missing a declaration for `raqm_version_string`), but placed in an # non-overridable directory for distutils. Thus, on that distro, force # the use of a cleanly downloaded header. try: is_arch = "Arch Linux" in Path("/etc/os-release").read_text() except OSError: is_arch = False has_pkgconfig_raqm = False if not is_arch: try: has_pkgconfig_raqm = get_pkgconfig( f"--atleast-version={MIN_RAQM_VERSION}", "raqm") except (FileNotFoundError, CalledProcessError): pass if not has_pkgconfig_raqm: (tmp_include_dir / "raqm-version.h").write_text("") # Touch it. with urllib.request.urlopen( f"https://raw.githubusercontent.com/HOST-Oman/libraqm/" f"v{MIN_RAQM_VERSION}/src/raqm.h") as request, \ (tmp_include_dir / "raqm.h").open("wb") as file: file.write(request.read()) ext.include_dirs += [tmp_include_dir] if sys.platform == "linux": import cairo get_pkgconfig(f"--atleast-version={MIN_CAIRO_VERSION}", "cairo") ext.include_dirs += [cairo.get_include()] ext.extra_compile_args += [ "-std=c++1z", "-fvisibility=hidden", "-flto", "-Wall", "-Wextra", "-Wpedantic", *get_pkgconfig("--cflags", "cairo"), ] ext.extra_link_args += ["-flto"] if MANYLINUX: ext.extra_link_args += ["-static-libgcc", "-static-libstdc++"] elif sys.platform == "darwin": import cairo get_pkgconfig(f"--atleast-version={MIN_CAIRO_VERSION}", "cairo") ext.include_dirs += [cairo.get_include()] # On OSX<10.14, version-min=10.9 avoids deprecation warning wrt. # libstdc++, but assumes that the build uses non-Xcode-provided # LLVM. # On OSX>=10.14, assume that the build uses the normal toolchain. macosx_min_version = ("10.14" if LooseVersion( platform.mac_ver()[0]) >= "10.14" else "10.9") ext.extra_compile_args += [ "-std=c++1z", "-fvisibility=hidden", "-flto", f"-mmacosx-version-min={macosx_min_version}", *get_pkgconfig("--cflags", "cairo"), ] ext.extra_link_args += [ # version-min needs to be repeated to avoid a warning. "-flto", f"-mmacosx-version-min={macosx_min_version}", ] elif sys.platform == "win32": # Windows conda path for FreeType. ext.include_dirs += [Path(sys.prefix, "Library/include")] ext.extra_compile_args += [ "/std:c++17", "/Zc:__cplusplus", "/experimental:preprocessor", "/EHsc", "/D_USE_MATH_DEFINES", "/wd4244", "/wd4267", ] # cf. gcc -Wconversion. ext.libraries += ["psapi", "cairo", "freetype"] # Windows conda path for FreeType -- needs to be str, not Path. ext.library_dirs += [str(Path(sys.prefix, "Library/lib"))] # Workaround https://bugs.llvm.org/show_bug.cgi?id=33222 (clang # + libstdc++ + std::variant = compilation error). Note that # `.compiler.compiler` only exists for UnixCCompiler. if os.name == "posix": compiler_macros = subprocess.check_output( [*self.compiler.compiler, "-dM", "-E", "-x", "c", "/dev/null"], universal_newlines=True) if "__clang__" in compiler_macros: ext.extra_compile_args += ["-stdlib=libc++"] # Explicitly linking to libc++ is required to avoid picking up # the system C++ library (libstdc++ or an outdated libc++). ext.extra_link_args += ["-lc++"] super().build_extensions() if sys.platform == "win32": for dll in ["cairo.dll", "freetype.dll"]: for path in paths_from_link_libpaths(): if (path / dll).exists(): shutil.copy2(path / dll, Path(self.build_lib, "mplcairo")) break
def build_extensions(self): import pybind11 ext, = self.distribution.ext_modules ext.sources += [ "src/_feature_tests.cpp", "src/_mplcairo.cpp", "src/_os.cpp", "src/_util.cpp", "src/_pattern_cache.cpp", "src/_raqm.cpp", ] ext.depends += [ "setup.py", "src/_macros.h", "src/_mplcairo.h", "src/_os.h", "src/_util.h", "src/_pattern_cache.h", "src/_raqm.cpp", ] ext.language = "c++" tmp_include_dir = Path( self.get_finalized_command("build").build_base, "include") try: tmp_include_dir.mkdir(parents=True) except FileExistsError: # Py3.4 compat. pass ext.include_dirs += ([ tmp_include_dir, pybind11.get_include(user=True), pybind11.get_include() ]) try: get_pkg_config("--atleast-version={}".format(MIN_RAQM_VERSION), "raqm") except (FileNotFoundError, CalledProcessError): with urllib.request.urlopen( "https://raw.githubusercontent.com/HOST-Oman/libraqm/" "{}/src/raqm.h".format(RAQM_TAG)) as request, \ (tmp_include_dir / "raqm.h").open("wb") as file: file.write(request.read()) if sys.platform == "linux": import cairo get_pkg_config("--atleast-version={}".format(MIN_CAIRO_VERSION), "cairo") ext.include_dirs += [cairo.get_include()] ext.extra_compile_args += ([ "-std=c++1z", "-fvisibility=hidden", "-flto", "-Wall", "-Wextra", "-Wpedantic" ] + get_pkg_config("--cflags", "cairo")) ext.extra_link_args += (["-flto"]) if BUILD_TYPE is BuildType.Default: ext.extra_compile_args += (["-march=native"]) if BUILD_TYPE is BuildType.Manylinux: ext.extra_link_args += ([ "-static-libgcc", "-static-libstdc++" ]) elif sys.platform == "darwin": import cairo get_pkg_config("--atleast-version={}".format(MIN_CAIRO_VERSION), "cairo") ext.include_dirs += [cairo.get_include()] ext.extra_compile_args += ( # version-min=10.14 avoids deprecation warning wrt. libstdc++ & an error wrt the visit function ("has been explicitly made unavailable") [ "-std=c++1z", "-fvisibility=hidden", "-flto", "-mmacosx-version-min=10.14" ] + get_pkg_config("--cflags", "cairo")) ext.extra_link_args += ( # version-min needs to be repeated to avoid a warning. ["-flto", "-mmacosx-version-min=10.14"]) elif sys.platform == "win32": ext.include_dirs += ( # Windows conda path for FreeType. [str(Path(sys.prefix, "Library/include"))]) ext.extra_compile_args += ([ "/std:c++17", "/Zc:__cplusplus", "/EHsc", "/D_USE_MATH_DEFINES", "/wd4244", "/wd4267" ]) # cf. gcc -Wconversion. ext.libraries += (["psapi", "cairo", "freetype"]) ext.library_dirs += ( # Windows conda path for FreeType. [str(Path(sys.prefix, "Library/lib"))]) # Workaround https://bugs.llvm.org/show_bug.cgi?id=33222 (clang + # libstdc++ + std::variant = compilation error). Note that # `.compiler.compiler` only exists for UnixCCompiler. if os.name == "posix": compiler_macros = subprocess.check_output( self.compiler.compiler + ["-dM", "-E", "-x", "c", "/dev/null"], universal_newlines=True) if "__clang__" in compiler_macros: ext.extra_compile_args += ["-stdlib=libc++"] # Explicitly linking to libc++ is required to avoid picking up # the system C++ library (libstdc++ or an outdated libc++). ext.extra_link_args += ["-lc++"] super().build_extensions() if sys.platform == "win32": for dll in ["cairo.dll", "freetype.dll"]: for path in paths_from_link_libpaths(): if (path / dll).exists(): shutil.copy2(str(path / dll), str(Path(self.build_lib, "mplcairo"))) break
def finalize_options(self): if not self.distribution.have_run.get("egg_info", 1): # Just listing the MANIFEST; setup_requires are not available yet. super().finalize_options() return import cairo from pybind11.setup_helpers import Pybind11Extension self.distribution.ext_modules[:] = ext, = [ Pybind11Extension( "mplcairo._mplcairo", sources=(["src/_unity_build.cpp"] if UNITY_BUILD else sorted({*map(str, Path("src").glob("*.cpp"))} - {"src/_unity_build.cpp"})), depends=[ "setup.py", *map(str, Path("src").glob("*.h")), *map(str, Path("src").glob("*.cpp")), ], cxx_std=17, include_dirs=[cairo.get_include()], ) ] tmp_include_dir = Path( self.get_finalized_command("build").build_base, "include") tmp_include_dir.mkdir(parents=True, exist_ok=True) # On Arch Linux, the python-pillow (Arch) package # includes a version of ``raqm.h`` that is both invalid # (https://bugs.archlinux.org/task/57492) and now outdated (it is # missing a declaration for `raqm_version_string`), but placed in an # non-overridable directory for distutils. Thus, on that distro, force # the use of a cleanly downloaded header. try: is_arch = "Arch Linux" in Path("/etc/os-release").read_text() except OSError: is_arch = False if is_arch: has_pkgconfig_raqm = False else: try: get_pkgconfig(f"--atleast-version={MIN_RAQM_VERSION}", "raqm") except (FileNotFoundError, CalledProcessError): has_pkgconfig_raqm = False else: has_pkgconfig_raqm = True if has_pkgconfig_raqm: ext.extra_compile_args += get_pkgconfig("--cflags", "raqm") else: (tmp_include_dir / "raqm-version.h").write_text("") # Touch it. with urllib.request.urlopen( f"https://raw.githubusercontent.com/HOST-Oman/libraqm/" f"v{MIN_RAQM_VERSION}/src/raqm.h") as request, \ (tmp_include_dir / "raqm.h").open("wb") as file: file.write(request.read()) ext.include_dirs += [tmp_include_dir] if os.name == "posix": get_pkgconfig(f"--atleast-version={MIN_CAIRO_VERSION}", "cairo") ext.extra_compile_args += [ "-flto", "-Wall", "-Wextra", "-Wpedantic", *get_pkgconfig("--cflags", "cairo"), ] ext.extra_link_args += ["-flto"] if MANYLINUX: ext.extra_link_args += ["-static-libgcc", "-static-libstdc++"] elif os.name == "nt": # Windows conda path for FreeType. ext.include_dirs += [Path(sys.prefix, "Library/include")] ext.extra_compile_args += [ "/experimental:preprocessor", "/wd4244", "/wd4267", # cf. gcc -Wconversion. ] ext.libraries += ["psapi", "cairo", "freetype"] # Windows conda path for FreeType -- needs to be str, not Path. ext.library_dirs += [str(Path(sys.prefix, "Library/lib"))] super().finalize_options()
def include_dirs(self): # Computing include_dirs requires pycairo, # so we make it a property and import cairo lazily, # after it's installed through setup_requires import cairo return [cairo.get_include()] + self.cairomm_pkgconfig("--cflags-only-I")