diff options
Diffstat (limited to 'build/generator/gen_win_dependencies.py')
-rw-r--r-- | build/generator/gen_win_dependencies.py | 1465 |
1 files changed, 1465 insertions, 0 deletions
diff --git a/build/generator/gen_win_dependencies.py b/build/generator/gen_win_dependencies.py new file mode 100644 index 0000000..68a1784 --- /dev/null +++ b/build/generator/gen_win_dependencies.py @@ -0,0 +1,1465 @@ +# +# +# 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("'", "'\\''") + "'" |