#!/usr/bin/python #This should be run with the "Source" #directory as the CWD. import os.path # ############################################################## # Parameters (Feel free To change) # ############################################################## # For creating the executable: verbose = False exe_name = '../Release/Program.exe' source_list_file = '../BuildTools/source_file_names.txt' header_only_list_file = '../BuildTools/header_only_file_names.txt' lib_list_file = '../BuildTools/lib_names.txt' lib_paths_file = '../BuildTools/lib_paths.txt' resource_str = '' #resource_str = '../Resources/resource.o' # Mac OS stuff (ignore if not on a Mac): frameworks_file = '../BuildTools/frameworks.txt' framework_paths_file = '../BuildTools/framework_paths_file.txt' # For this script to deal with # the source files property: main_file_name = 'Common/main' source_subdirs_list_file = '../BuildTools/source_subdirs_names.txt' # ############################################################## # The Compilation Command (Feel free to change) # ############################################################## def comp_action(name): return '\tg++ -std=c++11 -Wall -O3 -o Obj/' + name.replace('.cpp','') + '.o -c ' + name + '\n' # ############################################################## # Reading Input Files # ############################################################## # Reading in the source file names # (that have both a .cpp + .h version), # the header only file names, # and the library file names. def file_to_list(file_name): f = open(file_name, 'r') list = [] while 1: raw = f.readline() if raw == "": break s = raw.strip() if s == "": continue list.append(s) return list print('Reading input files') #source_file_names = file_to_list(source_list_file) #header_only_file_names = file_to_list(header_only_list_file) lib_names = file_to_list(lib_list_file) lib_paths = file_to_list(lib_paths_file) source_subdirs = file_to_list(source_subdirs_list_file) frameworks = file_to_list(frameworks_file) framework_paths = file_to_list(framework_paths_file) #For the .h and .cpp files, using all such files found #within the current working directory and subdirectories. cpp_file_names = [] h_file_names = [] h_and_cpp_file_names = [] for dir_name, subdirs, files in os.walk('.'): for file in files: filename = dir_name + '/' + file fn = filename.replace('./', '') fn = fn.replace('.\\', '') #windows... if fn.endswith('.cpp'): cpp_file_names.append(fn) h_and_cpp_file_names.append(fn) if fn.endswith('.h'): h_file_names.append(fn) h_and_cpp_file_names.append(fn) # ############################################################## # Heavy Dudy Individual Source File Compiling # ############################################################## print('Calculating sourcecode dependencies') def calc_dependencies(f): temp_f = open(f,'r') lines = temp_f.readlines() result = [] for line in lines: if line.startswith('#include '): words = line.rsplit('\"') if len(words) >= 2: result.append(words[1]) return result local_dep = {} for fn in h_and_cpp_file_names: local_dep[fn] = calc_dependencies(fn) #Printing local dependencies: if verbose: print('*****************************') print('LOCAL DEPENDENCIES') for f in h_and_cpp_file_names: print(f + ':') for d in local_dep[f]: print(' ' + d) print('') print('*****************************') print('DEEP DEPENDENCIES') # Will return the full name of the file if # it exists in a source subdir. # Otherwise, the empty string will be returned. def source_file_listed(fn): striped_fn = fn.replace('../', '') if striped_fn in h_and_cpp_file_names: return striped_fn for dir_name in source_subdirs: test_fn = dir_name + '/' + striped_fn if test_fn in h_and_cpp_file_names: return test_fn return "" # A helper function for calculating all # files recursively included from a given file. #Note: This algorithm really sucks: #it should work by using dynamic programming instead! def calc_full_dep(fn,d,path,visited): #Checking for cyclic header dependency: if (fn in path): print('Error: Cyclic header dependency: ' + fn + ':') print(path) #exit() return set([fn]) #To prevent exponential searching: if fn in visited: return set([]) else: visited.append(fn) #Printing what was searched: if verbose: ws = "" for i in range(len(path)): ws += ' ' print(ws + fn) path.append(fn) accum = set([fn]) for f in d[fn]: full_fn = source_file_listed(f) if full_fn == "": print('*** Error: source file not being listed: ' + f) print(' file was included from: ' + fn) exit() new_path = list(path) accum = accum.union( calc_full_dep(full_fn,d,new_path,visited) ) return accum full_dep = {} for fn in cpp_file_names: res = calc_full_dep(fn, local_dep, [], []) if verbose: print('\n') #res = res.difference( set([fn]) ) full_dep[fn] = res; #Invidivual source file compiling: #(whenever a file that is recursively included by the #target is modified, the target must be recompiled). comp_targets_str = "" for name in cpp_file_names: stripped_n = name.rsplit('.')[0] depend_str = "" for dp in full_dep[name]: depend_str += dp + ' ' comp_targets_str += 'Obj/' + stripped_n + '.o: ' + depend_str + '\n' comp_targets_str += comp_action(name) # ############################################################## # Writing Stuff # ############################################################## #The file to be written to: f_out = open('Makefile', 'w') print('Writing Makefile') #The main target: #print('Writing main target') f_out.write('proj: comp link\n\n') f_out.write('clean:\n') for fn in cpp_file_names: f_out.write('\trm -f Obj/' + fn.replace('.cpp','') + '.o\n') f_out.write('\n') #For forcibly recompiling all: f_out.write('comp_all:\n') #print('Writing comp_all target') for name in cpp_file_names: f_out.write(comp_action(name)) f_out.write('\n') #Writing individual compilation targets #print('Writing individual comp targets') f_out.write(comp_targets_str) f_out.write('\n') #Compilation target: #print('Writing comp target') f_out.write('comp:'); for name in cpp_file_names: f_out.write(' Obj/' + name.replace('.cpp','') + '.o') f_out.write('\n\n') #Linking target: #print('Writing link target') link_str = '\tg++ -lstdc++' for path in lib_paths: link_str += ' -L' + path link_str += ' -o ' + exe_name for path in framework_paths: link_str += ' -F' + path for name in cpp_file_names: link_str += ' Obj/' + name.replace('.cpp','') + '.o' link_str += ' ' + resource_str for lib in lib_names: link_str += ' ' + lib for framework in frameworks: link_str += ' -framework ' + framework link_str += '\n' f_out.write('link:\n') f_out.write(link_str)