4 # Copyright 2008 Develer S.r.l. (http://www.develer.com/)
9 # Author: Lorenzo Berni <duplo@develer.com>
19 import DefineException
21 # Try to use the new parsing module for the module information and the define lists
24 def isBertosDir(directory):
25 return os.path.exists(directory + "/VERSION")
27 def bertosVersion(directory):
28 return open(directory + "/VERSION").readline().strip()
30 def createBertosProject(projectInfos):
31 directory = projectInfos.info("PROJECT_PATH")
32 sourcesDir = projectInfos.info("SOURCES_PATH")
33 if not os.path.isdir(directory):
35 f = open(directory + "/project.bertos", "w")
36 f.write(repr(projectInfos))
38 ## Destination source dir
39 srcdir = directory + "/bertos"
40 shutil.rmtree(srcdir, True)
41 shutil.copytree(sourcesDir + "/bertos", srcdir)
42 ## Destination makefile
43 makefile = directory + "/Makefile"
44 if os.path.exists(makefile):
46 makefile = open("mktemplates/Makefile").read()
47 makefile = makefileGenerator(projectInfos, makefile)
48 open(directory + "/Makefile", "w").write(makefile)
49 ## Destination project dir
50 prjdir = directory + "/" + os.path.basename(directory)
51 shutil.rmtree(prjdir, True)
53 ## Destination configurations files
54 cfgdir = prjdir + "/cfg"
55 shutil.rmtree(cfgdir, True)
57 for key, value in projectInfos.info("CONFIGURATIONS").items():
58 string = open(sourcesDir + "/" + key, "r").read()
59 for parameter, infos in value.items():
60 value = infos["value"]
61 if "unsigned" in infos["informations"].keys() and infos["informations"]["unsigned"]:
63 if "long" in infos["informations"].keys() and infos["informations"]["long"]:
65 string = sub(string, parameter, value)
66 f = open(cfgdir + "/" + os.path.basename(key), "w")
70 makefile = open("mktemplates/template.mk", "r").read()
71 makefile = mkGenerator(projectInfos, makefile)
72 open(prjdir + "/" + os.path.basename(prjdir) + ".mk", "w").write(makefile)
74 def mkGenerator(projectInfos, makefile):
76 Generates the mk file for the current project.
79 mkData["pname"] = os.path.basename(projectInfos.info("PROJECT_PATH"))
80 mkData["cpuname"] = projectInfos.info("CPU_INFOS")["CPU_NAME"]
81 mkData["cflags"] = " ".join(projectInfos.info("CPU_INFOS")["C_FLAGS"])
82 mkData["ldflags"] = " ".join(projectInfos.info("CPU_INFOS")["LD_FLAGS"])
84 while makefile.find(key) != -1:
85 makefile = makefile.replace(key, mkData[key])
88 def makefileGenerator(projectInfos, makefile):
90 Generate the Makefile for the current project.
92 # TODO: write a general function that works for both the mk file and the Makefile
93 while makefile.find("project_name") != -1:
94 makefile = makefile.replace("project_name", os.path.basename(projectInfos.info("PROJECT_PATH")))
98 path = os.environ["PATH"]
100 path = path.split(";")
102 path = path.split(":")
105 def findToolchains(pathList):
107 for element in pathList:
108 for toolchain in glob.glob(element+ "/" + const.GCC_NAME):
109 if not os.path.islink(toolchain):
110 toolchains.append(toolchain)
111 return list(set(toolchains))
113 def getToolchainInfo(output):
115 expr = re.compile("Target: .*")
116 target = expr.findall(output)
118 info["target"] = target[0].split("Target: ")[1]
119 expr = re.compile("gcc version [0-9,.]*")
120 version = expr.findall(output)
121 if len(version) == 1:
122 info["version"] = version[0].split("gcc version ")[1]
123 expr = re.compile("gcc version [0-9,.]* \(.*\)")
124 build = expr.findall(output)
126 build = build[0].split("gcc version ")[1]
127 build = build[build.find("(") + 1 : build.find(")")]
128 info["build"] = build
129 expr = re.compile("Configured with: .*")
130 configured = expr.findall(output)
131 if len(configured) == 1:
132 info["configured"] = configured[0].split("Configured with: ")[1]
133 expr = re.compile("Thread model: .*")
134 thread = expr.findall(output)
136 info["thread"] = thread[0].split("Thread model: ")[1]
139 def loadSourceTree(project):
140 fileList = [f for f in os.walk(project.info("SOURCES_PATH"))]
141 project.setInfo("FILE_LIST", fileList)
143 def findDefinitions(ftype, project):
144 L = project.info("FILE_LIST")
147 for filename in element[2]:
148 if fnmatch.fnmatch(filename, ftype):
149 definitions.append((filename, element[0]))
152 def loadCpuInfos(project):
154 for definition in findDefinitions(const.CPU_DEFINITION, project):
155 cpuInfos.append(getInfos(definition))
158 def getInfos(definition):
160 D.update(const.CPU_DEF)
161 def include(filename, dict = D, directory=definition[1]):
162 execfile(directory + "/" + filename, {}, D)
163 D["include"] = include
164 include(definition[0], D)
165 D["CPU_NAME"] = definition[0].split(".")[0]
166 D["DEFINITION_PATH"] = definition[1] + "/" + definition[0]
170 def loadModuleData(project):
173 configurationInfoDict = {}
174 for filename, path in findDefinitions("*.h", project):
175 commentList = newParser.getCommentList(open(path + "/" + filename, "r").read())
176 if len(commentList) > 0:
178 configurationInfo = {}
180 toBeParsed, moduleDict = newParser.loadModuleDefinition(commentList[0])
181 except newParser.ParseError, err:
182 print "error in file %s. line: %d - statement %s" % (path + "/" + filename, err.line_number, err.line)
186 for module, information in moduleDict.items():
187 if "configuration" in information.keys() and len(information["configuration"]):
188 configuration = moduleDict[module]["configuration"]
189 configurationInfo[configuration] = loadConfigurationInfos(project.info("SOURCES_PATH") + "/" + configuration)
190 moduleInfoDict.update(moduleDict)
191 configurationInfoDict.update(configurationInfo)
194 listDict = newParser.loadDefineLists(commentList[1:])
195 listInfoDict.update(listDict)
196 except newParser.ParseError, err:
197 print "error in file %s. line: %d - statement %s" % (path + "/" + filename, err.line_number, err.line)
201 for filename, path in findDefinitions("*_" + project.info("CPU_INFOS")["TOOLCHAIN"] + ".h", project):
202 commentList = newParser.getCommentList(open(path + "/" + filename, "r").read())
203 listInfoDict.update(newParser.loadDefineLists(commentList))
204 project.setInfo("MODULES", moduleInfoDict)
205 project.setInfo("LISTS", listInfoDict)
206 project.setInfo("CONFIGURATIONS", configurationInfoDict)
209 def loadModuleData_old(project):
211 Loads all the module data, like module definition, list definition, and module configurations
212 int the given BProject, using the SOURCES_PATH information from this as the base for find the
217 configurationsInfoDict = {}
218 for filename, path in findDefinitions("*.h", project):
219 moduleInfos, listInfos, configurationInfos= loadModuleInfos(path + "/" + filename)
220 moduleInfosDict.update(moduleInfos)
221 listInfosDict.update(listInfos)
222 for configuration in configurationInfos.keys():
223 configurationsInfoDict[configuration] = loadConfigurationInfos(project.info("SOURCES_PATH") + "/" + configuration)
224 print "*_" + project.info("CPU_INFOS")["TOOLCHAIN"] + ".h"
225 for filename, path in findDefinitions("*_" + project.info("CPU_INFOS")["TOOLCHAIN"] + ".h", project):
226 listInfosDict.update(loadDefineLists(path + "/" + filename))
227 project.setInfo("MODULES", moduleInfosDict)
228 project.setInfo("LISTS", listInfosDict)
229 project.setInfo("CONFIGURATIONS", configurationsInfoDict)
231 def getDefinitionBlocks(text):
233 Take a text and return a list of tuple (description, name-value).
236 block_tmp = re.findall(r"/\*{2}\s*([^*]*\*(?:[^/*][^*]*\*+)*)/\s*#define\s+((?:[^/]*?/?)+)\s*?(?:/{2,3}[^<].*?)?$", text, re.MULTILINE)
237 for comment, define in block_tmp:
238 block.append((" ".join(re.findall(r"^\s*\*?\s*(.*?)\s*?(?:/{2}.*?)?$", comment, re.MULTILINE)).strip(), define))
239 block += re.findall(r"/{3}\s*([^<].*?)\s*#define\s+((?:[^/]*?/?)+)\s*?(?:/{2,3}[^<].*?)?$", text, re.MULTILINE)
240 block += [(comment, define) for define, comment in re.findall(r"#define\s*(.*?)\s*/{3}<\s*(.+?)\s*?(?:/{2,3}[^<].*?)?$", text, re.MULTILINE)]
243 def formatParamNameValue(text):
245 Take the given string and return a tuple with the name of the parameter in the first position
246 and the value in the second.
248 block = re.findall("\s*([^\s]+)\s*(.+?)\s*$", text, re.MULTILINE)
251 def getDescriptionInformations(text):
253 Take the doxygen comment and strip the wizard informations, returning the tuple
254 (comment, wizard_informations)
256 index = text.find("$WIZARD")
258 exec(text[index + 1:])
259 informations = WIZARD
260 return text[:index].strip(), informations
262 return text.strip(), {}
264 def loadConfigurationInfos(path):
266 Return the module configurations found in the given file as a dict with the
267 parameter name as key and a dict containig the fields above as value:
268 "value": the value of the parameter
269 "description": the description of the parameter
270 "informations": a dict containig optional informations:
271 "type": "int" | "boolean" | "enum"
272 "min": the minimum value for integer parameters
273 "max": the maximum value for integer parameters
274 "long": boolean indicating if the num is a long
275 "value_list": the name of the enum for enum parameters
278 configurationInfos = {}
279 for comment, define in getDefinitionBlocks(open(path, "r").read()):
280 name, value = formatParamNameValue(define)
281 description, informations = getDescriptionInformations(comment)
282 configurationInfos[name] = {}
283 configurationInfos[name]["value"] = value
284 configurationInfos[name]["informations"] = informations
285 if ("type" in configurationInfos[name]["informations"].keys() and
286 configurationInfos[name]["informations"]["type"] == "int" and
287 configurationInfos[name]["value"].find("L") != -1):
288 configurationInfos[name]["informations"]["long"] = True
289 configurationInfos[name]["value"] = configurationInfos[name]["value"].replace("L", "")
290 if ("type" in configurationInfos[name]["informations"].keys() and
291 configurationInfos[name]["informations"]["type"] == "int" and
292 configurationInfos[name]["value"].find("U") != -1):
293 configurationInfos[name]["informations"]["unsigned"] = True
294 configurationInfos[name]["value"] = configurationInfos[name]["value"].replace("U", "")
295 configurationInfos[name]["description"] = description
296 return configurationInfos
298 raise DefineException.ConfigurationDefineException(path, name)
300 def loadDefineLists(path):
302 Return a dict with the name of the list as key and a list of string as value
305 string = open(path, "r").read()
306 commentList = re.findall(r"/\*{2}\s*([^*]*\*(?:[^/*][^*]*\*+)*)/", string)
307 commentList = [" ".join(re.findall(r"^\s*\*?\s*(.*?)\s*?(?:/{2}.*?)?$", comment, re.MULTILINE)).strip() for comment in commentList]
309 for comment in commentList:
310 index = comment.find("$WIZARD_LIST")
312 exec(comment[index + 1:])
313 listDict.update(WIZARD_LIST)
316 raise DefineException.EnumDefineException(path)
318 def loadModuleInfos(path):
320 Returns the module infos and the lists infos founded in the file located in the path,
321 and the configurations infos for the module defined in this file.
326 configurationsInfos = {}
327 string = open(path, "r").read()
328 commentList = re.findall(r"/\*{2}\s*([^*]*\*(?:[^/*][^*]*\*+)*)/", string)
329 commentList = [" ".join(re.findall(r"^\s*\*?\s*(.*?)\s*?(?:/{2}.*?)?$", comment, re.MULTILINE)).strip() for comment in commentList]
330 if len(commentList) > 0:
331 comment = commentList[0]
332 if comment.find("$WIZARD_MODULE") != -1:
333 index = comment.find("$WIZARD_MODULE")
335 # 14 is the length of "$WIZARD_MODULE"
336 if len(comment[index + 14:].strip()) > 0:
337 exec(comment[index + 1:])
338 moduleInfos[WIZARD_MODULE["name"]] = {"depends": WIZARD_MODULE["depends"],
339 "configuration": WIZARD_MODULE["configuration"],
342 index = comment.find("\\brief")
344 description = comment[index + 7:]
345 description = description[:description.find(" * ")]
346 moduleInfos[WIZARD_MODULE["name"]]["description"] = description
347 if "configuration" in WIZARD_MODULE.keys() and len(WIZARD_MODULE["configuration"]) > 0:
348 configurationsInfos[WIZARD_MODULE["configuration"]] = {}
349 listInfos.update(loadDefineLists(path))
350 return moduleInfos, listInfos, configurationsInfos
352 raise DefineException.ModuleDefineException(path)
354 def sub(string, parameter, value):
356 Substitute the given value at the given parameter define in the given string
358 return re.sub(r"(?P<define>#define\s+" + parameter + r"\s+)([^\s]+)", r"\g<define>" + value, string)
360 def isInt(informations):
362 Return True if the value is a simple int.
364 if ("long" not in informatios.keys() or not informations["long"]) and ("unsigned" not in informations.keys() or informations["unsigned"]):
369 def isLong(informations):
371 Return True if the value is a long.
373 if "long" in informations.keys() and informations["long"] and "unsigned" not in informations.keys():
378 def isUnsigned(informations):
380 Return True if the value is an unsigned.
382 if "unsigned" in informations.keys() and informations["unsigned"] and "long" not in informations.keys():
387 def isUnsignedLong(informations):
389 Return True if the value is an unsigned long.
391 if "unsigned" in informations.keys() and "long" in informations.keys() and informations["unsigned"] and informations["long"]: