#!/usr/bin/env python # -*- coding:utf-8 -*- '''gnu make 里面统一用 / 来分割路径''' import sys import os import os.path import time import getpass import shutil import Globals import Macros import Compiler from Builder import Builder from VLWorkspace import VLWorkspaceST from BuildSettings import BuildSettingsST from Project import Project from EnvVarSettings import EnvVar from EnvVarSettings import EnvVarSettings from EnvVarSettings import EnvVarSettingsST BUILDER_NAME = 'GNU makefile for g++/gcc' from Globals import EscapeString, EscStr4MkSh, PosixPath, SplitSmclStr EscStr = EscapeString # DEPRECATED def __SplitStrBySemicolon(string): '''把 ';' 作为分隔符字符串分割,支持 '\\' 转义''' charli = [] result = [] esc = False for c in string: if c == '\\': esc = True continue if c == ';' and not esc: if charli: result.append(''.join(charli)) del charli[:] continue charli.append(c) esc = False if charli: result.append(''.join(charli)) del charli[:] return result # 用 Globals.SplitSmclStr() 代替了 def SplitStrBySemicolon(string): '''把 ';' 作为分隔符字符串分割,如果想输入 ';'本身,用加倍之即可 ";;"''' charli = [] result = [] l = len(string) idx = 0 while idx < l: c = string[idx] if c == ';': # 向前查看一个字符,如果仍然是 ';',当单个 ';',否则就分割 if idx+1 >= l: nextChar = '' else: nextChar = string[idx+1] if nextChar == ';': idx += 1 # 跳过当前 charli.append(nextChar) else: # 一次分割 if charli: result.append(''.join(charli)) del charli[:] else: charli.append(c) idx += 1 if charli: result.append(''.join(charli)) del charli[:] return result def SmclStr2MkStr(string): '''分号分割的字符串安全转为 Makefile 的字符串 NOTE: 分号分割的字符串是作为原始的命令行参数传过去的,无须作特殊的转义''' li = SplitSmclStr(string) return " ".join(li) def IsCxxSource(fileName): #ext = os.path.splitext(fileName)[1][1:] #return ext in set(['cpp', 'cxx', 'c++', 'cc']) return Globals.IsCppSourceFile(fileName) def IsCSource(fileName): #ext = os.path.splitext(fileName)[1][1:] #return ext in set(['c']) return Globals.IsCSourceFile(fileName) class BuilderGnuMake(Builder): '''GNU make''' '''需要先处理的字符串包括: 路径名,文件名,其他自动生成的可能用在命令行上的字符串。 这样会存在一个问题,例如 s := a b 会被改为 s := "a b",但这样在字符串比较是 ifeq $(s,a b) 会失败, 这个情况无法解决,根本原因是 GNU make 和 shell 处理的不一致造成的, 一般只要确保需要比较的字符串是常规字符串即可,其他就直接引用好了 使用 GNU make 的内置函数的话,是没法处理文件带空白的情况的。所以无法支持 带空白的源文件名。''' def __init__(self, d = {}): Builder.__init__(self, d) #self.name = BUILDER_NAME def Export(self, projName, wspConfName = '', force = False): return self.Exports(projName, wspConfName, force) def Exports(self, projNames, wspConfName = "", force = False): '''导出 Makefile 的接口,这个不算通用接口吧?! 若 wspConfName 为空,即表示用当前选择的工作区设置''' if not projNames: return False if isinstance(projNames, str): projNames = [projNames] # 忽略不存在的项目 removeList = [] for projName in projNames: projInst = VLWorkspaceST.Get().FindProjectByName(projName) if not projInst: removeList.append(projName) print "%s not found" % projName continue matrix = VLWorkspaceST.Get().GetBuildMatrix() if not wspConfName: wspConfName = matrix.GetSelectedConfigurationName() else: force = True # 不使用默认设置,就肯定要强制 # 工作区的 Makefile wspMakefile = VLWorkspaceST.Get().GetName() + '_wsp.mk' # 转为绝对路径 wspMakefile = os.path.join(VLWorkspaceST.Get().dirName, wspMakefile) text = '' text += 'PHONY := all clean\n\n' allTgtText = 'all:\n' cleanTgtText = 'clean:\n' customTgtText = '' for idx, projName in enumerate(projNames): # 项目设置名称 projInst = VLWorkspaceST.Get().FindProjectByName(projName) if not projInst: continue projConfName = matrix.GetProjectSelectedConf(wspConfName, projName) # 项目设置实例 projBldConfIns = VLWorkspaceST.Get().GetProjBuildConf( projName, projConfName) projMakefile = projName + ".mk" cddir = os.path.relpath(projInst.dirName, VLWorkspaceST.Get().dirName) envCmd = '' # FIXME: 找到办法把这个命令放到项目的 Makefile 前暂时这么做 cmplName = projBldConfIns.GetCompilerType() cmpl = BuildSettingsST.Get().GetCompilerByName(cmplName) if cmpl and cmpl.envSetupCmd: envCmd = '%s && ' % cmpl.envSetupCmd # all 目标的命令部分 allTgtText += \ '\t@echo "----------Building Project:[ %s - %s ]----------"\n'\ % (projName, projConfName) allTgtText += '\t@%scd %s && $(MAKE) -f %s $@\n' \ % (envCmd, EscStr4MkSh(cddir), EscStr4MkSh(projMakefile)) # clean 目标的命令部分 cleanTgtText += \ '\t@echo "----------Cleaning Project:[ %s - %s ]----------"\n'\ % (projName, projConfName) cleanTgtText += '\t@cd %s && $(MAKE) -f %s $@\n' \ % (EscStr4MkSh(cddir), EscStr4MkSh(projMakefile)) # 第一个项目的时候,需要添加 Custom Build 目标,如果必要的话 # 因为 Batch Build 是不支持特殊的 Custom Build 目标的 if idx == 0 and projBldConfIns.IsCustomBuild(): for k, v in projBldConfIns.GetCustomTargets().iteritems(): customTgtText += 'PHONY += %s\n' % k customTgtText += '%s:\n' % k customTgtText += '\t@cd %s && $(MAKE) -f %s $@\n' \ % (EscStr4MkSh(cddir), EscStr4MkSh(projMakefile)) # 生成项目自身的 Makefile self.GenerateMakefile(projName, projConfName, force) text += allTgtText + "\n" + cleanTgtText + "\n" + customTgtText text += '\n' text += '.PHONY: $(PHONY)\n' tmpf = Globals.TempFile() try: f = open(tmpf, "wb") f.write(text) f.close() shutil.move(tmpf, wspMakefile) except: os.remove(tmpf) raise #return text return True def GetPrepFileCmd(self, projName, fileName, wspConfName = ''): '''create a command to execute for preprocessing single source file''' '''fileName 应该是相对路径''' return self.__GetPrpOrObjCmd(projName, fileName, wspConfName, 'prp') def GetCmplFileCmd(self, projName, fileName, wspConfName = ''): '''create a command to execute for compiling single source file''' return self.__GetPrpOrObjCmd(projName, fileName, wspConfName, 'obj') def GetBuildCommand(self, projName, wspConfName = ''): return self.__GetDefaultBldCmd(projName, wspConfName) + ' all' def GetCleanCommand(self, projName, wspConfName = ''): return self.__GetDefaultBldCmd(projName, wspConfName) + ' clean' def GetBatchBuildCommand(self, projNames, wspConfName = ''): '''获取批量构建的命令''' if not projNames: return '' return self.__GetDefaultBldCmd(projNames, wspConfName) + ' all' def GetBatchCleanCommand(self, projNames, wspConfName = ''): '''获取批量清理的命令''' if not projNames: return '' return self.__GetDefaultBldCmd(projNames, wspConfName) + ' clean' 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 __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 __GetPrpOrObjCmd(self, projName, fileName, wspConfName = '', t = 'prp'): wspIns = VLWorkspaceST.Get() wspConfName = wspConfName \ or wspIns.GetBuildMatrix().GetSelectedConfigurationName() self.Exports(projName, wspConfName) projInst = wspIns.FindProjectByName(projName) projBldConfIns = self.GetProjectBuildConfig(projName, wspConfName) cmplName = projBldConfIns.GetCompilerType() cmpl = BuildSettingsST.Get().GetCompilerByName(cmplName) if projBldConfIns.IsCustomBuild(): return '' if not cmpl: # 编译器实例总会可能是空的 return 'echo "%s is not a valid complier!"' ds = Globals.DirSaver() os.chdir(projInst.dirName) if os.path.isabs(fileName): fileName = os.path.relpath(fileName) mkFile = '%s.mk' % projName bwd = projBldConfIns.GetIntermediateDirectory() or '.' # 展开所有 VimLite 内置变量 bwd = Globals.ExpandAllInterVariables(bwd, wspIns, projName, wspConfName) if t == 'prp': # 预处理目标 fn = os.path.splitext(fileName)[0] + cmpl.prpExt else: # 对象目标,用于编译文件 fn = os.path.splitext(fileName)[0] + cmpl.objExt tgt = '%s/%s' % (bwd, fn) cmd = 'cd %s && make -f %s %s ' % (EscStr4MkSh(projInst.dirName), EscStr4MkSh(mkFile), EscStr4MkSh(tgt)) return cmd def GetProjectBuildConfig(self, projName, wspConfName = ''): matrix = VLWorkspaceST.Get().GetBuildMatrix() if not wspConfName: wspConfName = matrix.GetSelectedConfigurationName() projConfName = matrix.GetProjectSelectedConf(wspConfName, projName) projInst = VLWorkspaceST.Get().FindProjectByName(projName) projBldConfIns = VLWorkspaceST.Get().GetProjBuildConf(projName, projConfName) return projBldConfIns def CreateFileTargets(self, projInst, projBldConfIns): '''返回 (文件列表变量定义文本, 编译文件的规则命令文本)''' text = '# ===== Sources and Objects and Depends and PrePrcs =====\n' text += 'Sources := \\\n' relFiles = projInst.GetAllFiles(False, projBldConfIns.GetName()) for idx, relFile in enumerate(relFiles): if not IsCxxSource(relFile) and not IsCSource(relFile): continue text += ' %s \\\n' % relFile text += '\n\n' rulesText = '' text += 'Objects := \\\n' for idx, relFile in enumerate(relFiles): isCxx = False isC = False if IsCxxSource(relFile): isCxx = True elif IsCSource(relFile): isC = True else: continue fn = os.path.splitext(os.path.basename(relFile))[0] text += ' $(OutDir)/%s$(ObjExt) \\\n' % fn # 预处理规则 rulesText += '$(OutDir)/%s$(PrpExt): %s\n' % (fn, relFile) if isC: rulesText += '\t$(CPrpCmd)\n' else: rulesText += '\t$(CxxPrpCmd)\n' rulesText += '\n' # 对象文件规则 rulesText += '$(OutDir)/%s$(ObjExt): %s $(OutDir)/%s$(DepExt)\n' \ % (fn, relFile, fn) if isC: rulesText += '\t$(CCmpCmd)\n' else: rulesText += '\t$(CxxCmpCmd)\n' rulesText += '\n' # 依赖文件规则 rulesText += '$(OutDir)/%s$(DepExt): %s\n' % (fn, relFile) if isC: rulesText += '\t@$(CDepGenCmd)\n' else: rulesText += '\t@$(CxxDepGenCmd)\n' rulesText += '\n' text += '\n\n' # 这两个列表就不需要写出来了 text += 'Depends := $(foreach Src,$(Sources),$(OutDir)/$(notdir $(basename $(Src)))$(DepExt))\n' text += 'PrePrcs := $(foreach Src,$(Sources),$(OutDir)/$(notdir $(basename $(Src)))$(PrpExt))\n' text += '\n' return text, rulesText def CreateAvailableMacros(self, projInst, projBldConfIns): '''内部定义的宏(变量),导出为 gnu make 的形式''' ws = VLWorkspaceST.Get() text = '' text += 'WorkspaceName := %s\n' \ % EscStr4MkSh(ws.GetName()) # 因为可能用在命令行中,所以需要转义 text += 'WorkspacePath := $(CURDIR)/%s\n' \ % EscStr4MkSh(os.path.relpath(ws.dirName, projInst.dirName)) text += 'ProjectName := %s\n' \ % EscStr4MkSh(projInst.GetName()) text += 'ProjectPath := $(CURDIR)\n' text += 'ConfigurationName := %s\n' \ % EscStr4MkSh(projBldConfIns.GetName()) text += 'IntermediateDirectory := %s\n' \ % EscStr4MkSh(projBldConfIns.GetOutDir()) or '.' text += 'OutDir := %s\n' % '$(IntermediateDirectory)' text += 'User := %s\n' \ % EscStr4MkSh(getpass.getuser()) text += 'Date := %s\n' \ % time.strftime('%Y-%m-%d', time.localtime()) return text def CreateConfigsVariables(self, projInst, projBldConfIns): cmplName = projBldConfIns.GetCompilerType() cmpl = BuildSettingsST.Get().GetCompilerByName(cmplName) if not cmpl: return "" text = '# ===== Compiler Variables =====\n' if cmpl.PATH: text += 'export PATH := %s:$(PATH)\n' % cmpl.PATH text += '\n' text += 'CCmpCmd = %s\n' % cmpl.cCmpCmd text += 'CxxCmpCmd = %s\n' % cmpl.cxxCmpCmd text += 'CPrpCmd = %s\n' % cmpl.cPrpCmd text += 'CxxPrpCmd = %s\n' % cmpl.cxxPrpCmd text += 'CDepGenCmd = %s\n' % cmpl.cDepGenCmd text += 'CxxDepGenCmd = %s\n' % cmpl.cxxDepGenCmd text += 'LinkCmd = %s\n' % cmpl.linkCmd text += 'ArGenCmd = %s\n' % cmpl.arGenCmd text += 'SoGenCmd = %s\n' % cmpl.soGenCmd text += '\n' text += 'ObjExt := %s\n' % cmpl.objExt text += 'DepExt := %s\n' % cmpl.depExt text += 'PrpExt := %s\n' % cmpl.prpExt text += '\n' text += 'CmpIncPaths := %s\n' % SmclStr2MkStr(cmpl.includePaths) text += 'CmpLibPaths := %s\n' % SmclStr2MkStr(cmpl.libraryPaths) text += '\n' text += 'IncPat = %s\n' % cmpl.incPat text += 'MacPat = %s\n' % cmpl.macPat text += 'LipPat = %s\n' % cmpl.lipPat text += 'LibPat = %s\n' % cmpl.libPat text += '\n' # 项目特定的变量 cmplOpts = projBldConfIns.GetCCompileOptions() cxxCmplOpts = projBldConfIns.GetCompileOptions() cCxxCmplOpts = projBldConfIns.GetCCxxCompileOptions() linkOpts = projBldConfIns.GetLinkOptions() incPaths = projBldConfIns.GetIncludePath() libPaths = projBldConfIns.GetLibPath() libraries = projBldConfIns.GetLibraries() macros = projBldConfIns.GetPreprocessor() projType = 'app' if projBldConfIns.GetProjectType() == Project.DYNAMIC_LIBRARY: projType = 'so' elif projBldConfIns.GetProjectType() == Project.STATIC_LIBRARY: projType = 'ar' text += '## ===== Project Variables =====\n' text += self.CreateAvailableMacros(projInst, projBldConfIns) text += 'OutputFile := %s\n' \ % EscStr4MkSh(projBldConfIns.GetOutputFileName()) or 'null' # 下面几个变量是由用户输入的,不是自动生成的,转义责任交给用户 text += 'CPPFLAGS := %s\n' % '' text += 'CCXXFLAGS := %s\n' % SmclStr2MkStr(cCxxCmplOpts) text += 'CFLAGS := $(CCXXFLAGS)\n' text += 'CFLAGS += %s\n' % SmclStr2MkStr(cmplOpts) text += 'CXXFLAGS := $(CCXXFLAGS)\n' text += 'CXXFLAGS += %s\n' % SmclStr2MkStr(cxxCmplOpts) text += 'IncPaths := %s\n' % SmclStr2MkStr(incPaths) text += 'Macros := %s\n' % SmclStr2MkStr(macros) text += 'LDFLAGS := %s\n' % SmclStr2MkStr(linkOpts) text += 'LibPaths := %s\n' % SmclStr2MkStr(libPaths) text += 'Libraries := %s\n' % SmclStr2MkStr(libraries) text += 'ProjectType := %s\n' % projType text += '\n' return text # ============================================================================ def test(): assert SplitStrBySemicolon('abc;def') == ['abc', 'def'] assert SplitStrBySemicolon(';abc;def') == ['abc', 'def'] assert SplitStrBySemicolon('abc;def;') == ['abc', 'def'] assert SplitStrBySemicolon('abc;;d;ef;') == ['abc;d', 'ef'] from BuilderManager import BuilderManagerST import json assert SplitStrBySemicolon("snke;;;snekg;") == ['snke;', 'snekg'] print SmclStr2MkStr("s n'\"\"'ke;;;snekg;") ins = VLWorkspaceST.Get() ins.OpenWorkspace("CxxParser/CxxParser.vlworkspace") print ins.projects return bm = BuilderManagerST.Get() #blder = BuilderGnuMake( #BuildSettingsST.Get().GetBuilderByName( #"GNU makefile for g++/gcc").ToDict()) blder = bm.GetActiveBuilderInstance() bs = BuildSettingsST.Get() #print bs.ToDict() #print bs.GetCompilerByName('gnu g++') print blder.Exports(['CxxParser']) #print blder.GenerateMakefile('CxxParser', 'mindll') #print '=' * 78 #print blder.GenerateMakefile('CxxParser', 'Debug') print blder.GetPrepFileCmd('CxxParser', 'main.cpp', 'Debug') print blder.GetCmplFileCmd('CxxParser', 'main.cpp', 'Debug') print blder.GetBuildCommand('CxxParser') print blder.GetCleanCommand('CxxParser') print blder.GetBatchBuildCommand(['CxxParser']) print blder.GetBatchCleanCommand(['CxxParser']) print json.dumps(blder.ToDict()) if __name__ == "__main__": test()