Пример #1
0
    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()
Пример #2
0
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')
Пример #3
0
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
Пример #4
0
    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 []
Пример #5
0
    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 []
Пример #6
0
    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
Пример #7
0
def test_get_include():
    include = cairo.get_include()
    assert isinstance(include, str)
    assert os.path.exists(include)
    assert os.path.isdir(include)
Пример #8
0
    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
Пример #9
0
    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
Пример #10
0
    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()
Пример #11
0
 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")