diff options
Diffstat (limited to 'PC/VS9.0/build_ssl.py')
-rw-r--r-- | PC/VS9.0/build_ssl.py | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/PC/VS9.0/build_ssl.py b/PC/VS9.0/build_ssl.py new file mode 100644 index 0000000..eb0b4c9 --- /dev/null +++ b/PC/VS9.0/build_ssl.py @@ -0,0 +1,238 @@ +# Script for building the _ssl and _hashlib modules for Windows. +# Uses Perl to setup the OpenSSL environment correctly +# and build OpenSSL, then invokes a simple nmake session +# for the actual _ssl.pyd and _hashlib.pyd DLLs. + +# THEORETICALLY, you can: +# * Unpack the latest SSL release one level above your main Python source +# directory. It is likely you will already find the zlib library and +# any other external packages there. +# * Install ActivePerl and ensure it is somewhere on your path. +# * Run this script from the PCBuild directory. +# +# it should configure and build SSL, then build the _ssl and _hashlib +# Python extensions without intervention. + +# Modified by Christian Heimes +# Now this script supports pre-generated makefiles and assembly files. +# Developers don't need an installation of Perl anymore to build Python. A svn +# checkout from our svn repository is enough. +# +# In Order to create the files in the case of an update you still need Perl. +# Run build_ssl in this order: +# python.exe build_ssl.py Release x64 +# python.exe build_ssl.py Release Win32 + +from __future__ import with_statement, print_function +import os +import re +import sys +import time +import subprocess +from shutil import copy +from distutils import log +from distutils.spawn import find_executable +from distutils.file_util import copy_file +from distutils.sysconfig import parse_makefile, expand_makefile_vars + +# The mk1mf.pl output filename template +# !!! This must match what is used in prepare_ssl.py +MK1MF_FMT = 'ms\\nt{}.mak' + +# The header files output directory name template +# !!! This must match what is used in prepare_ssl.py +INCLUDE_FMT = 'include{}' + +# Fetch all the directory definitions from VC properties +def get_project_properties(propfile): + macro_pattern = r'<UserMacro\s+Name="([^"]+?)"\s+Value="([^"]*?)"\s*/>' + with open(propfile) as fin: + items = re.findall(macro_pattern, fin.read(), re.MULTILINE) + props = dict(items) + for name, value in items: + try: + props[name] = expand_makefile_vars(value, props) + except TypeError: + # value contains undefined variable reference, drop it + del props[name] + return props + + +_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") +def fix_makefile(makefile, platform_makefile, suffix): + """Fix some stuff in all makefiles + """ + subs = { + 'PERL': 'rem', # just in case + 'CP': 'copy', + 'MKDIR': 'mkdir', + 'OUT_D': 'out' + suffix, + 'TMP_D': 'tmp' + suffix, + 'INC_D': INCLUDE_FMT.format(suffix), + 'INCO_D': '$(INC_D)\\openssl', + } + with open(platform_makefile) as fin, open(makefile, 'w') as fout: + for line in fin: + m = _variable_rx.match(line) + if m: + name = m.group(1) + if name in subs: + line = '%s=%s\n' % (name, subs[name]) + fout.write(line) + + +_copy_rx = re.compile(r'\t\$\(PERL\) ' + r'\$\(SRC_D\)\\util\\copy-if-different.pl ' + r'"([^"]+)"\s+"([^"]+)"') +def copy_files(makefile, makevars): + # Create the destination directories (see 'init' rule in nt.dll) + for varname in ('TMP_D', 'LIB_D', 'INC_D', 'INCO_D'): + dirname = makevars[varname] + if not os.path.isdir(dirname): + os.mkdir(dirname) + # Process the just local library headers (HEADER) as installed headers + # (EXHEADER) are handled by prepare_ssl.py (see 'headers' rule in nt.dll) + headers = set(makevars['HEADER'].split()) + with open(makefile) as fin: + for line in fin: + m = _copy_rx.match(line) + if m: + src, dst = m.groups() + src = expand_makefile_vars(src, makevars) + dst = expand_makefile_vars(dst, makevars) + if dst in headers: + copy_file(src, dst, preserve_times=False, update=True) + + +# Update buildinf.h for the build platform. +def fix_buildinf(makevars): + platform_cpp_symbol = 'MK1MF_PLATFORM_' + platform_cpp_symbol += makevars['PLATFORM'].replace('-', '_') + fn = expand_makefile_vars('$(INCL_D)\\buildinf.h', makevars) + with open(fn, 'w') as f: + # sanity check + f.write(('#ifndef {}\n' + ' #error "Windows build (PLATFORM={PLATFORM}) only"\n' + '#endif\n').format(platform_cpp_symbol, **makevars)) + buildinf = ( + '#define CFLAGS "compiler: cl {CFLAG}"\n' + '#define PLATFORM "{PLATFORM}"\n' + '#define DATE "{}"\n' + ).format(time.asctime(time.gmtime()), + **makevars) + f.write(buildinf) + print('Updating buildinf:') + print(buildinf) + sys.stdout.flush() + + +def main(): + if sys.argv[1] == "Debug": + print("OpenSSL debug builds aren't supported.") + elif sys.argv[1] != "Release": + raise ValueError('Unrecognized configuration: %s' % sys.argv[1]) + + if sys.argv[2] == "Win32": + platform = "VC-WIN32" + suffix = '32' + elif sys.argv[2] == "x64": + platform = "VC-WIN64A" + suffix = '64' + else: + raise ValueError('Unrecognized platform: %s' % sys.argv[2]) + + # Have the distutils functions display information output + log.set_verbosity(1) + + # Use the same properties that are used in the VS projects + solution_dir = os.path.dirname(__file__) + propfile = os.path.join(solution_dir, 'pyproject.vsprops') + props = get_project_properties(propfile) + + # Ensure we have the necessary external depenedencies + ssl_dir = os.path.join(solution_dir, props['opensslDir']) + if not os.path.isdir(ssl_dir): + print("Could not find the OpenSSL sources, try running " + "'build.bat -e'") + sys.exit(1) + + # Ensure the executables used herein are available. + if not find_executable('nmake.exe'): + print('Could not find nmake.exe, try running env.bat') + sys.exit(1) + + # add our copy of NASM to PATH. It will be on the same level as openssl + externals_dir = os.path.join(solution_dir, props['externalsDir']) + for dir in os.listdir(externals_dir): + if dir.startswith('nasm'): + nasm_dir = os.path.join(externals_dir, dir) + nasm_dir = os.path.abspath(nasm_dir) + old_path = os.environ['PATH'] + os.environ['PATH'] = os.pathsep.join([nasm_dir, old_path]) + break + else: + if not find_executable('nasm.exe'): + print('Could not find nasm.exe, please add to PATH') + sys.exit(1) + + # If the ssl makefiles do not exist, we invoke PCbuild/prepare_ssl.py + # to generate them. + platform_makefile = MK1MF_FMT.format(suffix) + if not os.path.isfile(os.path.join(ssl_dir, platform_makefile)): + pcbuild_dir = os.path.join(os.path.dirname(externals_dir), 'PCbuild') + prepare_ssl = os.path.join(pcbuild_dir, 'prepare_ssl.py') + rc = subprocess.call([sys.executable, prepare_ssl, ssl_dir]) + if rc: + print('Executing', prepare_ssl, 'failed (error %d)' % rc) + sys.exit(rc) + + old_cd = os.getcwd() + try: + os.chdir(ssl_dir) + + # Get the variables defined in the current makefile, if it exists. + makefile = MK1MF_FMT.format('') + try: + makevars = parse_makefile(makefile) + except EnvironmentError: + makevars = {'PLATFORM': None} + + # Rebuild the makefile when building for different a platform than + # the last run. + if makevars['PLATFORM'] != platform: + print("Updating the makefile...") + sys.stdout.flush() + # Firstly, apply the changes for the platform makefile into + # a temporary file to prevent any errors from this script + # causing false positives on subsequent runs. + new_makefile = makefile + '.new' + fix_makefile(new_makefile, platform_makefile, suffix) + makevars = parse_makefile(new_makefile) + + # Secondly, perform the make recipes that use Perl + copy_files(new_makefile, makevars) + + # Set our build information in buildinf.h. + # XXX: This isn't needed for a properly "prepared" SSL, but + # it fixes the current checked-in external (as of 2017-05). + fix_buildinf(makevars) + + # Finally, move the temporary file to its real destination. + if os.path.exists(makefile): + os.remove(makefile) + os.rename(new_makefile, makefile) + + # Now run make. + makeCommand = "nmake /nologo /f \"%s\" lib" % makefile + print("Executing ssl makefiles:", makeCommand) + sys.stdout.flush() + rc = os.system(makeCommand) + if rc: + print("Executing", makefile, "failed (error %d)" % rc) + sys.exit(rc) + finally: + os.chdir(old_cd) + sys.exit(rc) + +if __name__=='__main__': + main() |