1 import sys, os, os.path
2 from distutils.core import Extension
3 from distutils.errors import DistutilsOptionError
4 from versioninfo import get_base_dir, split_version
7 from Cython.Distutils import build_ext as build_pyx
8 import Cython.Compiler.Version
9 CYTHON_INSTALLED = True
11 CYTHON_INSTALLED = False
13 EXT_MODULES = ["lxml.etree", "lxml.objectify"]
15 PACKAGE_PATH = "src/lxml/"
17 if sys.version_info[0] >= 3:
18 _system_encoding = sys.getdefaultencoding()
19 if _system_encoding is None:
20 _system_encoding = "iso-8859-1" # :-)
21 def decode_input(data):
22 if isinstance(data, str):
24 return data.decode(_system_encoding)
26 def decode_input(data):
30 value = os.getenv(name)
32 value = decode_input(value)
33 if sys.platform == 'win32' and ';' in value:
34 return value.split(';')
40 def ext_modules(static_include_dirs, static_library_dirs,
41 static_cflags, static_binaries):
42 global XML2_CONFIG, XSLT_CONFIG
43 if OPTION_BUILD_LIBXML2XSLT:
44 from buildlibxml import build_libxml2xslt, get_prebuilt_libxml2xslt
45 if sys.platform.startswith('win'):
46 get_prebuilt_libxml2xslt(
47 OPTION_DOWNLOAD_DIR, static_include_dirs, static_library_dirs)
49 XML2_CONFIG, XSLT_CONFIG = build_libxml2xslt(
50 OPTION_DOWNLOAD_DIR, 'build/tmp',
51 static_include_dirs, static_library_dirs,
52 static_cflags, static_binaries,
53 libiconv_version=OPTION_LIBICONV_VERSION,
54 libxml2_version=OPTION_LIBXML2_VERSION,
55 libxslt_version=OPTION_LIBXSLT_VERSION,
56 multicore=OPTION_MULTICORE)
59 source_extension = ".pyx"
60 print("Building with Cython %s." % Cython.Compiler.Version.version)
62 from Cython.Compiler import Options
63 Options.generate_cleanup_code = 2
65 source_extension = ".c"
66 if not os.path.exists(PACKAGE_PATH + 'lxml.etree.c'):
67 print ("WARNING: Trying to build without Cython, but pre-generated "
68 "'%slxml.etree.c' does not seem to be available." % PACKAGE_PATH)
70 print ("Building without Cython.")
72 if OPTION_WITHOUT_OBJECTIFY:
73 modules = [ entry for entry in EXT_MODULES
74 if 'objectify' not in entry ]
78 lib_versions = get_library_versions()
80 print("Using build configuration of libxml2 %s and libxslt %s" %
83 print("Using build configuration of libxslt %s" %
86 _include_dirs = include_dirs(static_include_dirs)
87 _library_dirs = library_dirs(static_library_dirs)
88 _cflags = cflags(static_cflags)
89 _define_macros = define_macros()
90 _libraries = libraries()
93 message = "Building against libxml2/libxslt in "
94 if len(_library_dirs) > 1:
95 print(message + "one of the following directories:")
96 for dir in _library_dirs:
99 print(message + "the following directory: " +
102 if OPTION_AUTO_RPATH:
103 runtime_library_dirs = _library_dirs
105 runtime_library_dirs = []
107 if OPTION_SHOW_WARNINGS:
109 from Cython.Compiler import Errors
112 _cflags = ['-w'] + _cflags
115 for module in modules:
116 main_module_source = PACKAGE_PATH + module + source_extension
120 sources = [main_module_source],
121 depends = find_dependencies(module),
122 extra_compile_args = _cflags,
123 extra_objects = static_binaries,
124 define_macros = _define_macros,
125 include_dirs = _include_dirs,
126 library_dirs = _library_dirs,
127 runtime_library_dirs = runtime_library_dirs,
128 libraries = _libraries,
132 def find_dependencies(module):
133 if not CYTHON_INSTALLED:
135 package_dir = os.path.join(get_base_dir(), PACKAGE_PATH)
136 files = os.listdir(package_dir)
137 pxd_files = [ os.path.join(PACKAGE_PATH, filename) for filename in files
138 if filename.endswith('.pxd') ]
140 if 'etree' in module:
141 pxi_files = [ os.path.join(PACKAGE_PATH, filename)
142 for filename in files
143 if filename.endswith('.pxi')
144 and 'objectpath' not in filename ]
145 pxd_files = [ filename for filename in pxd_files
146 if 'etreepublic' not in filename ]
147 elif 'objectify' in module:
148 pxi_files = [ os.path.join(PACKAGE_PATH, 'objectpath.pxi') ]
152 return pxd_files + pxi_files
154 def extra_setup_args():
157 result['cmdclass'] = {'build_ext': build_pyx}
161 if sys.platform in ('win32',):
162 libs = ['libxslt', 'libexslt', 'libxml2', 'iconv']
164 libs = ['%s_a' % lib for lib in libs]
165 libs.extend(['zlib', 'WS2_32'])
169 libs = ['xslt', 'exslt', 'xml2', 'z', 'm']
172 def library_dirs(static_library_dirs):
174 if not static_library_dirs:
175 static_library_dirs = env_var('LIBRARY')
176 assert static_library_dirs, "Static build not configured, see doc/build.txt"
177 return static_library_dirs
178 # filter them from xslt-config --libs
180 possible_library_dirs = flags('libs')
181 for possible_library_dir in possible_library_dirs:
182 if possible_library_dir.startswith('-L'):
183 result.append(possible_library_dir[2:])
186 def include_dirs(static_include_dirs):
188 if not static_include_dirs:
189 static_include_dirs = env_var('INCLUDE')
190 return static_include_dirs
191 # filter them from xslt-config --cflags
193 possible_include_dirs = flags('cflags')
194 for possible_include_dir in possible_include_dirs:
195 if possible_include_dir.startswith('-I'):
196 result.append(possible_include_dir[2:])
199 def cflags(static_cflags):
205 if not static_cflags:
206 static_cflags = env_var('CFLAGS')
207 result.extend(static_cflags)
209 # anything from xslt-config --cflags that doesn't start with -I
210 possible_cflags = flags('cflags')
211 for possible_cflag in possible_cflags:
212 if not possible_cflag.startswith('-I'):
213 result.append(possible_cflag)
215 if sys.platform in ('darwin',):
217 if 'flat_namespace' in opt:
220 result.append('-flat_namespace')
226 if OPTION_WITHOUT_ASSERT:
227 macros.append(('PYREX_WITHOUT_ASSERTIONS', None))
228 if OPTION_WITHOUT_THREADING:
229 macros.append(('WITHOUT_THREADING', None))
230 if OPTION_WITH_REFNANNY:
231 macros.append(('CYTHON_REFNANNY', None))
234 _ERROR_PRINTED = False
236 def run_command(cmd, *args):
240 cmd = ' '.join((cmd,) + args)
245 sf, rf, ef = os.popen3(cmd)
248 stdout_data = rf.read()
251 p = subprocess.Popen(cmd, shell=True,
252 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
253 stdout_data, errors = p.communicate()
254 global _ERROR_PRINTED
255 if errors and not _ERROR_PRINTED:
256 _ERROR_PRINTED = True
257 print("ERROR: %s" % errors)
258 print("** make sure the development packages of libxml2 and libxslt are installed **\n")
259 return decode_input(stdout_data).strip()
261 def get_library_versions():
262 xml2_version = run_command(find_xml2_config(), "--version")
263 xslt_version = run_command(find_xslt_config(), "--version")
264 return xml2_version, xslt_version
267 xml2_flags = run_command(find_xml2_config(), "--%s" % option)
268 xslt_flags = run_command(find_xslt_config(), "--%s" % option)
270 flag_list = xml2_flags.split()
271 for flag in xslt_flags.split():
272 if flag not in flag_list:
273 flag_list.append(flag)
279 def find_xml2_config():
283 option = '--with-xml2-config='
285 if arg.startswith(option):
287 XML2_CONFIG = arg[len(option):]
290 # default: do nothing, rely only on xslt-config
291 XML2_CONFIG = os.getenv('XML2_CONFIG', '')
294 def find_xslt_config():
298 option = '--with-xslt-config='
300 if arg.startswith(option):
302 XSLT_CONFIG = arg[len(option):]
305 XSLT_CONFIG = os.getenv('XSLT_CONFIG', 'xslt-config')
310 def has_option(name):
312 sys.argv.remove('--%s' % name)
316 # allow passing all cmd line options also as environment variables
317 env_val = os.getenv(name.upper().replace('-', '_'), 'false').lower()
318 if env_val == "true":
322 def option_value(name):
323 for index, option in enumerate(sys.argv):
324 if option == '--' + name:
325 if index+1 >= len(sys.argv):
326 raise DistutilsOptionError(
327 'The option %s requires a value' % option)
328 value = sys.argv[index+1]
329 sys.argv[index:index+2] = []
331 if option.startswith('--' + name + '='):
332 value = option[len(name)+3:]
333 sys.argv[index:index+1] = []
335 env_val = os.getenv(name.upper().replace('-', '_'))
338 staticbuild = bool(os.environ.get('STATICBUILD', ''))
339 # pick up any commandline options and/or env variables
340 OPTION_WITHOUT_OBJECTIFY = has_option('without-objectify')
341 OPTION_WITHOUT_ASSERT = has_option('without-assert')
342 OPTION_WITHOUT_THREADING = has_option('without-threading')
343 OPTION_WITHOUT_CYTHON = has_option('without-cython')
344 OPTION_WITH_REFNANNY = has_option('with-refnanny')
345 if OPTION_WITHOUT_CYTHON:
346 CYTHON_INSTALLED = False
347 OPTION_STATIC = staticbuild or has_option('static')
348 OPTION_DEBUG_GCC = has_option('debug-gcc')
349 OPTION_SHOW_WARNINGS = has_option('warnings')
350 OPTION_AUTO_RPATH = has_option('auto-rpath')
351 OPTION_BUILD_LIBXML2XSLT = staticbuild or has_option('static-deps')
352 if OPTION_BUILD_LIBXML2XSLT:
354 OPTION_LIBXML2_VERSION = option_value('libxml2-version')
355 OPTION_LIBXSLT_VERSION = option_value('libxslt-version')
356 OPTION_LIBICONV_VERSION = option_value('libiconv-version')
357 OPTION_MULTICORE = option_value('multicore')
358 OPTION_DOWNLOAD_DIR = option_value('download-dir')
359 if OPTION_DOWNLOAD_DIR is None:
360 OPTION_DOWNLOAD_DIR = 'libs'