waf

FORK: waf with some random patches
git clone https://git.neptards.moe/neptards/waf.git
Log | Files | Refs | README

codelite.py (33888B)


      1 #! /usr/bin/env python
      2 # encoding: utf-8
      3 # CodeLite Project
      4 # Christian Klein (chrikle@berlios.de)
      5 # Created: Jan 2012
      6 # As templete for this file I used the msvs.py
      7 # I hope this template will work proper
      8 
      9 """
     10 Redistribution and use in source and binary forms, with or without
     11 modification, are permitted provided that the following conditions
     12 are met:
     13 
     14 1. Redistributions of source code must retain the above copyright
     15    notice, this list of conditions and the following disclaimer.
     16 
     17 2. Redistributions in binary form must reproduce the above copyright
     18    notice, this list of conditions and the following disclaimer in the
     19    documentation and/or other materials provided with the distribution.
     20 
     21 3. The name of the author may not be used to endorse or promote products
     22    derived from this software without specific prior written permission.
     23 
     24 THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
     25 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     27 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     28 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     30 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     32 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     33 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     34 POSSIBILITY OF SUCH DAMAGE.
     35 """
     36 
     37 """
     38  
     39 
     40 To add this tool to your project:
     41 def options(conf):
     42         opt.load('codelite')
     43 
     44 It can be a good idea to add the sync_exec tool too.
     45 
     46 To generate solution files:
     47 $ waf configure codelite
     48 
     49 To customize the outputs, provide subclasses in your wscript files:
     50 
     51 from waflib.extras import codelite
     52 class vsnode_target(codelite.vsnode_target):
     53         def get_build_command(self, props):
     54                 # likely to be required
     55                 return "waf.bat build"
     56         def collect_source(self):
     57                 # likely to be required
     58                 ...
     59 class codelite_bar(codelite.codelite_generator):
     60         def init(self):
     61                 codelite.codelite_generator.init(self)
     62                 self.vsnode_target = vsnode_target
     63 
     64 The codelite class re-uses the same build() function for reading the targets (task generators),
     65 you may therefore specify codelite settings on the context object:
     66 
     67 def build(bld):
     68         bld.codelite_solution_name = 'foo.workspace'
     69         bld.waf_command = 'waf.bat'
     70         bld.projects_dir = bld.srcnode.make_node('')
     71         bld.projects_dir.mkdir()
     72 
     73 
     74 ASSUMPTIONS:
     75 * a project can be either a directory or a target, project files are written only for targets that have source files
     76 * each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path
     77 """
     78 
     79 import os, re, sys
     80 import uuid # requires python 2.5
     81 from waflib.Build import BuildContext
     82 from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options
     83 
     84 HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'
     85 
     86 PROJECT_TEMPLATE = r'''<?xml version="1.0" encoding="utf-8"?>
     87 <CodeLite_Project Name="${project.name}" InternalType="Library">
     88   <Plugins>
     89     <Plugin Name="qmake">
     90       <![CDATA[00010001N0005Release000000000000]]>
     91     </Plugin>
     92   </Plugins>
     93   <Description/>
     94   <Dependencies/>
     95   <VirtualDirectory Name="src">
     96   ${for x in project.source}  
     97   ${if (project.get_key(x)=="sourcefile")}
     98   <File Name="${x.abspath()}"/>
     99   ${endif}
    100   ${endfor}  
    101   </VirtualDirectory>
    102   <VirtualDirectory Name="include">  
    103   ${for x in project.source}
    104   ${if (project.get_key(x)=="headerfile")}
    105   <File Name="${x.abspath()}"/>
    106   ${endif}
    107   ${endfor}
    108   </VirtualDirectory>  
    109   <Settings Type="Dynamic Library">
    110     <GlobalSettings>
    111       <Compiler Options="" C_Options="">
    112         <IncludePath Value="."/>
    113       </Compiler>
    114       <Linker Options="">
    115         <LibraryPath Value="."/>
    116       </Linker>
    117       <ResourceCompiler Options=""/>
    118     </GlobalSettings>
    119     <Configuration Name="Release" CompilerType="gnu gcc" ReleasegerType="GNU gdb Releaseger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
    120       <Compiler Options="" C_Options="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
    121         <IncludePath Value="."/>
    122         <IncludePath Value="."/>
    123       </Compiler>
    124       <Linker Options="" Required="yes">
    125         <LibraryPath Value=""/>
    126       </Linker>
    127       <ResourceCompiler Options="" Required="no"/>
    128       <General OutputFile="${xml:project.build_properties[0].output_file}" IntermediateDirectory="" Command="" CommandArguments="" PauseExecWhenProcTerminates="yes"/>
    129       <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
    130         <![CDATA[]]>
    131       </Environment>
    132       <Releaseger IsRemote="no" RemoteHostName="" RemoteHostPort="" ReleasegerPath="">
    133         <PostConnectCommands/>
    134         <StartupCommands/>
    135       </Releaseger>
    136       <PreBuild/>
    137       <PostBuild/>
    138       <CustomBuild Enabled="yes">
    139         $b = project.build_properties[0]}
    140         <RebuildCommand>${xml:project.get_rebuild_command(project.build_properties[0])}</RebuildCommand>
    141         <CleanCommand>${xml:project.get_clean_command(project.build_properties[0])}</CleanCommand>
    142         <BuildCommand>${xml:project.get_build_command(project.build_properties[0])}</BuildCommand> 
    143         <Target Name="Install">${xml:project.get_install_command(project.build_properties[0])}</Target>
    144         <Target Name="Build and Install">${xml:project.get_build_and_install_command(project.build_properties[0])}</Target>        
    145         <Target Name="Build All">${xml:project.get_build_all_command(project.build_properties[0])}</Target>
    146         <Target Name="Rebuild All">${xml:project.get_rebuild_all_command(project.build_properties[0])}</Target>
    147         <Target Name="Clean All">${xml:project.get_clean_all_command(project.build_properties[0])}</Target>
    148         <Target Name="Build and Install All">${xml:project.get_build_and_install_all_command(project.build_properties[0])}</Target>
    149         <PreprocessFileCommand/>
    150         <SingleFileCommand/>
    151         <MakefileGenerationCommand/>
    152         <ThirdPartyToolName>None</ThirdPartyToolName>
    153         <WorkingDirectory/>
    154       </CustomBuild>
    155       <AdditionalRules>
    156         <CustomPostBuild/>
    157         <CustomPreBuild/>
    158       </AdditionalRules>
    159       <Completion>
    160         <ClangCmpFlags/>
    161         <ClangPP/>
    162         <SearchPaths/>
    163       </Completion>
    164     </Configuration>
    165     <Configuration Name="Release" CompilerType="gnu gcc" ReleasegerType="GNU gdb Releaseger" Type="" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
    166       <Compiler Options="" C_Options="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" UseDifferentPCHFlags="no" PCHFlags="">
    167         <IncludePath Value="."/>
    168       </Compiler>
    169       <Linker Options="" Required="yes"/>
    170       <ResourceCompiler Options="" Required="no"/>
    171       <General OutputFile="" IntermediateDirectory="./Release" Command="" CommandArguments="" UseSeparateReleaseArgs="no" ReleaseArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/>
    172       <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
    173         <![CDATA[
    174       
    175       
    176       
    177       ]]>
    178       </Environment>
    179       <Releaseger IsRemote="no" RemoteHostName="" RemoteHostPort="" ReleasegerPath="">
    180         <PostConnectCommands/>
    181         <StartupCommands/>
    182       </Releaseger>
    183       <PreBuild/>
    184       <PostBuild/>
    185       <CustomBuild Enabled="no">
    186         <RebuildCommand/>
    187         <CleanCommand/>
    188         <BuildCommand/>
    189         <PreprocessFileCommand/>
    190         <SingleFileCommand/>
    191         <MakefileGenerationCommand/>
    192         <ThirdPartyToolName/>
    193         <WorkingDirectory/>
    194       </CustomBuild>
    195       <AdditionalRules>
    196         <CustomPostBuild/>
    197         <CustomPreBuild/>
    198       </AdditionalRules>
    199       <Completion>
    200         <ClangCmpFlags/>
    201         <ClangPP/>
    202         <SearchPaths/>
    203       </Completion>
    204     </Configuration>
    205   </Settings>
    206 </CodeLite_Project>'''
    207 
    208 
    209 
    210 
    211 SOLUTION_TEMPLATE = '''<?xml version="1.0" encoding="utf-8"?>
    212 <CodeLite_Workspace Name="${getattr(project, 'codelite_solution_name', None)[:-10]}" Database="./${getattr(project, 'codelite_solution_name', None)[:-10]}.tags">
    213 ${for p in project.all_projects}
    214   <Project Name = "${p.name}" Path = "${p.title}" Active="No"/>
    215 ${endfor}
    216   <BuildMatrix>
    217     <WorkspaceConfiguration Name="Release" Selected="yes">
    218 ${for p in project.all_projects}
    219       <Project Name="${p.name}" ConfigName="Release"/>        
    220 ${endfor}
    221     </WorkspaceConfiguration>        
    222   </BuildMatrix>
    223 </CodeLite_Workspace>'''
    224 
    225 
    226 
    227 COMPILE_TEMPLATE = '''def f(project):
    228         lst = []
    229         def xml_escape(value):
    230                 return value.replace("&", "&amp;").replace('"', "&quot;").replace("'", "&apos;").replace("<", "&lt;").replace(">", "&gt;")
    231 
    232         %s
    233 
    234         #f = open('cmd.txt', 'w')
    235         #f.write(str(lst))
    236         #f.close()
    237         return ''.join(lst)
    238 '''
    239 reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<code>[^}]*?)\})", re.M)
    240 def compile_template(line):
    241         """
    242         Compile a template expression into a python function (like jsps, but way shorter)
    243         """
    244         extr = []
    245         def repl(match):
    246                 g = match.group
    247                 if g('dollar'):
    248                         return "$"
    249                 elif g('backslash'):
    250                         return "\\"
    251                 elif g('subst'):
    252                         extr.append(g('code'))
    253                         return "<<|@|>>"
    254                 return None
    255 
    256         line2 = reg_act.sub(repl, line)
    257         params = line2.split('<<|@|>>')
    258         assert(extr)
    259 
    260 
    261         indent = 0
    262         buf = []
    263         app = buf.append
    264 
    265         def app(txt):
    266                 buf.append(indent * '\t' + txt)
    267 
    268         for x in range(len(extr)):
    269                 if params[x]:
    270                         app("lst.append(%r)" % params[x])
    271 
    272                 f = extr[x]
    273                 if f.startswith(('if', 'for')):
    274                         app(f + ':')
    275                         indent += 1
    276                 elif f.startswith('py:'):
    277                         app(f[3:])
    278                 elif f.startswith(('endif', 'endfor')):
    279                         indent -= 1
    280                 elif f.startswith(('else', 'elif')):
    281                         indent -= 1
    282                         app(f + ':')
    283                         indent += 1
    284                 elif f.startswith('xml:'):
    285                         app('lst.append(xml_escape(%s))' % f[4:])
    286                 else:
    287                         #app('lst.append((%s) or "cannot find %s")' % (f, f))
    288                         app('lst.append(%s)' % f)
    289 
    290         if extr:
    291                 if params[-1]:
    292                         app("lst.append(%r)" % params[-1])
    293 
    294         fun = COMPILE_TEMPLATE % "\n\t".join(buf)
    295         #print(fun)
    296         return Task.funex(fun)
    297 
    298 
    299 re_blank = re.compile('(\n|\r|\\s)*\n', re.M)
    300 def rm_blank_lines(txt):
    301         txt = re_blank.sub('\r\n', txt)
    302         return txt
    303 
    304 BOM = '\xef\xbb\xbf'
    305 try:
    306         BOM = bytes(BOM, 'latin-1') # python 3
    307 except (TypeError, NameError):
    308         pass
    309 
    310 def stealth_write(self, data, flags='wb'):
    311         try:
    312                 unicode
    313         except NameError:
    314                 data = data.encode('utf-8') # python 3
    315         else:
    316                 data = data.decode(sys.getfilesystemencoding(), 'replace')
    317                 data = data.encode('utf-8')
    318 
    319         if self.name.endswith('.project'):
    320                 data = BOM + data
    321 
    322         try:
    323                 txt = self.read(flags='rb')
    324                 if txt != data:
    325                         raise ValueError('must write')
    326         except (IOError, ValueError):
    327                 self.write(data, flags=flags)
    328         else:
    329                 Logs.debug('codelite: skipping %r', self)
    330 Node.Node.stealth_write = stealth_write
    331 
    332 re_quote = re.compile("[^a-zA-Z0-9-]")
    333 def quote(s):
    334         return re_quote.sub("_", s)
    335 
    336 def xml_escape(value):
    337         return value.replace("&", "&amp;").replace('"', "&quot;").replace("'", "&apos;").replace("<", "&lt;").replace(">", "&gt;")
    338 
    339 def make_uuid(v, prefix = None):
    340         """
    341         simple utility function
    342         """
    343         if isinstance(v, dict):
    344                 keys = list(v.keys())
    345                 keys.sort()
    346                 tmp = str([(k, v[k]) for k in keys])
    347         else:
    348                 tmp = str(v)
    349         d = Utils.md5(tmp.encode()).hexdigest().upper()
    350         if prefix:
    351                 d = '%s%s' % (prefix, d[8:])
    352         gid = uuid.UUID(d, version = 4)
    353         return str(gid).upper()
    354 
    355 def diff(node, fromnode):
    356         # difference between two nodes, but with "(..)" instead of ".."
    357         c1 = node
    358         c2 = fromnode
    359 
    360         c1h = c1.height()
    361         c2h = c2.height()
    362 
    363         lst = []
    364         up = 0
    365 
    366         while c1h > c2h:
    367                 lst.append(c1.name)
    368                 c1 = c1.parent
    369                 c1h -= 1
    370 
    371         while c2h > c1h:
    372                 up += 1
    373                 c2 = c2.parent
    374                 c2h -= 1
    375 
    376         while id(c1) != id(c2):
    377                 lst.append(c1.name)
    378                 up += 1
    379 
    380                 c1 = c1.parent
    381                 c2 = c2.parent
    382 
    383         for i in range(up):
    384                 lst.append('(..)')
    385         lst.reverse()
    386         return tuple(lst)
    387 
    388 class build_property(object):
    389         pass
    390 
    391 class vsnode(object):
    392         """
    393         Abstract class representing visual studio elements
    394         We assume that all visual studio nodes have a uuid and a parent
    395         """
    396         def __init__(self, ctx):
    397                 self.ctx = ctx # codelite context
    398                 self.name = '' # string, mandatory
    399                 self.vspath = '' # path in visual studio (name for dirs, absolute path for projects)
    400                 self.uuid = '' # string, mandatory
    401                 self.parent = None # parent node for visual studio nesting
    402 
    403         def get_waf(self):
    404                 """
    405                 Override in subclasses...
    406                 """
    407                 return '%s/%s' % (self.ctx.srcnode.abspath(), getattr(self.ctx, 'waf_command', 'waf'))
    408 
    409         def ptype(self):
    410                 """
    411                 Return a special uuid for projects written in the solution file
    412                 """
    413                 pass
    414 
    415         def write(self):
    416                 """
    417                 Write the project file, by default, do nothing
    418                 """
    419                 pass
    420 
    421         def make_uuid(self, val):
    422                 """
    423                 Alias for creating uuid values easily (the templates cannot access global variables)
    424                 """
    425                 return make_uuid(val)
    426 
    427 class vsnode_vsdir(vsnode):
    428         """
    429         Nodes representing visual studio folders (which do not match the filesystem tree!)
    430         """
    431         VS_GUID_SOLUTIONFOLDER = "2150E333-8FDC-42A3-9474-1A3956D46DE8"
    432         def __init__(self, ctx, uuid, name, vspath=''):
    433                 vsnode.__init__(self, ctx)
    434                 self.title = self.name = name
    435                 self.uuid = uuid
    436                 self.vspath = vspath or name
    437 
    438         def ptype(self):
    439                 return self.VS_GUID_SOLUTIONFOLDER
    440 
    441 class vsnode_project(vsnode):
    442         """
    443         Abstract class representing visual studio project elements
    444         A project is assumed to be writable, and has a node representing the file to write to
    445         """
    446         VS_GUID_VCPROJ = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
    447         def ptype(self):
    448                 return self.VS_GUID_VCPROJ
    449 
    450         def __init__(self, ctx, node):
    451                 vsnode.__init__(self, ctx)
    452                 self.path = node
    453                 self.uuid = make_uuid(node.abspath())
    454                 self.name = node.name
    455                 self.title = self.path.abspath()
    456                 self.source = [] # list of node objects
    457                 self.build_properties = [] # list of properties (nmake commands, output dir, etc)
    458 
    459         def dirs(self):
    460                 """
    461                 Get the list of parent folders of the source files (header files included)
    462                 for writing the filters
    463                 """
    464                 lst = []
    465                 def add(x):
    466                         if x.height() > self.tg.path.height() and x not in lst:
    467                                 lst.append(x)
    468                                 add(x.parent)
    469                 for x in self.source:
    470                         add(x.parent)
    471                 return lst
    472 
    473         def write(self):
    474                 Logs.debug('codelite: creating %r', self.path)
    475                 #print "self.name:",self.name
    476 
    477                 # first write the project file
    478                 template1 = compile_template(PROJECT_TEMPLATE)
    479                 proj_str = template1(self)
    480                 proj_str = rm_blank_lines(proj_str)
    481                 self.path.stealth_write(proj_str)
    482 
    483                 # then write the filter
    484                 #template2 = compile_template(FILTER_TEMPLATE)
    485                 #filter_str = template2(self)
    486                 #filter_str = rm_blank_lines(filter_str)
    487                 #tmp = self.path.parent.make_node(self.path.name + '.filters')
    488                 #tmp.stealth_write(filter_str)
    489 
    490         def get_key(self, node):
    491                 """
    492                 required for writing the source files
    493                 """
    494                 name = node.name
    495                 if name.endswith(('.cpp', '.c')):
    496                         return 'sourcefile'
    497                 return 'headerfile'
    498 
    499         def collect_properties(self):
    500                 """
    501                 Returns a list of triplet (configuration, platform, output_directory)
    502                 """
    503                 ret = []
    504                 for c in self.ctx.configurations:
    505                         for p in self.ctx.platforms:
    506                                 x = build_property()
    507                                 x.outdir = ''
    508 
    509                                 x.configuration = c
    510                                 x.platform = p
    511 
    512                                 x.preprocessor_definitions = ''
    513                                 x.includes_search_path = ''
    514 
    515                                 # can specify "deploy_dir" too
    516                                 ret.append(x)
    517                 self.build_properties = ret
    518 
    519         def get_build_params(self, props):
    520                 opt = ''
    521                 return (self.get_waf(), opt)
    522 
    523         def get_build_command(self, props):
    524                 return "%s build %s" % self.get_build_params(props)
    525 
    526         def get_clean_command(self, props):
    527                 return "%s clean %s" % self.get_build_params(props)
    528 
    529         def get_rebuild_command(self, props):
    530                 return "%s clean build %s" % self.get_build_params(props)
    531                 
    532         def get_install_command(self, props):
    533                 return "%s install %s" % self.get_build_params(props)
    534         def get_build_and_install_command(self, props):
    535                 return "%s build install %s" % self.get_build_params(props)
    536                 
    537         def get_build_and_install_all_command(self, props):
    538                 return "%s build install" % self.get_build_params(props)[0]
    539                 
    540         def get_clean_all_command(self, props):
    541                 return "%s clean" % self.get_build_params(props)[0]
    542         
    543         def get_build_all_command(self, props):
    544                 return "%s build" % self.get_build_params(props)[0]
    545                 
    546         def get_rebuild_all_command(self, props):
    547                 return "%s clean build" % self.get_build_params(props)[0]
    548 
    549         def get_filter_name(self, node):
    550                 lst = diff(node, self.tg.path)
    551                 return '\\'.join(lst) or '.'
    552 
    553 class vsnode_alias(vsnode_project):
    554         def __init__(self, ctx, node, name):
    555                 vsnode_project.__init__(self, ctx, node)
    556                 self.name = name
    557                 self.output_file = ''
    558 
    559 class vsnode_build_all(vsnode_alias):
    560         """
    561         Fake target used to emulate the behaviour of "make all" (starting one process by target is slow)
    562         This is the only alias enabled by default
    563         """
    564         def __init__(self, ctx, node, name='build_all_projects'):
    565                 vsnode_alias.__init__(self, ctx, node, name)
    566                 self.is_active = True
    567 
    568 class vsnode_install_all(vsnode_alias):
    569         """
    570         Fake target used to emulate the behaviour of "make install"
    571         """
    572         def __init__(self, ctx, node, name='install_all_projects'):
    573                 vsnode_alias.__init__(self, ctx, node, name)
    574 
    575         def get_build_command(self, props):
    576                 return "%s build install %s" % self.get_build_params(props)
    577 
    578         def get_clean_command(self, props):
    579                 return "%s clean %s" % self.get_build_params(props)
    580 
    581         def get_rebuild_command(self, props):
    582                 return "%s clean build install %s" % self.get_build_params(props)
    583 
    584 class vsnode_project_view(vsnode_alias):
    585         """
    586         Fake target used to emulate a file system view
    587         """
    588         def __init__(self, ctx, node, name='project_view'):
    589                 vsnode_alias.__init__(self, ctx, node, name)
    590                 self.tg = self.ctx() # fake one, cannot remove
    591                 self.exclude_files = Node.exclude_regs + '''
    592 waf-2*
    593 waf3-2*/**
    594 .waf-2*
    595 .waf3-2*/**
    596 **/*.sdf
    597 **/*.suo
    598 **/*.ncb
    599 **/%s
    600                 ''' % Options.lockfile
    601 
    602         def collect_source(self):
    603                 # this is likely to be slow
    604                 self.source = self.ctx.srcnode.ant_glob('**', excl=self.exclude_files)
    605 
    606         def get_build_command(self, props):
    607                 params = self.get_build_params(props) + (self.ctx.cmd,)
    608                 return "%s %s %s" % params
    609 
    610         def get_clean_command(self, props):
    611                 return ""
    612 
    613         def get_rebuild_command(self, props):
    614                 return self.get_build_command(props)
    615 
    616 class vsnode_target(vsnode_project):
    617         """
    618         CodeLite project representing a targets (programs, libraries, etc) and bound
    619         to a task generator
    620         """
    621         def __init__(self, ctx, tg):
    622                 """
    623                 A project is more or less equivalent to a file/folder
    624                 """
    625                 base = getattr(ctx, 'projects_dir', None) or tg.path
    626                 node = base.make_node(quote(tg.name) + ctx.project_extension) # the project file as a Node
    627                 vsnode_project.__init__(self, ctx, node)
    628                 self.name = quote(tg.name)
    629                 self.tg     = tg  # task generator
    630 
    631         def get_build_params(self, props):
    632                 """
    633                 Override the default to add the target name
    634                 """
    635                 opt = ''
    636                 if getattr(self, 'tg', None):
    637                         opt += " --targets=%s" % self.tg.name
    638                 return (self.get_waf(), opt)
    639 
    640         def collect_source(self):
    641                 tg = self.tg
    642                 source_files = tg.to_nodes(getattr(tg, 'source', []))
    643                 include_dirs = Utils.to_list(getattr(tg, 'codelite_includes', []))
    644                 include_files = []
    645                 for x in include_dirs:
    646                         if isinstance(x, str):
    647                                 x = tg.path.find_node(x)
    648                         if x:
    649                                 lst = [y for y in x.ant_glob(HEADERS_GLOB, flat=False)]
    650                                 include_files.extend(lst)
    651 
    652                 # remove duplicates
    653                 self.source.extend(list(set(source_files + include_files)))
    654                 self.source.sort(key=lambda x: x.abspath())
    655 
    656         def collect_properties(self):
    657                 """
    658                 CodeLite projects are associated with platforms and configurations (for building especially)
    659                 """
    660                 super(vsnode_target, self).collect_properties()
    661                 for x in self.build_properties:
    662                         x.outdir = self.path.parent.abspath()
    663                         x.preprocessor_definitions = ''
    664                         x.includes_search_path = ''
    665 
    666                         try:
    667                                 tsk = self.tg.link_task
    668                         except AttributeError:
    669                                 pass
    670                         else:                                
    671                                 x.output_file = tsk.outputs[0].abspath()
    672                                 x.preprocessor_definitions = ';'.join(tsk.env.DEFINES)
    673                                 x.includes_search_path = ';'.join(self.tg.env.INCPATHS)
    674 
    675 class codelite_generator(BuildContext):
    676         '''generates a CodeLite workspace'''
    677         cmd = 'codelite'
    678         fun = 'build'
    679 
    680         def init(self):
    681                 """
    682                 Some data that needs to be present
    683                 """
    684                 if not getattr(self, 'configurations', None):
    685                         self.configurations = ['Release'] # LocalRelease, RemoteDebug, etc
    686                 if not getattr(self, 'platforms', None):
    687                         self.platforms = ['Win32']
    688                 if not getattr(self, 'all_projects', None):
    689                         self.all_projects = []
    690                 if not getattr(self, 'project_extension', None):
    691                         self.project_extension = '.project'
    692                 if not getattr(self, 'projects_dir', None):
    693                         self.projects_dir = self.srcnode.make_node('')
    694                         self.projects_dir.mkdir()
    695 
    696                 # bind the classes to the object, so that subclass can provide custom generators
    697                 if not getattr(self, 'vsnode_vsdir', None):
    698                         self.vsnode_vsdir = vsnode_vsdir
    699                 if not getattr(self, 'vsnode_target', None):
    700                         self.vsnode_target = vsnode_target
    701                 if not getattr(self, 'vsnode_build_all', None):
    702                         self.vsnode_build_all = vsnode_build_all
    703                 if not getattr(self, 'vsnode_install_all', None):
    704                         self.vsnode_install_all = vsnode_install_all
    705                 if not getattr(self, 'vsnode_project_view', None):
    706                         self.vsnode_project_view = vsnode_project_view
    707 
    708                 self.numver = '11.00'
    709                 self.vsver  = '2010'
    710 
    711         def execute(self):
    712                 """
    713                 Entry point
    714                 """
    715                 self.restore()
    716                 if not self.all_envs:
    717                         self.load_envs()
    718                 self.recurse([self.run_dir])
    719 
    720                 # user initialization
    721                 self.init()
    722 
    723                 # two phases for creating the solution
    724                 self.collect_projects() # add project objects into "self.all_projects"
    725                 self.write_files() # write the corresponding project and solution files
    726 
    727         def collect_projects(self):
    728                 """
    729                 Fill the list self.all_projects with project objects
    730                 Fill the list of build targets
    731                 """
    732                 self.collect_targets()
    733                 #self.add_aliases()
    734                 #self.collect_dirs()
    735                 default_project = getattr(self, 'default_project', None)
    736                 def sortfun(x):
    737                         if x.name == default_project:
    738                                 return ''
    739                         return getattr(x, 'path', None) and x.path.abspath() or x.name
    740                 self.all_projects.sort(key=sortfun)
    741 
    742         def write_files(self):
    743                 """
    744                 Write the project and solution files from the data collected
    745                 so far. It is unlikely that you will want to change this
    746                 """
    747                 for p in self.all_projects:
    748                         p.write()
    749 
    750                 # and finally write the solution file
    751                 node = self.get_solution_node()
    752                 node.parent.mkdir()
    753                 Logs.warn('Creating %r', node)
    754                 #a = dir(self.root)
    755                 #for b in a:
    756                 #        print b
    757                 #print self.group_names
    758                 #print "Hallo2:   ",self.root.listdir()
    759                 #print getattr(self, 'codelite_solution_name', None)
    760                 template1 = compile_template(SOLUTION_TEMPLATE)
    761                 sln_str = template1(self)
    762                 sln_str = rm_blank_lines(sln_str)
    763                 node.stealth_write(sln_str)
    764 
    765         def get_solution_node(self):
    766                 """
    767                 The solution filename is required when writing the .vcproj files
    768                 return self.solution_node and if it does not exist, make one
    769                 """
    770                 try:
    771                         return self.solution_node
    772                 except:
    773                         pass
    774 
    775                 codelite_solution_name = getattr(self, 'codelite_solution_name', None)
    776                 if not codelite_solution_name:
    777                         codelite_solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '.workspace'
    778                         setattr(self, 'codelite_solution_name', codelite_solution_name)
    779                 if os.path.isabs(codelite_solution_name):
    780                         self.solution_node = self.root.make_node(codelite_solution_name)
    781                 else:
    782                         self.solution_node = self.srcnode.make_node(codelite_solution_name)
    783                 return self.solution_node
    784 
    785         def project_configurations(self):
    786                 """
    787                 Helper that returns all the pairs (config,platform)
    788                 """
    789                 ret = []
    790                 for c in self.configurations:
    791                         for p in self.platforms:
    792                                 ret.append((c, p))
    793                 return ret
    794 
    795         def collect_targets(self):
    796                 """
    797                 Process the list of task generators
    798                 """
    799                 for g in self.groups:
    800                         for tg in g:
    801                                 if not isinstance(tg, TaskGen.task_gen):
    802                                         continue
    803 
    804                                 if not hasattr(tg, 'codelite_includes'):
    805                                         tg.codelite_includes = tg.to_list(getattr(tg, 'includes', [])) + tg.to_list(getattr(tg, 'export_includes', []))
    806                                 tg.post()
    807                                 if not getattr(tg, 'link_task', None):
    808                                         continue
    809 
    810                                 p = self.vsnode_target(self, tg)
    811                                 p.collect_source() # delegate this processing
    812                                 p.collect_properties()                               
    813                                 self.all_projects.append(p)
    814 
    815         def add_aliases(self):
    816                 """
    817                 Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7
    818                 We also add an alias for "make install" (disabled by default)
    819                 """
    820                 base = getattr(self, 'projects_dir', None) or self.tg.path
    821 
    822                 node_project = base.make_node('build_all_projects' + self.project_extension) # Node
    823                 p_build = self.vsnode_build_all(self, node_project)
    824                 p_build.collect_properties()
    825                 self.all_projects.append(p_build)
    826 
    827                 node_project = base.make_node('install_all_projects' + self.project_extension) # Node
    828                 p_install = self.vsnode_install_all(self, node_project)
    829                 p_install.collect_properties()
    830                 self.all_projects.append(p_install)
    831 
    832                 node_project = base.make_node('project_view' + self.project_extension) # Node
    833                 p_view = self.vsnode_project_view(self, node_project)
    834                 p_view.collect_source()
    835                 p_view.collect_properties()
    836                 self.all_projects.append(p_view)
    837 
    838                 n = self.vsnode_vsdir(self, make_uuid(self.srcnode.abspath() + 'build_aliases'), "build_aliases")
    839                 p_build.parent = p_install.parent = p_view.parent = n
    840                 self.all_projects.append(n)
    841 
    842         def collect_dirs(self):
    843                 """
    844                 Create the folder structure in the CodeLite project view
    845                 """
    846                 seen = {}
    847                 def make_parents(proj):
    848                         # look at a project, try to make a parent
    849                         if getattr(proj, 'parent', None):
    850                                 # aliases already have parents
    851                                 return
    852                         x = proj.iter_path
    853                         if x in seen:
    854                                 proj.parent = seen[x]
    855                                 return
    856 
    857                         # There is not vsnode_vsdir for x.
    858                         # So create a project representing the folder "x"
    859                         n = proj.parent = seen[x] = self.vsnode_vsdir(self, make_uuid(x.abspath()), x.name)
    860                         n.iter_path = x.parent
    861                         self.all_projects.append(n)
    862 
    863                         # recurse up to the project directory
    864                         if x.height() > self.srcnode.height() + 1:
    865                                 make_parents(n)
    866 
    867                 for p in self.all_projects[:]: # iterate over a copy of all projects
    868                         if not getattr(p, 'tg', None):
    869                                 # but only projects that have a task generator
    870                                 continue
    871 
    872                         # make a folder for each task generator
    873                         p.iter_path = p.tg.path
    874                         make_parents(p)
    875