blob: 199c4efe2545cd45331c32c3561ce1bab1bd28ab [file] [log] [blame]
Zachary Ware10c2dba2014-05-09 09:07:50 -05001# Script for preparing OpenSSL for building on Windows.
2# Uses Perl to create nmake makefiles and otherwise prepare the way
3# for building on 32 or 64 bit platforms.
4
5# Script originally authored by Mark Hammond.
6# Major revisions by:
7# Martin v. Löwis
8# Christian Heimes
9# Zachary Ware
10
11# THEORETICALLY, you can:
12# * Unpack the latest OpenSSL release where $(opensslDir) in
13# PCbuild\pyproject.props expects it to be.
14# * Install ActivePerl and ensure it is somewhere on your path.
15# * Run this script with the OpenSSL source dir as the only argument.
16#
17# it should configure OpenSSL such that it is ready to be built by
18# ssl.vcxproj on 32 or 64 bit platforms.
19
20import os
21import re
22import sys
23import shutil
Tim Goldenfaf4d9c2014-05-09 18:01:44 +010024import subprocess
Zachary Ware10c2dba2014-05-09 09:07:50 -050025
26# Find all "foo.exe" files on the PATH.
27def find_all_on_path(filename, extras = None):
28 entries = os.environ["PATH"].split(os.pathsep)
29 ret = []
30 for p in entries:
31 fname = os.path.abspath(os.path.join(p, filename))
32 if os.path.isfile(fname) and fname not in ret:
33 ret.append(fname)
34 if extras:
35 for p in extras:
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 return ret
40
41# Find a suitable Perl installation for OpenSSL.
42# cygwin perl does *not* work. ActivePerl does.
43# Being a Perl dummy, the simplest way I can check is if the "Win32" package
44# is available.
45def find_working_perl(perls):
46 for perl in perls:
Tim Goldenfaf4d9c2014-05-09 18:01:44 +010047 try:
48 subprocess.check_output([perl, "-e", "use Win32;"])
49 except subprocess.CalledProcessError:
Zachary Ware10c2dba2014-05-09 09:07:50 -050050 continue
Tim Goldenfaf4d9c2014-05-09 18:01:44 +010051 else:
52 return perl
53
Zachary Ware10c2dba2014-05-09 09:07:50 -050054 if perls:
Tim Goldenfaf4d9c2014-05-09 18:01:44 +010055 print("The following perl interpreters were found:")
Zachary Ware10c2dba2014-05-09 09:07:50 -050056 for p in perls:
57 print(" ", p)
58 print(" None of these versions appear suitable for building OpenSSL")
59 else:
Tim Goldenfaf4d9c2014-05-09 18:01:44 +010060 print("NO perl interpreters were found on this machine at all!")
Zachary Ware10c2dba2014-05-09 09:07:50 -050061 print(" Please install ActivePerl and ensure it appears on your path")
Zachary Ware10c2dba2014-05-09 09:07:50 -050062
63def create_makefile64(makefile, m32):
64 """Create and fix makefile for 64bit
65
66 Replace 32 with 64bit directories
67 """
68 if not os.path.isfile(m32):
69 return
70 with open(m32) as fin:
71 with open(makefile, 'w') as fout:
72 for line in fin:
73 line = line.replace("=tmp32", "=tmp64")
74 line = line.replace("=out32", "=out64")
75 line = line.replace("=inc32", "=inc64")
76 # force 64 bit machine
77 line = line.replace("MKLIB=lib", "MKLIB=lib /MACHINE:X64")
78 line = line.replace("LFLAGS=", "LFLAGS=/MACHINE:X64 ")
79 # don't link against the lib on 64bit systems
80 line = line.replace("bufferoverflowu.lib", "")
81 fout.write(line)
82 os.unlink(m32)
83
Zachary Ware2897d072014-08-06 22:47:23 -050084def create_asms(makefile):
85 #create a custom makefile out of the provided one
86 asm_makefile = os.path.splitext(makefile)[0] + '.asm.mak'
87 with open(makefile) as fin:
88 with open(asm_makefile, 'w') as fout:
89 for line in fin:
90 # Keep everything up to the install target (it's convenient)
91 if line.startswith('install: all'):
92 break
93 else:
94 fout.write(line)
95 asms = []
96 for line in fin:
97 if '.asm' in line and line.strip().endswith('.pl'):
98 asms.append(line.split(':')[0])
99 while line.strip():
100 fout.write(line)
101 line = next(fin)
102 fout.write('\n')
103
104 fout.write('asms: $(TMP_D) ')
105 fout.write(' '.join(asms))
106 fout.write('\n')
107
108 os.system('nmake /f {} PERL=perl asms'.format(asm_makefile))
109 os.unlink(asm_makefile)
110
111
112
Zachary Ware10c2dba2014-05-09 09:07:50 -0500113def fix_makefile(makefile):
114 """Fix some stuff in all makefiles
115 """
116 if not os.path.isfile(makefile):
117 return
118 with open(makefile) as fin:
119 lines = fin.readlines()
120 with open(makefile, 'w') as fout:
121 for line in lines:
122 if line.startswith("PERL="):
123 continue
124 if line.startswith("CP="):
125 line = "CP=copy\n"
126 if line.startswith("MKDIR="):
127 line = "MKDIR=mkdir\n"
128 if line.startswith("CFLAG="):
129 line = line.strip()
130 for algo in ("RC5", "MDC2", "IDEA"):
131 noalgo = " -DOPENSSL_NO_%s" % algo
132 if noalgo not in line:
133 line = line + noalgo
134 line = line + '\n'
135 fout.write(line)
136
137def run_configure(configure, do_script):
138 print("perl Configure "+configure+" no-idea no-mdc2")
139 os.system("perl Configure "+configure+" no-idea no-mdc2")
140 print(do_script)
141 os.system(do_script)
142
143def cmp(f1, f2):
144 bufsize = 1024 * 8
145 with open(f1, 'rb') as fp1, open(f2, 'rb') as fp2:
146 while True:
147 b1 = fp1.read(bufsize)
148 b2 = fp2.read(bufsize)
149 if b1 != b2:
150 return False
151 if not b1:
152 return True
153
154def copy(src, dst):
155 if os.path.isfile(dst) and cmp(src, dst):
156 return
157 shutil.copy(src, dst)
158
159def prep(arch):
160 if arch == "x86":
161 configure = "VC-WIN32"
162 do_script = "ms\\do_nasm"
163 makefile="ms\\nt.mak"
164 m32 = makefile
165 dirsuffix = "32"
166 elif arch == "amd64":
167 configure = "VC-WIN64A"
168 do_script = "ms\\do_win64a"
169 makefile = "ms\\nt64.mak"
170 m32 = makefile.replace('64', '')
171 dirsuffix = "64"
172 #os.environ["VSEXTCOMP_USECL"] = "MS_OPTERON"
173 else:
174 raise ValueError('Unrecognized platform: %s' % arch)
175
176 # rebuild makefile when we do the role over from 32 to 64 build
177 if arch == "amd64" and os.path.isfile(m32) and not os.path.isfile(makefile):
178 os.unlink(m32)
179
180 # If the ssl makefiles do not exist, we invoke Perl to generate them.
181 # Due to a bug in this script, the makefile sometimes ended up empty
182 # Force a regeneration if it is.
183 if not os.path.isfile(makefile) or os.path.getsize(makefile)==0:
184 print("Creating the makefiles...")
185 sys.stdout.flush()
186 run_configure(configure, do_script)
187
188 if arch == "amd64":
189 create_makefile64(makefile, m32)
190 fix_makefile(makefile)
191 copy(r"crypto\buildinf.h", r"crypto\buildinf_%s.h" % arch)
192 copy(r"crypto\opensslconf.h", r"crypto\opensslconf_%s.h" % arch)
193 else:
194 print(makefile, 'already exists!')
195
Zachary Ware2897d072014-08-06 22:47:23 -0500196 print('creating asms...')
197 create_asms(makefile)
Zachary Ware10c2dba2014-05-09 09:07:50 -0500198
199def main():
200 if len(sys.argv) == 1:
201 print("Not enough arguments: directory containing OpenSSL",
202 "sources must be supplied")
203 sys.exit(1)
204
205 if len(sys.argv) > 2:
206 print("Too many arguments supplied, all we need is the directory",
207 "containing OpenSSL sources")
208 sys.exit(1)
209
210 ssl_dir = sys.argv[1]
211
Charles-François Natali6315ffa2014-06-20 22:41:21 +0100212 if not os.path.isdir(ssl_dir):
Zachary Ware10c2dba2014-05-09 09:07:50 -0500213 print(ssl_dir, "is not an existing directory!")
214 sys.exit(1)
215
216 # perl should be on the path, but we also look in "\perl" and "c:\\perl"
217 # as "well known" locations
218 perls = find_all_on_path("perl.exe", ["\\perl\\bin", "C:\\perl\\bin"])
219 perl = find_working_perl(perls)
220 if perl:
221 print("Found a working perl at '%s'" % (perl,))
222 else:
223 sys.exit(1)
224 sys.stdout.flush()
225
226 # Put our working Perl at the front of our path
227 os.environ["PATH"] = os.path.dirname(perl) + \
228 os.pathsep + \
229 os.environ["PATH"]
230
231 old_cwd = os.getcwd()
232 try:
233 os.chdir(ssl_dir)
234 for arch in ['amd64', 'x86']:
235 prep(arch)
236 finally:
237 os.chdir(old_cwd)
238
239if __name__=='__main__':
240 main()