1#! /usr/bin/env python3 2# Script for preparing OpenSSL for building on Windows. 3# Uses Perl to create nmake makefiles and otherwise prepare the way 4# for building on 32 or 64 bit platforms. 5 6# Script originally authored by Mark Hammond. 7# Major revisions by: 8# Martin v. Löwis 9# Christian Heimes 10# Zachary Ware 11 12# THEORETICALLY, you can: 13# * Unpack the latest OpenSSL release where $(opensslDir) in 14# PCbuild\pyproject.props expects it to be. 15# * Install ActivePerl and ensure it is somewhere on your path. 16# * Run this script with the OpenSSL source dir as the only argument. 17# 18# it should configure OpenSSL such that it is ready to be built by 19# ssl.vcxproj on 32 or 64 bit platforms. 20 21from __future__ import print_function 22 23import os 24import re 25import sys 26import subprocess 27from shutil import copy 28 29# Find all "foo.exe" files on the PATH. 30def find_all_on_path(filename, extras=None): 31 entries = os.environ["PATH"].split(os.pathsep) 32 ret = [] 33 for p in entries: 34 fname = os.path.abspath(os.path.join(p, filename)) 35 if os.path.isfile(fname) and fname not in ret: 36 ret.append(fname) 37 if extras: 38 for p in extras: 39 fname = os.path.abspath(os.path.join(p, filename)) 40 if os.path.isfile(fname) and fname not in ret: 41 ret.append(fname) 42 return ret 43 44 45# Find a suitable Perl installation for OpenSSL. 46# cygwin perl does *not* work. ActivePerl does. 47# Being a Perl dummy, the simplest way I can check is if the "Win32" package 48# is available. 49def find_working_perl(perls): 50 for perl in perls: 51 try: 52 subprocess.check_output([perl, "-e", "use Win32;"]) 53 except subprocess.CalledProcessError: 54 continue 55 else: 56 return perl 57 58 if perls: 59 print("The following perl interpreters were found:") 60 for p in perls: 61 print(" ", p) 62 print(" None of these versions appear suitable for building OpenSSL") 63 else: 64 print("NO perl interpreters were found on this machine at all!") 65 print(" Please install ActivePerl and ensure it appears on your path") 66 67 68def create_asms(makefile, tmp_d): 69 #create a custom makefile out of the provided one 70 asm_makefile = os.path.splitext(makefile)[0] + '.asm.mak' 71 with open(makefile) as fin, open(asm_makefile, 'w') as fout: 72 for line in fin: 73 # Keep everything up to the install target (it's convenient) 74 if line.startswith('install: all'): 75 break 76 fout.write(line) 77 asms = [] 78 for line in fin: 79 if '.asm' in line and line.strip().endswith('.pl'): 80 asms.append(line.split(':')[0]) 81 while line.strip(): 82 fout.write(line) 83 line = next(fin) 84 fout.write('\n') 85 86 fout.write('asms: $(TMP_D) ') 87 fout.write(' '.join(asms)) 88 fout.write('\n') 89 os.system('nmake /f {} PERL=perl TMP_D={} asms'.format(asm_makefile, tmp_d)) 90 91 92def copy_includes(makefile, suffix): 93 dir = 'include'+suffix+'\\openssl' 94 try: 95 os.makedirs(dir) 96 except OSError: 97 pass 98 copy_if_different = r'$(PERL) $(SRC_D)\util\copy-if-different.pl' 99 with open(makefile) as fin: 100 for line in fin: 101 if copy_if_different in line: 102 perl, script, src, dest = line.split() 103 if not '$(INCO_D)' in dest: 104 continue 105 # We're in the root of the source tree 106 src = src.replace('$(SRC_D)', '.').strip('"') 107 dest = dest.strip('"').replace('$(INCO_D)', dir) 108 print('copying', src, 'to', dest) 109 copy(src, dest) 110 111 112def run_configure(configure, do_script): 113 print("perl Configure "+configure+" no-idea no-mdc2") 114 os.system("perl Configure "+configure+" no-idea no-mdc2") 115 print(do_script) 116 os.system(do_script) 117 118 119def prep(arch): 120 makefile_template = "ms\\nt{}.mak" 121 generated_makefile = makefile_template.format('') 122 if arch == "x86": 123 configure = "VC-WIN32" 124 do_script = "ms\\do_nasm" 125 suffix = "32" 126 elif arch == "amd64": 127 configure = "VC-WIN64A" 128 do_script = "ms\\do_win64a" 129 suffix = "64" 130 #os.environ["VSEXTCOMP_USECL"] = "MS_OPTERON" 131 else: 132 raise ValueError('Unrecognized platform: %s' % arch) 133 134 print("Creating the makefiles...") 135 sys.stdout.flush() 136 # run configure, copy includes, create asms 137 run_configure(configure, do_script) 138 makefile = makefile_template.format(suffix) 139 try: 140 os.unlink(makefile) 141 except FileNotFoundError: 142 pass 143 os.rename(generated_makefile, makefile) 144 copy_includes(makefile, suffix) 145 146 print('creating asms...') 147 create_asms(makefile, 'tmp'+suffix) 148 149 150def main(): 151 if len(sys.argv) == 1: 152 print("Not enough arguments: directory containing OpenSSL", 153 "sources must be supplied") 154 sys.exit(1) 155 156 if len(sys.argv) > 2: 157 print("Too many arguments supplied, all we need is the directory", 158 "containing OpenSSL sources") 159 sys.exit(1) 160 161 ssl_dir = sys.argv[1] 162 163 if not os.path.isdir(ssl_dir): 164 print(ssl_dir, "is not an existing directory!") 165 sys.exit(1) 166 167 # perl should be on the path, but we also look in "\perl" and "c:\\perl" 168 # as "well known" locations 169 perls = find_all_on_path("perl.exe", [r"\perl\bin", 170 r"C:\perl\bin", 171 r"\perl64\bin", 172 r"C:\perl64\bin", 173 ]) 174 perl = find_working_perl(perls) 175 if perl: 176 print("Found a working perl at '%s'" % (perl,)) 177 else: 178 sys.exit(1) 179 if not find_all_on_path('nmake.exe'): 180 print('Could not find nmake.exe, try running env.bat') 181 sys.exit(1) 182 if not find_all_on_path('nasm.exe'): 183 print('Could not find nasm.exe, please add to PATH') 184 sys.exit(1) 185 sys.stdout.flush() 186 187 # Put our working Perl at the front of our path 188 os.environ["PATH"] = os.path.dirname(perl) + \ 189 os.pathsep + \ 190 os.environ["PATH"] 191 192 old_cwd = os.getcwd() 193 try: 194 os.chdir(ssl_dir) 195 for arch in ['amd64', 'x86']: 196 prep(arch) 197 finally: 198 os.chdir(old_cwd) 199 200if __name__=='__main__': 201 main() 202