def dictionaryFromJsonFile (file) : result = {} if not os.path.exists (os.path.abspath (file)): print (makefile.BOLD_RED () + "The '" + file + "' file does not exist" + makefile.ENDC ()) sys.exit (1) try: f = open (file, "r") result = json.loads (f.read ()) f.close () except: print (makefile.BOLD_RED () + "Syntax error in " + file + makefile.ENDC ()) sys.exit (1) return result
def runProcess(command): str = makefile.BOLD_GREEN() for s in command: str += " " + s str += makefile.ENDC() print(str) returncode = subprocess.call(command) if returncode != 0: print(makefile.BOLD_RED() + "Error " + str(returncode) + makefile.ENDC()) sys.exit(returncode)
def runProcessAndGetOutput (command) : result = "" childProcess = subprocess.Popen (command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) while True: out = childProcess.stdout.read(1) if out == '' and childProcess.poll() != None: break if out != '' : result += out #--- Wait for subprocess termination if childProcess.poll () == None : childProcess.wait () if childProcess.returncode != 0 : print (makefile.BOLD_RED () + "Error " + str (childProcess.returncode) + makefile.ENDC ()) sys.exit (childProcess.returncode) return result
def runProcess(command): returncode = subprocess.call(command) if returncode != 0: print(makefile.BOLD_RED() + "Error " + str(returncode) + makefile.ENDC()) sys.exit(returncode)
def buildCode (GOAL, projectDir, maxConcurrentJobs, verbose): DEV_FILES_DIR = os.path.dirname (os.path.realpath (__file__)) # print ("DEV_FILES_DIR: " + DEV_FILES_DIR) #--------------------------------------------------------------------------- Prepare os.chdir (projectDir) make = makefile.Make (GOAL) # make.mMacTextEditor = "BBEdit" # "Atom" allGoal = [] #--------------------------------------------------------------------------- Analyze JSON file print (makefile.BOLD_GREEN () + "--- Making " + projectDir + makefile.ENDC ()) dictionaire = dictionaryFromJsonFile (projectDir + "/makefile.json") # print ("JSON DICTIONARY: ") # print (dictionaire) #--------------------------------------------------------------------------- Find target targetNameSet = set () foundIRQSectionScheme = False for name in os.listdir (DEV_FILES_DIR + "/targets") : if not name.startswith ('.') : targetNameSet.add (name) if not "TARGET" in dictionaire: s = "\"TARGET\" is not defined in the makefile.json file; possible values:\n" for target in targetNameSet : s += " - \"" + target + "\"\n" print (makefile.BOLD_RED () + s + makefile.ENDC ()) sys.exit (1) targetName = dictionaire ["TARGET"] if not targetName in targetNameSet : s = "In the makefile.json file, \"TARGET\" value \"" + targetName + "\" is invalid; " s += "possible values:\n" for target in targetNameSet : s += " - \"" + target + "\"\n" print (makefile.BOLD_RED () + s + makefile.ENDC ()) sys.exit (1) TARGET_DIR = DEV_FILES_DIR + "/targets/" + targetName sys.path.append (TARGET_DIR + "/deployment") import deployment #--------------------------------------------------------------------------- Install compiler ? BASE_NAME = "arm-none-eabi" TOOL_DIR = download_and_install_gccarm.installGCCARMandGetToolDirectory () #--------------------------------------------------------------------------- Target Dictionary targetDictionary = dictionaryFromJsonFile (TARGET_DIR + "/helpers/target-parameters.json") #--------------------------------------------------------------------------- Configure compiler gccOptions = targetDictionary ["GCC-OPTIONS"] AS_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-as"] AS_TOOL_WITH_OPTIONS += gccOptions COMPILER_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-gcc"] COMPILER_TOOL_WITH_OPTIONS += gccOptions # LD_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-ld"] LD_TOOL_WITH_OPTIONS = COMPILER_TOOL_WITH_OPTIONS # OBJCOPY_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-objcopy"] DISPLAY_OBJ_SIZE_TOOL = [TOOL_DIR + "/bin/" + BASE_NAME + "-size"] # OBJDUMP_TOOL = TOOL_DIR + "/bin/" + BASE_NAME + "-objdump" #--------------------------------------------------------------------------- Parse JSON dictinary #--- SCHEME if "SCHEME" in dictionaire: SCHEME = dictionaire ["SCHEME"] schemeFilePath = TARGET_DIR + "/schemes/" + SCHEME + ".json" if os.path.exists (schemeFilePath) : schemeDictionary = dictionaryFromJsonFile (schemeFilePath) dictionaire ["UNUSED-IRQ-SCHEME"] = schemeDictionary ["UNUSED-IRQ-SCHEME"] dictionaire ["IRQ-SECTION-SCHEME"] = schemeDictionary ["IRQ-SECTION-SCHEME"] dictionaire ["SERVICE-SCHEME"] = schemeDictionary ["SERVICE-SCHEME"] dictionaire ["SECTION-SCHEME"] = schemeDictionary ["SECTION-SCHEME"] dictionaire ["SOURCES-IN-DEV-DIR"] = schemeDictionary ["SOURCES-IN-DEV-DIR"] else: print (makefile.RED () + makefile.BOLD () + "Unknow scheme '" + SCHEME + "'" + makefile.ENDC ()) sys.exit (1) #--- CPU_MHZ CPU_MHZ = 0 if "CPU-MHZ" in dictionaire: CPU_MHZ = dictionaire ["CPU-MHZ"] #--- ASSERTION_GENERATION ASSERTION_GENERATION = False if "ASSERTION-GENERATION" in dictionaire : ASSERTION_GENERATION = dictionaire ["ASSERTION-GENERATION"] #--- USER SOURCE_FILE_DIRECTORIES SOURCE_FILE_DIRECTORIES = [] if "SOURCE-DIR" in dictionaire : SOURCE_FILE_DIRECTORIES = dictionaire ["SOURCE-DIR"] #--- SYSTEM SOURCE_FILE_DIRECTORIES if "SOURCES-IN-DEV-DIR" in dictionaire : sourcesInDevDir = dictionaire ["SOURCES-IN-DEV-DIR"] for d in sourcesInDevDir : SOURCE_FILE_DIRECTORIES.append (TARGET_DIR + "/sources/" + d) #--- GROUP_SOURCES GROUP_SOURCES = False if "GROUP-SOURCES" in dictionaire: GROUP_SOURCES = dictionaire ["GROUP-SOURCES"] #--- TASK_COUNT TASK_COUNT = "0" # Means TASK_COUNT is not defined by JSON file if "TASK-COUNT" in dictionaire : TASK_COUNT = str (dictionaire ["TASK-COUNT"]) #--- LTO usesLTO = False if "LTO" in dictionaire : usesLTO = dictionaire ["LTO"] #--- SERVICE serviceScheme = "" if "SERVICE-SCHEME" in dictionaire : serviceScheme = dictionaire ["SERVICE-SCHEME"] #--- SECTION sectionScheme = "" if "SECTION-SCHEME" in dictionaire : sectionScheme = dictionaire ["SECTION-SCHEME"] #--- IRQ SECTION irqSectionScheme = "" if "IRQ-SECTION-SCHEME" in dictionaire : irqSectionScheme = dictionaire ["IRQ-SECTION-SCHEME"] #--- UNUSED IRQ unusedIRQScheme = "" if "UNUSED-IRQ-SCHEME" in dictionaire : unusedIRQScheme = dictionaire ["UNUSED-IRQ-SCHEME"] #--- DEPLOYMENT selectedDeployments = [] if "DEPLOYMENT" in dictionaire : selectedDeployments = dictionaire ["DEPLOYMENT"] #--------------------------------------------------------------------------- Directories BUILD_DIR = common_definitions.buildDirectory () GENERATED_SOURCE_DIR = common_definitions.generatedSourceDirectory () PRODUCT_DIR = common_definitions.productDirectory () ASBUILD_DIR = common_definitions.asDirectory () #--------------------------------------------------------------------------- Build source lists includeDirsInCompilerCommand = ["-I", GENERATED_SOURCE_DIR] H_SOURCE_SET = set () H_SOURCE_LIST = [] CPP_SOURCE_LIST = [] S_SOURCE_LIST = [] for f in SOURCE_FILE_DIRECTORIES : for root, dirs, files in os.walk (f) : includeDirsInCompilerCommand += ["-I", root] for name in files: sourcePath = os.path.join (root, name) (b, extension) = os.path.splitext (sourcePath) if extension == ".cpp" : CPP_SOURCE_LIST.append (sourcePath) elif extension == ".h" : H_SOURCE_LIST.append (sourcePath) if sourcePath in H_SOURCE_SET : print (makefile.BOLD_RED () + "Duplicated header file \"" + sourcePath + "\"" + makefile.ENDC ()) H_SOURCE_SET.add (sourcePath) elif extension == ".s" : S_SOURCE_LIST.append (sourcePath) elif extension == ".hs" : pass # Ok elif extension == ".ld" : pass # Ok elif extension != "" : # Ceci permet d'ignorer les fichés cachés (dont les noms commencent par un point) print (makefile.MAGENTA () + makefile.BOLD () + "Note: unhandled file " + sourcePath + makefile.ENDC ()) #--------------------------------------------------------------------------- Build base header file baseHeader_file = GENERATED_SOURCE_DIR + "/base.h" H_SOURCE_LIST.insert (0, baseHeader_file) rule = makefile.Rule ([baseHeader_file], "Build base header file") rule.mOpenSourceOnError = False rule.mDependences.append ("makefile.json") rule.mCommand += [DEV_FILES_DIR + "/build_base_header_file.py", baseHeader_file, str (CPU_MHZ), TASK_COUNT, targetName, "1" if ASSERTION_GENERATION else "0"] rule.mPriority = -1 make.addRule (rule) #--------------------------------------------------------------------------- Build all header file allHeadersSecondaryDependenceFile = BUILD_DIR + "/all-headers.dep" allHeaders_file = GENERATED_SOURCE_DIR + "/all-headers.h" rule = makefile.Rule ([allHeaders_file, allHeadersSecondaryDependenceFile], "Build all headers file") rule.mOpenSourceOnError = False rule.mDependences.append ("makefile.json") rule.mDependences += H_SOURCE_LIST rule.mCommand += [DEV_FILES_DIR + "/build_all_header_file.py", allHeaders_file, allHeadersSecondaryDependenceFile] rule.mCommand += H_SOURCE_LIST rule.enterSecondaryDependanceFile (allHeadersSecondaryDependenceFile, make) rule.mPriority = -1 make.addRule (rule) #--------------------------------------------------------------------------- Build precompiled header file # allHeadersSecondaryDependenceFile = GENERATED_SOURCE_DIR + "/all-headers.h" # precompiledHeader_file = GENERATED_SOURCE_DIR + "/all-headers.h.gch" # rule = makefile.Rule ([precompiledHeader_file], "Build Precompiled header file") # rule.mOpenSourceOnError = False # rule.mDependences.append ("makefile.json") # rule.mDependences.append (allHeadersSecondaryDependenceFile) # rule.mCommand += COMPILER_TOOL_WITH_OPTIONS # rule.mCommand += ["-DSTATIC=static __attribute__((unused))"] if GROUP_SOURCES else ["-DSTATIC="] # rule.mCommand += common_definitions.checkModeOptions () # rule.mCommand += common_definitions.C_Cpp_optimizationOptions () # rule.mCommand += common_definitions.Cpp_actualOptions (False) # rule.mCommand += includeDirsInCompilerCommand # rule.mCommand += ["-x", "c++-header", allHeadersSecondaryDependenceFile] # rule.mCommand += ["-o", precompiledHeader_file] # rule.mPriority = -1 # make.addRule (rule) # allGoal.append (precompiledHeader_file) #-------------------------------------------------------------- --- Build interrupt handler files interruptHandlerSFile = GENERATED_SOURCE_DIR + "/interrupt-handlers-assembly.s" interruptHandlerCppFile = GENERATED_SOURCE_DIR + "/interrupt-handlers-cpp.cpp" S_SOURCE_LIST.append (interruptHandlerSFile) CPP_SOURCE_LIST.append (interruptHandlerCppFile) rule = makefile.Rule ([interruptHandlerSFile, interruptHandlerCppFile], "Build interrupt files") rule.mOpenSourceOnError = False rule.mDependences += H_SOURCE_LIST rule.mDependences.append ("makefile.json") rule.mDependences.append (DEV_FILES_DIR + "/build_interrupt_handlers.py") if serviceScheme != "" : rule.mDependences.append (TARGET_DIR + "/generators-service/" + serviceScheme + "/service_generator.py") if sectionScheme != "" : rule.mDependences.append (TARGET_DIR + "/generators-section/" + sectionScheme + "/section_generator.py") if irqSectionScheme != "" : rule.mDependences.append (TARGET_DIR + "/generators-irq-section/" + irqSectionScheme + "/irq_section_generator.py") if unusedIRQScheme != "" : rule.mDependences.append (TARGET_DIR + "/generators-unused-irq/" + unusedIRQScheme + "/unused_irq_generator.py") rule.mCommand += [DEV_FILES_DIR + "/build_interrupt_handlers.py"] rule.mCommand += [TARGET_DIR] rule.mCommand += [interruptHandlerCppFile] rule.mCommand += [interruptHandlerSFile] rule.mCommand += [serviceScheme] rule.mCommand += [sectionScheme] rule.mCommand += [irqSectionScheme] rule.mCommand += [unusedIRQScheme] rule.mCommand += H_SOURCE_LIST rule.mPriority = -1 make.addRule (rule) #--------------------------------------------------------------------------- Group sources ? if GROUP_SOURCES : allSourceFile = GENERATED_SOURCE_DIR + "/all-sources.cpp" rule = makefile.Rule ([allSourceFile], "Group all sources") rule.mOpenSourceOnError = False rule.mDependences += CPP_SOURCE_LIST rule.mDependences.append ("makefile.json") rule.mCommand += [DEV_FILES_DIR + "/build_grouped_sources.py", allSourceFile] rule.mCommand += CPP_SOURCE_LIST rule.mPriority = -1 make.addRule (rule) CPP_SOURCE_LIST = [allSourceFile] #--------------------------------------------------------------------------- Build makefile rules objectFileList = [] asObjectFileList = [] #--- CPP source files for sourcePath in CPP_SOURCE_LIST : (goals, objectFiles, listingFiles) = addCppSourceFileToMakeFile ( sourcePath, make, BUILD_DIR, allHeadersSecondaryDependenceFile, COMPILER_TOOL_WITH_OPTIONS, includeDirsInCompilerCommand, usesLTO, GROUP_SOURCES, allHeaders_file, ASBUILD_DIR, AS_TOOL_WITH_OPTIONS ) allGoal += goals objectFileList += objectFiles asObjectFileList += listingFiles #-- Add ARM S files for sourcePath in S_SOURCE_LIST : (objectFiles, listingFiles) = addAsSourceFileToMakeFile ( sourcePath, make, BUILD_DIR, ASBUILD_DIR, AS_TOOL_WITH_OPTIONS, includeDirsInCompilerCommand ) objectFileList += objectFiles asObjectFileList += listingFiles #--------------------------------------------------------------------------- Enumerate deployments deploymentDictionary = deployment.deploymentDictionary () #--------------------------------------------------------------------- - Check selected deployments objectFileListDictionary = dict () for selectedDeployment in selectedDeployments : objectFileListDictionary [selectedDeployment] = list (objectFileList) if not selectedDeployment in deploymentDictionary.keys () : s = "Invalid deployment \"" + selectedDeployment + "\"; possible values:\n" for dep in deploymentDictionary.keys () : s += " - \"" + dep + "\"\n" print (makefile.BOLD_RED () + s + makefile.ENDC ()) sys.exit (1) #--------------------------------------------------------------- Additional source for deployement for selectedDeployment in selectedDeployments : additionalSourceDirectory = deployment.additionalSourceDirectoryForDeployment (selectedDeployment) if additionalSourceDirectory != "" : fullDirPath = TARGET_DIR + "/deployment/" + additionalSourceDirectory for name in sorted (os.listdir (fullDirPath)) : sourcePath = os.path.join (fullDirPath, name) (b, extension) = os.path.splitext (sourcePath) if extension == ".cpp" : (goals, objectFiles, listingFiles) = addCppSourceFileToMakeFile ( sourcePath, make, BUILD_DIR, allHeadersSecondaryDependenceFile, COMPILER_TOOL_WITH_OPTIONS, includeDirsInCompilerCommand, usesLTO, GROUP_SOURCES, allHeaders_file, ASBUILD_DIR, AS_TOOL_WITH_OPTIONS ) allGoal += goals objectFileListDictionary [selectedDeployment] += objectFiles asObjectFileList += listingFiles elif extension == ".s" : (objectFiles, listingFiles) = addAsSourceFileToMakeFile ( sourcePath, make, BUILD_DIR, ASBUILD_DIR, AS_TOOL_WITH_OPTIONS, includeDirsInCompilerCommand ) objectFileListDictionary [selectedDeployment] += objectFiles asObjectFileList += listingFiles elif extension != "" : # Ceci permet d'ignorer les fichés cachés (dont les noms commencent par un point) print (makefile.MAGENTA () + makefile.BOLD () + "Note: unhandled file " + sourcePath + makefile.ENDC ()) #--------------------------------------------------------------------------- Build deployment files runGoalDictionary = dict () for selectedDeployment in selectedDeployments : runGoalDictionary ["run-" + selectedDeployment] = selectedDeployment linkerScript = deploymentDictionary [selectedDeployment] LINKER_SCRIPT = TARGET_DIR + "/deployment/" + linkerScript PRODUCT = PRODUCT_DIR + "/deployment-" + selectedDeployment allGoal.append (PRODUCT + ".elf") #--- Add link rule rule = makefile.Rule ([PRODUCT + ".elf"], "Linking " + PRODUCT + ".elf") rule.mDependences += objectFileListDictionary [selectedDeployment] rule.mDependences.append (LINKER_SCRIPT) rule.mDependences.append ("makefile.json") rule.mCommand += LD_TOOL_WITH_OPTIONS rule.mCommand += objectFileListDictionary [selectedDeployment] rule.mCommand += ["-T" + LINKER_SCRIPT] rule.mCommand.append ("-Wl,-Map=" + PRODUCT + ".map") rule.mCommand += common_definitions.commonLinkerFlags (usesLTO) rule.mCommand += ["-o", PRODUCT + ".elf"] make.addRule (rule) make.addGoal ("run-" + selectedDeployment, allGoal, "Building " + selectedDeployment + " deployment and run") #--- Add deployment rules (goal, rule) = deployment.buildDeployment (PRODUCT, selectedDeployment, verbose) allGoal.append (goal) make.addRule (rule) # sys.path.pop () #--- Write deployment script pythonScriptFilePath = projectDir + "/2-run-" + selectedDeployment + "-via-usb.py" if not os.path.exists (pythonScriptFilePath) : f = open (DEV_FILES_DIR + "/deployment-script.py.txt", "r") genericScript = f.read () f.close () pythonScriptContents = genericScript.replace ("DEPLOYMENT", "run-" + selectedDeployment) f = open (pythonScriptFilePath, "wt") f.write (pythonScriptContents) f.close () #--- mode = os.stat (pythonScriptFilePath).st_mode # print (mode) mode += 0o0100 # Add execute permission # print (mode) os.chmod (pythonScriptFilePath, mode) #--------------------------------------------------------------------------- Goals make.addGoal ("all", allGoal, "Build all") make.addGoal ("view-hex", allGoal, "Building all and show hex") make.addGoal ("display-obj-size", allGoal, "Build binaries and display object sizes") make.addGoal ("as", asObjectFileList, "Compile C and C++ to assembly") #--------------------------------------------------------------------------- Run jobs #make.printRules () #make.checkRules () # make.writeRuleDependancesInDotFile ("dependances.dot") make.runGoal (maxConcurrentJobs, verbose) #--------------------------------------------------------------------------- Ok ? make.printErrorCountAndExitOnError () #---------------------------------------------------------------------------- "display-obj-size" if GOAL == "display-obj-size" : makefile.runCommand (DISPLAY_OBJ_SIZE_TOOL + objectFileList + ["-t"], "Display Object Size", False, verbose) #---------------------------------------------------------------------------- "All" or "run" if GOAL == "all" : for selectedDeployment in selectedDeployments : PRODUCT = PRODUCT_DIR + "/deployment-" + selectedDeployment s = runProcessAndGetOutput (DISPLAY_OBJ_SIZE_TOOL + ["-t"] + [PRODUCT + ".elf"]) secondLine = s.split('\n')[1] numbers = [int(s) for s in secondLine.split() if s.isdigit()] print ("Deployment \"" + selectedDeployment + "\":") print (" Code: " + str (numbers [0]) + " bytes") print (" Initialized data: " + str (numbers [1]) + " bytes") print (" RAM + STACK: " + str (numbers [2]) + " bytes") #---------------------------------------------------------------------------- Run ? if GOAL in runGoalDictionary.keys () : selectedDeployment = runGoalDictionary [GOAL] PRODUCT = PRODUCT_DIR + "/deployment-" + selectedDeployment DEPLOYMENT_DIR = TARGET_DIR + "/deployment" deployment.performDeployment (DEPLOYMENT_DIR, PRODUCT, selectedDeployment)