blob: 6894880d4302c1b7e029361c86664deee5b27873 [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
Zachary Warea59f9632015-04-09 15:48:32 -0500118 copy_if_different = r'$(PERL) $(SRC_D)\util\copy-if-different.pl'
Zachary Ware10c2dba2014-05-09 09:07:50 -0500119 with open(makefile) as fin:
120 lines = fin.readlines()
121 with open(makefile, 'w') as fout:
122 for line in lines:
123 if line.startswith("PERL="):
124 continue
125 if line.startswith("CP="):
126 line = "CP=copy\n"
127 if line.startswith("MKDIR="):
128 line = "MKDIR=mkdir\n"
129 if line.startswith("CFLAG="):
130 line = line.strip()
131 for algo in ("RC5", "MDC2", "IDEA"):
132 noalgo = " -DOPENSSL_NO_%s" % algo
133 if noalgo not in line:
134 line = line + noalgo
135 line = line + '\n'
Zachary Warea59f9632015-04-09 15:48:32 -0500136 if copy_if_different in line:
137 line = line.replace(copy_if_different, 'copy /Y')
Zachary Ware10c2dba2014-05-09 09:07:50 -0500138 fout.write(line)
139
140def run_configure(configure, do_script):
141 print("perl Configure "+configure+" no-idea no-mdc2")
142 os.system("perl Configure "+configure+" no-idea no-mdc2")
143 print(do_script)
144 os.system(do_script)
145
146def cmp(f1, f2):
147 bufsize = 1024 * 8
148 with open(f1, 'rb') as fp1, open(f2, 'rb') as fp2:
149 while True:
150 b1 = fp1.read(bufsize)
151 b2 = fp2.read(bufsize)
152 if b1 != b2:
153 return False
154 if not b1:
155 return True
156
157def copy(src, dst):
158 if os.path.isfile(dst) and cmp(src, dst):
159 return
160 shutil.copy(src, dst)
161
162def prep(arch):
163 if arch == "x86":
164 configure = "VC-WIN32"
165 do_script = "ms\\do_nasm"
166 makefile="ms\\nt.mak"
167 m32 = makefile
168 dirsuffix = "32"
169 elif arch == "amd64":
170 configure = "VC-WIN64A"
171 do_script = "ms\\do_win64a"
172 makefile = "ms\\nt64.mak"
173 m32 = makefile.replace('64', '')
174 dirsuffix = "64"
175 #os.environ["VSEXTCOMP_USECL"] = "MS_OPTERON"
176 else:
177 raise ValueError('Unrecognized platform: %s' % arch)
178
179 # rebuild makefile when we do the role over from 32 to 64 build
180 if arch == "amd64" and os.path.isfile(m32) and not os.path.isfile(makefile):
181 os.unlink(m32)
182
183 # If the ssl makefiles do not exist, we invoke Perl to generate them.
184 # Due to a bug in this script, the makefile sometimes ended up empty
185 # Force a regeneration if it is.
186 if not os.path.isfile(makefile) or os.path.getsize(makefile)==0:
187 print("Creating the makefiles...")
188 sys.stdout.flush()
189 run_configure(configure, do_script)
190
191 if arch == "amd64":
192 create_makefile64(makefile, m32)
193 fix_makefile(makefile)
194 copy(r"crypto\buildinf.h", r"crypto\buildinf_%s.h" % arch)
195 copy(r"crypto\opensslconf.h", r"crypto\opensslconf_%s.h" % arch)
196 else:
197 print(makefile, 'already exists!')
198
Zachary Ware2897d072014-08-06 22:47:23 -0500199 print('creating asms...')
200 create_asms(makefile)
Zachary Ware10c2dba2014-05-09 09:07:50 -0500201
202def main():
203 if len(sys.argv) == 1:
204 print("Not enough arguments: directory containing OpenSSL",
205 "sources must be supplied")
206 sys.exit(1)
207
208 if len(sys.argv) > 2:
209 print("Too many arguments supplied, all we need is the directory",
210 "containing OpenSSL sources")
211 sys.exit(1)
212
213 ssl_dir = sys.argv[1]
214
Charles-François Natali6315ffa2014-06-20 22:41:21 +0100215 if not os.path.isdir(ssl_dir):
Zachary Ware10c2dba2014-05-09 09:07:50 -0500216 print(ssl_dir, "is not an existing directory!")
217 sys.exit(1)
218
219 # perl should be on the path, but we also look in "\perl" and "c:\\perl"
220 # as "well known" locations
221 perls = find_all_on_path("perl.exe", ["\\perl\\bin", "C:\\perl\\bin"])
222 perl = find_working_perl(perls)
223 if perl:
224 print("Found a working perl at '%s'" % (perl,))
225 else:
226 sys.exit(1)
227 sys.stdout.flush()
228
229 # Put our working Perl at the front of our path
230 os.environ["PATH"] = os.path.dirname(perl) + \
231 os.pathsep + \
232 os.environ["PATH"]
233
234 old_cwd = os.getcwd()
235 try:
236 os.chdir(ssl_dir)
237 for arch in ['amd64', 'x86']:
238 prep(arch)
239 finally:
240 os.chdir(old_cwd)
241
242if __name__=='__main__':
243 main()