genmakefile.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #!/usr/bin/python3.1
  2. import sys, os, fnmatch, random
  3. from threading import Thread
  4. #======================================================================================================================================
  5. # GLOBAL VARS =
  6. #======================================================================================================================================
  7. source_paths = []
  8. precompiled_headers = []
  9. executable_name = "unamed_project"
  10. compiler = ""
  11. common_flags = ""
  12. compiler_flags = ""
  13. precompiled_headers_flags = ""
  14. linker_flags = ""
  15. #======================================================================================================================================
  16. # GetCommandOutput =
  17. #======================================================================================================================================
  18. def GetCommandOutput( command ):
  19. child = os.popen(command)
  20. data = child.read()
  21. err = child.close()
  22. if err:
  23. print( "GetCommandOutput failed:\n" + command )
  24. exit( 0 )
  25. return data
  26. #======================================================================================================================================
  27. # Threads =
  28. #======================================================================================================================================
  29. thread_list = []
  30. class target_thread_t( Thread ):
  31. def __init__( self, tid, range ):
  32. Thread.__init__( self )
  33. self.tid = tid
  34. self.range = range
  35. self.out_str = ""
  36. def run( self ):
  37. for i in self.range:
  38. source_file = source_files[i]
  39. self.out_str += GetCommandOutput( compiler + " -MM " + compiler_flags + " " + source_file.cpp_file + " -MT " + source_file.obj_file )
  40. self.out_str += "\t@echo Compiling " + source_file.cpp_file + "...\n"
  41. self.out_str += "\t@$(CXX) $(INCPATH) $(CFLAGS) " + source_file.cpp_file + " -o " + \
  42. source_file.obj_file + "\n\n"
  43. #print( "Im thread %d and I will make depends for %s" %(self.tid, source_file.fname) )
  44. #print( "Im thread %d and my i is %d" %(self.tid, i) )
  45. #======================================================================================================================================
  46. # source_file_t =
  47. #======================================================================================================================================
  48. class source_file_t:
  49. def __init__( self ):
  50. self.cpp_file = ""
  51. self.obj_file = ""
  52. #======================================================================================================================================
  53. # main =
  54. #======================================================================================================================================
  55. # Read the arguments
  56. input_cfgfile = ""
  57. output_makefile = ""
  58. i = 0
  59. while 1:
  60. i = i+1
  61. if i>=len(sys.argv): break
  62. arg = sys.argv[i]
  63. if arg == "-h" or arg == "-help" or arg == "--help":
  64. print( "Makefile generator by GODlike" )
  65. print( "usage: genmakefile.py [options] [-i input] [-o output]" )
  66. print( "options:" )
  67. print( "-h, -help, --help Print this text" )
  68. print( "-i Input config file. Default: gen.cfg.py" )
  69. print( "-o Output makefile. Default: Makefile" )
  70. exit(0)
  71. elif arg == "-i":
  72. input_cfgfile = sys.argv[i+1]
  73. i = i+1
  74. elif arg == "-o":
  75. output_makefile = sys.argv[i+1]
  76. i = i+1
  77. else:
  78. print( "Unrecognized argument " + arg )
  79. if output_makefile == "":
  80. output_makefile = "Makefile"
  81. if input_cfgfile == "":
  82. input_cfgfile = "gen.cfg.py"
  83. # Check if cfg exists
  84. if not os.path.exists( input_cfgfile ):
  85. print( "File " + input_cfgfile + " doesn't exist" )
  86. exit(0)
  87. # compile the cfg
  88. source = ""
  89. f = open( input_cfgfile, "r" )
  90. for line in f.readlines():
  91. source += line
  92. exec( compile( source, input_cfgfile, "exec" ) )
  93. # find the cpp files
  94. source_files = []
  95. for source_dir in source_paths:
  96. files = os.listdir( source_dir )
  97. for file_ in fnmatch.filter( files, "*.cpp" ):
  98. sfile = source_file_t()
  99. (fname_wo_ext, ext) = os.path.splitext( file_ )
  100. sfile.cpp_file = source_dir + "/" + file_
  101. sfile.obj_file = fname_wo_ext + ".o"
  102. # search all the source files and resolve conflicts in .o
  103. for sfile1 in source_files:
  104. if sfile1.obj_file == sfile.obj_file:
  105. print( "There is a conflict with \"" + sfile1.cpp_file + "\" and \"" + sfile.cpp_file + "\" but dont worry." )
  106. random.seed()
  107. sfile.obj_file = str(random.randint(1,99)) + "." + sfile.obj_file;
  108. source_files.append( sfile )
  109. # now the precompiled headers
  110. ph_files = []
  111. for header in precompiled_headers:
  112. ph_files.append( source_file_t( header ) )
  113. # build the string
  114. master_str = ""
  115. master_str += "CXX = " + compiler + "\n"
  116. master_str += "COMMONFLAGS = " + common_flags + "\n"
  117. master_str += "CFLAGS = $(COMMONFLAGS) " + compiler_flags + "\n"
  118. master_str += "PHFLAGS = $(CFLAGS) " + precompiled_headers_flags + "\n"
  119. master_str += "LFLAGS = $(COMMONFLAGS) " + linker_flags + "\n"
  120. master_str += "EXECUTABLE = " + executable_name + "\n"
  121. master_str += "INCPATH = "
  122. for path in include_paths:
  123. master_str += "-I" + path + " "
  124. compiler_flags += " -I" + path + " "
  125. master_str += "\n"
  126. master_str += "SOURCES = "
  127. for source_file in source_files:
  128. master_str += source_file.cpp_file + " "
  129. master_str += "\n"
  130. master_str += "OBJECTS = "
  131. for source_file in source_files:
  132. master_str += source_file.obj_file + " "
  133. master_str += "\n"
  134. master_str += "PRECOMPILED_HEADERS = "
  135. for header in ph_files:
  136. master_str += header.fname + ".gch "
  137. master_str += "\n\n"
  138. master_str += "all: $(PRECOMPILED_HEADERS) $(SOURCES) $(EXECUTABLE)\n\n"
  139. master_str += "$(EXECUTABLE): $(OBJECTS)\n"
  140. master_str += "\t@echo Linking...\n"
  141. master_str += "\t@$(CXX) $(OBJECTS) $(LFLAGS) -o $(EXECUTABLE)\n"
  142. master_str += "\t@echo All Done!\n\n"
  143. for header in ph_files:
  144. depend_str = GetCommandOutput( compiler + " -MM " + compiler_flags + " " + precompiled_headers_flags + " " + header.path + "/" +
  145. header.fname )
  146. master_str += depend_str.replace( header.fname_wo_ext + ".o", header.fname + ".gch" )
  147. master_str += "\t@echo Pre-compiling header " + header.fname + "...\n"
  148. master_str += "\t@$(CXX) $(INCPATH) $(PHFLAGS) " + header.path + "/" + header.fname + "\n\n"
  149. # write source file target
  150. threads_num = os.sysconf('SC_NPROCESSORS_ONLN')
  151. print( "I will invoke %d threads to make the dependencies..." % threads_num )
  152. num = len(source_files);
  153. items_per_thread = num // threads_num;
  154. for i in range(0, threads_num):
  155. begin = i*items_per_thread
  156. if i == threads_num-1:
  157. end = num
  158. else:
  159. end = begin + items_per_thread
  160. thread = target_thread_t( i, range( int(begin), int(end) ) )
  161. thread.start()
  162. thread_list.append( thread )
  163. for thread in thread_list:
  164. thread.join()
  165. for thread in thread_list:
  166. master_str += thread.out_str
  167. #for source_file in source_files:
  168. #master_str += source_file.fname_wo_ext + ".o: " + source_file.path + source_file.fname_wo_ext + ".cpp"
  169. #master_str += GetCommandOutput( compiler + " -M " + compiler_flags + " " + source_file.path + "/" + source_file.fname )
  170. #master_str += "\t@echo Compiling " + source_file.fname + "...\n"
  171. #master_str += "\t@$(CXX) $(INCPATH) $(CFLAGS) " + source_file.path + "/" + source_file.fname + "\n\n"
  172. master_str += "clean:\n"
  173. master_str += "\trm -f *.o\n"
  174. master_str += "\trm -f *.gch\n"
  175. master_str += "\trm -f *~\n"
  176. master_str += "\trm -f $(EXECUTABLE)\n\n"
  177. # write file
  178. f = open( output_makefile, "w" )
  179. f.write( master_str )
  180. print( "File \"" + output_makefile + "\" created!" )