blob: 68e26d9b074d67f07d669d560ac1ae2512ab3e69 [file] [log] [blame]
Christian Heimese8954f82007-11-22 11:21:16 +00001# Script for building the _ssl and _hashlib modules for Windows.
2# Uses Perl to setup the OpenSSL environment correctly
3# and build OpenSSL, then invokes a simple nmake session
4# for the actual _ssl.pyd and _hashlib.pyd DLLs.
5
6# THEORETICALLY, you can:
7# * Unpack the latest SSL release one level above your main Python source
8# directory. It is likely you will already find the zlib library and
9# any other external packages there.
10# * Install ActivePerl and ensure it is somewhere on your path.
11# * Run this script from the PCBuild directory.
12#
13# it should configure and build SSL, then build the _ssl and _hashlib
14# Python extensions without intervention.
15
16import os, sys, re, shutil
17
18# Find all "foo.exe" files on the PATH.
19def find_all_on_path(filename, extras = None):
20 entries = os.environ["PATH"].split(os.pathsep)
21 ret = []
22 for p in entries:
23 fname = os.path.abspath(os.path.join(p, filename))
24 if os.path.isfile(fname) and fname not in ret:
25 ret.append(fname)
26 if extras:
27 for p in extras:
28 fname = os.path.abspath(os.path.join(p, filename))
29 if os.path.isfile(fname) and fname not in ret:
30 ret.append(fname)
31 return ret
32
33# Find a suitable Perl installation for OpenSSL.
34# cygwin perl does *not* work. ActivePerl does.
35# Being a Perl dummy, the simplest way I can check is if the "Win32" package
36# is available.
37def find_working_perl(perls):
38 for perl in perls:
39 fh = os.popen(perl + ' -e "use Win32;"')
40 fh.read()
41 rc = fh.close()
42 if rc:
43 continue
44 return perl
45 print("Can not find a suitable PERL:")
46 if perls:
47 print(" the following perl interpreters were found:")
48 for p in perls:
49 print(" ", p)
50 print(" None of these versions appear suitable for building OpenSSL")
51 else:
52 print(" NO perl interpreters were found on this machine at all!")
53 print(" Please install ActivePerl and ensure it appears on your path")
54 print("The Python SSL module was not built")
55 return None
56
57# Locate the best SSL directory given a few roots to look into.
58def find_best_ssl_dir(sources):
59 candidates = []
60 for s in sources:
61 try:
62 # note: do not abspath s; the build will fail if any
63 # higher up directory name has spaces in it.
64 fnames = os.listdir(s)
65 except os.error:
66 fnames = []
67 for fname in fnames:
68 fqn = os.path.join(s, fname)
69 if os.path.isdir(fqn) and fname.startswith("openssl-"):
70 candidates.append(fqn)
71 # Now we have all the candidates, locate the best.
72 best_parts = []
73 best_name = None
74 for c in candidates:
75 parts = re.split("[.-]", os.path.basename(c))[1:]
76 # eg - openssl-0.9.7-beta1 - ignore all "beta" or any other qualifiers
77 if len(parts) >= 4:
78 continue
79 if parts > best_parts:
80 best_parts = parts
81 best_name = c
82 if best_name is not None:
83 print("Found an SSL directory at '%s'" % (best_name,))
84 else:
85 print("Could not find an SSL directory in '%s'" % (sources,))
86 sys.stdout.flush()
87 return best_name
88
89def fix_makefile(makefile, m32):
90 """Fix makefile for 64bit
91
92 Replace 32 with 64bit directories
93 """
94 if not os.path.isfile(m32):
95 return
96 with open(m32) as fin:
97 with open(makefile, 'w') as fout:
98 for line in fin:
99 line = line.replace("=tmp32", "=tmp64")
100 line = line.replace("=out32", "=out64")
101 line = line.replace("=inc32", "=inc64")
102 # force 64 bit machine
103 line = line.replace("MKLIB=lib", "MKLIB=lib /MACHINE:X64")
104 line = line.replace("LFLAGS=", "LFLAGS=/MACHINE:X64 ")
105 # don't link against the lib on 64bit systems
106 line = line.replace("bufferoverflowu.lib", "")
107 fout.write(line)
108 os.unlink(m32)
109
110def run_configure(configure, do_script):
111 print("perl Configure "+configure)
112 os.system("perl Configure "+configure)
113 print(do_script)
114 os.system(do_script)
115
116def main():
117 build_all = "-a" in sys.argv
118 if sys.argv[1] == "Release":
119 debug = False
120 elif sys.argv[1] == "Debug":
121 debug = True
122 else:
123 raise ValueError(str(sys.argv))
124
125 if sys.argv[2] == "Win32":
126 arch = "x86"
127 configure = "VC-WIN32"
128 do_script = "ms\\do_nasm"
129 makefile="ms\\nt.mak"
130 m32 = makefile
131 elif sys.argv[2] == "x64":
132 arch="amd64"
133 configure = "VC-WIN64A"
134 do_script = "ms\\do_win64a"
135 makefile = "ms\\nt64.mak"
136 m32 = makefile.replace('64', '')
137 #os.environ["VSEXTCOMP_USECL"] = "MS_OPTERON"
138 else:
139 raise ValueError(str(sys.argv))
140
141 make_flags = ""
142 if build_all:
143 make_flags = "-a"
144 # perl should be on the path, but we also look in "\perl" and "c:\\perl"
145 # as "well known" locations
146 perls = find_all_on_path("perl.exe", ["\\perl\\bin", "C:\\perl\\bin"])
147 perl = find_working_perl(perls)
148 if perl is None:
149 sys.exit(1)
150
151 print("Found a working perl at '%s'" % (perl,))
152 sys.stdout.flush()
153 # Look for SSL 2 levels up from pcbuild - ie, same place zlib etc all live.
154 ssl_dir = find_best_ssl_dir(("..\\..",))
155 if ssl_dir is None:
156 sys.exit(1)
157
158 old_cd = os.getcwd()
159 try:
160 os.chdir(ssl_dir)
161 # rebuild makefile when we do the role over from 32 to 64 build
162 if arch == "amd64" and os.path.isfile(m32) and not os.path.isfile(makefile):
163 os.unlink(m32)
164
165 # If the ssl makefiles do not exist, we invoke Perl to generate them.
166 # Due to a bug in this script, the makefile sometimes ended up empty
167 # Force a regeneration if it is.
168 if not os.path.isfile(makefile) or os.path.getsize(makefile)==0:
169 print("Creating the makefiles...")
170 sys.stdout.flush()
171 # Put our working Perl at the front of our path
172 os.environ["PATH"] = os.path.dirname(perl) + \
173 os.pathsep + \
174 os.environ["PATH"]
175 run_configure(configure, do_script)
176 if arch=="x86" and debug:
177 # the do_masm script in openssl doesn't generate a debug
178 # build makefile so we generate it here:
179 os.system("perl util\mk1mf.pl debug "+configure+" >"+makefile)
180
181 if arch == "amd64":
182 fix_makefile(makefile, m32)
183
184 # Now run make.
185 makeCommand = "nmake /nologo PERL=\"%s\" -f \"%s\"" %(perl, makefile)
186 print("Executing ssl makefiles:", makeCommand)
187 sys.stdout.flush()
188 rc = os.system(makeCommand)
189 if rc:
190 print("Executing "+makefile+" failed")
191 print(rc)
192 sys.exit(rc)
193 finally:
194 os.chdir(old_cd)
195 sys.exit(rc)
196
197if __name__=='__main__':
198 main()