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