]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | # Copyright Deniz Bahadir 2015 |
2 | # | |
3 | # Distributed under the Boost Software License, Version 1.0. | |
4 | # (See accompanying file LICENSE_1_0.txt or copy at | |
5 | # http://www.boost.org/LICENSE_1_0.txt) | |
6 | # | |
7 | # See http://www.boost.org/libs/mpl for documentation. | |
8 | # See http://stackoverflow.com/a/20660264/3115457 for further information. | |
9 | # See http://stackoverflow.com/a/29627158/3115457 for further information. | |
10 | ||
11 | import fix_boost_mpl_preprocess as fixmpl | |
12 | import argparse | |
13 | import sys | |
14 | import os | |
15 | import os.path | |
16 | import re | |
17 | import fileinput | |
18 | import shutil | |
19 | ||
20 | ||
21 | def create_more_container_files(sourceDir, suffix, maxElements, containers, containers2): | |
22 | """Creates additional files for the individual MPL-containers.""" | |
23 | ||
24 | # Create files for each MPL-container with 20 to 'maxElements' elements | |
25 | # which will be used during generation. | |
26 | for container in containers: | |
27 | for i in range(20, maxElements, 10): | |
28 | # Create copy of "template"-file. | |
29 | newFile = os.path.join( sourceDir, container, container + str(i+10) + suffix ) | |
30 | shutil.copyfile( os.path.join( sourceDir, container, container + "20" + suffix ), newFile ) | |
31 | # Adjust copy of "template"-file accordingly. | |
32 | for line in fileinput.input( newFile, inplace=1, mode="rU" ): | |
33 | line = re.sub(r'20', re.escape(str(i+10)), line.rstrip()) | |
34 | line = re.sub(r'11', re.escape(str(i + 1)), line.rstrip()) | |
35 | line = re.sub(r'10(?![0-9])', re.escape(str(i)), line.rstrip()) | |
36 | print(line) | |
37 | for container in containers2: | |
38 | for i in range(20, maxElements, 10): | |
39 | # Create copy of "template"-file. | |
40 | newFile = os.path.join( sourceDir, container, container + str(i+10) + "_c" + suffix ) | |
41 | shutil.copyfile( os.path.join( sourceDir, container, container + "20_c" + suffix ), newFile ) | |
42 | # Adjust copy of "template"-file accordingly. | |
43 | for line in fileinput.input( newFile, inplace=1, mode="rU" ): | |
44 | line = re.sub(r'20', re.escape(str(i+10)), line.rstrip()) | |
45 | line = re.sub(r'11', re.escape(str(i + 1)), line.rstrip()) | |
46 | line = re.sub(r'10(?![0-9])', re.escape(str(i)), line.rstrip()) | |
47 | print(line) | |
48 | ||
49 | ||
50 | def create_input_for_numbered_sequences(headerDir, sourceDir, containers, maxElements): | |
51 | """Creates additional source- and header-files for the numbered sequence MPL-containers.""" | |
52 | # Create additional container-list without "map". | |
53 | containersWithoutMap = containers[:] | |
54 | try: | |
55 | containersWithoutMap.remove('map') | |
56 | except ValueError: | |
57 | # We can safely ignore if "map" is not contained in 'containers'! | |
58 | pass | |
59 | # Create header/source-files. | |
60 | create_more_container_files(headerDir, ".hpp", maxElements, containers, containersWithoutMap) | |
61 | create_more_container_files(sourceDir, ".cpp", maxElements, containers, containersWithoutMap) | |
62 | ||
63 | ||
64 | def adjust_container_limits_for_variadic_sequences(headerDir, containers, maxElements): | |
65 | """Adjusts the limits of variadic sequence MPL-containers.""" | |
66 | for container in containers: | |
67 | headerFile = os.path.join( headerDir, "limits", container + ".hpp" ) | |
68 | regexMatch = r'(define\s+BOOST_MPL_LIMIT_' + container.upper() + r'_SIZE\s+)[0-9]+' | |
69 | regexReplace = r'\g<1>' + re.escape( str(maxElements) ) | |
70 | for line in fileinput.input( headerFile, inplace=1, mode="rU" ): | |
71 | line = re.sub(regexMatch, regexReplace, line.rstrip()) | |
72 | print(line) | |
73 | ||
74 | ||
75 | def current_boost_dir(): | |
76 | """Returns the (relative) path to the Boost source-directory this file is located in (if any).""" | |
77 | # Path to directory containing this script. | |
78 | path = os.path.dirname( os.path.realpath(__file__) ) | |
79 | # Making sure it is located in "${boost-dir}/libs/mpl/preprocessed". | |
80 | for directory in reversed( ["libs", "mpl", "preprocessed"] ): | |
81 | (head, tail) = os.path.split(path) | |
82 | if tail == directory: | |
83 | path = head | |
84 | else: | |
85 | return None | |
86 | return os.path.relpath( path ) | |
87 | ||
88 | ||
89 | ||
90 | def to_positive_multiple_of_10(string): | |
91 | """Converts a string into its encoded positive integer (greater zero) or throws an exception.""" | |
92 | try: | |
93 | value = int(string) | |
94 | except ValueError: | |
95 | msg = '"%r" is not a positive multiple of 10 (greater zero).' % string | |
96 | raise argparse.ArgumentTypeError(msg) | |
97 | if value <= 0 or value % 10 != 0: | |
98 | msg = '"%r" is not a positive multiple of 10 (greater zero).' % string | |
99 | raise argparse.ArgumentTypeError(msg) | |
100 | return value | |
101 | ||
102 | ||
103 | def to_existing_absolute_path(string): | |
104 | """Converts a path into its absolute path and verifies that it exists or throws an exception.""" | |
105 | value = os.path.abspath(string) | |
106 | if not os.path.exists( value ) or not os.path.isdir( value ): | |
107 | msg = '"%r" is not a valid path to a directory.' % string | |
108 | raise argparse.ArgumentTypeError(msg) | |
109 | return value | |
110 | ||
111 | ||
112 | def main(): | |
113 | """The main function.""" | |
114 | ||
115 | # Find the current Boost source-directory in which this script is located. | |
116 | sourceDir = current_boost_dir() | |
117 | if sourceDir == None: | |
118 | sourceDir = "" | |
119 | ||
120 | # Prepare and run cmdline-parser. | |
121 | cmdlineParser = argparse.ArgumentParser(description="A generator-script for pre-processed Boost.MPL headers.") | |
122 | cmdlineParser.add_argument("-v", "--verbose", dest='verbose', action='store_true', | |
123 | help="Be a little bit more verbose.") | |
124 | cmdlineParser.add_argument("-s", "--sequence-type", dest='seqType', choices=['variadic', 'numbered', 'both'], | |
125 | default='both', | |
126 | help="Only update pre-processed headers for the selected sequence types, " | |
127 | "either 'numbered' sequences, 'variadic' sequences or 'both' sequence " | |
128 | "types. (Default=both)") | |
129 | cmdlineParser.add_argument("--no-vector", dest='want_vector', action='store_false', | |
130 | help="Do not update pre-processed headers for Boost.MPL Vector.") | |
131 | cmdlineParser.add_argument("--no-list", dest='want_list', action='store_false', | |
132 | help="Do not update pre-processed headers for Boost.MPL List.") | |
133 | cmdlineParser.add_argument("--no-set", dest='want_set', action='store_false', | |
134 | help="Do not update pre-processed headers for Boost.MPL Set.") | |
135 | cmdlineParser.add_argument("--no-map", dest='want_map', action='store_false', | |
136 | help="Do not update pre-processed headers for Boost.MPL Map.") | |
137 | cmdlineParser.add_argument("--num-elements", dest='numElements', metavar="<num-elements>", | |
138 | type=to_positive_multiple_of_10, default=100, | |
139 | help="The maximal number of elements per container sequence. (Default=100)") | |
140 | cmdlineParser.add_argument(dest='sourceDir', metavar="<source-dir>", default=current_boost_dir(), nargs='?', | |
141 | type=to_existing_absolute_path, | |
142 | help="The source-directory of Boost. (Default=\"" + sourceDir + "\")") | |
143 | args = cmdlineParser.parse_args() | |
144 | ||
145 | # Some verbose debug output. | |
146 | if args.verbose: | |
147 | print "Arguments extracted from command-line:" | |
148 | print " verbose = ", args.verbose | |
149 | print " source directory = ", args.sourceDir | |
150 | print " num elements = ", args.numElements | |
151 | print " sequence type = ", args.seqType | |
152 | print " want: vector = ", args.want_vector | |
153 | print " want: list = ", args.want_list | |
154 | print " want: set = ", args.want_set | |
155 | print " want: map = ", args.want_map | |
156 | ||
157 | # Verify that we received any source-directory. | |
158 | if args.sourceDir == None: | |
159 | print "You should specify a valid path to the Boost source-directory." | |
160 | sys.exit(0) | |
161 | ||
162 | # The directories for header- and source files of Boost.MPL. | |
163 | # NOTE: Assuming 'args.sourceDir' is the source-directory of the entire boost project. | |
164 | headerDir = os.path.join( args.sourceDir, "boost", "mpl" ) | |
165 | sourceDir = os.path.join( args.sourceDir, "libs", "mpl", "preprocessed" ) | |
166 | # Check that the header/source-directories exist. | |
167 | if not os.path.exists( headerDir ) or not os.path.exists( sourceDir ): | |
168 | # Maybe 'args.sourceDir' is not the source-directory of the entire boost project | |
169 | # but instead of the Boost.MPL git-directory, only? | |
170 | headerDir = os.path.join( args.sourceDir, "include", "boost", "mpl" ) | |
171 | sourceDir = os.path.join( args.sourceDir, "preprocessed" ) | |
172 | if not os.path.exists( headerDir ) or not os.path.exists( sourceDir ): | |
173 | cmdlineParser.print_usage() | |
174 | print "error: Cannot find Boost.MPL header/source files in given Boost source-directory!" | |
175 | sys.exit(0) | |
176 | ||
177 | # Some verbose debug output. | |
178 | if args.verbose: | |
179 | print "Chosen header-directory: ", headerDir | |
180 | print "Chosen source-directory: ", sourceDir | |
181 | ||
182 | # Create list of containers for which files shall be pre-processed. | |
183 | containers = [] | |
184 | if args.want_vector: | |
185 | containers.append('vector') | |
186 | if args.want_list: | |
187 | containers.append('list') | |
188 | if args.want_set: | |
189 | containers.append('set') | |
190 | if args.want_map: | |
191 | containers.append('map') | |
192 | if containers == []: | |
193 | print "Nothing to do." | |
194 | print "(Why did you prevent generating pre-processed headers for all Boost.MPL container types?)" | |
195 | sys.exit(0) | |
196 | ||
197 | # Possibly fix the header-comments of input-files needed for pre-processing. | |
198 | if args.verbose: | |
199 | print "Checking if prior to pre-processing some input-files need fixing." | |
200 | needFixing = fixmpl.check_input_files(headerDir, sourceDir, containers, args.seqType, args.verbose) | |
201 | if needFixing: | |
202 | if args.verbose: | |
203 | print "Fixing of some input-files prior to pre-processing is needed." | |
204 | print "Will fix them now!" | |
205 | fixmpl.fix_input_files(headerDir, sourceDir, containers, args.seqType, args.verbose) | |
206 | ||
207 | # Some verbose debug output. | |
208 | if args.verbose: | |
209 | print "Containers for which to pre-process headers: ", containers | |
210 | ||
211 | # Create (additional) input files for generating pre-processed headers of numbered sequence MPL containers. | |
212 | if args.seqType == "both" or args.seqType == "numbered": | |
213 | create_input_for_numbered_sequences(headerDir, sourceDir, containers, args.numElements) | |
214 | # Modify settings for generating pre-processed headers of variadic sequence MPL containers. | |
215 | if args.seqType == "both" or args.seqType == "variadic": | |
216 | adjust_container_limits_for_variadic_sequences(headerDir, containers, args.numElements) | |
217 | ||
218 | # Generate MPL-preprocessed files. | |
219 | os.chdir( sourceDir ) | |
220 | if args.seqType == "both" or args.seqType == "numbered": | |
221 | if args.want_vector: | |
222 | if args.verbose: | |
223 | print "Pre-process headers for Boost.MPL numbered vectors." | |
224 | os.system( "python " + os.path.join( sourceDir, "preprocess_vector.py" ) + " all " + args.sourceDir ) | |
225 | if args.want_list: | |
226 | if args.verbose: | |
227 | print "Pre-process headers for Boost.MPL numbered lists." | |
228 | os.system( "python " + os.path.join( sourceDir, "preprocess_list.py" ) + " all " + args.sourceDir ) | |
229 | if args.want_set: | |
230 | if args.verbose: | |
231 | print "Pre-process headers for Boost.MPL numbered sets." | |
232 | os.system( "python " + os.path.join( sourceDir, "preprocess_set.py" ) + " all " + args.sourceDir ) | |
233 | if args.want_map: | |
234 | if args.verbose: | |
235 | print "Pre-process headers for Boost.MPL numbered maps." | |
236 | os.system( "python " + os.path.join( sourceDir, "preprocess_map.py" ) + " all " + args.sourceDir ) | |
237 | if args.seqType == "both" or args.seqType == "variadic": | |
238 | if args.verbose: | |
239 | print "Pre-process headers for Boost.MPL variadic containers." | |
240 | os.system( "python " + os.path.join( sourceDir, "preprocess.py" ) + " all " + args.sourceDir ) | |
241 | ||
242 | ||
243 | if __name__ == '__main__': | |
244 | main() |