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""" 10Redistribution and use in source and binary forms, with or without 11modification, are permitted provided that the following conditions 12are met: 13 141. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 172. 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 213. 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 24THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 25IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 28INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34POSSIBILITY OF SUCH DAMAGE. 35""" 36 37""" 38 39 40To add this tool to your project: 41def options(conf): 42 opt.load('codelite') 43 44It can be a good idea to add the sync_exec tool too. 45 46To generate solution files: 47$ waf configure codelite 48 49To customize the outputs, provide subclasses in your wscript files: 50 51from waflib.extras import codelite 52class 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 ... 59class codelite_bar(codelite.codelite_generator): 60 def init(self): 61 codelite.codelite_generator.init(self) 62 self.vsnode_target = vsnode_target 63 64The codelite class re-uses the same build() function for reading the targets (task generators), 65you may therefore specify codelite settings on the context object: 66 67def 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 74ASSUMPTIONS: 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 79import os, re, sys 80import uuid # requires python 2.5 81from waflib.Build import BuildContext 82from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options 83 84HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)' 85 86PROJECT_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="<Use Defaults>" DbgSetName="<Use Defaults>"> 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="<Use Defaults>" DbgSetName="<Use Defaults>"> 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 211SOLUTION_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 227COMPILE_TEMPLATE = '''def f(project): 228 lst = [] 229 def xml_escape(value): 230 return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") 231 232 %s 233 234 #f = open('cmd.txt', 'w') 235 #f.write(str(lst)) 236 #f.close() 237 return ''.join(lst) 238''' 239reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<code>[^}]*?)\})", re.M) 240def 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 299re_blank = re.compile('(\n|\r|\\s)*\n', re.M) 300def rm_blank_lines(txt): 301 txt = re_blank.sub('\r\n', txt) 302 return txt 303 304BOM = '\xef\xbb\xbf' 305try: 306 BOM = bytes(BOM, 'latin-1') # python 3 307except (TypeError, NameError): 308 pass 309 310def 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) 330Node.Node.stealth_write = stealth_write 331 332re_quote = re.compile("[^a-zA-Z0-9-]") 333def quote(s): 334 return re_quote.sub("_", s) 335 336def xml_escape(value): 337 return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") 338 339def 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 355def 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 388class build_property(object): 389 pass 390 391class 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 427class 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 441class 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 553class 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 559class 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 568class 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 584class 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 + ''' 592waf-2* 593waf3-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 616class 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 675class 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 876