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',
)
|