Imported Upstream version 2.3.5
[platform/upstream/python-lxml.git] / setupinfo.py
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
5
6 try:
7     from Cython.Distutils import build_ext as build_pyx
8     import Cython.Compiler.Version
9     CYTHON_INSTALLED = True
10 except ImportError:
11     CYTHON_INSTALLED = False
12
13 EXT_MODULES = ["lxml.etree", "lxml.objectify"]
14
15 PACKAGE_PATH = "src/lxml/"
16
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):
23             return data
24         return data.decode(_system_encoding)
25 else:
26     def decode_input(data):
27         return data
28
29 def env_var(name):
30     value = os.getenv(name)
31     if value:
32         value = decode_input(value)
33         if sys.platform == 'win32' and ';' in value:
34             return value.split(';')
35         else:
36             return value.split()
37     else:
38         return []
39
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)
48         else:
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)
57
58     if CYTHON_INSTALLED:
59         source_extension = ".pyx"
60         print("Building with Cython %s." % Cython.Compiler.Version.version)
61
62         from Cython.Compiler import Options
63         Options.generate_cleanup_code = 2
64     else:
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)
69         else:
70             print ("Building without Cython.")
71
72     if OPTION_WITHOUT_OBJECTIFY:
73         modules = [ entry for entry in EXT_MODULES
74                     if 'objectify' not in entry ]
75     else:
76         modules = EXT_MODULES
77
78     lib_versions = get_library_versions()
79     if lib_versions[0]:
80         print("Using build configuration of libxml2 %s and libxslt %s" % 
81               lib_versions)
82     else:
83         print("Using build configuration of libxslt %s" % 
84               lib_versions[1])
85
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()
91
92     if _library_dirs:
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:
97                 print("  " + dir)
98         else:
99             print(message + "the following directory: " +
100                   _library_dirs[0])
101
102     if OPTION_AUTO_RPATH:
103         runtime_library_dirs = _library_dirs
104     else:
105         runtime_library_dirs = []
106
107     if OPTION_SHOW_WARNINGS:
108         if CYTHON_INSTALLED:
109             from Cython.Compiler import Errors
110             Errors.LEVEL = 0
111     else:
112         _cflags = ['-w'] + _cflags
113
114     result = []
115     for module in modules:
116         main_module_source = PACKAGE_PATH + module + source_extension
117         result.append(
118             Extension(
119             module,
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,
129             ))
130     return result
131
132 def find_dependencies(module):
133     if not CYTHON_INSTALLED:
134         return []
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') ]
139
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') ]
149     else:
150         pxi_files = []
151
152     return pxd_files + pxi_files
153
154 def extra_setup_args():
155     result = {}
156     if CYTHON_INSTALLED:
157         result['cmdclass'] = {'build_ext': build_pyx}
158     return result
159
160 def libraries():
161     if sys.platform in ('win32',):
162         libs = ['libxslt', 'libexslt', 'libxml2', 'iconv']
163         if OPTION_STATIC:
164             libs = ['%s_a' % lib for lib in libs]
165         libs.extend(['zlib', 'WS2_32'])
166     elif OPTION_STATIC:
167         libs = ['z', 'm']
168     else:
169         libs = ['xslt', 'exslt', 'xml2', 'z', 'm']
170     return libs
171
172 def library_dirs(static_library_dirs):
173     if OPTION_STATIC:
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
179     result = []
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:])
184     return result
185
186 def include_dirs(static_include_dirs):
187     if OPTION_STATIC:
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
192     result = []
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:])
197     return result
198
199 def cflags(static_cflags):
200     result = []
201     if OPTION_DEBUG_GCC:
202         result.append('-g2')
203
204     if OPTION_STATIC:
205         if not static_cflags:
206             static_cflags = env_var('CFLAGS')
207         result.extend(static_cflags)
208     else:
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)
214
215     if sys.platform in ('darwin',):
216         for opt in result:
217             if 'flat_namespace' in opt:
218                 break
219         else:
220             result.append('-flat_namespace')
221
222     return result
223
224 def define_macros():
225     macros = []
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))
232     return macros
233
234 _ERROR_PRINTED = False
235
236 def run_command(cmd, *args):
237     if not cmd:
238         return ''
239     if args:
240         cmd = ' '.join((cmd,) + args)
241     try:
242         import subprocess
243     except ImportError:
244         # Python 2.3
245         sf, rf, ef = os.popen3(cmd)
246         sf.close()
247         errors = ef.read()
248         stdout_data = rf.read()
249     else:
250         # Python 2.4+
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()
260
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
265
266 def flags(option):
267     xml2_flags = run_command(find_xml2_config(), "--%s" % option)
268     xslt_flags = run_command(find_xslt_config(), "--%s" % option)
269
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)
274     return flag_list
275
276 XSLT_CONFIG = None
277 XML2_CONFIG = None
278
279 def find_xml2_config():
280     global XML2_CONFIG
281     if XML2_CONFIG:
282         return XML2_CONFIG
283     option = '--with-xml2-config='
284     for arg in sys.argv:
285         if arg.startswith(option):
286             sys.argv.remove(arg)
287             XML2_CONFIG = arg[len(option):]
288             return XML2_CONFIG
289     else:
290         # default: do nothing, rely only on xslt-config
291         XML2_CONFIG = os.getenv('XML2_CONFIG', '')
292     return XML2_CONFIG
293
294 def find_xslt_config():
295     global XSLT_CONFIG
296     if XSLT_CONFIG:
297         return XSLT_CONFIG
298     option = '--with-xslt-config='
299     for arg in sys.argv:
300         if arg.startswith(option):
301             sys.argv.remove(arg)
302             XSLT_CONFIG = arg[len(option):]
303             return XSLT_CONFIG
304     else:
305         XSLT_CONFIG = os.getenv('XSLT_CONFIG', 'xslt-config')
306     return XSLT_CONFIG
307
308 ## Option handling:
309
310 def has_option(name):
311     try:
312         sys.argv.remove('--%s' % name)
313         return True
314     except ValueError:
315         pass
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":
319         return True
320     return False
321
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] = []
330             return value
331         if option.startswith('--' + name + '='):
332             value = option[len(name)+3:]
333             sys.argv[index:index+1] = []
334             return value
335     env_val = os.getenv(name.upper().replace('-', '_'))
336     return env_val
337
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:
353     OPTION_STATIC = True
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'