def ExpandAllVariables(expression, workspace, projName, projConfName = '', fileName = ''): '''展开所有变量,所有变量引用的形式都会被替换 会展开脱字符(`)的表达式,但是,不展开 $(shell ) 形式的表达式 先展开内部的变量,再展开环境变量,最后展开 `` 的表达式 只作一次展开,不会递归展开 expression - 需要展开的表达式, 可为空 workspace - 工作区实例, 可为空 projName - 项目名字, 可为空 projConfName - 项目构建设置名称, 可为空 fileName - 文件名字, 要求为绝对路径, 可为空 RETURN - 展开后的表达式''' from EnvVarSettings import EnvVarSettingsST exp = expression # 先展开内置宏 exp = ExpandAllInterMacros(exp, workspace, projName, projConfName, fileName) # 再展开环境变量 exp = EnvVarSettingsST.Get().ExpandVariables(exp, trim=True) # 最后展开`` exp = ExpandBacktick(exp) # 最最后处理转义的 '$' return exp.replace('$$', '$')
def __GetDefaultBldCmd(self, projNames, wspConfName): '''projNames 可以是单个项目名称的字符串''' wspIns = VLWorkspaceST.Get() self.Exports(projNames, wspConfName) blderCmd = self.command blderCmd = EnvVarSettingsST.Get().ExpandVariables(blderCmd) wspMakefile = '%s_wsp.mk' % wspIns.GetName() return 'cd %s && %s %s' % (EscStr4MkSh( wspIns.dirName), blderCmd, EscStr4MkSh(wspMakefile))
def ExpandAllVariables_SList(exprList, workspace, projName, projConfName = '', fileName = ''): '''批量展开,经常用到''' from EnvVarSettings import EnvVarSettingsST # 先批量展开内部宏 exprList = ExpandAllInterMacros(exprList, workspace, projName, projConfName, fileName) result = [] for exp in exprList: # 再展开环境变量 exp = EnvVarSettingsST.Get().ExpandVariables(exp, trim=True) # 最后展开`` exp = ExpandBacktick(exp) # 最最后处理转义的 '$' result.append(exp.replace('$$', '$')) return result
def GenerateMakefile(self, projName, projConfName, force=False): '''此函数会跳过不必要的 Makefile 创建行为''' wspIns = VLWorkspaceST.Get() projInst = wspIns.FindProjectByName(projName) if not projInst or not projConfName: return False settings = projInst.GetSettings() projBldConfIns = wspIns.GetProjBuildConf(projName, projConfName) if not settings or not projBldConfIns: return False ds = Globals.DirSaver() os.chdir(projInst.dirName) absProjMakefile = os.path.join(projInst.dirName, projName + '.mk') # 如果已存在 makefile,且非强制,且项目文件没有修改,跳过 if not force and not projInst.IsModified() \ and os.path.exists(absProjMakefile): # 添加判断,比较项目文件与 makefile 的时间戳, # 只有 makefile 比项目文件新才跳过 mkModTime = Globals.GetMTime(absProjMakefile) if mkModTime > Globals.GetMTime(projInst.GetFileName()): return True # 无须重建,直接结束 # 自定义构建的处理是不一样的 isCustomBuild = projBldConfIns.IsCustomBuild() #isCustomBuild = True mkdir = 'gmkdir -p' if Globals.IsWindowsOS() else 'mkdir -p' # 重建流程 text = '' text += '##\n' text += '## Auto generated by Builder "%s" of VimLite\n' % self.name text += '## Do not edit this file, any manual changes will be erased\n' text += '##\n' # 输出环境变量 # 必须首先输出, 因为内部变量可能用到了环境变量 text += '\n' text += '##\n' text += '## User defined environment variables\n' text += '##\n' for envVar in EnvVarSettingsST.Get().GetActiveEnvVars(): #text += '%s := %s\n' % (envVar.GetKey(), envVar.GetValue()) text += '%s\n' % (envVar.GetString().replace('=', ':=', 1)) text += '\n' if isCustomBuild: # 自定义构建的处理 text += '## ===== Available Macros =====\n' text += self.CreateAvailableMacros(projInst, projBldConfIns) text += '\n' buildCmds = projBldConfIns.GetCustomBuildCmd() cleanCmds = projBldConfIns.GetCustomCleanCmd() workDir = projBldConfIns.GetCustomBuildWorkingDir() if not workDir: workDir = '.' cdCmd = 'cd $(WorkDir) && ' text += '''\ ## variables MKDIR := %s WorkDir := %s PHONY := all clean DirSanity Build Clean Rebuild ## builtin targets define BuildCommands %s endef define CleanCommands %s endef all: Build clean: Clean DirSanity: \t@$(MKDIR) $(WorkDir) Build: DirSanity \t$(BuildCommands) Clean: DirSanity \t$(CleanCommands) Rebuild: DirSanity \t$(CleanCommands) \t$(BuildCommands) ''' % (mkdir, EscStr4MkSh(workDir), cdCmd + buildCmds, cdCmd + cleanCmds) customTargets = projBldConfIns.GetCustomTargets() customTargetsText = '' for tgt, cmd in customTargets.iteritems(): customTargetsText += 'PHONY += %s\n' % tgt customTargetsText += '%s: DirSanity\n' % tgt customTargetsText += '\t%s\n' % (cdCmd + cmd, ) customTargetsText += '\n' text += customTargetsText text += '.PHONY: $(PHONY)' #### 自定义构建处理完毕 else: # 非自定义构建时的处理 text += self.CreateConfigsVariables(projInst, projBldConfIns) # 如此实现批量添加包含路径即可 text += '# auto\n' # 添加 CCXXFLAGS #text += 'CFLAGS += $(CCXXFLAGS)\n' #text += 'CXXFLAGS += $(CCXXFLAGS)\n' # CPPFLAGS 为 C 和 C++ 编译器共享 text += 'CPPFLAGS += $(foreach Dir,$(CmpIncPaths) $(IncPaths),$(IncPat))\n' # 预定义的宏 text += 'CPPFLAGS += $(foreach Mac,$(Macros),$(MacPat))\n' # 库文件搜索路径 text += 'LDFLAGS += $(foreach Lip,$(CmpLibPaths) $(LibPaths),$(LipPat))\n' # 链接的库 text += 'LDFLAGS += $(foreach Lib,$(Libraries),$(LibPat))\n' text += '\n' text += '# ###\n' # 源文件 text += 'SourceFile = $<\n' # 对象文件 text += 'ObjectFile = $(OutDir)/$(notdir $(basename $(SourceFile)))$(ObjExt)\n' # 输出的依赖文件 text += 'DependFile = $(OutDir)/$(notdir $(basename $(SourceFile)))$(DepExt)\n' # 输出的预处理文件 text += 'PrePrcFile = $(OutDir)/$(notdir $(basename $(SourceFile)))$(PrpExt)\n' text += '\n' t1, fileRules = self.CreateFileTargets(projInst, projBldConfIns) text += t1 preBldCmd = '' postBldCmd = '' preCmds = [ i for i in projBldConfIns.GetPreBuildCommands() if i.enabled ] if preCmds: preBldCmd += '\t@echo ===== Pre Build Commands Start... =====\n' preBldCmd += '\n'.join(['\t%s' % i.command for i in preCmds]) + '\n' preBldCmd += '\t@echo ===== Pre Build Commands Done. =====\n' postCmds = [ i for i in projBldConfIns.GetPostBuildCommands() if i.enabled ] if postCmds: postBldCmd += '\t@echo ===== Post Build Commands Start... =====\n' postBldCmd += '\n'.join(['\t%s' % i.command for i in postCmds]) + '\n' postBldCmd += '\t@echo ===== Post Build Commands Done. =====\n' text += 'MKDIR = %s\n' % (mkdir, ) # DirSanity -> PreBuild -> $(Objects) -> $(OutputFile) -> PostBuild # DirSanity 放到 all 的依赖列表的第一位,会跑得比较快,测试表明可用 # NOTE: 如果作为 PreBuild 的依赖,则可能 $(Objects): PreBuild 会导致 # 依赖查找,而先于 DirSanity 执行,最终会造成找不到 c 依赖文件而终止 # $(Objects): | PreBuild 的 PreBuild 仅为了顺序, # 不会影响 $(Objects) 的重建 text += '''\ PHONY = all clean PreBuild Building PostBuild DirSanity # ===== Targets ===== all: DirSanity PostBuild PostBuild: Building %s Building: $(OutputFile) $(OutputFile): $(Objects) ifeq ($(ProjectType),app) \t$(LinkCmd) endif ifeq ($(ProjectType),so) \t$(SoGenCmd) endif ifeq ($(ProjectType),ar) \t$(ArGenCmd) endif $(Objects): | PreBuild PreBuild: %s DirSanity: \t@$(MKDIR) $(OutDir) \t@$(MKDIR) $(dir $(OutputFile)) clean: \t$(RM) $(PrePrcs) \t$(RM) $(Depends) \t$(RM) $(Objects) \t$(RM) $(OutputFile) ''' % (postBldCmd, preBldCmd) text += fileRules # NOTE: include 的时候,如果文件不存在,会在本 Makefile 中查找以这个 # 文件名为目标的规则,如果这个规则需要一些中间目录的话,就会出错, # 因为这个查找是先于任何规则的,即使 Makefile 的第一个规则就是创建 # 中间目录也没有用 #text += '#-include $(Depends)\n' #text += '-include $(OutDir)/*$(DepExt)\n' # 用这句才行,真不懂 text += '''\ ifeq ($(shell test -d $(OutDir) && echo yes || echo no),yes) -include $(Depends) endif ''' text += '\n' text += '.PHONY: $(PHONY)\n' #### 内建构建处理完毕 #absProjMakefile = 'test.mk' # 写到文件 tmpf = Globals.TempFile() try: f = open(tmpf, "wb") f.write(text) f.close() shutil.move(tmpf, absProjMakefile) except: os.remove(tmpf) print '%s: save failed!' % absProjMakefile raise projInst.SetModified(False) #return text return True
def ExpandAllInterVariables(expression, workspace, projName, projConfName='', fileName='', trim=False): '''展开所有内部变量 expression - 需要展开的表达式, 可为空 workspace - 工作区实例, 可为空 projName - 项目名字, 可为空 projConfName - 项目构建设置名称, 可为空 fileName - 文件名字, 要求为绝对路径, 可为空 trim - 是否用空字符展开没有定义的变量引用 支持的变量有: $(User) $(Date) $(CodeLitePath) $(WorkspaceName) $(WorkspacePath) $(ProjectName) $(ProjectPath) $(ConfigurationName) $(IntermediateDirectory) - 这个变量可能嵌套 $(OutDir) - 这个变量可能嵌套 $(ProjectFiles) $(ProjectFilesAbs) $(CurrentFileName) $(CurrentFileExt) $(CurrentFilePath) $(CurrentFileFullPath) ''' from EnvVarSettings import EnvVarSettingsST if not '$' in expression: return expression dVariables = {} dVariables['User'] = getpass.getuser() dVariables['Date'] = time.strftime('%Y-%m-%d', time.localtime()) dVariables['CodeLitePath'] = os.path.expanduser('~/.codelite') if workspace: dVariables['WorkspaceName'] = workspace.GetName() dVariables['WorkspacePath'] = workspace.dirName project = workspace.FindProjectByName(projName) if project: dVariables['ProjectName'] = project.GetName() dVariables['ProjectPath'] = project.dirName bldConf = workspace.GetProjBuildConf(project.GetName(), projConfName) if bldConf: dVariables['ConfigurationName'] = bldConf.GetName() imd = bldConf.GetIntermediateDirectory() # 先展开中间目录的变量 # 中间目录不能包含自身和自身的别名 $(OutDir) # 可包含的变量为此之前添加的变量 imd = EnvVarSettingsST.Get().ExpandVariables(imd) imd = ExpandVariables(imd, dVariables) dVariables['IntermediateDirectory'] = imd dVariables['OutDir'] = imd # NOTE: 是必定包含忽略的文件的 if '$(ProjectFiles)' in expression: dVariables['ProjectFiles'] = \ ' '.join([ '"%s"' % i for i in project.GetAllFiles()]) if '$(ProjectFilesAbs)' in expression: dVariables['ProjectFilesAbs'] = \ ' '.join([ '"%s"' % i for i in project.GetAllFiles(True)]) if fileName: dVariables['CurrentFileName'] = \ os.path.splitext(os.path.basename(fileName))[0] dVariables['CurrentFileExt'] = \ os.path.splitext(os.path.basename(fileName))[1][1:] dVariables['CurrentFilePath'] = \ NormalizePath(os.path.dirname(fileName)) dVariables['CurrentFileFullPath'] = NormalizePath(fileName) if dVariables.has_key('OutDir'): # 这个变量由于由用户定义,所以可以嵌套变量 imd = dVariables['OutDir'] del dVariables['OutDir'] del dVariables['IntermediateDirectory'] imd = ExpandVariables(imd, dVariables, False) # 再展开环境变量 imd = EnvVarSettingsST.Get().ExpandVariables(imd, True) dVariables['OutDir'] = imd dVariables['IntermediateDirectory'] = dVariables['OutDir'] # 先这样展开,因为内部变量不允许覆盖,内部变量可以保证不嵌套变量 expression = ExpandVariables(expression, dVariables, False) # 再展开环境变量, 因为内部变量不可能包含环境变量 expression = EnvVarSettingsST.Get().ExpandVariables(expression, trim) return expression