1#! /usr/bin/env python
2
3# ------------------------------------------------------------------------------
4
5# Import modules
6import sys
7import os
8import os.path
9import getopt
10import re
11import string
12
13# Global variables for command line options, with default settings.
14script_name  = ""
15dry_run_flag = False
16verbose_flag = False
17
18# Global constants
19config_dirname     = "config"
20source_dirname     = "src"
21object_dirname     = "obj"
22object_extension   = ".obj"
23leaf_list_path     = "build/config/leaf_list"
24revision_filename  = "revision"
25rev_varname        = "REVISION"
26pwd_varname        = "PWD"
27arch_varname       = "ARCH_STR"
28build_varname      = "BUILD_STR"
29ccompiler_varname  = "CCOMPILER_STR"
30
31
32# ------------------------------------------------------------------------------
33
34def print_usage():
35
36	# Print help information.
37	print " "
38	print " %s" % script_name
39	print " "
40	print " Field G. Van Zee"
41	print " "
42	print " Create a config.mk file that is to be included by the nmake Makefile."
43	print " This config.mk file is based on a template, but also includes variable"
44	print " definitions that are needed for the specific build were are performing."
45	print " The variables which are currently appended to config.mk at runtime are:"
46	print "   - the revision string"
47	print "   - the path to the current working directory"
48	print "   - the build string (e.g. debug, release)"
49	print "   - the architecture string (e.g. x86, x64)"
50	print "   - the C compiler to use (e.g. icl, cl)"
51	print "   - a list of paths to the object files to be compiled"
52	print " The config.mk file is placed within the config subdirectory."
53	print " "
54	print " Usage:"
55	print "   %s [options] flat_dir arch build ccompiler path\\to\\config.mk.in" % script_name
56	print " "
57	print " The following options are accepted:"
58	print " "
59	print "   -d          dry-run"
60	print "                 Go through all the motions, but don't actually output"
61	print "                 the nmake definition file."
62	print "   -v          verbose"
63	print "                 Be verbose about actions (one line of output her action)."
64	print " "
65
66	# Exit the script.
67	sys.exit()
68
69# ------------------------------------------------------------------------------
70
71def main():
72
73	# Extern our global veriables.
74	global script_name
75	global dry_run_flag
76	global verbose_flag
77
78	# Get the script name so we can use it in our output.
79	( script_dir, script_name ) = os.path.split( sys.argv[0] )
80
81	try:
82
83		# Get the command line options.
84		options, args = getopt.getopt( sys.argv[1:], "dv")
85
86	except getopt.GetoptError, err:
87
88		# print help information and exit:
89		print str( err ) # will print something like "option -a not recognized"
90		print_usage()
91
92	# Parse our expected command line options.
93	for o, a in options:
94
95		if o == "-d":
96			dry_run_flag = True
97		elif o == "-v":
98			verbose_flag = True
99		else:
100			assert False, "unhandled option"
101
102	# Check the number of arguments after command line option processing.
103	n_args = len( args )
104	if n_args != 5:
105		print_usage()
106
107	# Acquire the non-optional arguments.
108	flat_dir         = args[0]
109	arch_string      = args[1]
110	build_string     = args[2]
111	ccompiler_string = args[3]
112	input_filepath   = args[4]
113
114	# Acquire the list of leaf-type directories we will descend into.
115	leaf_list = read_leaf_list()
116
117	# Read the contents of the template file.
118	template_file_line_list = read_template_file( input_filepath )
119
120	# Initialize a new list for the lines to be output
121	output_file_line_list = template_file_line_list
122
123	# Read the revision number from the revision file.
124	rev_num_str = read_revision_file( revision_filename )
125
126	# Add a variable for the revision number of the code we're working with.
127	rev_var_value = rev_varname + " = " + rev_num_str + "\n"
128	output_file_line_list.append( rev_var_value )
129
130	# Add a variable for the path to the current working directory and append
131	# it to our list.
132	pwd_var_value = pwd_varname + " = " + os.getcwd() + "\n"
133	output_file_line_list.append( pwd_var_value )
134
135	# Add a variable for the architecture string and append it to our list.
136	arch_var_value = arch_varname + " = " + arch_string + "\n"
137	output_file_line_list.append( arch_var_value )
138
139	# Add a variable for the build type string and append it to our list.
140	build_var_value = build_varname + " = " + build_string + "\n"
141	output_file_line_list.append( build_var_value )
142
143	# Add a variable for the C compiler string and append it to our list.
144	ccompiler_var_value = ccompiler_varname + " = " + ccompiler_string + "\n"
145	output_file_line_list.append( ccompiler_var_value )
146
147	# Walk the flat subdirectories for each of the leaves.
148	for leaf_spec in leaf_list:
149
150		# Unpack the leaf_spec tuple.
151		leaf_name, src_exts, hdr_exts = leaf_spec
152
153		# Create the paths to the source and object subdirectories.
154		src_dirpath = os.path.join( flat_dir, source_dirname, leaf_name )
155		obj_dirpath = os.path.join( flat_dir, object_dirname, leaf_name, arch_string, build_string )
156
157		# Get a list of files from the leaf subdirectory.
158		src_filenames = os.listdir( src_dirpath )
159
160		# This will be the nmake variable name to which we will assign the list
161		# of source files.
162		nmake_varname = leaf_name.upper() + "_OBJS"
163
164		# Generate the line to output.
165		leaf_line = generate_object_list( nmake_varname, src_filenames, src_exts, obj_dirpath )
166
167		# Accumulate the lines.
168		output_file_line_list.append( leaf_line )
169
170	# Get the filename part of the input filepath.
171	input_filedir, input_filename = os.path.split( input_filepath )
172
173	# Remove the .in extension in the output filename.
174	output_filename = re.sub( '.mk.in', '.mk', input_filename )
175
176	# Construct the filepath for the output file.
177	output_filepath = os.path.join( flat_dir, config_dirname, output_filename )
178
179	# Write the output lines.
180	write_output_file( output_filepath, output_file_line_list )
181
182# ------------------------------------------------------------------------------
183
184def read_revision_file( filepath ):
185
186	# Try to open the revision file.
187	try:
188
189		revision_file = open( filepath, 'r' )
190
191	except IOError, err:
192
193		print "%s: Couldn't open revision file %s" % ( script_name, filepath )
194		sys.exit(1)
195
196	# Read the first (and only) line.
197	line = revision_file.readline()
198
199	# Close the file.
200	revision_file.close()
201
202	# Grab the string and strip the it of whitespace (should just be a newline).
203	rev_num_str = line.strip()
204
205	# Return the revision number string.
206	return rev_num_str
207
208# ------------------------------------------------------------------------------
209
210def generate_object_list( nmake_varname, src_filenames, src_exts, obj_dirpath ):
211
212	# Initialize the string as an assignment operation.
213	the_line = nmake_varname + " = "
214
215	# Return early if there are no source extensions for this leaf spec.
216	if src_exts == []:
217		return ""
218
219	# Construct a pattern to match any file ending with any of the source file
220	# extensions given. This string is going to look something like ".[cf]".
221	src_pattern = '\.['
222	for src_ext in src_exts:
223		src_pattern = src_pattern + src_ext
224	src_pattern = src_pattern + ']'
225
226	# Consider all source files.
227	for src_filename in src_filenames:
228
229		obj_filename = re.sub( src_pattern, '.obj', src_filename )
230
231		# Create the full path to the file.
232		obj_filepath = os.path.join( obj_dirpath, obj_filename )
233
234		# Be verbose if verbosity was requested.
235		if verbose_flag == True:
236			print "%s: adding file %s" % ( script_name, obj_filepath )
237
238		# And then add it to the list.
239		the_line = the_line + obj_filepath + " "
240
241	# Be verbose if verbosity was requested.
242	if verbose_flag == True:
243		print "%s: %s" % ( script_name, the_line )
244
245	# Append a newline to the end of the line, for file.writelines().
246	the_line = the_line + "\n"
247
248	# Return the new line.
249	return the_line
250
251# ------------------------------------------------------------------------------
252
253def read_template_file( template_filepath ):
254
255	# Open the template file as read-only.
256	template_file = open( template_filepath, 'r' )
257
258	# Read all lines in the template file.
259	template_file_lines = template_file.readlines()
260
261	# Close the file.
262	template_file.close()
263
264	# Return the list of lines in the template file.
265	return template_file_lines
266
267# ------------------------------------------------------------------------------
268
269def write_output_file( output_filepath, output_lines ):
270
271	# Take action only if this is not a dry run.
272	if dry_run_flag == False:
273
274		# Open the template file as writable.
275		output_file = open( output_filepath, 'w' )
276
277		# Write the lines.
278		output_file.writelines( output_lines )
279
280		# Close the file.
281		output_file.close()
282
283# ------------------------------------------------------------------------------
284
285def read_leaf_list():
286
287	# Open the leaf list file.
288	leaf_file = open( leaf_list_path, 'r' )
289
290	# Read the lines in the file.
291	line_list = leaf_file.readlines()
292
293	# Start with a blank list.
294	leaf_list = []
295
296	# Iterate over the lines.
297	for line in line_list:
298
299		# Split the specification by colon to separate the fields.
300		fields = string.split( string.strip( line ), ':' )
301
302		# Get the individual fields of the specification.
303		name     = fields[0]
304		src_exts = string.split( fields[1], ',' )
305		hdr_exts = string.split( fields[2], ',' )
306
307		# If it's a singleton list of an empty string, make it an empty list.
308		if len(src_exts) == 1:
309			if src_exts[0] == '':
310				src_exts = []
311
312		# If it's a singleton list of an empty string, make it an empty list.
313		if len(hdr_exts) == 1:
314			if hdr_exts[0] == '':
315				hdr_exts = []
316
317		# Pack the fields into a tuple.
318		leaf_spec = ( name, src_exts, hdr_exts )
319
320		# Append the tuple to our list.
321		leaf_list.append( leaf_spec )
322
323	# Return the list.
324	return leaf_list
325
326# ------------------------------------------------------------------------------
327
328# Begin by executing main().
329main()
330