| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- import sys, os, os.path
- from distutils.core import Extension
- from distutils.errors import DistutilsOptionError
- from versioninfo import get_base_dir, split_version
- try:
- from Cython.Distutils import build_ext as build_pyx
- import Cython.Compiler.Version
- CYTHON_INSTALLED = True
- except ImportError:
- CYTHON_INSTALLED = False
- EXT_MODULES = ["lxml.etree", "lxml.objectify"]
- PACKAGE_PATH = "src%slxml%s" % (os.path.sep, os.path.sep)
- INCLUDE_PACKAGE_PATH = PACKAGE_PATH + 'includes'
- if sys.version_info[0] >= 3:
- _system_encoding = sys.getdefaultencoding()
- if _system_encoding is None:
- _system_encoding = "iso-8859-1" # :-)
- def decode_input(data):
- if isinstance(data, str):
- return data
- return data.decode(_system_encoding)
- else:
- def decode_input(data):
- return data
- def env_var(name):
- value = os.getenv(name)
- if value:
- value = decode_input(value)
- if sys.platform == 'win32' and ';' in value:
- return value.split(';')
- else:
- return value.split()
- else:
- return []
- def ext_modules(static_include_dirs, static_library_dirs,
- static_cflags, static_binaries):
- global XML2_CONFIG, XSLT_CONFIG
- if OPTION_BUILD_LIBXML2XSLT:
- from buildlibxml import build_libxml2xslt, get_prebuilt_libxml2xslt
- if sys.platform.startswith('win'):
- get_prebuilt_libxml2xslt(
- OPTION_DOWNLOAD_DIR, static_include_dirs, static_library_dirs)
- else:
- XML2_CONFIG, XSLT_CONFIG = build_libxml2xslt(
- OPTION_DOWNLOAD_DIR, 'build/tmp',
- static_include_dirs, static_library_dirs,
- static_cflags, static_binaries,
- libiconv_version=OPTION_LIBICONV_VERSION,
- libxml2_version=OPTION_LIBXML2_VERSION,
- libxslt_version=OPTION_LIBXSLT_VERSION,
- multicore=OPTION_MULTICORE)
- if OPTION_WITHOUT_OBJECTIFY:
- modules = [ entry for entry in EXT_MODULES
- if 'objectify' not in entry ]
- else:
- modules = EXT_MODULES
- c_files_exist = [ os.path.exists('%s%s.c' % (PACKAGE_PATH, module)) for module in modules ]
- if CYTHON_INSTALLED and (OPTION_WITH_CYTHON or False in c_files_exist):
- source_extension = ".pyx"
- print("Building with Cython %s." % Cython.Compiler.Version.version)
- # generate module cleanup code
- from Cython.Compiler import Options
- Options.generate_cleanup_code = 3
- Options.clear_to_none = False
- elif not OPTION_WITHOUT_CYTHON and False in c_files_exist:
- for exists, module in zip(c_files_exist, modules):
- if not exists:
- raise RuntimeError(
- "ERROR: Trying to build without Cython, but pre-generated '%s%s.c' "
- "is not available (pass --without-cython to ignore this error)." % (
- PACKAGE_PATH, module))
- else:
- if False in c_files_exist:
- for exists, module in zip(c_files_exist, modules):
- if not exists:
- print("WARNING: Trying to build without Cython, but pre-generated "
- "'%s%s.c' is not available." % (PACKAGE_PATH, module))
- source_extension = ".c"
- print("Building without Cython.")
- lib_versions = get_library_versions()
- if lib_versions[0]:
- print("Using build configuration of libxml2 %s and libxslt %s" %
- lib_versions)
- else:
- print("Using build configuration of libxslt %s" %
- lib_versions[1])
- _include_dirs = include_dirs(static_include_dirs)
- _library_dirs = library_dirs(static_library_dirs)
- _cflags = cflags(static_cflags)
- _define_macros = define_macros()
- _libraries = libraries()
- _include_dirs.append(os.path.join(get_base_dir(), INCLUDE_PACKAGE_PATH))
- if _library_dirs:
- message = "Building against libxml2/libxslt in "
- if len(_library_dirs) > 1:
- print(message + "one of the following directories:")
- for dir in _library_dirs:
- print(" " + dir)
- else:
- print(message + "the following directory: " +
- _library_dirs[0])
- if OPTION_AUTO_RPATH:
- runtime_library_dirs = _library_dirs
- else:
- runtime_library_dirs = []
- if CYTHON_INSTALLED and OPTION_SHOW_WARNINGS:
- from Cython.Compiler import Errors
- Errors.LEVEL = 0
- result = []
- for module in modules:
- main_module_source = PACKAGE_PATH + module + source_extension
- result.append(
- Extension(
- module,
- sources = [main_module_source],
- depends = find_dependencies(module),
- extra_compile_args = _cflags,
- extra_objects = static_binaries,
- define_macros = _define_macros,
- include_dirs = _include_dirs,
- library_dirs = _library_dirs,
- runtime_library_dirs = runtime_library_dirs,
- libraries = _libraries,
- ))
- if CYTHON_INSTALLED and OPTION_WITH_CYTHON_GDB:
- for ext in result:
- ext.cython_gdb = True
- if CYTHON_INSTALLED and source_extension == '.pyx':
- # build .c files right now and convert Extension() objects
- from Cython.Build import cythonize
- result = cythonize(result)
- return result
- def find_dependencies(module):
- if not CYTHON_INSTALLED:
- return []
- base_dir = get_base_dir()
- package_dir = os.path.join(base_dir, PACKAGE_PATH)
- includes_dir = os.path.join(base_dir, INCLUDE_PACKAGE_PATH)
- pxd_files = [ os.path.join(includes_dir, filename)
- for filename in os.listdir(includes_dir)
- if filename.endswith('.pxd') ]
- if 'etree' in module:
- pxi_files = [ os.path.join(PACKAGE_PATH, filename)
- for filename in os.listdir(package_dir)
- if filename.endswith('.pxi')
- and 'objectpath' not in filename ]
- pxd_files = [ filename for filename in pxd_files
- if 'etreepublic' not in filename ]
- elif 'objectify' in module:
- pxi_files = [ os.path.join(PACKAGE_PATH, 'objectpath.pxi') ]
- else:
- pxi_files = []
- return pxd_files + pxi_files
- def extra_setup_args():
- result = {}
- if CYTHON_INSTALLED:
- result['cmdclass'] = {'build_ext': build_pyx}
- return result
- def libraries():
- if sys.platform in ('win32',):
- libs = ['libxslt', 'libexslt', 'libxml2', 'iconv']
- if OPTION_STATIC:
- libs = ['%s_a' % lib for lib in libs]
- libs.extend(['zlib', 'WS2_32'])
- elif OPTION_STATIC:
- libs = ['z', 'm']
- else:
- libs = ['xslt', 'exslt', 'xml2', 'z', 'm']
- return libs
- def library_dirs(static_library_dirs):
- if OPTION_STATIC:
- if not static_library_dirs:
- static_library_dirs = env_var('LIBRARY')
- assert static_library_dirs, "Static build not configured, see doc/build.txt"
- return static_library_dirs
- # filter them from xslt-config --libs
- result = []
- possible_library_dirs = flags('libs')
- for possible_library_dir in possible_library_dirs:
- if possible_library_dir.startswith('-L'):
- result.append(possible_library_dir[2:])
- return result
- def include_dirs(static_include_dirs):
- if OPTION_STATIC:
- if not static_include_dirs:
- static_include_dirs = env_var('INCLUDE')
- return static_include_dirs
- # filter them from xslt-config --cflags
- result = []
- possible_include_dirs = flags('cflags')
- for possible_include_dir in possible_include_dirs:
- if possible_include_dir.startswith('-I'):
- result.append(possible_include_dir[2:])
- return result
- def cflags(static_cflags):
- result = []
- if not OPTION_SHOW_WARNINGS:
- result.append('-w')
- if OPTION_DEBUG_GCC:
- result.append('-g2')
- if OPTION_STATIC:
- if not static_cflags:
- static_cflags = env_var('CFLAGS')
- result.extend(static_cflags)
- else:
- # anything from xslt-config --cflags that doesn't start with -I
- possible_cflags = flags('cflags')
- for possible_cflag in possible_cflags:
- if not possible_cflag.startswith('-I'):
- result.append(possible_cflag)
- if sys.platform in ('darwin',):
- for opt in result:
- if 'flat_namespace' in opt:
- break
- else:
- result.append('-flat_namespace')
- return result
- def define_macros():
- macros = []
- if OPTION_WITHOUT_ASSERT:
- macros.append(('PYREX_WITHOUT_ASSERTIONS', None))
- if OPTION_WITHOUT_THREADING:
- macros.append(('WITHOUT_THREADING', None))
- if OPTION_WITH_REFNANNY:
- macros.append(('CYTHON_REFNANNY', None))
- if OPTION_WITH_UNICODE_STRINGS:
- macros.append(('LXML_UNICODE_STRINGS', '1'))
- return macros
- _ERROR_PRINTED = False
- def run_command(cmd, *args):
- if not cmd:
- return ''
- if args:
- cmd = ' '.join((cmd,) + args)
- try:
- import subprocess
- except ImportError:
- # Python 2.3
- sf, rf, ef = os.popen3(cmd)
- sf.close()
- errors = ef.read()
- stdout_data = rf.read()
- else:
- # Python 2.4+
- p = subprocess.Popen(cmd, shell=True,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout_data, errors = p.communicate()
- global _ERROR_PRINTED
- if errors and not _ERROR_PRINTED:
- _ERROR_PRINTED = True
- print("ERROR: %s" % errors)
- print("** make sure the development packages of libxml2 and libxslt are installed **\n")
- return decode_input(stdout_data).strip()
- def get_library_versions():
- xml2_version = run_command(find_xml2_config(), "--version")
- xslt_version = run_command(find_xslt_config(), "--version")
- return xml2_version, xslt_version
- def flags(option):
- xml2_flags = run_command(find_xml2_config(), "--%s" % option)
- xslt_flags = run_command(find_xslt_config(), "--%s" % option)
- flag_list = xml2_flags.split()
- for flag in xslt_flags.split():
- if flag not in flag_list:
- flag_list.append(flag)
- return flag_list
- XSLT_CONFIG = None
- XML2_CONFIG = None
- def find_xml2_config():
- global XML2_CONFIG
- if XML2_CONFIG:
- return XML2_CONFIG
- option = '--with-xml2-config='
- for arg in sys.argv:
- if arg.startswith(option):
- sys.argv.remove(arg)
- XML2_CONFIG = arg[len(option):]
- return XML2_CONFIG
- else:
- # default: do nothing, rely only on xslt-config
- XML2_CONFIG = os.getenv('XML2_CONFIG', '')
- return XML2_CONFIG
- def find_xslt_config():
- global XSLT_CONFIG
- if XSLT_CONFIG:
- return XSLT_CONFIG
- option = '--with-xslt-config='
- for arg in sys.argv:
- if arg.startswith(option):
- sys.argv.remove(arg)
- XSLT_CONFIG = arg[len(option):]
- return XSLT_CONFIG
- else:
- XSLT_CONFIG = os.getenv('XSLT_CONFIG', 'xslt-config')
- return XSLT_CONFIG
- ## Option handling:
- def has_option(name):
- try:
- sys.argv.remove('--%s' % name)
- return True
- except ValueError:
- pass
- # allow passing all cmd line options also as environment variables
- env_val = os.getenv(name.upper().replace('-', '_'), 'false').lower()
- if env_val == "true":
- return True
- return False
- def option_value(name):
- for index, option in enumerate(sys.argv):
- if option == '--' + name:
- if index+1 >= len(sys.argv):
- raise DistutilsOptionError(
- 'The option %s requires a value' % option)
- value = sys.argv[index+1]
- sys.argv[index:index+2] = []
- return value
- if option.startswith('--' + name + '='):
- value = option[len(name)+3:]
- sys.argv[index:index+1] = []
- return value
- env_val = os.getenv(name.upper().replace('-', '_'))
- return env_val
- staticbuild = bool(os.environ.get('STATICBUILD', ''))
- # pick up any commandline options and/or env variables
- OPTION_WITHOUT_OBJECTIFY = has_option('without-objectify')
- OPTION_WITH_UNICODE_STRINGS = has_option('with-unicode-strings')
- OPTION_WITHOUT_ASSERT = has_option('without-assert')
- OPTION_WITHOUT_THREADING = has_option('without-threading')
- OPTION_WITHOUT_CYTHON = has_option('without-cython')
- OPTION_WITH_CYTHON = has_option('with-cython')
- OPTION_WITH_CYTHON_GDB = has_option('cython-gdb')
- OPTION_WITH_REFNANNY = has_option('with-refnanny')
- if OPTION_WITHOUT_CYTHON:
- CYTHON_INSTALLED = False
- OPTION_STATIC = staticbuild or has_option('static')
- OPTION_DEBUG_GCC = has_option('debug-gcc')
- OPTION_SHOW_WARNINGS = has_option('warnings')
- OPTION_AUTO_RPATH = has_option('auto-rpath')
- OPTION_BUILD_LIBXML2XSLT = staticbuild or has_option('static-deps')
- if OPTION_BUILD_LIBXML2XSLT:
- OPTION_STATIC = True
- OPTION_LIBXML2_VERSION = option_value('libxml2-version')
- OPTION_LIBXSLT_VERSION = option_value('libxslt-version')
- OPTION_LIBICONV_VERSION = option_value('libiconv-version')
- OPTION_MULTICORE = option_value('multicore')
- OPTION_DOWNLOAD_DIR = option_value('download-dir')
- if OPTION_DOWNLOAD_DIR is None:
- OPTION_DOWNLOAD_DIR = 'libs'
|