123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- #! /usr/bin/env python
- # -*- coding: UTF-8 -*-
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- import sys, os, subprocess, shutil, json
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- import makefile
- import common_definitions
- import download_and_install_gccarm
- import teensy_cli_loader_builder
- import dev_platform
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- # Run process and wait for termination *
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- def runProcess (command) :
- returncode = subprocess.call (command)
- if returncode != 0 :
- print (makefile.BOLD_RED () + "Error " + str (returncode) + makefile.ENDC ())
- sys.exit (returncode)
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- # Run process, get output and wait for termination *
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- def runProcessAndGetOutput (command) :
- result = ""
- childProcess = subprocess.Popen (command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- 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
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- # dictionaryFromJsonFile *
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- 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
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- # buildCode *
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
- def buildCode (GOAL, projectDir, maxConcurrentJobs, showCommand):
- #--------------------------------------------------------------------------- Prepare
- os.chdir (projectDir)
- make = makefile.Make (GOAL)
- make.mMacTextEditor = "TextWrangler" # "Atom"
- allGoal = []
- #--------------------------------------------------------------------------- Install Linux UDEV rules ?
- platform = dev_platform.getPlatform ()
- if (platform == "linux") or (platform == "linux32") :
- import udev_on_linux
- udev_on_linux.installUDEVrulesOnLinux ()
- #--------------------------------------------------------------------------- Install compiler ?
- BASE_NAME = "arm-none-eabi"
- TOOL_DIR = download_and_install_gccarm.installGCCARMandGetToolDirectory ()
- AS_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-as", "-mthumb", "-mcpu=cortex-m4"]
- COMPILER_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-gcc", "-mthumb", "-mcpu=cortex-m4"]
- 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"
- #--------------------------------------------------------------------------- Install Teensy loader CLI ?
- TEENSY_CLI_LOADER_PATH = teensy_cli_loader_builder.buildAndGetPath (TOOL_DIR + "/bin")
- #--------------------------------------------------------------------------- Analyze JSON file
- print (makefile.BOLD_GREEN () + "--- Making " + projectDir + makefile.ENDC ())
- dictionaire = dictionaryFromJsonFile (projectDir + "/makefile.json")
- #--- TEENSY
- linkerScript = ""
- teensyName = ""
- if dictionaire.has_key ("TEENSY") :
- TeensyKey = dictionaire ["TEENSY"]
- if (TeensyKey == "3.1") or (TeensyKey == "3.2") :
- teensyName = "TEENSY31"
- linkerScript = "teensy-3-1.ld"
- elif (TeensyKey == "3.5") :
- teensyName = "TEENSY35"
- linkerScript = "teensy-3-5.ld"
- elif (TeensyKey == "3.6") :
- teensyName = "TEENSY36"
- linkerScript = "teensy-3-6.ld"
- else:
- make.enterError ('In the makefile.json file, the "TEENSY" key value is invalid (possible values: "3.1", "3.2", "3.5" or "3.6").')
- else:
- make.enterError ('The makefile.json file does not have a "TEENSY" key (possible values: "3.1", "3.2", "3.5" or "3.6").')
- #--- ASSERTION_GENERATION
- ASSERTION_GENERATION = False
- if dictionaire.has_key ("ASSERTION-GENERATION") and dictionaire ["ASSERTION-GENERATION"] :
- ASSERTION_GENERATION = True
- #--- CPU_MHZ
- CPU_MHZ = 0
- if dictionaire.has_key ("CPU-MHZ") :
- CPU_MHZ = dictionaire ["CPU-MHZ"]
- #--- SOURCE_FILE_DIRECTORIES
- SOURCE_FILE_DIRECTORIES = []
- if dictionaire.has_key ("SOURCE-DIR") :
- SOURCE_FILE_DIRECTORIES = dictionaire ["SOURCE-DIR"]
- #--- GROUP_SOURCES
- GROUP_SOURCES = False
- if dictionaire.has_key ("GROUP-SOURCES") :
- GROUP_SOURCES = dictionaire ["GROUP-SOURCES"]
- #--- TASK_COUNT
- TASK_COUNT = "0" # Means TASK_COUNT is not defined by JSON file
- if dictionaire.has_key ("TASK-COUNT") :
- TASK_COUNT = str (dictionaire ["TASK-COUNT"])
- #--- LTO
- usesLTO = False
- if dictionaire.has_key ("LTO") and dictionaire ["LTO"] :
- usesLTO = True
- #--- SERVICE
- serviceScheme = ""
- if dictionaire.has_key ("SERVICE-SCHEME") :
- serviceScheme = dictionaire ["SERVICE-SCHEME"]
- #--- SECTION
- sectionScheme = ""
- if dictionaire.has_key ("SECTION-SCHEME") :
- sectionScheme = dictionaire ["SECTION-SCHEME"]
- #--------------------------------------------------------------------------- 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, "-I", projectDir]
- 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)
- elif extension == ".s" :
- S_SOURCE_LIST.append (sourcePath)
- 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/build_base_header_file.py", baseHeader_file, str (CPU_MHZ), TASK_COUNT, teensyName, "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/build_all_header_file.py", allHeaders_file, allHeadersSecondaryDependenceFile]
- rule.mCommand += H_SOURCE_LIST
- rule.enterSecondaryDependanceFile (allHeadersSecondaryDependenceFile, make)
- rule.mPriority = -1
- make.addRule (rule)
- #--------------------------------------------------------------------------- Build interrupt handler files
- interruptHandlerSFile = GENERATED_SOURCE_DIR + "/interrupt-handlers.s"
- interruptHandlerCppFile = GENERATED_SOURCE_DIR + "/interrupt-handler-helper.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/build_interrupt_handlers.py")
- rule.mCommand += ["../dev-files/build_interrupt_handlers.py"]
- rule.mCommand += [interruptHandlerCppFile]
- rule.mCommand += [interruptHandlerSFile]
- rule.mCommand += [serviceScheme]
- rule.mCommand += [sectionScheme]
- 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/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 :
- source = os.path.basename (sourcePath)
- objectFile = BUILD_DIR + "/" + source + ".o"
- objectFileForChecking = BUILD_DIR + "/" + source + ".check.o"
- asObjectFile = BUILD_DIR + "/" + source + ".s"
- #--- Checking source
- rule = makefile.Rule ([objectFileForChecking], "Checking " + source)
- rule.mOpenSourceOnError = False
- rule.mDependences.append (allHeaders_file)
- rule.mDependences.append (sourcePath)
- rule.mDependences.append ("makefile.json")
- rule.enterSecondaryDependanceFile (objectFileForChecking + ".dep", make)
- rule.mCommand += COMPILER_TOOL_WITH_OPTIONS
- rule.mCommand += common_definitions.checkModeOptions ()
- rule.mCommand += common_definitions.C_Cpp_optimizationOptions ()
- rule.mCommand += common_definitions.Cpp_actualOptions (False)
- rule.mCommand += ["-c", sourcePath]
- rule.mCommand += ["-o", objectFileForChecking]
- rule.mCommand += ["-DSTATIC="]
- rule.mCommand += includeDirsInCompilerCommand
- rule.mCommand += ["-MD", "-MP", "-MF", objectFileForChecking + ".dep"]
- make.addRule (rule)
- rule.mPriority = -1
- allGoal.append (objectFileForChecking)
- #--- Compile source
- rule = makefile.Rule ([objectFile], "Compiling " + source)
- rule.mOpenSourceOnError = False
- rule.mCommand += COMPILER_TOOL_WITH_OPTIONS
- rule.mCommand += common_definitions.C_Cpp_optimizationOptions ()
- rule.mCommand += common_definitions.Cpp_actualOptions (usesLTO)
- rule.mCommand += ["-g"]
- rule.mCommand += ["-c", sourcePath]
- rule.mCommand += ["-o", objectFile]
- rule.mCommand += ["-DSTATIC=static __attribute__((unused))"] if GROUP_SOURCES else ["-DSTATIC="]
- rule.mCommand += includeDirsInCompilerCommand
- rule.mCommand += ["-MD", "-MP", "-MF", objectFile + ".dep"]
- rule.mDependences.append (allHeaders_file)
- rule.mDependences.append (sourcePath)
- rule.mDependences.append ("makefile.json")
- rule.enterSecondaryDependanceFile (objectFile + ".dep", make)
- make.addRule (rule)
- objectFileList.append (objectFile)
- #--- objdump python source
- objdumpPythonFile = BUILD_DIR + "/" + source + ".objdump.py"
- rule = makefile.Rule ([objdumpPythonFile], "Building " + source + ".objdump.py")
- rule.mDependences.append (objectFile)
- rule.mDependences.append ("makefile.json")
- rule.mCommand += ["../dev-files/build_objdump.py", OBJDUMP_TOOL, source, objdumpPythonFile]
- rule.mPriority = -1
- make.addRule (rule)
- allGoal.append (objdumpPythonFile)
- #--- AS rule
- rule = makefile.Rule ([asObjectFile], "Compiling -> s " + source)
- rule.mOpenSourceOnError = False
- rule.mCommand += COMPILER_TOOL_WITH_OPTIONS
- rule.mCommand += common_definitions.C_Cpp_optimizationOptions ()
- rule.mCommand += common_definitions.Cpp_actualOptions (usesLTO)
- rule.mCommand += ["-S", sourcePath]
- rule.mCommand += ["-o", asObjectFile]
- rule.mCommand += ["-DSTATIC="]
- rule.mCommand += includeDirsInCompilerCommand
- rule.mCommand += ["-MD", "-MP", "-MF", asObjectFile + ".dep"]
- rule.mDependences.append (sourcePath)
- rule.mDependences.append (allHeaders_file)
- rule.mDependences.append ("makefile.json")
- rule.enterSecondaryDependanceFile (asObjectFile + ".dep", make)
- make.addRule (rule)
- #--- AS rule, getting output assembler file
- listingFile = ASBUILD_DIR + "/" + source + ".s.list"
- rule = makefile.Rule ([listingFile], "Assembling -> listing " + source)
- rule.mOpenSourceOnError = False
- rule.mCommand += AS_TOOL_WITH_OPTIONS
- rule.mCommand += [asObjectFile]
- rule.mCommand += ["-o", "/dev/null"]
- rule.mCommand += ["-aln=" + listingFile]
- rule.mDependences.append (asObjectFile)
- rule.mDependences.append (allHeaders_file)
- rule.mDependences.append ("makefile.json")
- make.addRule (rule)
- asObjectFileList.append (listingFile)
- #-- Add ARM S files
- for sourcePath in S_SOURCE_LIST :
- source = os.path.basename (sourcePath)
- objectFile = BUILD_DIR + "/" + source + ".o"
- objectFileForChecking = BUILD_DIR + "/" + source + ".check.o"
- asObjectFile = ASBUILD_DIR + "/" + source + ".s"
- if sourcePath != "" :
- rule = makefile.Rule ([objectFile], "Assembling " + source)
- rule.mOpenSourceOnError = False
- rule.mCommand += AS_TOOL_WITH_OPTIONS
- rule.mCommand += [sourcePath]
- rule.mCommand += ["-o", objectFile]
- rule.mCommand += includeDirsInCompilerCommand
- rule.mCommand += ["--MD", objectFile + ".dep"]
- rule.mDependences.append (sourcePath)
- rule.mDependences.append ("makefile.json")
- rule.enterSecondaryDependanceFile (objectFile + ".dep", make)
- make.addRule (rule)
- objectFileList.append (objectFile)
- #--- Add listing file
- listingFile = ASBUILD_DIR + "/" + source + ".list"
- rule = makefile.Rule ([listingFile], "Assembling -> listing " + source)
- rule.mOpenSourceOnError = False
- rule.mCommand += AS_TOOL_WITH_OPTIONS
- rule.mCommand += [sourcePath]
- rule.mCommand += ["-o", "/dev/null"]
- rule.mCommand += ["-aln=" + listingFile]
- rule.mDependences.append (sourcePath)
- rule.mDependences.append ("makefile.json")
- make.addRule (rule)
- asObjectFileList.append (listingFile)
- #--------------------------------------------------------------------------- Link for internal flash
- PRODUCT_INTERNAL_FLASH = PRODUCT_DIR + "/product"
- LINKER_SCRIPT_INTERNAL_FLASH = "../dev-files/" + linkerScript
- allGoal.append (PRODUCT_INTERNAL_FLASH + ".elf")
- #--- Add link rule
- rule = makefile.Rule ([PRODUCT_INTERNAL_FLASH + ".elf"], "Linking " + PRODUCT_INTERNAL_FLASH + ".elf")
- rule.mDependences += objectFileList
- rule.mDependences.append (LINKER_SCRIPT_INTERNAL_FLASH)
- rule.mDependences.append ("makefile.json")
- rule.mCommand += LD_TOOL_WITH_OPTIONS
- rule.mCommand += objectFileList
- rule.mCommand += ["-T" + LINKER_SCRIPT_INTERNAL_FLASH]
- rule.mCommand.append ("-Wl,-Map=" + PRODUCT_INTERNAL_FLASH + ".map")
- rule.mCommand += common_definitions.commonLinkerFlags (usesLTO)
- rule.mCommand += ["-o", PRODUCT_INTERNAL_FLASH + ".elf"]
- make.addRule (rule)
- #--- Add hex rule
- allGoal.append (PRODUCT_INTERNAL_FLASH + ".hex")
- rule = makefile.Rule ([PRODUCT_INTERNAL_FLASH + ".hex"], "Hexing " + PRODUCT_INTERNAL_FLASH + ".hex")
- rule.mDependences.append (PRODUCT_INTERNAL_FLASH + ".elf")
- rule.mDependences.append ("makefile.json")
- rule.mCommand += OBJCOPY_TOOL_WITH_OPTIONS
- rule.mCommand.append ("-O")
- rule.mCommand.append ("ihex")
- rule.mCommand.append (PRODUCT_INTERNAL_FLASH + ".elf")
- rule.mCommand.append (PRODUCT_INTERNAL_FLASH + ".hex")
- make.addRule (rule)
- #--------------------------------------------------------------------------- Goals
- make.addGoal ("all", allGoal, "Build all")
- make.addGoal ("run", allGoal, "Building all and run")
- 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, showCommand)
- #--------------------------------------------------------------------------- Ok ?
- make.printErrorCountAndExitOnError ()
- #---------------------------------------------------------------------------- "display-obj-size"
- if GOAL == "display-obj-size" :
- makefile.runCommand (DISPLAY_OBJ_SIZE_TOOL + objectFileList + ["-t"], "Display Object Size", False, showCommand)
- #---------------------------------------------------------------------------- "All" or "run"
- if (GOAL == "all") or (GOAL == "run") or (GOAL == "view-hex") :
- s = runProcessAndGetOutput (DISPLAY_OBJ_SIZE_TOOL + ["-t"] + [PRODUCT_INTERNAL_FLASH + ".elf"])
- secondLine = s.split('\n')[1]
- numbers = [int(s) for s in secondLine.split() if s.isdigit()]
- print (" ROM code: " + str (numbers [0]) + " bytes")
- print (" ROM data: " + str (numbers [1]) + " bytes")
- print (" RAM + STACK: " + str (numbers [2]) + " bytes")
- #----------------------------------------------- Run ?
- if GOAL == "run":
- FLASH_TEENSY = [TEENSY_CLI_LOADER_PATH, "-w", "-v", "-mmcu=TEENSY36"]
- print (makefile.BOLD_BLUE () + "Loading Teensy..." + makefile.ENDC ())
- runProcess (FLASH_TEENSY + [PRODUCT_INTERNAL_FLASH + ".hex"])
- print (makefile.BOLD_GREEN () + "Success" + makefile.ENDC ())
- elif GOAL == "view-hex":
- print (makefile.BOLD_GREEN () + "View hex..." + makefile.ENDC ())
- scriptDir = os.path.dirname (os.path.abspath (__file__))
- runProcess (["python", scriptDir+ "/view-hex.py", PRODUCT_INTERNAL_FLASH + ".hex"])
- #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
|