-
-
Notifications
You must be signed in to change notification settings - Fork 16
/
make_headers.py
115 lines (101 loc) · 5.23 KB
/
make_headers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""Generate header files from Boost source distribution."""
import argparse
import gzip
import logging
import pkg_resources
import pathlib
import platform
import urllib.request
import shutil
import subprocess
import tarfile
import tempfile
from time import time
logging.basicConfig()
def _generate_headers(ver: str, verbose: bool):
# setup logging
logger = logging.getLogger('boost-make-headers')
if verbose:
logger.setLevel(logging.INFO)
# base is where this script is located
base = pathlib.Path(__file__).parent
BOOST_VER_DOT = pkg_resources.parse_version(ver).base_version
BOOST_VER_UND = '_'.join(BOOST_VER_DOT.split('.'))
# download gzipped tarball
# location of tarballs can also be found at https://www.boost.org/users/download/
archive_name = f'boost_{BOOST_VER_UND}'
url = f'https://boostorg.jfrog.io/artifactory/main/release/{BOOST_VER_DOT}/source/{archive_name}.tar.gz'
t0 = time()
with urllib.request.urlopen(url) as response:
logger.info(f'Starting download of BOOST {BOOST_VER_DOT} source distribution')
with gzip.GzipFile(fileobj=response) as uncompressed, tempfile.NamedTemporaryFile(delete=False, suffix='.tar') as ntf:
logger.info(f'Saving Boost tarball to {ntf.name}')
shutil.copyfileobj(uncompressed, ntf)
logger.info(f'Finished downloading and uncompressing in {time() - t0:.2f} seconds')
ntf.flush()
logger.info('Starting to extract')
t0 = time()
try:
with tarfile.open(ntf.name, 'r') as tar, tempfile.TemporaryDirectory() as tmpdir:
dst = pathlib.Path(tmpdir)
tar.extractall(path=dst)
logger.info(f'Finished extracting to {dst / archive_name} in {time() - t0:.2f} seconds')
# configure build by calling bootstrap.sh
logger.info('Starting configure')
t0 = time()
bootstrap_script = './bootstrap.sh' if platform.system() != 'Windows' else 'boostrap.bat'
with open(base / 'bootstrap.log', 'w') as fp:
if subprocess.run([f'{bootstrap_script}',
f'--prefix={dst / "boost_tmp_build"}',
'--with-libraries=math'],
cwd=dst / archive_name,
stdout=fp, stderr=fp).returncode != 0:
raise ValueError(f'Failed to run {bootstrap_script}!')
logger.info(f'Completed configure in {time() - t0:.2f} seconds')
# Do the build, will create some binaries but we will ignore these
logger.info('Starting build')
t0 = time()
with open(base / 'b2.log', 'w') as fp:
b2_script = './b2' if platform.system() != 'Windows' else 'b2'
if subprocess.run([b2_script, 'install'],
cwd=dst / archive_name,
stdout=fp, stderr=fp).returncode != 0:
raise ValueError(f'Failed to run {b2_script} install!')
# ensure the include/ directory really does exist where we think it does
if not (dst / 'boost_tmp_build').exists():
raise ValueError('Headers failed to generate!')
logger.info(f'Completed build in {time() - t0:.2f} seconds')
# Remove old headers and replace with new headers and move License, README
logger.info('Updating header files')
if (base / 'boost').exists():
shutil.rmtree(base / 'boost')
for f in pathlib.Path(__file__).parent.glob("Boost_*_README.md"):
f.unlink()
shutil.move(dst / 'boost_tmp_build/include/boost', base / 'boost')
shutil.move(dst / archive_name / 'LICENSE_1_0.txt', base / 'LICENSE_1_0.txt')
shutil.move(dst / archive_name / 'README.md', base / f'Boost_{BOOST_VER_UND}_README.md')
finally:
# We want to save the tar file as a temporary file and simultaneously
# extract it, meaning it will need to be opened in a context manager
# multiple times. While Linux can handle nested context managers
# using the same file handle, Windows cannot. So we have to mark the
# temporary file "ntf" as delete=False, close its context manager, and
# then ensure cleanup happens in this "finally" statement
ntf.close()
logger.info('Done creating base Boost headers!')
logger.info("Applying patches...")
patch_dir = pathlib.Path(__file__).parent / "patches"
for f in patch_dir.glob("*.patch"):
if subprocess.run(["git", "apply", str(f)], cwd=base).returncode != 0:
logger.error(f"Failed to apply patch: {f}. Skipping.")
logger.info(f"Applied {f}")
else:
logger.info("Found no patches to apply!")
logger.info("Done!")
if __name__ == '__main__':
parser = argparse.ArgumentParser(__doc__)
parser.add_argument('--boost-version', type=str,
help='Boost version to download formatted as [major].[minor].[patch].', required=True)
parser.add_argument('-v', action='store_true', help='Enable verbose logging.', default=False)
args = parser.parse_args()
_generate_headers(ver=args.boost_version, verbose=args.v)