% # # @file build_py.goilTemplate # # @section desc File description # # Template to generate a build file in Python using the system # developed by Pierre Molinaro # # @section copyright Copyright # # Trampoline RTOS # # Trampoline is copyright (c) CNRS, University of Nantes, Ecole Centrale de Nantes # Trampoline is protected by the French intellectual property law. # # This software is distributed under the GNU Public Licence V2. # Check the LICENSE file in the root directory of Trampoline # # @section infos File informations # # $Date$ # $Rev$ # $Author$ # $URL$ # if not exists OS::BUILD_S::CFLAGS then let OS::BUILD_S::CFLAGS := @() end if if not exists OS::BUILD_S::ASFLAGS then let OS::BUILD_S::ASFLAGS := @() end if if not exists OS::BUILD_S::LDFLAGS then let OS::BUILD_S::LDFLAGS := @() end if let postgoals := @[] if exists POSTBUILD then let postgoals := mapof exists POSTBUILD default ( @() ) by NAME end if %#! /usr/bin/env python # -*- coding: UTF-8 -*- #---------------------------------------------------------------------- #--- Python Build file for application % !CPUNAME % #--- automatically generated by goil on % !TIMESTAMP % #--- from root OIL file % !OILFILENAME % #--- #--- Compiling a Trampoline application is done in 2 stages #--- 1 - From the OIL file, a set of files is generated as long as #--- build options. Among these files are the build.py and make.py #--- files. make.py contains compilation rules when the OIL file #--- and the included OIL files are modified. make.py is only #--- written once when the goil command is typed. #--- 2 - From all the C/assembly files (OS, Application, librairies, #--- configuration, ...), the objects and the executable are #--- produced. This is done by the build.py file. #--- build.py is generated each time goil is called by make.py #---------------------------------------------------------------------- import sys, os, subprocess, string, distutils.spawn from string import Template #--- Add some function for Python3 support if sys.version_info[0] >=3 : def bytesdecode(obj) : return obj.decode(sys.stdout.encoding) else : def bytesdecode(obj) : return obj #--- Add the location of makefile.py to the import path sys.path.append("% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/make") #--- Import the makefile system in python import makefile, projfile #--- To work with relative paths scriptDir = os.path.dirname (os.path.abspath (sys.argv[0])) os.chdir (scriptDir) #--- Get goal as first argument askedGoal = "all" if len (sys.argv) > 1 : askedGoal = sys.argv [1] if askedGoal == "all" or askedGoal == "clean" : goal = askedGoal else : goal = "all" #--- Get max parallel jobs as second argument maxParallelJobs = 0 # 0 means use host processor count if len (sys.argv) > 2 : maxParallelJobs = int (sys.argv [2]) #--- Instanciate a new makefile object make = makefile.Make(goal) #---------------------------------------------------------------------- #--- Various variables used after #---------------------------------------------------------------------- compiler = r"% !OS::BUILD_S::COMPILER %" cppCompiler = r"% !OS::BUILD_S::CPPCOMPILER %" linker = r"% !OS::BUILD_S::LINKER %" assembler = r"% !OS::BUILD_S::ASSEMBLER %" autosar = % ! TrueFalse(AUTOSAR) % autosar_sc = % !OS::SCALABILITYCLASS % autosar_osapplications = % !TrueFalse(OS::SCALABILITYCLASS == 3 | OS::SCALABILITYCLASS == 4) % with_ioc = % ! TrueFalse([IOC length] > 0) % with_com = % ! TrueFalse(USECOM) % scheduler = "% !OS::SCHEDULER %" trampoline_base_path = "% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/" cflags = [] cppflags = [] ldflags = [] asflags = [] # flags that should appear at the beginning of the command. precflags = [] precppflags = [] preldflags = [] preasflags = [] includeDirs = [] % #CFLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::CFLAGS default ( @() ) do % cflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in exists OS::BUILD_S::CFLAGS default ( @() ) do % cflags += "% !flags::VALUE %".split()% end foreach #PRE CFLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::PRECFLAGS default ( @() ) do % precflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in exists OS::BUILD_S::PRECFLAGS default ( @() ) do % precflags += "% !flags::VALUE %".split()% end foreach #CPPFLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::CPPFLAGS default ( @() ) do % cppflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in exists OS::BUILD_S::CPPFLAGS default ( @() ) do % cppflags += "% !flags::VALUE %".split()% end foreach #PRECPPFLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::PRECPPFLAGS default ( @() ) do % precppflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in exists OS::BUILD_S::PRECPPFLAGS default ( @() ) do % precppflags += "% !flags::VALUE %".split()% end foreach #COMMON FLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::COMMONFLAGS default ( @() ) do % cflags += "% !flags::VALUE %".split() cppflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in exists OS::BUILD_S::COMMONFLAGS default ( @() ) do % cflags += "% !flags::VALUE %".split() cppflags += "% !flags::VALUE %".split()% end foreach #PRE COMMON FLAGS #COMMON FLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::PRECOMMONFLAGS default ( @() ) do % precflags += "% !flags::VALUE %".split() precppflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in exists OS::BUILD_S::PRECOMMONFLAGS default ( @() ) do % precflags += "% !flags::VALUE %".split() precppflags += "% !flags::VALUE %".split()% end foreach #include dirs let MACHINESPATH := OS::BUILD_S::TRAMPOLINE_BASE_PATH+"/machines" foreach platform in exists PLATFORM_FILES default ( @() ) do% includeDirs += ["-I","% !MACHINESPATH + "/" + platform::PATH %"]% end foreach foreach library in exists USEDLIB default ( @() ) do% includeDirs += ["-I","% !MACHINESPATH + "/" + library::PATH %"]% end foreach % if with_ioc: includeDirs += ["-I", "% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/ioc"] includeDirs += ["-I", "% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/os"] includeDirs += ["-I", "% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/debug"] includeDirs += ["-I", "% !PROJECT %"] cflags += includeDirs cppflags += includeDirs asflags += includeDirs % #LDFLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::LDFLAGS default ( @() ) do % ldflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in OS::BUILD_S::LDFLAGS do % ldflags += "% !flags::VALUE %".split()% end foreach #PRE LDFLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::PRELDFLAGS default ( @() ) do % preldflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in exists OS::BUILD_S::PRELDFLAGS default ( @() ) do % preldflags += "% !flags::VALUE %".split()% end foreach if exists OS::MEMMAP_S::LINKER then % ldflags += ["-L", "% !PROJECT %"] ldflags += ["-T", "%!OS::MEMMAP_S::LINKER_S::SCRIPT %"]% end if #ASFLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::ASFLAGS default ( @() ) do % asflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in exists OS::BUILD_S::ASFLAGS default ( @() ) do % asflags += "% !flags::VALUE %".split()% end foreach #PRE ASFLAGS foreach optionSet in exists BUILDOPTIONS default ( @() ) do foreach flags in exists optionSet::PREASFLAGS default ( @() ) do % preasflags += "% !flags::VALUE %".split()% end foreach end foreach foreach flags in exists OS::BUILD_S::PREASFLAGS default ( @() ) do % preasflags += "% !flags::VALUE %".split()% end foreach if [TARGET leftSubString: 5] != "posix" then % #---------------------------------------------------------------------- #--- Try to detect automatically the location of libc and libgcc #--- This supposes the compiler has a (something)-gcc name #--- for non posix target #---------------------------------------------------------------------- if "gcc" in compiler: compilerFullPath = makefile.find_executable(compiler) if compilerFullPath != None: #--- Extract the (something) from the compiler executable name compilerParts = compiler.split('-') compilerParts.pop() compilerPrefix = "-".join(compilerParts) #--- Get the full path of the compiler compilerToolChainPath = os.path.dirname(os.path.dirname(compilerFullPath)) #--- Get the version of the compiler, [:-1] removes the carriage return compilerVersion = subprocess.check_output([compiler, '-dumpversion'])[:-1] #--- Build the libc and libgcc paths procLibc =subprocess.Popen([compilerFullPath,"-print-file-name=libc.a"]+cflags,stdout=subprocess.PIPE) procLibgcc=subprocess.Popen([compilerFullPath,"-print-libgcc-file-name"]+cflags,stdout=subprocess.PIPE) procLibc.wait() procLibgcc.wait() libcPath = os.path.dirname(procLibc.stdout.readline().strip()) libgccPath = os.path.dirname(procLibgcc.stdout.readline().strip()) #--- Add both to linker flags ldflags += ['-L' + bytesdecode(libcPath), '-lc'] ldflags += ['-L' + bytesdecode(libgccPath), '-lgcc'] % end if % #---------------------------------------------------------------------- #--- Build the source files list #---------------------------------------------------------------------- cSourceList = [] cppSourceList = [] sSourceList = [] oilSourceList = [] #--- OIL file oilSourceList.append("% !OILFILENAME %") #--- Kernel files % let KERNEL_MAP := mapof KERNEL by NAME let path := KERNEL_MAP["osek_kernel"]::PATH+"/" foreach file in KERNEL_MAP["osek_kernel"]::FILE do % cSourceList.append(projfile.ProjectFile("% !path+file::VALUE %", trampoline_base_path))% end foreach if USECOM then % cflags += ["-I", "% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/com"] cppflags += ["-I", "% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/com"]% let path := KERNEL_MAP["com_kernel"]::PATH+"/" foreach file in KERNEL_MAP["com_kernel"]::FILE do % cSourceList.append(projfile.ProjectFile("% !path+file::VALUE %", trampoline_base_path))% end foreach end if if OS::SCALABILITYCLASS > 0 then % cflags += ["-I", "% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/autosar"] cppflags += ["-I", "% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/autosar"]% let path := KERNEL_MAP["autosar_kernel"]::PATH+"/" foreach file in KERNEL_MAP["autosar_kernel"]::FILE do % cSourceList.append(projfile.ProjectFile("% !path+file::VALUE %", trampoline_base_path))% end foreach if (exists USEMEMORYPROTECTION default (false)) | (exists OS::TIMINGPROTECTION default (false)) then let path := KERNEL_MAP["protec_kernel"]::PATH+"/" foreach file in KERNEL_MAP["protec_kernel"]::FILE do % cSourceList.append(projfile.ProjectFile("% !path+file::VALUE %", trampoline_base_path))% end foreach end if end if foreach module in exists OS::KERNEL_MODULE default ( @() ) do if exists KERNEL_MAP[module::VALUE] then if module::VALUE != "osek_kernel" & module::VALUE != "com_kernel" & module::VALUE != "autosar_kernel" & module::VALUE != "protec_kernel" then let path := KERNEL_MAP[module::VALUE]::PATH+"/" % cflags += ["-I", "% !OS::BUILD_S::TRAMPOLINE_BASE_PATH %/% !KERNEL_MAP[module::VALUE]::PATH%"]% foreach file in KERNEL_MAP[module::VALUE]::FILE do % cSourceList.append(projfile.ProjectFile("% !path+file::VALUE %", trampoline_base_path))% end foreach else error module:"Module does not exist" end if end if end foreach #--- Services files% foreach service_set in APIUSED do foreach file in service_set::FILE do % cSourceList.append(projfile.ProjectFile("% !service_set::DIRECTORY+"/"+file::VALUE %.c", trampoline_base_path))% end foreach end foreach foreach src in exists OS::BUILD_S::APP_SRC default ( @() ) before % #--- Add C files of the application% do % cSourceList.append(projfile.ProjectFile("% !src::VALUE %"))% end foreach foreach src in exists OS::BUILD_S::APP_CPPSRC default ( @() ) before % #--- Add C++ files of the application% do % cppSourceList.append(projfile.ProjectFile("% !src::VALUE %"))% end foreach % #--- Add generated files cSourceList.append(projfile.ProjectFile("% !PROJECT %/tpl_app_config.c")) % if OS::SYSTEM_CALL then % cSourceList.append(projfile.ProjectFile("% !PROJECT %/tpl_dispatch_table.c")) cSourceList.append(projfile.ProjectFile("% !PROJECT %/tpl_invoque.S"))% else % cSourceList.append(projfile.ProjectFile("% !PROJECT %/tpl_os.c"))% end if if [TRANSACTION length] > 0 then % cSourceList.append(projfile.ProjectFile("% !PROJECT %/stm_structure.c"))% end if if [IOC length] > 0 then % cSourceList.append(projfile.ProjectFile("% !PROJECT %/tpl_ioc_api_config.c"))% end if foreach platform in exists GENERATED_FILES default ( @() ) do if not exists platform::CFILE then let platform::CFILE := @() end if if not exists platform::ASFILE then let platform::ASFILE := @() end if foreach file in platform::CFILE do % cSourceList.append(projfile.ProjectFile("% !PROJECT+"/"+file::VALUE %"))% end foreach foreach file in platform::ASFILE do % sSourceList.append(projfile.ProjectFile("% !PROJECT+"/"+file::VALUE %"))% end foreach end foreach foreach platform in exists PLATFORM_FILES default ( @() ) do if not exists platform::CFILE then let platform::CFILE := @() end if if not exists platform::CPPFILE then let platform::CPPFILE := @() end if if not exists platform::ASFILE then let platform::ASFILE := @() end if foreach file in platform::CFILE do % cSourceList.append(projfile.ProjectFile("% !"machines/"+platform::PATH+"/"+file::VALUE %", trampoline_base_path))% end foreach foreach file in platform::CPPFILE do % cppSourceList.append(projfile.ProjectFile("% !"machines/"+platform::PATH+"/"+file::VALUE %", trampoline_base_path))% end foreach foreach file in platform::ASFILE do % sSourceList.append(projfile.ProjectFile("% !"machines/"+platform::PATH+"/"+file::VALUE %", trampoline_base_path))% end foreach end foreach # add the libraries foreach library in exists USEDLIB default ( @() ) do if not exists library::CFILE then let library::CFILE := @() end if if not exists library::CPPFILE then let library::CPPFILE := @() end if if not exists library::ASFILE then let library::ASFILE := @() end if foreach file in library::CFILE do % cSourceList.append(projfile.ProjectFile("% !"machines/"+library::PATH+"/"+file::VALUE %", trampoline_base_path))% end foreach foreach file in library::CPPFILE do % cppSourceList.append(projfile.ProjectFile("% !"machines/"+library::PATH+"/"+file::VALUE %", trampoline_base_path))% end foreach foreach file in library::ASFILE do % sSourceList.append(projfile.ProjectFile("% !"machines/"+library::PATH+"/"+file::VALUE %", trampoline_base_path))% end foreach end foreach % #---------------------------------------------------------------------- #--- Build the object list and the compiler dependancies #---------------------------------------------------------------------- objectList = [] for sourceFile in cSourceList: source = sourceFile.src() object = sourceFile.obj("build") depObject = sourceFile.dep("build") objectList.append(object) rule = makefile.Rule([object], "Compiling " + source) rule.deleteTargetDirectoryOnClean() rule.mDependences.append(source) rule.mCommand.append(compiler) rule.mCommand += precflags rule.mCommand += ["-c", source] rule.mCommand += ["-o", object] rule.mCommand += ["-MD", "-MP", "-MF", depObject] rule.mCommand += cflags rule.enterSecondaryDependanceFile (depObject, make) make.addRule(rule) for sourceFile in cppSourceList: source = sourceFile.src() object = sourceFile.obj("build") depObject = sourceFile.dep("build") objectList.append(object) rule = makefile.Rule([object], "Compiling " + source) rule.deleteTargetDirectoryOnClean() rule.mDependences.append(source) rule.mCommand.append(cppCompiler) rule.mCommand += precppflags rule.mCommand += ["-c", source] rule.mCommand += ["-o", object] rule.mCommand += ["-MD", "-MP", "-MF", depObject] rule.mCommand += cppflags rule.enterSecondaryDependanceFile (depObject, make) make.addRule(rule) for sourceFile in sSourceList: source = sourceFile.src() object = sourceFile.obj("build") objectList.append(object) rule = makefile.Rule([object], "Assembling " + source) rule.mDependences.append(source) rule.mCommand.append(assembler) rule.mCommand += preasflags rule.mCommand += ["-c", source] rule.mCommand += ["-o", object] rule.mCommand += asflags make.addRule(rule) product = "% !OS::BUILD_S::APP_NAME %" rule = makefile.Rule ([product], "Linking " + product) rule.deleteTargetFileOnClean() rule.mDeleteTargetOnError = True rule.mDependences += objectList rule.mCommand += [linker] rule.mCommand += ["-o", product] rule.mCommand += preldflags rule.mCommand += objectList rule.mCommand += ldflags% let target := OS::BUILD_S::APP_NAME if exists postgoals["all"] then let inFile := target foreach command in postgoals["all"]::COMMAND do if command::INPUT == "ORIGINAL_TARGET" then let inFile := OS::BUILD_S::APP_NAME end if let command::SUBGOAL := exists command::SUBGOAL default(false) if command::SUBGOAL then% if askedGoal == "% !command::SUBGOAL_S::NAME %":% else% if True:% end if # if inFile == "ORIGINAL_TARGET" then # let outFile := OS::BUILD_S::APP_NAME # else let outFile := inFile + exists command::OUTPUT default("") # end if if command::TYPE == "COPIER" then % postCommand = makefile.PostCommand("Generating binary % !outFile % from % !inFile %") postCommand.mCommand.append(r"% !OS::BUILD_S::COPIER %")% elsif command::TYPE == "COMPILER" then elsif command::TYPE == "ASSEMBLER" then elsif command::TYPE == "LINKER" then elsif command::TYPE == "CUSTOM" then % postCommand = makefile.PostCommand("% !command::TYPE_S::MESSAGE % % !inFile %") postCommand.mCommand.append("% !command::TYPE_S::NAME %")% end if foreach option in command::PREOPTION do % postCommand.mCommand += "% !option::VALUE %".split()% end foreach% postCommand.mCommand.append("% !inFile %")% if exists command::OUTPUT then% postCommand.mCommand.append("% !outFile %")% end if let inFile := outFile% rule.mPostCommands.append(postCommand)% end foreach end if % make.addRule (rule) make.addGoal("all", [product], "Building all") make.addGoal("compile", objectList, "Compile source files") % foreach goal in exists GOAL default( @() ) do % rule = makefile.Rule([], "% !goal::MESSAGE %") depList = []% foreach dep in goal::DEPENDENCY do if dep::VALUE == "TARGET" then % depList.append("% !target %")% else % depList.append("% !dep::VALUE_S::NAME %")% end if end foreach % rule.mDependences += depList rule.mCommand.append("% !goal::COMMAND %")% foreach arg in goal::ARGUMENT do % rule.mCommand.append("% !arg::VALUE %")% end foreach % make.addRule(rule) make.addGoal("% !goal::NAME %", depList, "% !goal::MESSAGE %")% end foreach % make.runGoal(maxParallelJobs, maxParallelJobs == 1) postVariableMapping = dict( MACHINE_PATH='% ! MACHINESPATH %', ARCH_PATH='% ! MACHINESPATH + "/" + ARCH %', BOARD_PATH='% ! MACHINESPATH + "/" + TARGET %', TARGET='% ! TARGET %' ) % foreach pc in exists POSTCOMMAND default ( @() ) before% #---------------------------------------------------------------------- #--- post commands #---------------------------------------------------------------------- if make.errorCount() == 0:% do% if askedGoal == "% !pc::NAME %" :% foreach cmd in pc::COMMAND do let commandLine := cmd::COMMAND + " " foreach opt in exists cmd::PREOPTION default ( @() ) do let commandLine := commandLine + opt::VALUE + " " end foreach% commandLine = "% !commandLine %"% foreach opt in exists cmd::PREOPT default ( @() ) do if opt::VALUE == "ENVAR" then% if os.environ.get('% !opt::VALUE_S::NAME %') != None: commandLine += "% !opt::VALUE_S::OPT %" + os.environ['% !opt::VALUE_S::NAME %'] + " " else: print("Cannot % !pc::NAME %, environment variable % !opt::VALUE_S::NAME % is not defined") exit(1)% elsif opt::VALUE == "LITERAL" then% commandLine += "% !opt::VALUE_S::OPT + opt::VALUE_S::VALUE %"% end if end foreach if exists cmd::INPUT then if cmd::INPUT == "TARGET" then% commandLine += "% !target + cmd::INPUT_S::EXT + " "%"% else% commandLine += "% !cmd::INPUT_S::SOURCE + " "%"% end if end if if exists cmd::OUTPUT then% commandLine += "% !OUTPUT + " " %"% end if let commandLine := "" foreach opt in exists cmd::POSTOPTION default ( @() ) do let commandLine := commandLine + opt::VALUE + " " end foreach if commandLine != "" then % commandLine += "% !commandLine %"% end if % commandLineTemplate = Template(commandLine) commandLine = commandLineTemplate.safe_substitute(postVariableMapping) if makefile.find_executable("% !cmd::COMMAND %") != None: print("\033[1m\033[95m% !cmd::MESSAGE % % !OS::BUILD_S::APP_NAME % on % ! TARGET %\033[0m") subprocess.call(commandLine, shell=True) else: print("Command '% !cmd::COMMAND %' not in PATH")% end foreach end foreach% make.printErrorCountAndExitOnError() #---------------------------------------------------------------------- #-- End of build.py #----------------------------------------------------------------------