File: setup.py

package info (click to toggle)
pycares 5.0.0-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,956 kB
  • sloc: ansic: 30,744; python: 3,003; makefile: 218; sh: 143
file content (177 lines) | stat: -rwxr-xr-x 6,874 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import shutil
import subprocess
import sys

from setuptools import setup
from setuptools.command.build_ext import build_ext


use_system_lib = bool(int(os.environ.get('PYCARES_USE_SYSTEM_LIB', 0)))

class cares_build_ext(build_ext):
    def add_include_dir(self, dir, force=False):
        if use_system_lib and not force:
            return
        dirs = self.compiler.include_dirs
        if dir not in dirs:
            dirs.insert(0, dir)
        self.compiler.set_include_dirs(dirs)

    def build_extensions(self):
        # Use system c-ares library if requested
        if use_system_lib:
            self.compiler.add_library('cares')
            build_ext.build_extensions(self)
            return

        # Check for CMake availability
        cmake_cmd = shutil.which('cmake')
        if not cmake_cmd:
            raise RuntimeError(
                "CMake >= 3.5 is required to build pycares.\n"
                "Please install CMake from https://cmake.org/ or through your system package manager:\n"
                "  Ubuntu/Debian: apt-get install cmake\n"
                "  RHEL/CentOS/Fedora: dnf install cmake\n"
                "  macOS: brew install cmake\n"
                "  Windows: Download from https://cmake.org/download/\n"
                "  FreeBSD: pkg install cmake"
            )

        # Set up directories
        cares_dir = os.path.join('deps', 'c-ares')
        build_temp = os.path.abspath(os.path.join(self.build_temp, 'c-ares-build'))
        install_dir = os.path.abspath(os.path.join(self.build_temp, 'c-ares-install'))
        os.makedirs(build_temp, exist_ok=True)
        os.makedirs(install_dir, exist_ok=True)

        # Configure c-ares with CMake
        cmake_args = [
            '-DCARES_STATIC=ON',
            '-DCARES_SHARED=OFF',
            '-DCARES_BUILD_TOOLS=OFF',
            '-DCARES_BUILD_TESTS=OFF',
            '-DCARES_INSTALL=ON',
            '-DCARES_THREADS=ON',
            '-DCARES_STATIC_PIC=ON',  # Position independent code for static lib
            '-DCMAKE_BUILD_TYPE=Release',
            '-DCMAKE_CONFIGURATION_TYPES=Release',  # For multi-config generators (VS, Xcode)
            f'-DCMAKE_INSTALL_PREFIX={install_dir}',
        ]

        # Platform-specific configuration
        if sys.platform == 'darwin':
            # Set minimum macOS deployment target
            cmake_args.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12')
        elif sys.platform == 'win32':
            # Windows-specific handling
            if 'mingw' in self.compiler.compiler_type:
                cmake_args.extend(['-G', 'MinGW Makefiles'])

            # Handle static runtime if needed
            if hasattr(self, 'compiler') and hasattr(self.compiler, 'compile_options'):
                for flag in self.compiler.compile_options:
                    if '/MT' in str(flag):
                        cmake_args.append('-DCARES_MSVC_STATIC_RUNTIME=ON')
                        break

        # Run CMake configure
        print(f"Configuring c-ares with CMake in {build_temp}")
        subprocess.check_call(
            [cmake_cmd, os.path.abspath(cares_dir)] + cmake_args,
            cwd=build_temp
        )

        # Build c-ares
        print("Building c-ares...")
        build_args = ['--build', '.', '--config', 'Release']

        # Use parallel build if available
        if sys.platform != 'win32':
            try:
                import multiprocessing
                build_args.extend(['--parallel', str(multiprocessing.cpu_count())])
            except (ImportError, NotImplementedError):
                pass

        subprocess.check_call([cmake_cmd] + build_args, cwd=build_temp)

        # Install c-ares to temp directory
        print(f"Installing c-ares to {install_dir}")
        install_args = ['--install', '.', '--config', 'Release']
        subprocess.check_call([cmake_cmd] + install_args, cwd=build_temp)

        # Find the installed library
        if sys.platform == 'win32':
            # Windows libraries
            possible_paths = [
                os.path.join(install_dir, 'lib', 'cares.lib'),
                os.path.join(install_dir, 'lib', 'cares_static.lib'),
                os.path.join(install_dir, 'lib', 'libcares.a'),  # MinGW
            ]
        else:
            possible_paths = [
                os.path.join(install_dir, 'lib', 'libcares.a'),
                os.path.join(install_dir, 'lib64', 'libcares.a'),
            ]

        lib_path = None
        for path in possible_paths:
            if os.path.exists(path):
                lib_path = path
                break

        if not lib_path:
            raise RuntimeError(
                f"Could not find installed c-ares library in {install_dir}.\n"
                f"Checked: {', '.join(possible_paths)}"
            )

        print(f"Found c-ares library at: {lib_path}")

        # Set up include directories from the install directory
        # This includes all headers (original + generated like ares_build.h, ares_config.h)
        self.add_include_dir(os.path.join(install_dir, 'include'), force=True)
        # Also need internal headers from src/lib for some definitions
        self.add_include_dir(os.path.join(cares_dir, 'src', 'lib'), force=True)

        # Set up the extension to link against the static library
        self.extensions[0].extra_objects = [lib_path]

        # Add platform-specific libraries and macros
        if sys.platform == 'win32':
            self.compiler.add_library('ws2_32')
            self.compiler.add_library('advapi32')
            self.compiler.add_library('iphlpapi')
            self.compiler.define_macro('CARES_STATICLIB', 1)
        else:
            self.compiler.define_macro('HAVE_CONFIG_H', 1)
            self.compiler.define_macro('_LARGEFILE_SOURCE', 1)
            self.compiler.define_macro('_FILE_OFFSET_BITS', 64)
            self.compiler.define_macro('CARES_STATICLIB', 1)

            if sys.platform.startswith('linux'):
                self.compiler.add_library('rt')
            elif sys.platform == 'darwin':
                self.compiler.define_macro('_DARWIN_USE_64_BIT_INODE', 1)
            elif sys.platform.startswith('freebsd') or sys.platform.startswith('dragonfly'):
                self.compiler.add_library('kvm')
            elif sys.platform.startswith('sunos'):
                self.compiler.add_library('socket')
                self.compiler.add_library('nsl')
                self.compiler.add_library('kstat')

        # Build the Python extension
        build_ext.build_extensions(self)


# Most configuration has been moved to pyproject.toml
# Only build-related configuration remains here
setup(
    cmdclass={'build_ext': cares_build_ext},
    cffi_modules=['src/_cffi_src/build_cares.py:ffi'],
    ext_package='pycares',
)