-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmerge_boost_cycles.py
executable file
·156 lines (144 loc) · 5.61 KB
/
merge_boost_cycles.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3
# See import_boost.py for usage.
import argparse
import json
import re
import urllib.request
import os
import os.path
import shutil
import bru
import copy
from collections import OrderedDict
import pdb # only if you want to add pdb.set_trace()
def get_library():
return bru.get_library()
def merge_key(source, target, key):
""" in-place merge """
assert isinstance(source, dict)
assert isinstance(target, dict)
if not key in source:
return # nothing to merge
value = source[key]
if key in target:
merge_elem(value, target[key])
else:
# no need to merge, just copy
target[key] = value
def merge_dict(source, target):
""" in-place merge """
assert isinstance(source, dict)
assert isinstance(target, dict)
for key in source.keys():
merge_key(source, target, key)
def merge_list(source, target):
""" in-place merge """
# don't create duplicates
assert isinstance(source, list)
assert isinstance(target, list)
merged = set(source).union(set(target))
target.clear()
target += merged
def merge_elem(source, target):
""" in-place merge """
if isinstance(target, list) and isinstance(source, list):
merge_list(source, target)
elif isinstance(target, dict) and isinstance(source, dict):
merge_dict(source, target)
elif isinstance(target, str) and isinstance(source, str) and target == source:
pass # nothing to do
else:
raise Exception('merge_elem cannot merge {} into {}'.format(
source, target))
# WARNING: after I started generating a *.gyp file for each
# modularized boost lib it turned out that gyp complained about
# dependency cycles between boost libs, and gyp refuses to generate
# makefiles between modules with circular deps (even with
# gyp --no-circular-check). Any modularization effort that ends up
# with dep cycles seems like a fail to me, I wonder what criterions
# where used for boost modularization :( In any case: we could
# auto-merge each cluster of circular dependent libs (choosing the
# conceptually highest-level cluster member's module name as the name
# for the cluster) if the number of dep cycles is small. See also
# http://lists.boost.org/Archives/boost/2014/06/214634.php
# for more details.
# Also see dep graphs at
# http://www.steveire.com/boost/after-edge-removal-june-14/range.png
# http://www.steveire.com/boost/deps-june-14/thread.png
# http://www.steveire.com/boost/deps-june-14/date_time.png
# http://www.steveire.com/boost/deps-june-14/regex.png
# See also cycle status at
# https://svn.boost.org/trac/boost/wiki/ModuleDepednecies
def fix_annoying_dependency_cycle(module_names, target_module, version):
""" merge all bru & gyp files together, making module_names[0] the
merge target """
print('merging dependency cycle:', module_names, 'into', target_module)
library = get_library()
formulas = list(map(
lambda module_name: library.load_formula(module_name, version),
module_names))
gyps = list(map(
lambda formula: library.load_gyp(formula),
formulas))
# Merge the *.bru files.
# Replace each source formula with a formula that has only a single
# dependency to the merged formula, and with no tar.gz urls:
target_formula = copy.deepcopy(formulas[0])
target_formula['module'] = target_module
target_formula['url'] = []
for merge_source in formulas:
if not isinstance(merge_source['url'], list):
merge_source['url'] = [ merge_source['url'] ]
merge_key(merge_source, target_formula, 'url')
merge_key(merge_source, target_formula, 'dependencies')
merge_source['url'] = []
merge_source['dependencies'] = { target_module: version }
bru.save_formula(merge_source)
#xxx TODO: remove deps to merge_sources from target_formula
bru.save_formula(target_formula)
# Merge the *.gyp files.
# Replace the original gyp files with one that depends on the merged
# dependency only, and forwards all its settings via
# gyp's export_dependent_settings.
target_gyp = copy.deepcopy(gyps[0])
merged_target = target_gyp['targets'][0]
merged_target['target_name'] = target_module
merged_target['include_dirs'] = []
merged_target['sources'] = []
merge_dep = '../{}/{}.gyp:*'.format(
target_module, target_module)
for i in range(len(gyps)):
formula = formulas[i]
gyp = gyps[i]
targets = gyp['targets']
assert len(targets) == 1
source = targets[0]
for key in ['all_dependent_settings', 'direct_dependent_settings',
'include_dirs', 'sources']:
if key in source:
merge_key(source, merged_target, key)
del source[key]
source['dependencies'] = [ merge_dep ]
source['export_dependent_settings'] = [ merge_dep ]
bru.save_gyp(formula, gyp)
#xxx TODO: remove deps to merge_sources from target_gyp
bru.save_gyp(target_formula, target_gyp)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("version", help = "version of boost libs to merge, e.g. 1.57.0")
args = parser.parse_args()
version = args.version
fix_annoying_dependency_cycle([
'boost-mpl',
'boost-type_traits',
'boost-typeof',
'boost-utility'],
'boost-mpl-type_traits-typeof-utility',
version)
fix_annoying_dependency_cycle([
'boost-math',
'boost-lexical_cast'],
'boost-lexical_cast-math',
version)
if __name__ == "__main__":
main()