genmakefile.py 8.0 KB

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