Source code for gdeps.codeblocks

#!python3

# Copyright 2007-2017 Gemr. All Rights Reserved.
# Licensed to MIT see LICENSE.txt

import os
import shutil
import warnings

import gdeps as GDeps
# MONKEYPatching : http://www.kaarsemaker.net/blog/2013/10/10/cdata-support-in-elementtree/
# https://github.com/seveas/python-hpilo.git
import xml.etree.ElementTree as etree

__author__ = 'Suryavarman (http://sourceforge.net/u/suryavarman/profile/)'

if hasattr(etree, '_serialize_xml'):
    etree._original_serialize_xml = etree._serialize_xml

    def _serialize_xml(write, elem, *args, **kwargs):

        if elem.tag == 'str':
            write("<%s>\n					<![CDATA[%s]]>\n				</%s>\n			" % (elem.tag, elem.text.strip(), elem.tag))
            return

        if elem.tag == 's':
            write("<%s>\n						<![CDATA[%s]]>\n					</%s>\n			" % (elem.tag, elem.text.strip(), elem.tag))
            return

        return etree._original_serialize_xml(write, elem, *args, **kwargs)

    etree._serialize_xml = etree._serialize['xml'] = _serialize_xml
else:
    raise RuntimeError("Don't know how to monkeypatch XML serializer workarounds. Please report a bug at https://github.com/seveas/python-hpilo")


# https://wiki.python.org/moin/EscapingXml

[docs]class CodeBlocks(GDeps.Ide): """ Code::Blocks is a free C, C++ and Fortran IDE built to meet the most demanding needs of its users. It is designed to be very extensible and fully configurable. Config KEY username : default value "" Trouble shooting : If you have : cl Command line warning D9024 : unrecognized source file type the error come from CB : Sometime CB generate a good command line with a good include directory : [...] /IX:\GDeps\trunk\GDeps\gdeps\test\test_codeblocks-solution\dir0 [...] sometime no : cl.exe /nologo X:\GDeps\trunk\GDeps\gdeps\test\test_codeblocks-solution\dir0 The reason you project options, you have to define your include in the directory section and not in the option section. Good : Test_Project-0error0warning.cbp <Compiler> <Add directory="$(#test_CB_dir)" /> </Compiler> Bad: Test_Project-1error.cbp <Compiler> <Add option="$(#test_CB_dir)" /> </Compile """ ms_KeyAppdataCBDir = "appdatacbdir" r""" The key config file is "appdatacbdir" Example : appdatacbdir = C:\\Users\\Gandi\\AppData\\Roaming\\codeblocks @remarks your are not oblige to define this key but if you use a daemon the default user will be the system and not the current session user. The result of this is Codeblocks cannot find the default.conf. In this case you have to define the default.conf directory. @remarks For each build we use a copy of this one in a temporary directory """ ms_ConfFileName = '\\\\default.conf' """ Default CodeBlocks config filename. """ def __init__(self, inConfigFile, inSectionName, inCompilers, inCompilersAlias=[]): GDeps.Ide.__init__(self, inConfigFile, inSectionName, CodeBlocks.getTypeName(), inCompilers, inCompilersAlias) self.m_ErrorRegexp = r"(.*: error:.*|.*failed.*)" self.m_WarningRegexp = r".*: warning:.*" self.m_AddIncludes = []
[docs] def build(self, inProjectPath, inProjectName, inCompiler, inTargetName="all", inLogFilePath="Output_Buid_CodeBlocks.log", inWildCard="cbp", inRebuildAll=True, inIdeParams={}, inCompilerArgs={}): """ Build the project or the solution file from the current dir. Keywords arguments : :param inProjectPath: the project path :param inProjectName: the project or the solution name :param inCompiler: allow the ide to know witch compiler it has to call, like to define the address model :param inTargetName: with codeblocks always "all" :param inLogFilePath: define the output file log :param inWildCard: project wildcard == cbp solution wildcard = workspace :param inRebuildAll: by default we rebuild all. This is a chronophage but cleaner. default( True ) :param inIdeParams: To define GCV (Global compiler variable) use this syntax : inPrams[#MY_GCV] = "C:\PATH\MY\GCV" :param inCompilerArgs: Send the associate compilers arguments. :type inCompilerArgs: dict { str : array of str } >>> {['CXXFLAGS'] : ['-g -std=c++11 -Wall -pedantic']} or it can be like that >>> {['CXXFLAGS'] : ['-g', '-std=c++11', '-Wall', '-pedantic']} Actually the the key doesn't matter. All it's a compiler option. :todo: USe the compiler option flags 'CFLAGS' and 'CXXFLAGS' """ self.beginGCV(inIdeParams) self.parse_ide_option_args(inIdeParams) self.parse_ide_option_args(inCompilerArgs) try: """ @link http://wiki.codeblocks.org/index.php?title=Code::Blocks_command_line_arguments """ # the compiler generate the log file self.m_ErrorRegexp = inCompiler.m_ErrorRegexp self.m_WarningRegexp = inCompiler.m_WarningRegexp self.m_SplitRegexp = inCompiler.m_SplitRegexp aBuildType = " --rebuild " if inRebuildAll else " --build " aAppDataCBDir = " --user-data-dir=" + '"' + self.getTemporaryCBConfigDir() + '"' # aProjectFullFileName = ".\\" + inProjectName + "." + inWildCard aProjectFullFileName = os.path.normpath(inProjectPath + "\\" + inProjectName + "." + inWildCard) assert os.path.exists(aProjectFullFileName), " The project file doesn't exist : " + aProjectFullFileName # see --script=<str> specify a script file to run after loading # www.squirrel-lang.org # http://wiki.codeblocks.org/index.php/Scripting_Code::Blocks # http://wiki.codeblocks.org/index.php/Variable_expansion # http://wiki.codeblocks.org/index.php/Scripting_commands#ProjectFile # http: // wiki.codeblocks.org / index.php / Startup_script # Example # Should we check the compiler ? # local CompilerId = base.GetCompilerID(); # if (CompilerId.Matches(_T("gcc"))) # SetActiveBuildTarget # http://wiki.codeblocks.org/index.php/Build_scripts # http://forums.codeblocks.org/index.php?topic=16475.0 # aProject.GetBuildTarget().AddCompilerOption() # aProject.GetBuildTarget().AddIncludeDir('C:\Program Files (x86)\Microsoft DirectX SDK (November 2008)\Include') # aProject.GetBuildTarget().AddResourceIncludeDir() # aProject.GetBuildTarget().AddLibDir() # aProject.GetBuildTarget().AddCommandsBeforeBuild() # aProject.GetBuildTarget().AddCommandsAfterBuild() aStartupScriptStr = ('Log(_T("Running startup script"));\n' ' local aProject = GetProjectManager().GetActiveProject();\n' ' if (!IsNull(aProject))\n' ' {\n' ' aProject.SetActiveBuildTarget(_T("' + inTargetName + '"));\n' ' }\n' ' function SetBuildOptions(base)\n' ' {' ' if (PLATFORM == PLATFORM_MSW)\n' ' {\n') for include in self.m_AddIncludes: aStartupScriptStr += ' aProject.GetBuildTarget().AddIncludeDir("' + include + '")' if inCompilerArgs: # to avoid AttributeError: 'NoneType' object has no attribute 'items' for aKey, aValue in inCompilerArgs.items(): for aOption in aValue: aStartupScriptStr += 'base.AddCompilerOption(_T("' + aOption + '"));\n' # example -Wno-attributes aStartupScriptStr += (' }\n' ' } // end of SetBuildOptions\n') aStartupScriptFileName = inProjectPath + "\\" + inCompiler.m_TypeName + '_' + inTargetName + '.script' with open(aStartupScriptFileName, 'w') as aScripFile: aScripFile.write(aStartupScriptStr) aScriptCmd = ' --script="' + aStartupScriptFileName + '"' GDeps.call('"' + self.m_Dir + "\\codeblocks.exe" + '"' + aBuildType + '"' + aProjectFullFileName + '"' + " --target=" + '"' + inTargetName + '"' + aAppDataCBDir + aScriptCmd + " --debug-log --no-check-associations --no-splash-screen > " + '"' + inLogFilePath + '"', False) except IOError: self.endGCV() print('cannot build', inProjectName) else: self.endGCV()
[docs] def read(self, inSection): GDeps.Ide.read(self, inSection) self.m_CBConfigDir = os.environ['APPDATA'] + '\\codeblocks' if not os.path.isdir(self.m_CBConfigDir): self.m_CBConfigDir = os.environ['APPDATA'] + '\\CodeBlocks' r""" The Codeblocks configuration file directory where's is the default.conf. By default is is the current App data dir Example : C:\\Users\\UserName\\AppData\\Roaming\\codeblocks or C:\\Users\\UserName\\AppData\\Roaming\\CodeBlocks The key config file is GDeps.CodeBlocks.ms_KeyAppdataCBDir """ if CodeBlocks.ms_KeyAppdataCBDir in inSection: self.m_CBConfigDir = inSection[CodeBlocks.ms_KeyAppdataCBDir] aDefaultConfPath = os.path.normpath(self.m_CBConfigDir + GDeps.CodeBlocks.ms_ConfFileName) if not os.path.isfile(aDefaultConfPath): warnings.warn("The appdata environment variable doesn't match with an existing folder. We have to use the " "gdeps «codeblocks_default.conf»", ResourceWarning) self.m_CBConfigDir = os.path.normpath(os.path.dirname(os.path.abspath(__file__))) aDefaultConfFilePath = os.path.normpath(self.m_CBConfigDir + r'\\codeblocks_default.conf') aDefaultConfPath = os.path.normpath(self.m_CBConfigDir + GDeps.CodeBlocks.ms_ConfFileName) if os.path.isfile(aDefaultConfFilePath): """ We create a copy of codeblocks_default.conf with the name default.conf into the gdeps library directory. :todo: Use a temporary directory """ shutil.copy(aDefaultConfFilePath, aDefaultConfPath) else: assert os.path.exists(aDefaultConfPath, 'We cannot find the the CodeBlocks sample default.conf : ' + aDefaultConfPath)
[docs] def write(self): aSection = GDeps.Ide.write(self) aSection[CodeBlocks.ms_KeyAppdataCBDir] = self.m_CBConfigDir return aSection
@staticmethod
[docs] def getTypeName(): return "CodeBlocks"
@staticmethod
[docs] def getTemporaryCBConfigDir(): """ return a directory ( the current dir for the build ) to: - copy the self.m_CBConfigDir - modify this one - build with this Config file """ return os.getcwd()
[docs] def beginGCV(self, inParams): """ @link https://www.microsoft.com/security/portal/mmpc/shared/variables.aspx """ self.m_XmlTmpPath = self.getTemporaryCBConfigDir() + GDeps.CodeBlocks.ms_ConfFileName if os.path.exists(self.m_CBConfigDir): self.m_XmlPath = self.m_CBConfigDir + GDeps.CodeBlocks.ms_ConfFileName shutil.copy2(self.m_XmlPath, self.m_XmlTmpPath) else: assert False, 'We cannot find the AppData\\Roaming\\codeblocks folder.' pass if os.path.exists(self.m_XmlTmpPath): # http://lxml.de/2.1/api.html # set the global variables # aXMLParser = etree.XMLParser(strip_cdata=False) aTree = etree.parse(self.m_XmlTmpPath) aRoot = aTree.getroot() # for child in aRoot.iterfind('.//str'): # print('tag : ' + child.tag) # print('attrib : ' + str(child.attrib)) # print('tail : ' + str(child.tail)) # print('text : ' + child.text) # print('child : ' + str(child)) # https://docs.python.org/3/library/xml.etree.elementtree.html # access to : CodeBlocksConfig / gcv / sets / default / wx / BASE / str = <![CDATA[D:\Working\GDeps\trunk\GDeps\gdeps\test\codeblocks\wxMSW-2.8.12]]> # http://www.kaarsemaker.net/blog/2013/10/10/cdata-support-in-elementtree/ # http://www.crummy.com/software/BeautifulSoup/bs4/doc/ print(inParams) for aKey, aValue in inParams.items(): if "#" in aKey: # print(aKey) aGCV = aKey[1:] aGCV = aGCV.lower() # print(aGCV) # print( aRoot.findall( './/gcv/sets/default/' + aGCV ) ) # aCDATAValue = '<![CDATA[' + aValue + ']]>' aTreeKeyGCV = './/gcv/sets/default/' + aGCV aKeyGCVs = aRoot.findall(aTreeKeyGCV) if not aKeyGCVs: # create the GCV child # print('not find') for aDefault in aRoot.iterfind('.//gcv/sets/default'): aKeyNode = etree.SubElement(aDefault, aGCV) aBase = etree.SubElement(aKeyNode, 'BASE') aStr = etree.SubElement(aBase, 'str') aStr.text = aValue # print('Add ' + aStr.text) else: for aIt in aRoot.findall(aTreeKeyGCV + '/BASE/str'): # print(aIt) # print(aIt.text) aIt.text = aValue aTestFindGCV = False for aIt in aRoot.findall(aTreeKeyGCV + '/BASE/str'): if not aTestFindGCV: aTestFindGCV = aIt.text == aValue assert aTestFindGCV, 'The ' + aGCV + ' adding/setting in the conf file has failed.' # https://github.com/behave/behave/issues/201 aTree.write(self.m_XmlTmpPath) else: assert False, "The file " + self.m_XmlTmpPath + " doesn't exist!"
[docs] def endGCV(self): shutil.copy2(self.m_XmlTmpPath, self.m_XmlTmpPath + '.log') os.remove(self.m_XmlTmpPath)
[docs] def parse_ide_option_args(self, parameters): for key, param in parameters.items(): if GDeps.Keys.ms_IdeAddInclude == key: self.m_AddIncludes.append(param)