Skip to content

Commit 617b544

Browse files
committed
windows: support for building OpenSSL from sources
This is extremely hacky. But I think it produces the necessary files to support static linking. Things still aren't hooked up to CPython's build system.
1 parent 6888ed6 commit 617b544

File tree

4 files changed

+130
-1
lines changed

4 files changed

+130
-1
lines changed

README.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ To build a Python distribution for macOS::
4141

4242
$ ./build-macos.py
4343

44+
To build a Python distribution for Windows x64::
45+
46+
# Install ActivePerl
47+
# From a Visual Studio 2017 x64 native tools command prompt:
48+
$ set PERL=c:\path\to\activeperl\bin\perl.exe
49+
$ py.exe build-windows.py
50+
4451
Requirements
4552
============
4653

build-windows.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ def run():
6464

6565

6666
if __name__ == '__main__':
67+
if 'PERL' not in os.environ:
68+
print('PERL must point to a perl executable')
69+
sys.exit(1)
70+
6771
try:
6872
if 'PYBUILD_BOOTSTRAPPED' not in os.environ:
6973
bootstrap()

cpython-windows/build.py

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import os
88
import pathlib
99
import re
10+
import shutil
1011
import subprocess
1112
import sys
1213
import tempfile
@@ -768,13 +769,112 @@ def run_msbuild(msbuild: pathlib.Path, pcbuild_path: pathlib.Path,
768769
exec_and_log(args, str(pcbuild_path), os.environ)
769770

770771

772+
def build_openssl_for_arch(perl_path, arch: str, openssl_archive, nasm_archive,
773+
build_root: pathlib.Path):
774+
openssl_version = DOWNLOADS['openssl']['version']
775+
nasm_version = DOWNLOADS['nasm-windows-bin']['version']
776+
777+
778+
log('extracting %s to %s' % (openssl_archive, build_root))
779+
extract_tar_to_directory(openssl_archive, build_root)
780+
log('extracting %s to %s' % (nasm_archive, build_root))
781+
extract_tar_to_directory(nasm_archive, build_root)
782+
783+
nasm_path = build_root / ('cpython-bin-deps-nasm-%s' % nasm_version)
784+
785+
env = dict(os.environ)
786+
# Add Perl and nasm paths to front of PATH.
787+
env['PATH'] = '%s;%s;%s' % (
788+
perl_path.parent,
789+
nasm_path,
790+
env['PATH'],
791+
)
792+
793+
source_root = build_root / ('openssl-%s' % openssl_version)
794+
795+
if arch == 'x86':
796+
configure = 'VC-WIN32'
797+
prefix = '32'
798+
elif arch == 'amd64':
799+
configure = 'VC-WIN64A'
800+
prefix = '64'
801+
else:
802+
print('invalid architecture: %s' % arch)
803+
sys.exit(1)
804+
805+
# The official CPython OpenSSL builds hack ms/uplink.c to change the
806+
# ``GetModuleHandle(NULL)`` invocation to load things from _ssl.pyd
807+
# instead. But since we statically link the _ssl extension, this hackery
808+
# is not required.
809+
810+
# Set DESTDIR to affect install location.
811+
dest_dir = build_root / 'install'
812+
env['DESTDIR'] = str(dest_dir)
813+
install_root = dest_dir / prefix
814+
815+
exec_and_log([str(perl_path), 'Configure', configure, 'no-idea', 'no-mdc2',
816+
'--prefix=/%s' % prefix], source_root, env)
817+
exec_and_log(['nmake'], source_root, env)
818+
819+
# We don't care about accessory files, docs, etc. So just run `install_sw`
820+
# target to get the main files.
821+
exec_and_log(['nmake', 'install_sw'], source_root, env)
822+
823+
# Copy the _static libraries as well.
824+
for l in ('crypto', 'ssl'):
825+
basename = 'lib%s_static.lib' % l
826+
source = source_root / basename
827+
dest = install_root / 'lib' / basename
828+
log('copying %s to %s' % (source, dest))
829+
shutil.copyfile(source, dest)
830+
831+
832+
def build_openssl(perl_path: pathlib.Path):
833+
"""Build OpenSSL from sources using the Perl executable specified."""
834+
835+
# First ensure the dependencies are in place.
836+
openssl_archive = download_entry('openssl', BUILD)
837+
nasm_archive = download_entry('nasm-windows-bin', BUILD)
838+
839+
with tempfile.TemporaryDirectory() as td:
840+
td = pathlib.Path(td)
841+
842+
root_32 = td / 'x86'
843+
root_64 = td / 'x64'
844+
root_32.mkdir()
845+
root_64.mkdir()
846+
847+
# Then build the 32 and 64 bit OpenSSL installs in parallel
848+
# (because nmake doesn't do parallel builds).
849+
# TODO we need to adjust the environment to pull in a x86 toolchain
850+
# in order for this to work.
851+
fs = []
852+
with concurrent.futures.ThreadPoolExecutor(2) as e:
853+
#fs.append(e.submit(build_openssl_for_arch, perl_path, 'x86',
854+
# openssl_archive, nasm_archive, root_32))
855+
fs.append(e.submit(build_openssl_for_arch, perl_path, 'amd64',
856+
openssl_archive, nasm_archive, root_64))
857+
858+
for f in fs:
859+
f.result()
860+
861+
install = td / 'out'
862+
#shutil.copytree(root_32 / 'install' / '32', install / 'openssl' / 'win32')
863+
shutil.copytree(root_64 / 'install' / '64', install / 'openssl' / 'amd64')
864+
865+
dest_archive = BUILD / 'openssl-windows.tar'
866+
with dest_archive.open('wb') as fh:
867+
create_tar_from_directory(fh, install)
868+
869+
771870
def build_cpython(pgo=False):
772871
msbuild = find_msbuild()
773872
log('found MSBuild at %s' % msbuild)
774873

775874
# The python.props file keys off MSBUILD, so it needs to be set.
776875
os.environ['MSBUILD'] = str(msbuild)
777876

877+
activeperl_installer = download_entry('activeperl', BUILD)
778878
bzip2_archive = download_entry('bzip2', BUILD)
779879
#openssl_archive = download_entry('openssl', BUILD)
780880
openssl_bin_archive = download_entry('openssl-windows-bin', BUILD)
@@ -864,11 +964,17 @@ def main():
864964
BUILD.mkdir(exist_ok=True)
865965

866966
log_path = BUILD / 'build.log'
867-
LOG_PREFIX[0] = 'cpython'
868967

869968
with log_path.open('wb') as log_fh:
870969
LOG_FH[0] = log_fh
871970

971+
# TODO need better dependency checking.
972+
openssl_out = BUILD / 'openssl-windows.tar'
973+
if not openssl_out.exists():
974+
LOG_PREFIX[0] = 'openssl'
975+
build_openssl(pathlib.Path(os.environ['PERL']))
976+
977+
LOG_PREFIX[0] = 'cpython'
872978
build_cpython()
873979

874980
if __name__ == '__main__':

pythonbuild/downloads.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

55
DOWNLOADS = {
6+
'activeperl': {
7+
'url': 'https://downloads.activestate.com/ActivePerl/releases/5.26.3.2603/ActivePerl-5.26.3.2603-MSWin32-x64-a95bce075.exe',
8+
'size': 22429768,
9+
'sha256': 'bbd88265ab6d0ceb5ec2a6cd9870b0e9cd35b0d9be7671df840b0f239726b28d',
10+
'version': '5.26.3.2603',
11+
},
612
# 6.0.19 is the last version licensed under the Sleepycat license.
713
'bdb': {
814
'url': 'https://ftp.tw.freebsd.org/distfiles/bdb/db-6.0.19.tar.gz',
@@ -195,6 +201,12 @@
195201
'sha256': 'c4684e220473fb2bdb0b95e43183c4701b6b103acac5ec23385e41a9a77fc9b1',
196202
'version': '1.1.0j',
197203
},
204+
'nasm-windows-bin': {
205+
'url': 'https://github.com/python/cpython-bin-deps/archive/nasm-2.11.06.tar.gz',
206+
'size': 384826,
207+
'sha256': '8af0ae5ceed63fa8a2ded611d44cc341027a91df22aaaa071efedc81437412a5',
208+
'version': '2.11.06',
209+
},
198210
'readline': {
199211
'url': 'ftp://ftp.gnu.org/gnu/readline/readline-6.3.tar.gz',
200212
'size': 2468560,

0 commit comments

Comments
 (0)