1from __future__ import with_statement, print_function 2# Script for building the _ssl and _hashlib modules for Windows. 3# Uses Perl to setup the OpenSSL environment correctly 4# and build OpenSSL, then invokes a simple nmake session 5# for the actual _ssl.pyd and _hashlib.pyd DLLs. 6 7# THEORETICALLY, you can: 8# * Unpack the latest SSL release one level above your main Python source 9# directory. It is likely you will already find the zlib library and 10# any other external packages there. 11# * Install ActivePerl and ensure it is somewhere on your path. 12# * Run this script from the PCBuild directory. 13# 14# it should configure and build SSL, then build the _ssl and _hashlib 15# Python extensions without intervention. 16 17# Modified by Christian Heimes 18# Now this script supports pre-generated makefiles and assembly files. 19# Developers don't need an installation of Perl anymore to build Python. A svn 20# checkout from our svn repository is enough. 21# 22# In Order to create the files in the case of an update you still need Perl. 23# Run build_ssl in this order: 24# python.exe build_ssl.py Release x64 25# python.exe build_ssl.py Release Win32 26 27from __future__ import with_statement 28import os, sys, re, shutil 29import subprocess 30 31# Find all "foo.exe" files on the PATH. 32def find_all_on_path(filename, extras = None): 33 entries = os.environ["PATH"].split(os.pathsep) 34 ret = [] 35 for p in entries: 36 fname = os.path.abspath(os.path.join(p, filename)) 37 if os.path.isfile(fname) and fname not in ret: 38 ret.append(fname) 39 if extras: 40 for p in extras: 41 fname = os.path.abspath(os.path.join(p, filename)) 42 if os.path.isfile(fname) and fname not in ret: 43 ret.append(fname) 44 return ret 45 46# Find a suitable Perl installation for OpenSSL. 47# cygwin perl does *not* work. ActivePerl does. 48# Being a Perl dummy, the simplest way I can check is if the "Win32" package 49# is available. 50def find_working_perl(perls): 51 for perl in perls: 52 try: 53 subprocess.check_output([perl, "-e", "use win32;"]) 54 except Subprocess.CalledProcessError: 55 continue 56 else: 57 return perl 58 print("Can not find a suitable PERL:") 59 if perls: 60 print(" the following perl interpreters were found:") 61 for p in perls: 62 print(" ", p) 63 print(" None of these versions appear suitable for building OpenSSL") 64 else: 65 print(" NO perl interpreters were found on this machine at all!") 66 print(" Please install ActivePerl and ensure it appears on your path") 67 return None 68 69# Fetch SSL directory from VC properties 70def get_ssl_dir(): 71 propfile = (os.path.join(os.path.dirname(__file__), 'pyproject.vsprops')) 72 with open(propfile) as f: 73 m = re.search('openssl-([^"]+)"', f.read()) 74 return "..\..\externals\openssl-"+m.group(1) 75 76 77def create_makefile64(makefile, m32): 78 """Create and fix makefile for 64bit 79 80 Replace 32 with 64bit directories 81 """ 82 if not os.path.isfile(m32): 83 return 84 with open(m32) as fin: 85 with open(makefile, 'w') as fout: 86 for line in fin: 87 line = line.replace("=tmp32", "=tmp64") 88 line = line.replace("=out32", "=out64") 89 line = line.replace("=inc32", "=inc64") 90 # force 64 bit machine 91 line = line.replace("MKLIB=lib", "MKLIB=lib /MACHINE:X64") 92 line = line.replace("LFLAGS=", "LFLAGS=/MACHINE:X64 ") 93 # don't link against the lib on 64bit systems 94 line = line.replace("bufferoverflowu.lib", "") 95 fout.write(line) 96 os.unlink(m32) 97 98def fix_makefile(makefile): 99 """Fix some stuff in all makefiles 100 """ 101 if not os.path.isfile(makefile): 102 return 103 fin = open(makefile) 104 with open(makefile) as fin: 105 lines = fin.readlines() 106 with open(makefile, 'w') as fout: 107 for line in lines: 108 if line.startswith("PERL="): 109 continue 110 if line.startswith("CP="): 111 line = "CP=copy\n" 112 if line.startswith("MKDIR="): 113 line = "MKDIR=mkdir\n" 114 if line.startswith("CFLAG="): 115 line = line.strip() 116 for algo in ("RC5", "MDC2", "IDEA"): 117 noalgo = " -DOPENSSL_NO_%s" % algo 118 if noalgo not in line: 119 line = line + noalgo 120 line = line + '\n' 121 fout.write(line) 122 123def run_configure(configure, do_script): 124 print("perl Configure "+configure+" no-idea no-mdc2") 125 os.system("perl Configure "+configure+" no-idea no-mdc2") 126 print(do_script) 127 os.system(do_script) 128 129def main(): 130 build_all = "-a" in sys.argv 131 if sys.argv[1] == "Release": 132 debug = False 133 elif sys.argv[1] == "Debug": 134 debug = True 135 else: 136 raise ValueError(str(sys.argv)) 137 138 if sys.argv[2] == "Win32": 139 arch = "x86" 140 configure = "VC-WIN32" 141 do_script = "ms\\do_nasm" 142 makefile="ms\\nt.mak" 143 m32 = makefile 144 elif sys.argv[2] == "x64": 145 arch="amd64" 146 configure = "VC-WIN64A" 147 do_script = "ms\\do_win64a" 148 makefile = "ms\\nt64.mak" 149 m32 = makefile.replace('64', '') 150 #os.environ["VSEXTCOMP_USECL"] = "MS_OPTERON" 151 else: 152 raise ValueError(str(sys.argv)) 153 154 make_flags = "" 155 if build_all: 156 make_flags = "-a" 157 # perl should be on the path, but we also look in "\perl" and "c:\\perl" 158 # as "well known" locations 159 perls = find_all_on_path("perl.exe", [r"\perl\bin", 160 r"C:\perl\bin", 161 r"\perl64\bin", 162 r"C:\perl64\bin", 163 ]) 164 perl = find_working_perl(perls) 165 if perl: 166 print("Found a working perl at '%s'" % (perl,)) 167 # Set PERL for the makefile to find it 168 os.environ["PERL"] = perl 169 else: 170 print("No Perl installation was found. Existing Makefiles are used.") 171 sys.stdout.flush() 172 # Look for SSL 2 levels up from pcbuild - ie, same place zlib etc all live. 173 ssl_dir = get_ssl_dir() 174 if ssl_dir is None: 175 sys.exit(1) 176 177 # add our copy of NASM to PATH. It will be on the same level as openssl 178 for dir in os.listdir(os.path.join(ssl_dir, os.pardir)): 179 if dir.startswith('nasm'): 180 nasm_dir = os.path.join(ssl_dir, os.pardir, dir) 181 nasm_dir = os.path.abspath(nasm_dir) 182 old_path = os.environ['PATH'] 183 os.environ['PATH'] = os.pathsep.join([nasm_dir, old_path]) 184 break 185 else: 186 print('NASM was not found, make sure it is on PATH') 187 188 189 old_cd = os.getcwd() 190 try: 191 os.chdir(ssl_dir) 192 # rebuild makefile when we do the role over from 32 to 64 build 193 if arch == "amd64" and os.path.isfile(m32) and not os.path.isfile(makefile): 194 os.unlink(m32) 195 196 # If the ssl makefiles do not exist, we invoke Perl to generate them. 197 # Due to a bug in this script, the makefile sometimes ended up empty 198 # Force a regeneration if it is. 199 if not os.path.isfile(makefile) or os.path.getsize(makefile)==0: 200 if perl is None: 201 print("Perl is required to build the makefiles!") 202 sys.exit(1) 203 204 print("Creating the makefiles...") 205 sys.stdout.flush() 206 # Put our working Perl at the front of our path 207 os.environ["PATH"] = os.path.dirname(perl) + \ 208 os.pathsep + \ 209 os.environ["PATH"] 210 run_configure(configure, do_script) 211 if debug: 212 print("OpenSSL debug builds aren't supported.") 213 #if arch=="x86" and debug: 214 # # the do_masm script in openssl doesn't generate a debug 215 # # build makefile so we generate it here: 216 # os.system("perl util\mk1mf.pl debug "+configure+" >"+makefile) 217 218 if arch == "amd64": 219 create_makefile64(makefile, m32) 220 fix_makefile(makefile) 221 shutil.copy(r"crypto\buildinf.h", r"crypto\buildinf_%s.h" % arch) 222 shutil.copy(r"crypto\opensslconf.h", r"crypto\opensslconf_%s.h" % arch) 223 224 # Now run make. 225 if arch == "amd64": 226 rc = os.system("nasm -f win64 -DNEAR -Ox -g ms\\uptable.asm") 227 if rc: 228 print("nasm assembler has failed.") 229 sys.exit(rc) 230 231 shutil.copy(r"crypto\buildinf_%s.h" % arch, r"crypto\buildinf.h") 232 shutil.copy(r"crypto\opensslconf_%s.h" % arch, r"crypto\opensslconf.h") 233 234 #makeCommand = "nmake /nologo PERL=\"%s\" -f \"%s\"" %(perl, makefile) 235 makeCommand = "nmake /nologo -f \"%s\"" % makefile 236 print("Executing ssl makefiles:", makeCommand) 237 sys.stdout.flush() 238 rc = os.system(makeCommand) 239 if rc: 240 print("Executing "+makefile+" failed") 241 print(rc) 242 sys.exit(rc) 243 finally: 244 os.chdir(old_cd) 245 sys.exit(rc) 246 247if __name__=='__main__': 248 main() 249