• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Script for building the _ssl module for Windows.
2# Uses Perl to setup the OpenSSL environment correctly
3# and build OpenSSL, then invokes a simple nmake session
4# for _ssl.pyd itself.
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 PC/VC6 directory.
12#
13# it should configure and build SSL, then build the ssl Python extension
14# without intervention.
15
16# Modified by Christian Heimes
17# Now this script supports pre-generated makefiles and assembly files.
18# Developers don't need an installation of Perl anymore to build Python. A svn
19# checkout from our svn repository is enough.
20
21import os, sys, re, shutil
22
23# Find all "foo.exe" files on the PATH.
24def find_all_on_path(filename, extras = None):
25    entries = os.environ["PATH"].split(os.pathsep)
26    ret = []
27    for p in entries:
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    if extras:
32        for p in extras:
33            fname = os.path.abspath(os.path.join(p, filename))
34            if os.path.isfile(fname) and fname not in ret:
35                ret.append(fname)
36    return ret
37
38# Find a suitable Perl installation for OpenSSL.
39# cygwin perl does *not* work.  ActivePerl does.
40# Being a Perl dummy, the simplest way I can check is if the "Win32" package
41# is available.
42def find_working_perl(perls):
43    for perl in perls:
44        fh = os.popen('"%s" -e "use Win32;"' % perl)
45        fh.read()
46        rc = fh.close()
47        if rc:
48            continue
49        return perl
50    print "Can not find a suitable PERL:"
51    if perls:
52        print " the following perl interpreters were found:"
53        for p in perls:
54            print " ", p
55        print " None of these versions appear suitable for building OpenSSL"
56    else:
57        print " NO perl interpreters were found on this machine at all!"
58    print " Please install ActivePerl and ensure it appears on your path"
59    return None
60
61# Locate the best SSL directory given a few roots to look into.
62def find_best_ssl_dir(sources):
63    candidates = []
64    for s in sources:
65        try:
66            # note: do not abspath s; the build will fail if any
67            # higher up directory name has spaces in it.
68            fnames = os.listdir(s)
69        except os.error:
70            fnames = []
71        for fname in fnames:
72            fqn = os.path.join(s, fname)
73            if os.path.isdir(fqn) and fname.startswith("openssl-"):
74                candidates.append(fqn)
75    # Now we have all the candidates, locate the best.
76    best_parts = []
77    best_name = None
78    for c in candidates:
79        parts = re.split("[.-]", os.path.basename(c))[1:]
80        # eg - openssl-0.9.7-beta1 - ignore all "beta" or any other qualifiers
81        if len(parts) >= 4:
82            continue
83        if parts > best_parts:
84            best_parts = parts
85            best_name = c
86    if best_name is not None:
87        print "Found an SSL directory at '%s'" % (best_name,)
88    else:
89        print "Could not find an SSL directory in '%s'" % (sources,)
90    sys.stdout.flush()
91    return best_name
92
93def fix_makefile(makefile):
94    """Fix some stuff in all makefiles
95    """
96    if not os.path.isfile(makefile):
97        return
98    # 2.4 compatibility
99    fin = open(makefile)
100    if 1: # with open(makefile) as fin:
101        lines = fin.readlines()
102        fin.close()
103    fout = open(makefile, 'w')
104    if 1: # with open(makefile, 'w') as fout:
105        for line in lines:
106            if line.startswith("PERL="):
107                continue
108            if line.startswith("CP="):
109                line = "CP=copy\n"
110            if line.startswith("MKDIR="):
111                line = "MKDIR=mkdir\n"
112            if line.startswith("CFLAG="):
113                line = line.strip()
114                for algo in ("RC5", "MDC2", "IDEA"):
115                    noalgo = " -DOPENSSL_NO_%s" % algo
116                    if noalgo not in line:
117                        line = line + noalgo
118                line = line + '\n'
119            fout.write(line)
120    fout.close()
121
122def run_configure(configure, do_script):
123    print "perl Configure "+configure
124    os.system("perl Configure "+configure)
125    print do_script
126    os.system(do_script)
127
128def cmp(f1, f2):
129    bufsize = 1024 * 8
130    with open(f1, 'rb') as fp1, open(f2, 'rb') as fp2:
131        while True:
132            b1 = fp1.read(bufsize)
133            b2 = fp2.read(bufsize)
134            if b1 != b2:
135                return False
136            if not b1:
137                return True
138
139def copy(src, dst):
140    if os.path.isfile(dst) and cmp(src, dst):
141        return
142    shutil.copy(src, dst)
143
144def main():
145    debug = "-d" in sys.argv
146    build_all = "-a" in sys.argv
147    if 1: # Win32
148        arch = "x86"
149        configure = "VC-WIN32"
150        do_script = "ms\\do_nasm"
151        makefile="ms\\nt.mak"
152        m32 = makefile
153        dirsuffix = "32"
154    configure += " no-idea no-rc5 no-mdc2"
155    make_flags = ""
156    if build_all:
157        make_flags = "-a"
158    # perl should be on the path, but we also look in "\perl" and "c:\\perl"
159    # as "well known" locations
160    perls = find_all_on_path("perl.exe", ["\\perl\\bin", "C:\\perl\\bin"])
161    perl = find_working_perl(perls)
162    if perl:
163        print "Found a working perl at '%s'" % (perl,)
164    else:
165        print "No Perl installation was found. Existing Makefiles are used."
166    sys.stdout.flush()
167    # Look for SSL 3 levels up from PC/VC6 - ie, same place zlib etc all live.
168    ssl_dir = find_best_ssl_dir(("..\\..\\..",))
169    if ssl_dir is None:
170        sys.exit(1)
171
172    old_cd = os.getcwd()
173    try:
174        os.chdir(ssl_dir)
175        # If the ssl makefiles do not exist, we invoke Perl to generate them.
176        # Due to a bug in this script, the makefile sometimes ended up empty
177        # Force a regeneration if it is.
178        if not os.path.isfile(makefile) or os.path.getsize(makefile)==0:
179            if perl is None:
180                print "Perl is required to build the makefiles!"
181                sys.exit(1)
182
183            print "Creating the makefiles..."
184            sys.stdout.flush()
185            # Put our working Perl at the front of our path
186            os.environ["PATH"] = os.path.dirname(perl) + \
187                                          os.pathsep + \
188                                          os.environ["PATH"]
189            run_configure(configure, do_script)
190            if debug:
191                print "OpenSSL debug builds aren't supported."
192            #if arch=="x86" and debug:
193            #    # the do_masm script in openssl doesn't generate a debug
194            #    # build makefile so we generate it here:
195            #    os.system("perl util\mk1mf.pl debug "+configure+" >"+makefile)
196
197            fix_makefile(makefile)
198            copy(r"crypto\buildinf.h", r"crypto\buildinf_%s.h" % arch)
199            copy(r"crypto\opensslconf.h", r"crypto\opensslconf_%s.h" % arch)
200
201        # If the assembler files don't exist in tmpXX, copy them there
202        if perl is None:
203            if not os.path.exists("tmp"+dirsuffix):
204                os.mkdir("tmp"+dirsuffix)
205            for f in os.listdir("asm"+dirsuffix):
206                if not f.endswith(".asm"): continue
207                if os.path.isfile(r"tmp%s\%s" % (dirsuffix, f)): continue
208                shutil.copy(r"asm%s\%s" % (dirsuffix, f), "tmp"+dirsuffix)
209
210        # Now run make.
211        copy(r"crypto\buildinf_%s.h" % arch, r"crypto\buildinf.h")
212        copy(r"crypto\opensslconf_%s.h" % arch, r"crypto\opensslconf.h")
213
214        #makeCommand = "nmake /nologo PERL=\"%s\" -f \"%s\"" %(perl, makefile)
215        makeCommand = "nmake /nologo -f \"%s\"" % makefile
216        print "Executing ssl makefiles:", makeCommand
217        sys.stdout.flush()
218        rc = os.system(makeCommand)
219        if rc:
220            print "Executing "+makefile+" failed"
221            print rc
222            sys.exit(rc)
223    finally:
224        os.chdir(old_cd)
225    # And finally, we can build the _ssl module itself for Python.
226    defs = "SSL_DIR=%s" % (ssl_dir,)
227    if debug:
228        defs = defs + " " + "DEBUG=1"
229    rc = os.system('nmake /nologo -f _ssl.mak ' + defs + " " + make_flags)
230    sys.exit(rc)
231
232if __name__=='__main__':
233    main()
234