# # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # # gen_win_dependencies.py # # base class for generating windows projects, containing the # dependency locator code shared between the test runner and # the make file generators # import os import sys import fnmatch import re import subprocess import string if sys.version_info[0] >= 3: # Python >=3.0 from io import StringIO else: # Python <3.0 try: from cStringIO import StringIO except ImportError: from StringIO import StringIO import gen_base import ezt class SVNCommonLibrary: def __init__(self, name, include_dirs, lib_dir, lib_name, version=None, debug_lib_dir=None, debug_lib_name=None, dll_dir=None, dll_name=None, debug_dll_dir=None, debug_dll_name=None, defines=[], forced_includes=[], extra_bin=[]): self.name = name if include_dirs: self.include_dirs = include_dirs if isinstance(include_dirs, list) \ else [include_dirs] else: self.include_dirs = [] self.defines = defines if not defines or isinstance(defines, list) else [defines] self.lib_dir = lib_dir self.lib_name = lib_name self.version = version self.dll_dir = dll_dir self.dll_name = dll_name self.forced_includes = forced_includes if not forced_includes \ or isinstance(forced_includes, list) \ else [forced_includes] if debug_lib_dir: self.debug_lib_dir = debug_lib_dir else: self.debug_lib_dir = lib_dir if debug_lib_name: self.debug_lib_name = debug_lib_name else: self.debug_lib_name = lib_name if debug_dll_dir: self.debug_dll_dir = debug_dll_dir else: self.debug_dll_dir = dll_dir if debug_dll_name: self.debug_dll_name = debug_dll_name else: self.debug_dll_name = dll_name self.extra_bin = extra_bin class GenDependenciesBase(gen_base.GeneratorBase): """This intermediate base class exists to be instantiated by win-tests.py, in order to obtain information from build.conf and library paths without actually doing any generation.""" _extension_map = { ('exe', 'target'): '.exe', ('exe', 'object'): '.obj', ('lib', 'target'): '.dll', ('lib', 'object'): '.obj', ('pyd', 'target'): '.pyd', ('pyd', 'object'): '.obj', ('so', 'target'): '.so', ('so', 'object'): '.obj', } _libraries = {} # Dict of SVNCommonLibrary instances of found libraries _optional_libraries = [ # List of optional libraries to suppress warnings 'db', 'intl', 'serf', 'sasl', 'swig', 'perl', 'python', 'ruby', 'java_sdk', 'openssl', 'apr_memcache', # So optional, we don't even have any code to detect them on Windows 'magic', ] # When build.conf contains a 'when = SOMETHING' where SOMETHING is not in # this list, then the project is not generated on Windows. _windows_when = [ 'INSTALL_APACHE_MODS', # not 'SVN_USE_GMOCK', ] def parse_options(self, options): self.apr_path = 'apr' self.apr_util_path = 'apr-util' self.apr_iconv_path = 'apr-iconv' self.serf_path = None self.bdb_path = None self.httpd_path = None self.libintl_path = None self.zlib_path = 'zlib' self.openssl_path = None self.jdk_path = None self.junit_path = None self.swig_path = None self.vs_version = '2002' self.sln_version = '7.00' self.vcproj_version = '7.00' self.vcproj_extension = '.vcproj' self.sqlite_path = 'sqlite-amalgamation' self.skip_sections = { 'mod_dav_svn': None, 'mod_authz_svn': None, 'mod_dontdothat' : None, 'libsvn_auth_kwallet': None, 'libsvn_auth_gnome_keyring': None } # Instrumentation options self.disable_shared = None self.static_apr = None self.static_openssl = None self.instrument_apr_pools = None self.instrument_purify_quantify = None self.sasl_path = None self.cpp_defines = [] # NLS options self.enable_nls = None for opt, val in options: if opt == '--with-berkeley-db': self.bdb_path = val elif opt == '--with-apr': self.apr_path = val elif opt == '--with-apr-util': self.apr_util_path = val elif opt == '--with-apr-iconv': self.apr_iconv_path = val elif opt == '--with-serf': self.serf_path = val elif opt == '--with-httpd': self.httpd_path = val del self.skip_sections['mod_dav_svn'] del self.skip_sections['mod_authz_svn'] del self.skip_sections['mod_dontdothat'] elif opt == '--with-libintl': self.libintl_path = val self.enable_nls = 1 elif opt == '--with-jdk': self.jdk_path = val elif opt == '--with-junit': self.junit_path = val elif opt == '--with-zlib': self.zlib_path = val elif opt == '--with-swig': self.swig_path = val elif opt == '--with-sqlite': self.sqlite_path = val elif opt == '--with-sasl': self.sasl_path = val elif opt == '--with-openssl': self.openssl_path = val elif opt == '--enable-purify': self.instrument_purify_quantify = 1 self.instrument_apr_pools = 1 elif opt == '--enable-quantify': self.instrument_purify_quantify = 1 elif opt == '--enable-pool-debug': self.instrument_apr_pools = 1 elif opt == '--enable-nls': self.enable_nls = 1 elif opt == '--disable-shared': self.disable_shared = 1 elif opt == '--with-static-apr': self.static_apr = 1 elif opt == '--with-static-openssl': self.static_openssl = 1 elif opt == '-D': self.cpp_defines.append(val) elif opt == '--vsnet-version': if val == '2002' or re.match('^7(\.\d+)?$', val): self.vs_version = '2002' self.sln_version = '7.00' self.vcproj_version = '7.00' self.vcproj_extension = '.vcproj' elif val == '2003' or re.match('^8(\.\d+)?$', val): self.vs_version = '2003' self.sln_version = '8.00' self.vcproj_version = '7.10' self.vcproj_extension = '.vcproj' elif val == '2005' or re.match('^9(\.\d+)?$', val): self.vs_version = '2005' self.sln_version = '9.00' self.vcproj_version = '8.00' self.vcproj_extension = '.vcproj' elif val == '2008' or re.match('^10(\.\d+)?$', val): self.vs_version = '2008' self.sln_version = '10.00' self.vcproj_version = '9.00' self.vcproj_extension = '.vcproj' elif val == '2010': self.vs_version = '2010' self.sln_version = '11.00' self.vcproj_version = '10.0' self.vcproj_extension = '.vcxproj' elif val == '2012' or val == '11': self.vs_version = '2012' self.sln_version = '12.00' self.vcproj_version = '11.0' self.vcproj_extension = '.vcxproj' elif val == '2013' or val == '12': self.vs_version = '2013' self.sln_version = '12.00' self.vcproj_version = '12.0' self.vcproj_extension = '.vcxproj' elif val == '2015' or val == '14': self.vs_version = '2015' self.sln_version = '12.00' self.vcproj_version = '14.0' self.vcproj_extension = '.vcxproj' elif re.match('^20\d+$', val): print('WARNING: Unknown VS.NET version "%s",' ' assuming VS2012. Your VS can probably upgrade') self.vs_version = '2012' self.sln_version = '12.00' self.vcproj_version = '11.0' self.vcproj_extension = '.vcxproj' elif re.match('^1\d+$', val): self.vs_version = val self.sln_version = '12.00' self.vcproj_version = val + '.0' self.vcproj_extension = '.vcxproj' else: print('WARNING: Unknown VS.NET version "%s",' ' assuming "%s"\n' % (val, '7.00')) def __init__(self, fname, verfname, options, find_libs=True): # parse (and save) the options that were passed to us self.parse_options(options) # Initialize parent gen_base.GeneratorBase.__init__(self, fname, verfname, options) # These files will be excluded from the build when they're not # explicitly listed as project sources. self._excluded_from_build = frozenset(self.private_includes + self.private_built_includes) if find_libs: self.find_libraries(False) def find_libraries(self, show_warnings): "find required and optional libraries" # Required dependencies self._find_apr() self._find_apr_util_etc() self._find_zlib() self._find_sqlite(show_warnings) # Optional dependencies self._find_httpd(show_warnings) self._find_bdb(show_warnings) self._find_openssl(show_warnings) self._find_serf(show_warnings) self._find_sasl(show_warnings) self._find_libintl(show_warnings) self._find_jdk(show_warnings) # Swig (optional) dependencies if self._find_swig(show_warnings): self._find_perl(show_warnings) self._find_python(show_warnings) self._find_ruby(show_warnings) def _find_apr(self): "Find the APR library and version" minimal_apr_version = (1, 3, 0) if not self.apr_path: sys.stderr.write("ERROR: Use '--with-apr' option to configure APR " + \ "location.\n") sys.exit(1) inc_base = os.path.join(self.apr_path, 'include') if os.path.isfile(os.path.join(inc_base, 'apr-1', 'apr_version.h')): inc_path = os.path.join(inc_base, 'apr-1') elif os.path.isfile(os.path.join(inc_base, 'apr_version.h')): inc_path = inc_base else: sys.stderr.write("ERROR: 'apr_version' not found.\n") sys.stderr.write("Use '--with-apr' option to configure APR location.\n") sys.exit(1) version_file_path = os.path.join(inc_path, 'apr_version.h') txt = open(version_file_path).read() vermatch = re.search(r'^\s*#define\s+APR_MAJOR_VERSION\s+(\d+)', txt, re.M) major = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+APR_MINOR_VERSION\s+(\d+)', txt, re.M) minor = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+APR_PATCH_VERSION\s+(\d+)', txt, re.M) patch = int(vermatch.group(1)) version = (major, minor, patch) self.apr_version = apr_version = '%d.%d.%d' % version if version < minimal_apr_version: sys.stderr.write("ERROR: apr %s or higher is required " "(%s found)\n" % ( '.'.join(str(v) for v in minimal_apr_version), self.apr_version)) sys.exit(1) suffix = '' if major > 0: suffix = '-%d' % major defines = [] if self.static_apr: lib_name = 'apr%s.lib' % suffix lib_dir = os.path.join(self.apr_path, 'LibR') dll_dir = None debug_dll_dir = None dll_name = None defines.extend(["APR_DECLARE_STATIC"]) if not os.path.isdir(lib_dir) and \ os.path.isfile(os.path.join(self.apr_path, 'lib', lib_name)): # Installed APR instead of APR-Source lib_dir = os.path.join(self.apr_path, 'lib') debug_lib_dir = None else: debug_lib_dir = os.path.join(self.apr_path, 'LibD') else: lib_name = 'libapr%s.lib' % suffix if os.path.isfile(os.path.join(self.apr_path, 'lib', lib_name)): # Installed APR instead of APR-Source lib_dir = os.path.join(self.apr_path, 'lib') debug_lib_dir = None else: lib_dir = os.path.join(self.apr_path, 'Release') if os.path.isfile(os.path.join(self.apr_path, 'Debug', lib_name)): debug_lib_dir = os.path.join(self.apr_path, 'Debug') else: debug_lib_dir = None dll_name = 'libapr%s.dll' % suffix if os.path.isfile(os.path.join(lib_dir, dll_name)): dll_dir = lib_dir debug_dll_dir = debug_lib_dir else: dll_dir = os.path.join(self.apr_path, 'bin') debug_dll_dir = None extra_bin = [] if dll_dir: bin_files = os.listdir(dll_dir) if debug_dll_dir and os.path.isdir(debug_dll_dir): debug_bin_files = os.listdir(debug_dll_dir) else: debug_bin_files = bin_files for bin in bin_files: if bin in debug_bin_files: if re.match('^(lib)?apr[-_].*' + suffix + '(d)?.dll$', bin): extra_bin.append(bin) self._libraries['apr'] = SVNCommonLibrary('apr', inc_path, lib_dir, lib_name, apr_version, debug_lib_dir=debug_lib_dir, dll_dir=dll_dir, dll_name=dll_name, debug_dll_dir=debug_dll_dir, defines=defines, extra_bin=extra_bin) def _find_apr_util_etc(self): "Find the APR-util library and version" minimal_aprutil_version = (1, 3, 0) inc_base = os.path.join(self.apr_util_path, 'include') if os.path.isfile(os.path.join(inc_base, 'apr-1', 'apu_version.h')): inc_path = os.path.join(inc_base, 'apr-1') elif os.path.isfile(os.path.join(inc_base, 'apu_version.h')): inc_path = inc_base else: sys.stderr.write("ERROR: 'apu_version' not found.\n") sys.stderr.write("Use '--with-apr-util' option to configure APR-Util location.\n") sys.exit(1) version_file_path = os.path.join(inc_path, 'apu_version.h') txt = open(version_file_path).read() vermatch = re.search(r'^\s*#define\s+APU_MAJOR_VERSION\s+(\d+)', txt, re.M) major = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+APU_MINOR_VERSION\s+(\d+)', txt, re.M) minor = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+APU_PATCH_VERSION\s+(\d+)', txt, re.M) patch = int(vermatch.group(1)) version = (major, minor, patch) self.aprutil_version = aprutil_version = '%d.%d.%d' % version if version < minimal_aprutil_version: sys.stderr.write("ERROR: apr-util %s or higher is required " "(%s found)\n" % ( '.'.join(str(v) for v in minimal_aprutil_version), aprutil_version)) sys.exit(1) suffix = '' if major > 0: suffix = '-%d' % major defines = [] if self.static_apr: lib_name = 'aprutil%s.lib' % suffix lib_dir = os.path.join(self.apr_util_path, 'LibR') dll_dir = None debug_dll_dir = None dll_name = None defines.extend(["APU_DECLARE_STATIC"]) if not os.path.isdir(lib_dir) and \ os.path.isfile(os.path.join(self.apr_util_path, 'lib', lib_name)): # Installed APR-Util instead of APR-Util-Source lib_dir = os.path.join(self.apr_util_path, 'lib') debug_lib_dir = None else: debug_lib_dir = os.path.join(self.apr_util_path, 'LibD') else: lib_name = 'libaprutil%s.lib' % suffix lib_dir = os.path.join(self.apr_util_path, 'Release') if not os.path.isdir(lib_dir) and \ os.path.isfile(os.path.join(self.apr_util_path, 'lib', lib_name)): # Installed APR-Util instead of APR-Util-Source lib_dir = os.path.join(self.apr_util_path, 'lib') debug_lib_dir = lib_dir else: debug_lib_dir = os.path.join(self.apr_util_path, 'Debug') dll_name = 'libaprutil%s.dll' % suffix if os.path.isfile(os.path.join(lib_dir, dll_name)): dll_dir = lib_dir debug_dll_dir = debug_lib_dir else: dll_dir = os.path.join(self.apr_util_path, 'bin') debug_dll_dir = None extra_bin = [] if dll_dir: bin_files = os.listdir(dll_dir) if debug_dll_dir and os.path.isdir(debug_dll_dir): debug_bin_files = os.listdir(debug_dll_dir) else: debug_bin_files = bin_files for bin in bin_files: if bin in debug_bin_files: if re.match('^(lib)?aprutil[-_].*' + suffix + '(d)?.dll$', bin): extra_bin.append(bin) self._libraries['aprutil'] = SVNCommonLibrary('apr-util', inc_path, lib_dir, lib_name, aprutil_version, debug_lib_dir=debug_lib_dir, dll_dir=dll_dir, dll_name=dll_name, debug_dll_dir=debug_dll_dir, defines=defines, extra_bin=extra_bin) # Perhaps apr-util can also provide memcached support if version >= (1, 3, 0) : self._libraries['apr_memcache'] = SVNCommonLibrary( 'apr_memcache', inc_path, lib_dir, None, aprutil_version, defines=['SVN_HAVE_MEMCACHE']) # And now find expat # If we have apr-util as a source location, it is in a subdir. # If we have an install package it is in the lib subdir if os.path.exists(os.path.join(self.apr_util_path, 'xml/expat')): inc_path = os.path.join(self.apr_util_path, 'xml/expat/lib') lib_dir = os.path.join(self.apr_util_path, 'xml/expat/lib/LibR') debug_lib_dir = os.path.join(self.apr_util_path, 'xml/expat/lib/LibD') else: inc_path = os.path.join(self.apr_util_path, 'include') lib_dir = os.path.join(self.apr_util_path, 'lib') debug_lib_dir = None version_file_path = os.path.join(inc_path, 'expat.h') if not os.path.exists(version_file_path): sys.stderr.write("ERROR: '%s' not found.\n" % version_file_path); sys.stderr.write("Use '--with-apr-util' option to configure APR-Util's XML location.\n"); sys.exit(1) txt = open(version_file_path).read() vermatch = re.search(r'^\s*#define\s+XML_MAJOR_VERSION\s+(\d+)', txt, re.M) major = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+XML_MINOR_VERSION\s+(\d+)', txt, re.M) minor = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+XML_MICRO_VERSION\s+(\d+)', txt, re.M) patch = int(vermatch.group(1)) # apr-Util 0.9-1.4 compiled expat to 'xml.lib', but apr-util 1.5 switched # to the more common 'libexpat.lib' libname = 'libexpat.lib' if not os.path.exists(os.path.join(lib_dir, 'libexpat.lib')): libname = 'xml.lib' version = (major, minor, patch) xml_version = '%d.%d.%d' % version self._libraries['xml'] = SVNCommonLibrary('expat', inc_path, lib_dir, libname, xml_version, debug_lib_dir = debug_lib_dir, defines=['XML_STATIC']) def _find_httpd(self, show_warnings): "Find Apache HTTPD and version" minimal_httpd_version = (2, 2, 0) if not self.httpd_path: return inc_base = os.path.join(self.httpd_path, 'include') if os.path.isfile(os.path.join(inc_base, 'apache26', 'ap_release.h')): inc_path = os.path.join(inc_base, 'apache26') elif os.path.isfile(os.path.join(inc_base, 'apache24', 'ap_release.h')): inc_path = os.path.join(inc_base, 'apache24') elif os.path.isfile(os.path.join(inc_base, 'apache22', 'ap_release.h')): inc_path = os.path.join(inc_base, 'apache22') elif os.path.isfile(os.path.join(inc_base, 'apache20', 'ap_release.h')): inc_path = os.path.join(inc_base, 'apache20') elif os.path.isfile(os.path.join(inc_base, 'apache2', 'ap_release.h')): inc_path = os.path.join(inc_base, 'apache2') elif os.path.isfile(os.path.join(inc_base, 'apache', 'ap_release.h')): inc_path = os.path.join(inc_base, 'apache') elif os.path.isfile(os.path.join(inc_base, 'ap_release.h')): inc_path = inc_base else: if show_warnings: print('WARNING: \'ap_release.h\' not found') print("Use '--with-httpd' to configure openssl location."); return version_file_path = os.path.join(inc_path, 'ap_release.h') txt = open(version_file_path).read() vermatch = re.search(r'^\s*#define\s+AP_SERVER_MAJORVERSION_NUMBER\s+(\d+)', txt, re.M) major = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+AP_SERVER_MINORVERSION_NUMBER\s+(\d+)', txt, re.M) minor = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+AP_SERVER_PATCHLEVEL_NUMBER\s+(\d+)', txt, re.M) patch = int(vermatch.group(1)) version = (major, minor, patch) httpd_version = '%d.%d.%d' % version if version < minimal_httpd_version: if show_warnings: print("WARNING: httpd %s or higher is required " "(%s found)\n" % ( '.'.join(str(v) for v in minimal_httpd_version), httpd_version)) return lib_name = 'libhttpd.lib' lib_base = self.httpd_path debug_lib_dir = None if os.path.isfile(os.path.join(lib_base, 'lib', lib_name)): # Install location lib_dir = os.path.join(lib_base, 'lib') elif os.path.isfile(os.path.join(lib_base, 'Release', lib_name)): # Source location lib_dir = os.path.join(lib_base, 'Release') if os.path.isfile(os.path.join(lib_base, 'Debug', lib_name)): debug_lib_dir = os.path.join(lib_base, 'Debug') # Our modules run inside httpd, so we don't have to find binaries self._libraries['httpd'] = SVNCommonLibrary('httpd', inc_path, lib_dir, lib_name, httpd_version, debug_lib_dir=debug_lib_dir, defines=['AP_DECLARE_EXPORT']) # And now find mod_dav if os.path.isfile(os.path.join(inc_path, 'mod_dav.h')): # Install location, we are lucky inc_path = inc_path elif os.path.isfile(os.path.join(lib_base, 'modules/dav/main/mod_dav.h')): # Source location inc_path = os.path.join(lib_base, 'modules/dav/main') else: if show_warnings: print("WARNING: Can't find mod_dav.h in the httpd directory") return lib_name = 'mod_dav.lib' if os.path.isfile(os.path.join(lib_dir, lib_name)): # Same location as httpd lib_dir = lib_dir elif os.path.isfile(os.path.join(lib_base, 'modules/dav/main/Release', lib_name)): # Source location lib_dir = os.path.join(lib_base, 'modules/dav/main/Release') if os.path.isfile(os.path.join(lib_base, 'modules/dav/main/Debug', lib_name)): debug_lib_dir = os.path.join(lib_base, 'modules/dav/main/Debug') else: debug_lib_dir = None else: if show_warnings: print("WARNING: Can't find mod_dav.lib in the httpd directory") return self._libraries['mod_dav'] = SVNCommonLibrary('mod_dav', inc_path, lib_dir, lib_name, httpd_version, debug_lib_dir=debug_lib_dir) def _find_zlib(self): "Find the ZLib library and version" minimal_zlib_version = (1, 2, 5) if not self.zlib_path or not os.path.isdir(self.zlib_path): sys.stderr.write("ERROR: '%s' not found.\n" % self.zlib_path); sys.stderr.write("Use '--with-zlib' option to configure ZLib location.\n"); sys.exit(1) if os.path.isdir(os.path.join(self.zlib_path, 'include')): # We have an install location inc_path = os.path.join(self.zlib_path, 'include') lib_path = os.path.join(self.zlib_path, 'lib') # Different build options produce different library names :( if os.path.exists(os.path.join(lib_path, 'zlibstatic.lib')): # CMake default: zlibstatic.lib (static) and zlib.lib (dll) lib_name = 'zlibstatic.lib' elif os.path.exists(os.path.join(lib_path, 'zlibstat.lib')): # Visual Studio project file default: zlibstat.lib (static) and zlibwapi.lib (dll) lib_name = 'zlibstat.lib' else: # Standard makefile produces zlib.lib (static) and zdll.lib (dll) lib_name = 'zlib.lib' debug_lib_name = None else: # We have a source location inc_path = lib_path = self.zlib_path lib_name = 'zlibstat.lib' debug_lib_name = 'zlibstatD.lib' version_file_path = os.path.join(inc_path, 'zlib.h') if not os.path.exists(version_file_path): sys.stderr.write("ERROR: '%s' not found.\n" % version_file_path); sys.stderr.write("Use '--with-zlib' option to configure ZLib location.\n"); sys.exit(1) txt = open(version_file_path).read() vermatch = re.search( r'^\s*#define\s+ZLIB_VERSION\s+"(\d+)\.(\d+)\.(\d+)(?:\.\d)?"', txt, re.M) version = tuple(map(int, vermatch.groups())) self.zlib_version = '%d.%d.%d' % version if version < minimal_zlib_version: sys.stderr.write("ERROR: ZLib %s or higher is required " "(%s found)\n" % ( '.'.join(str(v) for v in minimal_zlib_version), self.zlib_version)) sys.exit(1) self._libraries['zlib'] = SVNCommonLibrary('zlib', inc_path, lib_path, lib_name, self.zlib_version, debug_lib_name=debug_lib_name) def _find_bdb(self, show_warnings): "Find the Berkeley DB library and version" # try default path to detect BDB support, unless different path is # specified so to keep pre 1.10-behavior for BDB detection on Windows bdb_path = 'db4-win32' if self.bdb_path: bdb_path = self.bdb_path inc_path = os.path.join(bdb_path, 'include') db_h_path = os.path.join(inc_path, 'db.h') if not os.path.isfile(db_h_path): if show_warnings and self.bdb_path: print('WARNING: \'%s\' not found' % (db_h_path,)) print("Use '--with-berkeley-db' to configure BDB location."); return # Obtain bdb version from db.h txt = open(db_h_path).read() maj_match = re.search(r'DB_VERSION_MAJOR\s+(\d+)', txt) min_match = re.search(r'DB_VERSION_MINOR\s+(\d+)', txt) patch_match = re.search(r'DB_VERSION_PATCH\s+(\d+)', txt) if maj_match and min_match and patch_match: ver = (int(maj_match.group(1)), int(min_match.group(1)), int(patch_match.group(1))) else: return version = '%d.%d.%d' % ver versuffix = '%d%d' % (ver[0], ver[1]) # Before adding "60" to this list, see build/ac-macros/berkeley-db.m4. if versuffix not in ( '50', '51', '52', '53', '40', '41', '42', '43', '44', '45', '46', '47', '48', ): return lib_dir = os.path.join(bdb_path, 'lib') lib_name = 'libdb%s.lib' % (versuffix,) if not os.path.exists(os.path.join(lib_dir, lib_name)): return # Do we have a debug version? debug_lib_name = 'libdb%sd.lib' % (versuffix,) if not os.path.isfile(os.path.join(lib_dir, debug_lib_name)): debug_lib_name = None dll_dir = os.path.join(bdb_path, 'bin') # Are there binaries we should copy for testing? dll_name = os.path.splitext(lib_name)[0] + '.dll' if not os.path.isfile(os.path.join(dll_dir, dll_name)): dll_name = None if debug_lib_name: debug_dll_name = os.path.splitext(debug_lib_name)[0] + '.dll' if not os.path.isfile(os.path.join(dll_dir, debug_dll_name)): debug_dll_name = None else: debug_dll_name = None # Usually apr-util doesn't find BDB on Windows, so we help apr-util # by defining the value ourselves (Legacy behavior) defines = ['APU_HAVE_DB=1', 'SVN_LIBSVN_FS_LINKS_FS_BASE'] self._libraries['db'] = SVNCommonLibrary('db', inc_path, lib_dir, lib_name, version, debug_lib_name=debug_lib_name, dll_dir=dll_dir, dll_name=dll_name, debug_dll_name=debug_dll_name, defines=defines) def _find_openssl(self, show_warnings): "Find openssl" if not self.openssl_path: return version_path = os.path.join(self.openssl_path, 'inc32/openssl/opensslv.h') if os.path.isfile(version_path): # We have an OpenSSL Source location # For legacy reason inc_dir = os.path.join(self.openssl_path, 'inc32') if self.static_openssl: lib_dir = os.path.join(self.openssl_path, 'out32') bin_dir = None else: lib_dir = os.path.join(self.openssl_path, 'out32dll') bin_dir = lib_dir elif os.path.isfile(os.path.join(self.openssl_path, 'include/openssl/opensslv.h')): version_path = os.path.join(self.openssl_path, 'include/openssl/opensslv.h') inc_dir = os.path.join(self.openssl_path, 'include') lib_dir = os.path.join(self.openssl_path, 'lib') if self.static_openssl: bin_dir = None else: bin_dir = os.path.join(self.openssl_path, 'bin') else: if show_warnings: print('WARNING: \'opensslv.h\' not found') print("Use '--with-openssl' to configure openssl location."); return txt = open(version_path).read() vermatch = re.search( r'#\s*define\s+OPENSSL_VERSION_TEXT\s+"OpenSSL\s+((\d+)\.(\d+).(\d+)([^ -]*))', txt) version = (int(vermatch.group(2)), int(vermatch.group(3)), int(vermatch.group(4))) openssl_version = vermatch.group(1) self._libraries['openssl'] = SVNCommonLibrary('openssl', inc_dir, lib_dir, 'ssleay32.lib', openssl_version, dll_name='ssleay32.dll', dll_dir=bin_dir) self._libraries['libeay32'] = SVNCommonLibrary('openssl', inc_dir, lib_dir, 'libeay32.lib', openssl_version, dll_name='libeay32.dll', dll_dir=bin_dir) def _find_perl(self, show_warnings): "Find the right perl library name to link swig bindings with" fp = os.popen('perl -MConfig -e ' + escape_shell_arg( 'print "$Config{libperl}\\n"; ' 'print "$Config{PERL_REVISION}.$Config{PERL_VERSION}.' '$Config{PERL_SUBVERSION}\\n"; ' 'print "$Config{archlib}\\n"'), 'r') try: line = fp.readline() if line: perl_lib = line.strip() else: return line = fp.readline() if line: perl_version = line.strip() perl_ver = perl_version.split('.') else: return line = fp.readline() if line: lib_dir = os.path.join(line.strip(), 'CORE') inc_dir = lib_dir finally: fp.close() perl_ver = tuple(map(int, perl_ver)) forced_includes = [] if perl_ver >= (5, 18, 0): forced_includes.append('swigutil_pl__pre_perl.h') self._libraries['perl'] = SVNCommonLibrary('perl', inc_dir, lib_dir, perl_lib, perl_version, forced_includes=forced_includes) def _find_ruby(self, show_warnings): "Find the right Ruby library name to link swig bindings with" lib_dir = None inc_dirs = [] # Pass -W0 to stifle the "-e:1: Use RbConfig instead of obsolete # and deprecated Config." warning if we are using Ruby 1.9. fp = os.popen('ruby -rrbconfig -W0 -e ' + escape_shell_arg( "puts RbConfig::CONFIG['ruby_version'];" "puts RbConfig::CONFIG['LIBRUBY'];" "puts RbConfig::CONFIG['libdir'];" "puts RbConfig::CONFIG['rubyhdrdir'];" "puts RbConfig::CONFIG['arch'];"), 'r') try: line = fp.readline() if line: ruby_version = line.strip() line = fp.readline() if line: ruby_lib = line.strip() line = fp.readline() if line: lib_dir = line.strip() line = fp.readline() if line: inc_base = line.strip() inc_dirs = [inc_base] line = fp.readline() if line: inc_dirs.append(os.path.join(inc_base, line.strip())) finally: fp.close() if not lib_dir: return # Visual C++ prior to VS2015 doesn't have a standard compliant snprintf if self.vs_version < '2015': defines = ['snprintf=_snprintf'] else: defines = [] ver = ruby_version.split('.') ver = tuple(map(int, ver)) if ver >= (1, 8, 0): defines.extend(["HAVE_RB_ERRINFO"]) forced_includes = [] if ver >= (1, 8, 0): # Swig redefines NUM2LL as NUM2LONG if it isn't defined, but on Windows # ruby 1.8+ declares NUM2LL as a static inline function. # (LL2NUM and NUM2ULL don't have these problems) defines.extend(['NUM2LL=NUM2LL']) if ver >= (1, 9, 0): forced_includes.append('swigutil_rb__pre_ruby.h') defines.extend(["SVN_SWIG_RUBY__CUSTOM_RUBY_CONFIG"]) self._libraries['ruby'] = SVNCommonLibrary('ruby', inc_dirs, lib_dir, ruby_lib, ruby_version, defines=defines, forced_includes=forced_includes) def _find_python(self, show_warnings): "Find the appropriate options for creating SWIG-based Python modules" try: from distutils import sysconfig inc_dir = sysconfig.get_python_inc() lib_dir = os.path.join(sysconfig.PREFIX, "libs") except ImportError: return self._libraries['python'] = SVNCommonLibrary('python', inc_dir, lib_dir, None, sys.version.split(' ')[0]) def _find_jdk(self, show_warnings): "Find details about an installed jdk" jdk_path = self.jdk_path self.jdk_path = None # No jdk on errors minimal_jdk_version = (1, 0, 0) # ### Provide sane default if not jdk_path: jdk_ver = None try: try: # Python >=3.0 import winreg except ImportError: # Python <3.0 import _winreg as winreg key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\JavaSoft\Java Development Kit") # Find the newest JDK version. num_values = winreg.QueryInfoKey(key)[1] for i in range(num_values): (name, value, key_type) = winreg.EnumValue(key, i) if name == "CurrentVersion": jdk_ver = value break # Find the JDK path. if jdk_ver is not None: key = winreg.OpenKey(key, jdk_ver) num_values = winreg.QueryInfoKey(key)[1] for i in range(num_values): (name, value, key_type) = winreg.EnumValue(key, i) if name == "JavaHome": jdk_path = value break winreg.CloseKey(key) except (ImportError, EnvironmentError): pass if not jdk_path or not os.path.isdir(jdk_path): return try: outfp = subprocess.Popen([os.path.join(jdk_path, 'bin', 'javah.exe'), '-version'], stdout=subprocess.PIPE).stdout line = outfp.read() if line: vermatch = re.search(r'"(([0-9]+(\.[0-9]+)+)(_[._0-9]+)?)"', line, re.M) else: vermatch = None if vermatch: version = tuple(map(int, vermatch.groups()[1].split('.'))) versionstr = vermatch.groups()[0] else: if show_warnings: print('Could not find installed JDK,') return outfp.close() except OSError: if show_warnings: print('Could not find installed JDK,') return if version < minimal_jdk_version: if show_warnings: print('Found java jdk %s, but >= %s is required. ' 'javahl will not be built.\n' % \ (versionstr, '.'.join(str(v) for v in minimal_jdk_version))) return self.jdk_path = jdk_path inc_dirs = [ os.path.join(jdk_path, 'include'), os.path.join(jdk_path, 'include', 'win32'), ] lib_dir = os.path.join(jdk_path, 'lib') # The JDK provides .lib files, but we currently don't use these. self._libraries['java_sdk'] = SVNCommonLibrary('java-sdk', inc_dirs, lib_dir, None, versionstr) def _find_swig(self, show_warnings): "Find details about an installed swig" minimal_swig_version = (1, 3, 25) if not self.swig_path: swig_exe = 'swig.exe' else: swig_exe = os.path.abspath(os.path.join(self.swig_path, 'swig.exe')) if self.swig_path is not None: self.swig_exe = os.path.abspath(os.path.join(self.swig_path, 'swig.exe')) else: self.swig_exe = 'swig' swig_version = None try: fp = subprocess.Popen([self.swig_exe, '-version'], stdout=subprocess.PIPE).stdout txt = fp.read() if txt: vermatch = re.search(r'^SWIG\ Version\ (\d+)\.(\d+)\.(\d+)', txt, re.M) else: vermatch = None if vermatch: swig_version = tuple(map(int, vermatch.groups())) fp.close() except OSError: swig_version = None if not swig_version: if show_warnings: print('Could not find installed SWIG') return False swig_ver = '%d.%d.%d' % (swig_version) if swig_version < minimal_swig_version: if show_warnings: print('Found swig %s, but >= %s is required. ' 'the swig bindings will not be built.\n' % (swig_version, '.'.join(str(v) for v in minimal_swig_version))) return try: fp = subprocess.Popen([self.swig_exe, '-swiglib'], stdout=subprocess.PIPE).stdout lib_dir = fp.readline().strip() fp.close() except OSError: lib_dir = None fp.close() if not lib_dir: if show_warnings: print('Could not find libdir of installed SWIG') return False if (not self.swig_path and os.path.isfile(os.path.join(lib_dir, '../swig.exe'))): self.swig_path = os.path.dirname(lib_dir) inc_dirs = [ 'subversion/bindings/swig', 'subversion/bindings/swig/proxy', 'subversion/bindings/swig/include', ] self.swig_libdir = lib_dir self.swig_version = swig_version self._libraries['swig'] = SVNCommonLibrary('swig', inc_dirs, lib_dir, None, swig_ver) return True def _get_serf_version(self, inc_dir): "Retrieves the serf version from serf.h" # shouldn't be called unless serf is there assert inc_dir and os.path.exists(inc_dir) serf_ver_maj = None serf_ver_min = None serf_ver_patch = None # serf.h should be present if not os.path.exists(os.path.join(inc_dir, 'serf.h')): return None, None, None txt = open(os.path.join(inc_dir, 'serf.h')).read() maj_match = re.search(r'SERF_MAJOR_VERSION\s+(\d+)', txt) min_match = re.search(r'SERF_MINOR_VERSION\s+(\d+)', txt) patch_match = re.search(r'SERF_PATCH_VERSION\s+(\d+)', txt) if maj_match: serf_ver_maj = int(maj_match.group(1)) if min_match: serf_ver_min = int(min_match.group(1)) if patch_match: serf_ver_patch = int(patch_match.group(1)) return serf_ver_maj, serf_ver_min, serf_ver_patch def _find_serf(self, show_warnings): "Check if serf and its dependencies are available" minimal_serf_version = (1, 3, 4) if not self.serf_path: return inc_dir = self.serf_path if os.path.isfile(os.path.join(inc_dir, 'serf.h')): # Source layout lib_dir = self.serf_path debug_lib_dir = None inc_dir = self.serf_path elif os.path.isfile(os.path.join(self.serf_path, 'include/serf-1/serf.h')): # Install layout inc_dir = os.path.join(self.serf_path, 'include/serf-1') lib_dir = os.path.join(self.serf_path, 'lib') debug_lib_dir = None elif os.path.isfile(os.path.join(self.serf_path, 'include/serf-2/serf.h')): # Install layout inc_dir = os.path.join(self.serf_path, 'include/serf-2') lib_dir = os.path.join(self.serf_path, 'lib') debug_lib_dir = None else: if show_warnings: print('WARNING: \'serf.h\' not found') print("Use '--with-serf' to configure serf location."); return version = self._get_serf_version(inc_dir) serf_version = '.'.join(str(v) for v in version) if version < minimal_serf_version: if show_warnings: print('Found serf %s, but >= %s is required. ' 'ra_serf will not be built.\n' % (serf_version, '.'.join(str(v) for v in minimal_serf_version))) return serf_ver_maj = version[0] if serf_ver_maj > 0: lib_name = 'serf-%d.lib' % (serf_ver_maj,) else: lib_name = 'serf.lib' defines = ['SVN_HAVE_SERF', 'SVN_LIBSVN_CLIENT_LINKS_RA_SERF'] self._libraries['serf'] = SVNCommonLibrary('serf', inc_dir, lib_dir, lib_name, serf_version, debug_lib_dir=debug_lib_dir, defines=defines) def _find_sasl(self, show_warnings): "Check if sals is available" minimal_sasl_version = (2, 0, 0) if not self.sasl_path: return inc_dir = os.path.join(self.sasl_path, 'include') version_file_path = os.path.join(inc_dir, 'sasl.h') if not os.path.isfile(version_file_path): if show_warnings: print('WARNING: \'%s\' not found' % (version_file_path,)) print("Use '--with-sasl' to configure sasl location."); return txt = open(version_file_path).read() vermatch = re.search(r'^\s*#define\s+SASL_VERSION_MAJOR\s+(\d+)', txt, re.M) major = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+SASL_VERSION_MINOR\s+(\d+)', txt, re.M) minor = int(vermatch.group(1)) vermatch = re.search(r'^\s*#define\s+SASL_VERSION_STEP\s+(\d+)', txt, re.M) patch = int(vermatch.group(1)) version = (major, minor, patch) sasl_version = '.'.join(str(v) for v in version) if version < minimal_sasl_version: if show_warnings: print('Found sasl %s, but >= %s is required. ' 'sals support will not be built.\n' % (sasl_version, '.'.join(str(v) for v in minimal_serf_version))) return lib_dir = os.path.join(self.sasl_path, 'lib') if os.path.isfile(os.path.join(lib_dir, 'libsasl.dll')): dll_dir = lib_dir dll_name = 'libsasl.dll' elif os.path.isfile(os.path.join(self.sasl_path, 'bin', 'libsasl.dll')): dll_dir = os.path.join(self.sasl_path, 'bin') dll_name = 'libsasl.dll' else: # Probably a static compilation dll_dir = None dll_name = None self._libraries['sasl'] = SVNCommonLibrary('sasl', inc_dir, lib_dir, 'libsasl.lib', sasl_version, dll_dir=dll_dir, dll_name=dll_name, defines=['SVN_HAVE_SASL']) def _find_libintl(self, show_warnings): "Find gettext support" minimal_libintl_version = (0, 14, 1) if not self.enable_nls or not self.libintl_path: return; # We support 2 scenarios. if os.path.isfile(os.path.join(self.libintl_path, 'inc', 'libintl.h')) and\ os.path.isfile(os.path.join(self.libintl_path, 'lib', 'intl3_svn.lib')): # 1. Subversion's custom libintl based on gettext 0.14.1 inc_dir = os.path.join(self.libintl_path, 'inc') lib_dir = os.path.join(self.libintl_path, 'lib') dll_dir = os.path.join(self.libintl_path, 'bin') lib_name = 'intl3_svn.lib' dll_name = 'intl3_svn.dll' elif os.path.isfile(os.path.join(self.libintl_path, \ 'include', 'libintl.h')): # 2. A gettext install inc_dir = os.path.join(self.libintl_path, 'include') lib_dir = os.path.join(self.libintl_path, 'lib') dll_dir = os.path.join(self.libintl_path, 'bin') lib_name = 'intl.lib' dll_name = 'intl.dll' else: if (show_warnings): print('WARNING: \'libintl.h\' not found') print("Use '--with-libintl' to configure libintl location.") return version_file_path = os.path.join(inc_dir, 'libintl.h') txt = open(version_file_path).read() match = re.search(r'^\s*#define\s+LIBINTL_VERSION\s+((0x)?[0-9A-Fa-f]+)', txt, re.M) ver = int(match.group(1), 0) version = (ver >> 16, (ver >> 8) & 0xFF, ver & 0xFF) libintl_version = '.'.join(str(v) for v in version) if version < minimal_libintl_version: if show_warnings: print('Found libintl %s, but >= %s is required.\n' % \ (libintl_version, '.'.join(str(v) for v in minimal_libintl_version))) return self._libraries['intl'] = SVNCommonLibrary('libintl', inc_dir, lib_dir, lib_name, libintl_version, dll_dir=dll_dir, dll_name=dll_name) def _find_sqlite(self, show_warnings): "Find the Sqlite library and version" minimal_sqlite_version = (3, 7, 12) # For SQLite we support 3 scenarios: # - Installed in standard directory layout # - Installed in legacy directory layout # - Amalgamation compiled directly into our libraries sqlite_base = self.sqlite_path lib_dir = None dll_dir = None dll_name = None defines = [] lib_name = 'sqlite3.lib' if os.path.isfile(os.path.join(sqlite_base, 'include/sqlite3.h')): # Standard layout inc_dir = os.path.join(sqlite_base, 'include') lib_dir = os.path.join(sqlite_base, 'lib') # We assume a static library, but let's support shared in this case if os.path.isfile(os.path.join(sqlite_base, 'bin/sqlite3.dll')): dll_dir = os.path.join(sqlite_base, 'bin') dll_name = 'sqlite3.dll' elif os.path.isfile(os.path.join(sqlite_base, 'inc/sqlite3.h')): # Standard layout inc_dir = os.path.join(sqlite_base, 'inc') lib_dir = os.path.join(sqlite_base, 'lib') # We assume a static library, but let's support shared in this case if os.path.isfile(os.path.join(sqlite_base, 'bin/sqlite3.dll')): dll_dir = os.path.join(sqlite_base, 'bin') dll_name = 'sqlite3.dll' elif (os.path.isfile(os.path.join(sqlite_base, 'sqlite3.h')) and os.path.isfile(os.path.join(sqlite_base, 'sqlite3.c'))): # Amalgamation inc_dir = sqlite_base lib_dir = None lib_name = None defines.append('SVN_SQLITE_INLINE') else: sys.stderr.write("ERROR: SQLite not found\n") sys.stderr.write("Use '--with-sqlite' option to configure sqlite location.\n"); sys.exit(1) version_file_path = os.path.join(inc_dir, 'sqlite3.h') txt = open(version_file_path).read() match = re.search(r'^\s*#define\s+SQLITE_VERSION\s+' r'"(\d+)\.(\d+)\.(\d+)(?:\.(\d))?"', txt, re.M) version = match.groups() # Sqlite doesn't add patch numbers for their ordinary releases if not version[3]: version = version[0:3] version = tuple(map(int, version)) sqlite_version = '.'.join(str(v) for v in version) if version < minimal_sqlite_version: sys.stderr.write("ERROR: sqlite %s or higher is required " "(%s found)\n" % ( '.'.join(str(v) for v in minimal_sqlite_version), sqlite_version)) sys.exit(1) self._libraries['sqlite'] = SVNCommonLibrary('sqlite', inc_dir, lib_dir, lib_name, sqlite_version, dll_dir=dll_dir, dll_name=dll_name, defines=defines) # ============================================================================ # This is a cut-down and modified version of code from: # subversion/subversion/bindings/swig/python/svn/core.py # if sys.platform == "win32": _escape_shell_arg_re = re.compile(r'(\\+)(\"|$)') def escape_shell_arg(arg): # The (very strange) parsing rules used by the C runtime library are # described at: # http://msdn.microsoft.com/library/en-us/vclang/html/_pluslang_Parsing_C.2b2b_.Command.2d.Line_Arguments.asp # double up slashes, but only if they are followed by a quote character arg = re.sub(_escape_shell_arg_re, r'\1\1\2', arg) # surround by quotes and escape quotes inside arg = '"' + arg.replace('"', '"^""') + '"' return arg else: def escape_shell_arg(str): return "'" + str.replace("'", "'\\''") + "'"