sc: filter: rtf: use a separate document stream
[LibreOffice.git] / bin / gbuild-to-ide
blobb7c290cb828530e5d71c3ecb9bbe3cf66b84a8f3
1 #! /usr/bin/env python3
2 # -*- Mode: python; tab-width: 4; indent-tabs-mode: t -*-
4 # This file is part of the LibreOffice project.
6 # This Source Code Form is subject to the terms of the Mozilla Public
7 # License, v. 2.0. If a copy of the MPL was not distributed with this
8 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 import argparse
12 import ntpath
13 import os
14 import os.path
15 import shutil
16 import re
17 import sys
18 import uuid
19 import json
20 import xml.etree.ElementTree as ET
21 import xml.dom.minidom as minidom
22 import traceback
23 import subprocess
24 from sys import platform
25 import collections
26 import urllib.parse
28 class GbuildLinkTarget:
29     def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs):
30         (self.name, self.location, self.include, self.include_sys, self.defs, self.cxxobjects, self.cxxflags, self.cobjects, self.cflags, self.linked_libs) = (
31             name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs)
33     def short_name(self):
34         return self.name
36     def is_empty(self):
37         return not self.include and not self.defs and not self.cxxobjects and not self.cobjects and not self.linked_libs
39     def __str__(self):
40         return '%s at %s with include path: %s, isystem includes: %s, defines: %s, objects: %s, cxxflags: %s, cobjects: %s, cflags: %s and linked libs: %s' % (
41             self.short_name(), self.location, self.include, self.include_sys, self.defs, self.cxxobjects,
42             self.cxxflags, self.cobjects, self.cflags, self.linked_libs)
45 class GbuildLib(GbuildLinkTarget):
46     def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs):
47         GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs)
49     def short_name(self):
50         """Return the short name of target based on the Library_* makefile name"""
51         return 'Library %s' % self.name
53     def target_name(self):
54         return 'Library_%s' % self.name
56     def library_name(self):
57         return self.name
59 class GbuildTest(GbuildLinkTarget):
60     def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs):
61         GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs)
63     def short_name(self):
64         """Return the short name of target based n the CppunitTest_* makefile names"""
65         return 'CppunitTest %s' % self.name
67     def target_name(self):
68         return 'CppunitTest_%s' % self.name
70 class GbuildExe(GbuildLinkTarget):
71     def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs):
72         GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs)
74     def short_name(self):
75         """Return the short name of target based on the Executable_* makefile name"""
76         return 'Executable %s' % self.name
78     def target_name(self):
79         return 'Executable_%s' % self.name
82 class GbuildParser:
83     """Main data model object.
85     Attributes:
86         target_by_path     : dict[path:string, set(target)]
87                                where target is one of the GbuildLinkTarget subclasses
88         target_by_location : dict[path:string, set(target)]
89                                where target is one of the GbuildLinkTarget subclasses
90     """
91     def __init__(self, makecmd):
92         self.makecmd = makecmd
93         self.binpath = os.path.dirname(os.environ['GPERF']) # woha, this is quite a hack
94         (self.srcdir, self.builddir, self.instdir, self.workdir) = (os.environ['SRCDIR'], os.environ['BUILDDIR'], os.environ['INSTDIR'], os.environ['WORKDIR'])
95         (self.libs, self.exes, self.tests, self.modulenamelist) = ([], [], [], [])
96         (self.target_by_path, self.target_by_location) = ({}, {})
98     includepattern = re.compile(r'-I(\S+)')
99     isystempattern = re.compile(r'-isystem\s*(\S+)')
100     warningpattern = re.compile(r'-W\S+')
101     libpattern = re.compile(r'Library_(.*)\.mk')
102     exepattern = re.compile(r'Executable_(.*)\.mk')
103     testpattern = re.compile(r'CppunitTest_(.*)\.mk')
105     @staticmethod
106     def __split_includes(includes):
107         foundisystem = GbuildParser.isystempattern.findall(includes)
108         foundincludes = [includeswitch.strip() for includeswitch in GbuildParser.includepattern.findall(includes) if
109                 len(includeswitch) > 2]
110         return (foundincludes, foundisystem)
112     @staticmethod
113     def __split_objs(objsline):
114         return [obj for obj in objsline.strip().split(' ') if len(obj) > 0 and obj != 'CXXOBJECTS' and obj != 'COBJECTS' and obj != '+=']
116     @staticmethod
117     def __split_defs(defsline):
118         defs = {}
119         alldefs = [defswitch.strip() for defswitch in defsline.strip().lstrip('-D').split(' -D') if len(defswitch) > 2]
120         for d in alldefs:
121             dparts = d.split(' -U')
122             """after dparts.pop(0), dparts will contain only undefs"""
123             defparts = dparts.pop(0).strip().split('=')
124             if len(defparts) == 1:
125                 defparts.append(None)
126             defs[defparts[0]] = defparts[1]
127             """Drop undefed items (if any) from previous defs"""
128             for u in dparts:
129                 defs.pop(u.strip(), '')
130         defs["LIBO_INTERNAL_ONLY"] = None
131         return defs
133     @staticmethod
134     def __split_flags(flagsline, flagslineappend):
135         return [cxxflag.strip() for cxxflag in GbuildParser.warningpattern.sub('', '%s %s' % (flagsline, flagslineappend)).split(' ') if len(cxxflag) > 1]
137     @staticmethod
138     def __lib_from_json(json):
139         (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
140         return GbuildLib(
141             GbuildParser.libpattern.match(os.path.basename(json['MAKEFILE'])).group(1),
142             os.path.dirname(json['MAKEFILE']),
143             foundincludes,
144             foundisystem,
145             GbuildParser.__split_defs(json['DEFS']),
146             GbuildParser.__split_objs(json['CXXOBJECTS']),
147             GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
148             GbuildParser.__split_objs(json['COBJECTS']),
149             GbuildParser.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
150             json['LINKED_LIBS'].strip().split(' '))
152     @staticmethod
153     def __test_from_json(json):
154         (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
155         testname_match = GbuildParser.testpattern.match(os.path.basename(json['MAKEFILE']))
157         # Workaround strange writer test makefile setup
158         if testname_match is None:
159             testname = "StrangeWriterMakefiles"
160         else:
161             testname = testname_match.group(1)
163         return GbuildTest(
164             testname,
165             os.path.dirname(json['MAKEFILE']),
166             foundincludes,
167             foundisystem,
168             GbuildParser.__split_defs(json['DEFS']),
169             GbuildParser.__split_objs(json['CXXOBJECTS']),
170             GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
171             GbuildParser.__split_objs(json['COBJECTS']),
172             GbuildParser.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
173             json['LINKED_LIBS'].strip().split(' '))
175     @staticmethod
176     def __exe_from_json(json):
177         (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
178         return GbuildExe(
179             GbuildParser.exepattern.match(os.path.basename(json['MAKEFILE'])).group(1),
180             os.path.dirname(json['MAKEFILE']),
181             foundincludes,
182             foundisystem,
183             GbuildParser.__split_defs(json['DEFS']),
184             GbuildParser.__split_objs(json['CXXOBJECTS']),
185             GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
186             GbuildParser.__split_objs(json['COBJECTS']),
187             GbuildParser.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
188             json['LINKED_LIBS'].strip().split(' '))
190     def parse(self):
191         for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Library')):
192             with open(os.path.join(self.workdir, 'GbuildToJson', 'Library', jsonfilename), 'r') as f:
193                 lib = self.__lib_from_json(json.load(f))
194                 self.libs.append(lib)
195         for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Executable')):
196             with open(os.path.join(self.workdir, 'GbuildToJson', 'Executable', jsonfilename), 'r') as f:
197                 exe = self.__exe_from_json(json.load(f))
198                 self.exes.append(exe)
199         for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest')):
200             with open(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest', jsonfilename), 'r') as f:
201                 test = self.__test_from_json(json.load(f))
202                 self.tests.append(test)
203         for target in set(self.libs) | set(self.exes) | set(self.tests):
204             if target.location not in self.target_by_location:
205                 self.target_by_location[target.location] = set()
206             self.target_by_location[target.location] |= set([target])
207             for cxx in target.cxxobjects:
208                 path = '/'.join(cxx.split('/')[:-1])
209                 if path not in self.target_by_path:
210                     self.target_by_path[path] = set()
211                 self.target_by_path[path] |= set([target])
212             for c in target.cobjects:
213                 path = '/'.join(c.split('/')[:-1])
214                 if path not in self.target_by_path:
215                     self.target_by_path[path] = set()
216                 self.target_by_path[path] |= set([target])
217         for location in self.target_by_location:
218             self.modulenamelist.append(os.path.split(location)[1])
219         return self
222 class IdeIntegrationGenerator:
224     def __init__(self, gbuildparser, ide):
225         self.gbuildparser = gbuildparser
226         self.ide = ide
228     def emit(self):
229         pass
231 class EclipseCDTIntegrationGenerator(IdeIntegrationGenerator):
233     def __init__(self, gbuildparser, ide):
234         IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
236     def create_include_paths(self):
237         for module in self.gbuildparser.modulenamelist:
238             modulepath = os.path.join(self.gbuildparser.builddir, module)
239             includedirfile = open(os.path.join(modulepath, '.eclipsesettingfile'), 'w')
240             modulelibs = []
241             for lib in self.gbuildparser.target_by_path.keys():
242                 if lib.startswith(module+'/'):
243                     modulelibs.append(lib)
244             include = set()
245             for lib in modulelibs:
246                 for target in self.gbuildparser.target_by_path[lib]:
247                     include |= set(target.include)
248             includedirfile.write('\n'.join(include))
249             includedirfile.close()
252     def create_macros(self):
253         for module in self.gbuildparser.modulenamelist:
254             modulepath = os.path.join(self.gbuildparser.builddir, module)
255             macrofile = open(os.path.join(modulepath, '.macros'), 'w')
256             modulelibs = []
257             for lib in self.gbuildparser.target_by_path.keys():
258                 if lib.startswith(module+'/'):
259                     modulelibs.append(lib)
260             define = []
261             defineset = set()
262             for lib in modulelibs:
263                 for target in self.gbuildparser.target_by_path[lib]:
264                     for i in target.defs.keys():
265                         tmp = str(i) +','+str(target.defs[i])
266                         if tmp not in defineset:
267                             defineset.add(tmp)
268             macrofile.write('\n'.join(defineset))
269             macrofile.close()
272     def create_settings_file(self):
274         settingsfiletemplate = """\
275 <?xml version="1.0" encoding="UTF-8"?>
276 <cdtprojectproperties>
277 <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths">
278 <language name="C++ Source File">
281 </language>
282 <language name="C Source File">
284 </language>
285 <language name="Object File">
287 </language>
288 <language name="Assembly Source File">
290 </language>
291 </section>
292 <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros">
293 <language name="C++ Source File">
295 </language>
296 <language name="C Source File">
298 </language>
299 <language name="Object File">
301 </language>
302 <language name="Assembly Source File">
304 </language>
305 </section>
306 </cdtprojectproperties>
307 """ 
309         for module in self.gbuildparser.modulenamelist:
310             tempxml = []
311             modulepath = os.path.join(self.gbuildparser.builddir, module)
313             settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
314             settingsfile.write(settingsfiletemplate)
315             settingsfile.close()
317             settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'r')
318             tempxml = settingsfile.readlines()
319             tempinclude = open(os.path.join(modulepath, '.eclipsesettingfile'), 'r')
320             tempmacro = open(os.path.join(modulepath, '.macros'), 'r')
321             for includepath in tempinclude:
322                 if includepath[-1:] == "\n":
323                     includepath = includepath[:-1]
324                 templine = "<includepath>%s</includepath>\n" % includepath
325                 tempxml.insert(5, templine)
327             for line in tempmacro:
328                 macroskeyvalue = line.split(',')
329                 macrokey = macroskeyvalue[0]
330                 macrovalue = macroskeyvalue[1]
331                 if macrovalue[-1:] == "\n":
332                     macrovalue = macrovalue[:-1] 
333                 templine = "<macro><name>%s</name><value>%s</value></macro>\n" %(macrokey, macrovalue)
334                 tempxml.insert(-13, templine)
335             tempxml="".join(tempxml)
336             settingsfile.close
338             settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
339             settingsfile.write(tempxml)
340             settingsfile.close()
341             os.remove(os.path.join(modulepath, '.eclipsesettingfile'))
342             os.remove(os.path.join(modulepath, '.macros'))
344     def emit(self):
345         self.create_include_paths()
346         self.create_macros()
347         self.create_settings_file() 
349 class CodeliteIntegrationGenerator(IdeIntegrationGenerator):
351     def __init__(self, gbuildparser, ide):
352         IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
354     def emit(self):
355         self.create_workspace_file()
356         for module in self.gbuildparser.modulenamelist:
357             self.create_project_file(module)
358         #self.create_project_file('vcl')
360     def create_workspace_file(self):
361         root_node = ET.Element('CodeLite_Workspace', Name='libo2', Database='./libo2.tags', Version='10.0.0')
362         for module in self.gbuildparser.modulenamelist:
363             ET.SubElement(root_node, 'Project', Name=module, Path='%s/%s.project' % (module, module), Active='No')
364         build_matrix_node = ET.SubElement(root_node, 'BuildMatrix')
365         workspace_config_node = ET.SubElement(build_matrix_node, 'WorkspaceConfiguration', Name='Debug', Selected='yes')
366         ET.SubElement(workspace_config_node, 'Environment')
367         for module in self.gbuildparser.modulenamelist:
368             ET.SubElement(workspace_config_node, 'Project', Name=module, ConfigName='Debug')
369         workspace_config_node = ET.SubElement(build_matrix_node, 'WorkspaceConfiguration', Name='Release', Selected='yes')
370         ET.SubElement(workspace_config_node, 'Environment')
371         for module in self.gbuildparser.modulenamelist:
372             ET.SubElement(workspace_config_node, 'Project', Name=module, ConfigName='Release')
374         self.write_pretty_xml(root_node, os.path.join(self.gbuildparser.builddir, 'libo2.workspace'))
376     def create_project_file(self, module_name):
377         root_node = ET.Element('CodeLite_Project', Name=module_name, InternalType='')
378         ET.SubElement(root_node, 'Plugins')
380         # add CXX files
381         virtual_dirs = collections.defaultdict(set)
382         for target_path in self.gbuildparser.target_by_path.keys():
383             if target_path.startswith(module_name+'/'):
384                 for target in self.gbuildparser.target_by_path[target_path]:
385                     for file in target.cxxobjects:
386                         relative_file = '/'.join(file.split('/')[1:])
387                         path = '/'.join(file.split('/')[1:-1])
388                         virtual_dirs[path].add(relative_file + '.cxx')
389         # add HXX files
390         all_libs = set(self.gbuildparser.libs) | set(self.gbuildparser.exes)
391         for lib in all_libs:
392             if lib.name == module_name:
393                 for hdir in lib.include:
394                     # only want the module-internal ones
395                     if hdir.startswith(module_name+'/'):
396                         for hf in os.listdir(hdir):
397                             if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
398                                 path = '/'.join(hf.split('/')[1:-1])
399                                 virtual_dirs[path].add(hf)
400         # add HXX files from the root/include/** folders
401         module_include = os.path.join(self.gbuildparser.builddir, 'include', module_name)
402         if os.path.exists(module_include):
403             for hf in os.listdir(module_include):
404                 if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
405                     path = '../include/' + ('/'.join(hf.split('/')[1:-1]))
406                     virtual_dirs['include/' + module_name].add('../include/' + module_name + '/' + hf)
408         for vd_name in sorted(virtual_dirs.keys()):
409             vd_files = sorted(virtual_dirs[vd_name])
410             parent_node = root_node
411             for subname in vd_name.split('/'):
412                 parent_node = ET.SubElement(parent_node, 'VirtualDirectory', Name=subname)
413             for file in vd_files:
414                 ET.SubElement(parent_node, 'File', Name=file)
416         ET.SubElement(root_node, 'Description')
417         ET.SubElement(root_node, 'Dependencies')
418         ET.SubElement(root_node, 'Dependencies', Name='Debug')
419         ET.SubElement(root_node, 'Dependencies', Name='Release')
421         settingstemplate = """\
422   <Settings Type="Dynamic Library">
423     <GlobalSettings>
424       <Compiler Options="" C_Options="" Assembler="">
425         <IncludePath Value="."/>
426       </Compiler>
427       <Linker Options="">
428         <LibraryPath Value="."/>
429       </Linker>
430       <ResourceCompiler Options=""/>
431     </GlobalSettings>
432     <Configuration Name="Debug" CompilerType="clang( based on LLVM 3.5.0 )" DebuggerType="GNU gdb debugger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
433       <Compiler Options="-g" C_Options="-g" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
434         <IncludePath Value="."/>
435       </Compiler>
436       <Linker Options="" Required="yes"/>
437       <ResourceCompiler Options="" Required="no"/>
438       <General OutputFile="" IntermediateDirectory="./Debug" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
439       <BuildSystem Name="Default"/>
440       <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
441         <![CDATA[]]>
442       </Environment>
443       <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
444         <DebuggerSearchPaths/>
445         <PostConnectCommands/>
446         <StartupCommands/>
447       </Debugger>
448       <PreBuild/>
449       <PostBuild/>
450       <CustomBuild Enabled="yes">
451         <RebuildCommand/>
452         <CleanCommand>make %s.clean</CleanCommand>
453         <BuildCommand>make %s.build</BuildCommand>
454         <PreprocessFileCommand/>
455         <SingleFileCommand/>
456         <MakefileGenerationCommand/>
457         <ThirdPartyToolName>None</ThirdPartyToolName>
458         <WorkingDirectory>$(WorkspacePath)</WorkingDirectory>
459       </CustomBuild>
460       <AdditionalRules>
461         <CustomPostBuild/>
462         <CustomPreBuild/>
463       </AdditionalRules>
464       <Completion EnableCpp11="no" EnableCpp14="no">
465         <ClangCmpFlagsC/>
466         <ClangCmpFlags/>
467         <ClangPP/>
468         <SearchPaths/>
469       </Completion>
470     </Configuration>
471     <Configuration Name="Release" CompilerType="clang( based on LLVM 3.5.0 )" DebuggerType="GNU gdb debugger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
472       <Compiler Options="" C_Options="" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
473         <IncludePath Value="."/>
474       </Compiler>
475       <Linker Options="-O2" Required="yes"/>
476       <ResourceCompiler Options="" Required="no"/>
477       <General OutputFile="" IntermediateDirectory="./Release" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
478       <BuildSystem Name="Default"/>
479       <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
480         <![CDATA[]]>
481       </Environment>
482       <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
483         <DebuggerSearchPaths/>
484         <PostConnectCommands/>
485         <StartupCommands/>
486       </Debugger>
487       <PreBuild/>
488       <PostBuild/>
489       <CustomBuild Enabled="yes">
490         <RebuildCommand/>
491         <CleanCommand>make %s.clean</CleanCommand>
492         <BuildCommand>make %s.build</BuildCommand>
493         <PreprocessFileCommand/>
494         <SingleFileCommand/>
495         <MakefileGenerationCommand/>
496         <ThirdPartyToolName>None</ThirdPartyToolName>
497         <WorkingDirectory>$(WorkspacePath)</WorkingDirectory>
498       </CustomBuild>
499       <AdditionalRules>
500         <CustomPostBuild/>
501         <CustomPreBuild/>
502       </AdditionalRules>
503       <Completion EnableCpp11="no" EnableCpp14="no">
504         <ClangCmpFlagsC/>
505         <ClangCmpFlags/>
506         <ClangPP/>
507         <SearchPaths/>
508       </Completion>
509     </Configuration>
510   </Settings>
512         root_node.append(ET.fromstring(settingstemplate % (module_name, module_name, module_name, module_name)))
514         self.write_pretty_xml(root_node, os.path.join(self.gbuildparser.builddir, module_name, '%s.project' % module_name))
516     def write_pretty_xml(self, node, file_path):
517         xml_str = ET.tostring(node, encoding='unicode')
518         pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
519         with open(file_path, 'w') as f:
520             f.write(pretty_str.decode())
522 class DebugIntegrationGenerator(IdeIntegrationGenerator):
524     def __init__(self, gbuildparser, ide):
525         IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
527     def emit(self):
528         print(self.gbuildparser.srcdir)
529         print(self.gbuildparser.builddir)
530         for lib in self.gbuildparser.libs:
531             print(lib)
532         for exe in self.gbuildparser.exes:
533             print(exe)
534         for test in self.gbuildparser.tests:
535             print(test)
538 class VimIntegrationGenerator(IdeIntegrationGenerator):
540     def __init__(self, gbuildparser, ide):
541         IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
543     def emit(self):
544         global_list = []
545         for lib in set(self.gbuildparser.libs) | set(self.gbuildparser.tests) | set(self.gbuildparser.exes):
546             entries = []
547             for file in lib.cxxobjects:
548                 filePath = os.path.join(self.gbuildparser.srcdir, file) + ".cxx"
549                 entry = {'directory': lib.location, 'file': filePath, 'command': self.generateCommand(lib, filePath)}
550                 entries.append(entry)
551             global_list.extend(entries)
552         with open('compile_commands.json', 'w') as export_file:
553             json.dump(global_list, export_file)
555     def generateCommand(self, lib, file):
556         command = 'clang++ -Wall'
557         for key, value in lib.defs.items():
558             command += ' -D'
559             command += key
560             if value is not None:
561                 command += '='
562                 command += value
564         for include in lib.include:
565             command += ' -I'
566             command += include
567         for isystem in lib.include_sys:
568             command += ' -isystem '
569             command += isystem
570         for cxxflag in lib.cxxflags:
571             command += ' '
572             command += cxxflag
573         command += ' -c '
574         command += file
575         return command
578 class KdevelopIntegrationGenerator(IdeIntegrationGenerator):
580     def encode_int(self, i):
581         temp = '%08x' % i
582         return '\\x%s\\x%s\\x%s\\x%s' % (temp[0:2], temp[2:4], temp[4:6], temp[6:8])
584     def encode_string(self, string):
585         result = self.encode_int(len(string) * 2)
586         for c in string.encode('utf-16-be'):
587             if c in range(32, 126):
588                 result += chr(c)
589             else:
590                 result += '\\x%02x' % c
591         return result
593     def generate_buildsystemconfigtool(self, configid, tool, args, exe, typenr):
594         return KdevelopIntegrationGenerator.buildsystemconfigtooltemplate % {'configid': configid, 'tool': tool,
595                                                                              'args': args, 'exe': exe, 'typenr': typenr}
597     buildsystemconfigtooltemplate = """
598 [CustomBuildSystem][BuildConfig%(configid)d][Tool%(tool)s]
599 Arguments=%(args)s
600 Enabled=true
601 Environment=
602 Executable=%(exe)s
603 Type=%(typenr)d
607     def generate_buildsystemconfig(self, configid, moduledir, builddir, title, buildparms=''):
608         result = KdevelopIntegrationGenerator.buildsystemconfigtemplate % {'configid': configid, 'builddir': builddir,
609                                                                            'title': title}
610         result += self.generate_buildsystemconfigtool(configid, 'Clean', 'clean %s' % buildparms,
611                                                       self.gbuildparser.makecmd, 3)
612         result += self.generate_buildsystemconfigtool(configid, 'Build', 'all %s' % buildparms,
613                                                       self.gbuildparser.makecmd, 0)
614         return result
616     buildsystemconfigtemplate = """
617 [CustomBuildSystem][BuildConfig%(configid)d]
618 BuildDir=file://%(builddir)s
619 Title=%(title)s
623     def generate_buildsystem(self, moduledir):
624         result = KdevelopIntegrationGenerator.buildsystemtemplate % {'defaultconfigid': 0}
625         result += self.generate_buildsystemconfig(0, moduledir, moduledir, 'Module Build -- Release')
626         result += self.generate_buildsystemconfig(1, moduledir, self.gbuildparser.builddir, 'Full Build -- Release')
627         result += self.generate_buildsystemconfig(2, moduledir, moduledir, 'Module Build -- Debug', 'debug=T')
628         result += self.generate_buildsystemconfig(3, moduledir, self.gbuildparser.builddir, 'Full Build -- Debug',
629                                                   'debug=T')
630         return result
632     buildsystemtemplate = """
633 [CustomBuildSystem]
634 CurrentConfiguration=BuildConfig%(defaultconfigid)d
638     def generate_launch(self, launchid, launchname, executablepath, args, workdir):
639         return KdevelopIntegrationGenerator.launchtemplate % {'launchid': launchid, 'launchname': launchname,
640                                                               'executablepath': executablepath, 'args': args,
641                                                               'workdir': workdir}
643     launchtemplate = """
644 [Launch][Launch Configuration %(launchid)d]
645 Configured Launch Modes=execute
646 Configured Launchers=nativeAppLauncher
647 Name=%(launchname)s
648 Type=Native Application
650 [Launch][Launch Configuration %(launchid)d][Data]
651 Arguments=%(args)s
652 Dependencies=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x00)
653 Dependency Action=Nothing
654 EnvironmentGroup=default
655 Executable=file://%(executablepath)s
656 External Terminal=konsole --noclose --workdir %%workdir -e %%exe
657 Project Target=
658 Use External Terminal=false
659 Working Directory=file://%(workdir)s
660 isExecutable=true
664     def generate_launches(self, moduledir):
665         launches = ','.join(['Launch Configuration %d' % i for i in range(7)])
666         result = KdevelopIntegrationGenerator.launchestemplate % {'launches': launches}
667         result += self.generate_launch(0, 'Local tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
668                                        'unitcheck', moduledir)
669         result += self.generate_launch(1, 'Local tests -- slow tests (unitcheck, slowcheck, screenshot)', self.gbuildparser.makecmd,
670                                        'unitcheck slowcheck screenshot', moduledir)
671         result += self.generate_launch(2, 'Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
672                                        self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck', moduledir)
673         result += self.generate_launch(3, 'Global tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
674                                        'unitcheck', self.gbuildparser.builddir)
675         result += self.generate_launch(4, 'Global tests -- slow tests (unitcheck, slowcheck, screenshot)',
676                                        self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot', self.gbuildparser.builddir)
677         result += self.generate_launch(5, 'Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
678                                        self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck',
679                                        self.gbuildparser.builddir)
680         result += self.generate_launch(6, 'Run LibreOffice',
681                                        os.path.join(self.gbuildparser.instdir, 'program/soffice.bin'), '',
682                                        self.gbuildparser.instdir)
683         return result
685     launchestemplate = """
686 [Launch]
687 Launch Configurations=%(launches)s
691     def write_modulebeef(self, moduledir, modulename):
692         beefdir = os.path.join(moduledir, '.kdev4')
693         os.mkdir(beefdir)
694         beeffile = open(os.path.join(beefdir, 'Module_%s.kdev4' % modulename), 'w')
695         beeffile.write(self.generate_buildsystem(moduledir))
696         beeffile.write(self.generate_launches(moduledir))
697         beeffile.close()
699     def write_modulestub(self, moduledir, modulename):
700         stubfile = open(os.path.join(moduledir, 'Module_%s.kdev4' % modulename), 'w')
701         stubfile.write(KdevelopIntegrationGenerator.modulestubtemplate % {'modulename': modulename,
702                                                                           'builditem': self.encode_string(
703                                                                               'Module_%s' % modulename)})
704         stubfile.close()
706     modulestubtemplate = """
707 [Buildset]
708 BuildItems=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x0b\\x00\\x00\\x00\\x00\\x01%(builditem)s)
710 [Project]
711 Name=Module_%(modulename)s
712 Manager=KDevCustomBuildSystem
713 VersionControl=kdevgit
716     def write_includepaths(self, path):
717         includedirfile = open(os.path.join(path, '.kdev_include_paths'), 'w')
718         include = set()
719         for target in self.gbuildparser.target_by_path[path]:
720             include |= set(target.include)
721         includedirfile.write('\n'.join(include))
722         includedirfile.close()
724     def __init__(self, gbuildparser, ide):
725         IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
727     def emit(self):
728         for path in self.gbuildparser.target_by_path:
729             self.write_includepaths(path)
730         for location in self.gbuildparser.target_by_location:
731             for f in os.listdir(location):
732                 if f.endswith('.kdev4'):
733                     try:
734                         os.remove(os.path.join(location, f))
735                     except OSError:
736                         shutil.rmtree(os.path.join(location, f))
737         for location in self.gbuildparser.target_by_location:
738             modulename = os.path.split(location)[1]
739             self.write_modulestub(location, modulename)
740             self.write_modulebeef(location, modulename)
743 class XcodeIntegrationGenerator(IdeIntegrationGenerator):
745     def indent(self, file, level):
746         if level == 0:
747             return
748         for i in range(0, level):
749             file.write(' ')
751     def write_object(self, object, file, indent):
752         if isinstance(object, int):
753             file.write('%d' % object)
754         elif isinstance(object, str) and not re.search('[^A-Za-z0-9_]', object):
755             file.write('%s' % object)
756         elif isinstance(object, str):
757             file.write('"%s"' % object)
758         elif isinstance(object, dict):
759             self.write_dict(object, file, indent)
761     # Write a dictionary out as an "old-style (NeXT) ASCII plist"
762     def write_dict(self, dict, file, indent):
763         file.write('{')
764         file.write('\n')
765         for key in sorted(dict.keys()):
766             self.indent(file, indent + 1)
767             file.write('%s = ' % key)
768             self.write_object(dict[key], file, indent + 1)
769             file.write(';\n')
770         self.indent(file, indent)
771         file.write('}')
773     def write_dict_to_plist(self, dict, file):
774         file.write('// !$*UTF8*$!\n')
775         self.write_dict(dict, file, 0)
777     def get_product_type(self, modulename):
778         if modulename in self.gbuildparser.libs:
779             return 'com.apple.product-type.library.dynamic'
780         elif modulename in self.gbuildparser.exes:
781             return 'com.apple.product-type.something'
783     counter = 0
785     def generate_id(self):
786         XcodeIntegrationGenerator.counter = XcodeIntegrationGenerator.counter + 1
787         return str('X%07x' % XcodeIntegrationGenerator.counter)
789     def generate_build_phases(self, modulename):
790         result = [self.sourcesBuildPhaseId]
791         return result
793     def generate_root_object(self, modulename):
794         result = {'isa': 'PBXProject',
795                   'attributes': {'LastUpgradeCheck': '0500',
796                                  'ORGANIZATIONNAME': 'LibreOffice'},
797                   'buildConfigurationList': self.generate_id(),
798                   'compatibilityVersion': 'Xcode 3.2',
799                   'hasScannedForEncodings': 0,
800                   'knownRegions': ['en'],
801                   'mainGroup': self.mainGroupId,
802                   'productRefGroup': self.productRefGroupId,
803                   'projectDirPath': '',
804                   'projectRoot': '',
805                   'targets': self.targetId}
806         return result
808     def generate_target(self, modulename):
809         result = {'isa': 'PBXNativeTarget',
810                   'buildConfigurationList': self.generate_id(),
811                   'buildPhases': self.generate_build_phases(modulename),
812                   'buildRules': [],
813                   'dependencies': [],
814                   'name': modulename,
815                   'productName': modulename,
816                   'productReference': self.productReferenceId,
817                   'productType': self.get_product_type(modulename)}
818         return result
820     def generate_main_group(self, modulename):
821         result = {'isa': 'PBXGroup',
822                   'children': [self.subMainGroupId, self.productGroupId],
823                   'sourceTree': '<group>'}
824         return result
826     def generate_sub_main_children(self, modulename):
827         return {}
829     def generate_sub_main_group(self, modulename):
830         result = {'isa': 'PBXGroup',
831                   'children': self.generate_sub_main_children(modulename),
832                   'path': modulename,
833                   'sourceTree': '<group>'}
834         return result
836     def generate_product_group(self, modulename):
837         result = {'isa': 'PBXGroup',
838                   'children': [self.productReferenceId],
839                   'name': 'Products',
840                   'sourceTree': '<group>'}
841         return result
843     def build_source_list(self, module):
844         self.sourceRefList = {}
845         self.sourceList = {}
847         for i in module.cxxobjects:
848             ref = self.generate_id()
849             self.sourceList[self.generate_id()] = ref
850             self.sourceRefList[ref] = {'lastKnownFileType': 'sourcecode.cpp.cpp',
851                                        'path': i + '.cxx',
852                                        'sourceTree': '<group>'}
854     def generate_sources_build_phase(self, modulename):
855         result = {'isa': 'PBXSourcesBuildPhase',
856                   'buildActionMask': 2147483647,
857                   'files': self.sourceList.keys(),
858                   'runOnlyForDeploymentPostprocessing': 0}
859         return result
861     def generate_project(self, target):
862         self.rootObjectId = self.generate_id()
863         self.mainGroupId = self.generate_id()
864         self.subMainGroupId = self.generate_id()
865         self.productReferenceId = self.generate_id()
866         self.productRefGroupId = self.generate_id()
867         self.productGroupId = self.generate_id()
868         self.targetId = self.generate_id()
869         self.build_source_list(target)
870         self.sourcesBuildPhaseId = self.generate_id()
871         objects = {self.rootObjectId: self.generate_root_object(target),
872                    self.targetId: self.generate_target(target),
873                    self.mainGroupId: self.generate_main_group(target),
874                    self.subMainGroupId: self.generate_sub_main_group(target),
875                    self.productGroupId: self.generate_product_group(target),
876                    self.sourcesBuildPhaseId: self.generate_sources_build_phase(target)
877                    }
878         for i in self.sourceList.keys():
879             ref = self.sourceList[i]
880             objects[i] = {'isa': 'PBXBuildFile',
881                           'fileRef': ref}
882             objects[ref] = {'isa': 'PBXFileReference',
883                             'lastKnownFileType': self.sourceRefList[ref]['lastKnownFileType'],
884                             'path': self.sourceRefList[ref]['path']}
885         project = {'archiveVersion': 1,
886                    'classes': {},
887                    'objectVersion': 46,
888                    'objects': objects,
889                    'rootObject': self.rootObjectId}
890         return project
892     # For some reverse-engineered documentation on the project.pbxproj format,
893     # see http://www.monobjc.net/xcode-project-file-format.html .
894     def write_xcodeproj(self, moduledir, target):
895         xcodeprojdir = os.path.join(moduledir, '%s.xcodeproj' % target.target_name())
896         try:
897             os.mkdir(xcodeprojdir)
898         except:
899             pass
900         self.write_dict_to_plist(self.generate_project(target),
901                                  open(os.path.join(xcodeprojdir, 'project.pbxproj'), 'w'))
903     def __init__(self, gbuildparser, ide):
904         IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
906     def emit(self):
907         self.rootlocation = './'
908         for location in self.gbuildparser.target_by_location:
909             # module = location.split('/')[-1]
910             # module_directory = os.path.join(self.rootlocation, module)
911             for target in self.gbuildparser.target_by_location[location]:
912                 # project_path = os.path.join(module_directory, '%s.pbxroj' % target.target_name())
913                 self.write_xcodeproj(location, target)
916 class VisualStudioIntegrationGenerator(IdeIntegrationGenerator):
918     def __init__(self, gbuildparser, ide):
919         IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
920         self.toolset = os.environ['VCTOOLSET']
921         self.solution_directory = self.gbuildparser.builddir
922         self.configurations = {
923             'Build': {
924                 'build': self.module_make_command('%(target)s'),
925                 'clean': self.module_make_command('%(target)s.clean'),
926                 'rebuild': self.module_make_command('%(target)s.clean %(target)s')
927             },
928             'Unit Tests': {
929                 'build': self.module_make_command('unitcheck'),
930                 'clean': self.module_make_command('clean'),
931                 'rebuild': self.module_make_command('clean unitcheck'),
932             },
933             'Integration tests': {
934                 'build': self.module_make_command('unitcheck slowcheck screenshot subsequentcheck'),
935                 'clean': self.module_make_command('clean'),
936                 'rebuild': self.module_make_command('clean unitcheck slowcheck screenshot subsequentcheck')
937             }
938         }
940     def module_make_command(self, targets):
941         return '%(sh)s -c "PATH=\\"/bin:$PATH\\";BUILDDIR=\\"%(builddir)s\\" %(makecmd)s -rsC %(location)s ' + targets + '"'
943     class Project:
945         def __init__(self, guid, target, project_path):
946             self.guid = guid
947             self.target = target
948             self.path = project_path
950     def emit(self):
951         all_projects = []
952         for location in self.gbuildparser.target_by_location:
953             projects = []
954             module = location.split('/')[-1]
955             module_directory = os.path.join(self.solution_directory, module)
956             for target in self.gbuildparser.target_by_location[location]:
957                 project_path = os.path.join(module_directory, '%s.vcxproj' % target.target_name())
958                 project_guid = self.write_project(project_path, target)
959                 p = VisualStudioIntegrationGenerator.Project(project_guid, target, project_path)
960                 projects.append(p)
961             self.write_solution(os.path.join(module_directory, '%s.sln' % module), projects)
962             all_projects += projects
964         self.write_solution(os.path.join(self.solution_directory, 'LibreOffice.sln'), all_projects)
966     @staticmethod
967     def gen_guid(category, name):
968         return str(uuid.uuid5(uuid.NAMESPACE_URL, 'vnd.libreoffice.vs-ide-integration:' + category + '/' + urllib.parse.quote(name))).upper()
970     nmake_project_guid = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
971     nmake_folder_guid = '2150E333-8FDC-42A3-9474-1A3956D46DE8'
973     def get_dependency_libs(self, linked_libs, library_projects):
974         dependency_libs = {}
975         for linked_lib in linked_libs:
976             for library_project in library_projects:
977                 if library_project.target.library_name() == linked_lib:
978                     dependency_libs[library_project.guid] = library_project
979         return dependency_libs
981     def write_solution(self, solution_path, projects):
982         print('Solution %s:' % os.path.splitext(os.path.basename(solution_path))[0], end='')
983         library_projects = [project for project in projects if project.target in self.gbuildparser.libs]
984         test_projects = [project for project in projects if project.target in self.gbuildparser.tests]
985         executable_projects = [project for project in projects if project.target in self.gbuildparser.exes]
986         with open(solution_path, 'w') as f:
987             f.write('Microsoft Visual Studio Solution File, Format Version 12.00\n')
988             for project in projects:
989                 target = project.target
990                 print(' %s' % target.target_name(), end='')
991                 proj_path = os.path.relpath(project.path, os.path.abspath(os.path.dirname(solution_path)))
992                 f.write('Project("{%s}") = "%s", "%s", "{%s}"\n' %
993                         (VisualStudioIntegrationGenerator.nmake_project_guid,
994                          target.short_name(), proj_path, project.guid))
995                 libs_in_solution = self.get_dependency_libs(target.linked_libs,
996                                                             library_projects)
997                 if libs_in_solution:
998                     f.write('\tProjectSection(ProjectDependencies) = postProject\n')
999                     for lib_guid in libs_in_solution.keys():
1000                         f.write('\t\t{%(guid)s} = {%(guid)s}\n' % {'guid': lib_guid})
1001                     f.write('\tEndProjectSection\n')
1002                 f.write('EndProject\n')
1003             f.write('Project("{%s}") = "Utility", "Utility", "{6778240E-8B6B-47A0-AC31-7E7A257B97E6}"\n' %
1004                     (VisualStudioIntegrationGenerator.nmake_folder_guid))
1005             f.write('\tProjectSection(SolutionItems) = preProject\n')
1006             # The natvis file gives pretty-printed variable values when debugging
1007             natvis_path = os.path.join(gbuildparser.srcdir, 'solenv/vs/LibreOffice.natvis')
1008             f.write('\t\t%(natvis)s = %(natvis)s\n' % {'natvis': natvis_path})
1009             f.write('\tEndProjectSection\n')
1010             f.write('EndProject\n')
1011             # Folders to group tests/libraries/executables
1012             nmake_tests_guid = 'CF544F7B-9D02-4D83-8370-5887851209B7'
1013             nmake_libraries_guid = 'C624F43D-616C-4627-B58F-F5C2047B7BDC'
1014             nmake_executables_guid = '1CD80999-9FA9-4BA9-B4D9-6E33035CF648'
1015             f.write('Project("{%s}") = "Tests", "Tests", "{%s}"\n' %
1016                     (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_tests_guid))
1017             f.write('EndProject\n')
1018             f.write('Project("{%s}") = "Libraries", "Libraries", "{%s}"\n' %
1019                     (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_libraries_guid))
1020             f.write('EndProject\n')
1021             f.write('Project("{%s}") = "Executables", "Executables", "{%s}"\n' %
1022                     (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_executables_guid))
1023             f.write('EndProject\n')
1024             # end Folders to group tests/libraries/executables
1025             f.write('Global\n')
1026             platform = 'Win32'
1027             f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
1028             for cfg in self.configurations:
1029                 f.write('\t\t%(cfg)s|%(platform)s = %(cfg)s|%(platform)s\n' % {'cfg': cfg, 'platform': platform})
1030             f.write('\tEndGlobalSection\n')
1031             # Group projects to folders
1032             f.write('\tGlobalSection(NestedProjects) = preSolution\n')
1033             for project in test_projects:
1034                 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_tests_guid))
1035             for project in library_projects:
1036                 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_libraries_guid))
1037             for project in executable_projects:
1038                 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_executables_guid))
1039             f.write('\tEndGlobalSection\n')
1040             # end Group projects to folders
1041             f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
1042             # Specifies project configurations for solution configuration
1043             for project in projects:
1044                 for cfg in self.configurations:
1045                     params = {'guid': project.guid, 'sol_cfg': cfg, 'proj_cfg': cfg, 'platform': platform}
1046                     f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.ActiveCfg = %(proj_cfg)s|%(platform)s\n' % params)
1047                     # Build.0 is basically 'Build checkbox' in configuration manager
1048                     f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.Build.0 = %(proj_cfg)s|%(platform)s\n' % params)
1049             f.write('\tEndGlobalSection\n')
1050             f.write('EndGlobal\n')
1051         print('')
1053     @staticmethod
1054     def to_long_names(shortnames):
1055         if platform == "cygwin":
1056             return (subprocess.check_output(["cygpath", "-wal"] + shortnames).decode("utf-8", "strict").rstrip()).split("\n")
1057         else:
1058             return shortnames
1060     # Unescape the values: \"tklo.dll\" => "tklo.dll"
1061     escapepattern = re.compile(r'\\(.)')
1063     @staticmethod
1064     def defs_list(defs):
1065         defines_list = []
1066         # List defines
1067         for key, value in defs.items():
1068             define = key
1069             if value is not None:
1070                 define += '=' + VisualStudioIntegrationGenerator.escapepattern.sub(r'\1', value)
1071             defines_list.append(define)
1072         return defines_list
1074     def write_project(self, project_path, target):
1075         # See info at http://blogs.msdn.com/b/visualstudio/archive/2010/05/14/a-guide-to-vcxproj-and-props-file-structure.aspx
1076         folder = os.path.dirname(project_path)
1077         if not os.path.exists(folder):
1078             os.makedirs(folder)
1079         project_guid = self.gen_guid('project', target.short_name())
1080         cxxflags = ' '.join(target.cxxflags)
1081         ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
1082         ET.register_namespace('', ns)
1083         proj_node = ET.Element('{%s}Project' % ns, DefaultTargets='Build', ToolsVersion='4.0')
1084         proj_confs_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns, Label='ProjectConfigurations')
1085         platform = 'Win32'
1086         for configuration in self.configurations:
1087             proj_conf_node = ET.SubElement(proj_confs_node,
1088                                            '{%s}ProjectConfiguration' % ns,
1089                                            Include='%s|%s' % (configuration, platform))
1090             conf_node = ET.SubElement(proj_conf_node, '{%s}Configuration' % ns)
1091             conf_node.text = configuration
1092             platform_node = ET.SubElement(proj_conf_node, '{%s}Platform' % ns)
1093             platform_node.text = platform
1095         globals_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='Globals')
1096         proj_guid_node = ET.SubElement(globals_node, '{%s}ProjectGuid' % ns)
1097         proj_guid_node.text = '{%s}' % project_guid
1098         proj_keyword_node = ET.SubElement(globals_node, '{%s}Keyword' % ns)
1099         proj_keyword_node.text = 'MakeFileProj'
1100         proj_name_node = ET.SubElement(globals_node, '{%s}ProjectName' % ns)
1101         proj_name_node.text = target.short_name()
1103         ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.Default.props')
1104         for configuration in self.configurations:
1105             conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label="Configuration",
1106                                       Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
1107             # Type of project used by the MSBuild to determine build process, see Microsoft.Makefile.targets
1108             conf_type_node = ET.SubElement(conf_node, '{%s}ConfigurationType' % ns)
1109             conf_type_node.text = 'Makefile'
1110             # This defines the version of Visual Studio which can show next to project names in the Solution Explorer
1111             platform_toolset_node = ET.SubElement(conf_node, '{%s}PlatformToolset' % ns)
1112             platform_toolset_node.text = self.toolset
1114         ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.props')
1115         ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionSettings')
1116         for configuration in self.configurations:
1117             prop_sheets_node = ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='Configuration',
1118                                              Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
1119             ET.SubElement(prop_sheets_node, '{%s}Import' % ns,
1120                           Project='$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props',
1121                           Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')",
1122                           Label='LocalAppDataPlatform')
1124         ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='UserMacros')
1125         # VS IDE (at least "Peek definition") is allergic to paths like "C:/PROGRA~2/WI3CF2~1/10/Include/10.0.14393.0/um"; see
1126         # https://developercommunity.visualstudio.com/content/problem/139659/vc-peek-definition-fails-to-navigate-to-windows-ki.html
1127         # We need to convert to long paths here. Do this once, since it's time-consuming operation.
1128         include_path_node_text = ';'.join(self.to_long_names(target.include))
1129         for cfg_name, cfg_targets in self.configurations.items():
1130             conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns,
1131                                       Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (cfg_name, platform))
1132             nmake_params = {
1133                 'sh': os.path.join(self.gbuildparser.binpath, 'dash.exe'),
1134                 'builddir': self.gbuildparser.builddir,
1135                 'location': target.location,
1136                 'makecmd': self.gbuildparser.makecmd,
1137                 'target': target.target_name()}
1138             nmake_build_node = ET.SubElement(conf_node, '{%s}NMakeBuildCommandLine' % ns)
1139             nmake_build_node.text = cfg_targets['build'] % nmake_params
1140             nmake_clean_node = ET.SubElement(conf_node, '{%s}NMakeCleanCommandLine' % ns)
1141             nmake_clean_node.text = cfg_targets['clean'] % nmake_params
1142             nmake_rebuild_node = ET.SubElement(conf_node, '{%s}NMakeReBuildCommandLine' % ns)
1143             nmake_rebuild_node.text = cfg_targets['rebuild'] % nmake_params
1144             nmake_output_node = ET.SubElement(conf_node, '{%s}NMakeOutput' % ns)
1145             nmake_output_node.text = os.path.join(self.gbuildparser.instdir, 'program', 'soffice.bin')
1146             nmake_defs_node = ET.SubElement(conf_node, '{%s}NMakePreprocessorDefinitions' % ns)
1147             nmake_defs_node.text = ';'.join(self.defs_list(target.defs) + ['$(NMakePreprocessorDefinitions)'])
1148             include_path_node = ET.SubElement(conf_node, '{%s}IncludePath' % ns)
1149             include_path_node.text = include_path_node_text
1150             additional_options_node = ET.SubElement(conf_node, '{%s}AdditionalOptions' % ns)
1151             additional_options_node.text = cxxflags
1153         ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % ns)
1155         cxxobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1156         for cxxobject in target.cxxobjects:
1157             cxxabspath = os.path.join(self.gbuildparser.srcdir, cxxobject)
1158             cxxfile = cxxabspath + '.cxx'
1159             if os.path.isfile(cxxfile):
1160                 ET.SubElement(cxxobjects_node, '{%s}ClCompile' % ns, Include=cxxfile)
1161             else:
1162                 print('Source %s in project %s does not exist' % (cxxfile, target.target_name()))
1164         cobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1165         for cobject in target.cobjects:
1166             cabspath = os.path.join(self.gbuildparser.srcdir, cobject)
1167             cfile = cabspath + '.c'
1168             if os.path.isfile(cfile):
1169                 ET.SubElement(cobjects_node, '{%s}ClCompile' % ns, Include=cfile)
1170             else:
1171                 print('Source %s in project %s does not exist' % (cfile, target.target_name()))
1173         includes_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1174         for cxxobject in target.cxxobjects:
1175             include_abs_path = os.path.join(self.gbuildparser.srcdir, cxxobject)
1176             hxxfile = include_abs_path + '.hxx'
1177             if os.path.isfile(hxxfile):
1178                 ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hxxfile)
1179             # Few files have corresponding .h files
1180             hfile = include_abs_path + '.h'
1181             if os.path.isfile(hfile):
1182                 ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hfile)
1183         for cobject in target.cobjects:
1184             include_abs_path = os.path.join(self.gbuildparser.srcdir, cobject)
1185             hfile = include_abs_path + '.h'
1186             if os.path.isfile(hfile):
1187                 ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hfile)
1188         ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.targets')
1189         ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionTargets')
1190         self.write_pretty_xml(proj_node, project_path)
1191         self.write_filters(project_path + '.filters',
1192                            os.path.join(self.gbuildparser.srcdir, os.path.basename(target.location)),
1193                            [cxx_node.get('Include') for cxx_node in cxxobjects_node.findall('{%s}ClCompile' % ns)],
1194                            [c_node.get('Include') for c_node in cobjects_node.findall('{%s}ClCompile' % ns)],
1195                            [include_node.get('Include') for include_node in includes_node.findall('{%s}ClInclude' % ns)])
1196         return project_guid
1198     def get_filter(self, module_dir, proj_file):
1199         return '\\'.join(os.path.relpath(proj_file, module_dir).split('/')[:-1])
1201     def get_subfilters(self, proj_filter):
1202         parts = proj_filter.split('\\')
1203         subfilters = set([proj_filter]) if proj_filter else set()
1204         for i in range(1, len(parts)):
1205             subfilters.add('\\'.join(parts[:i]))
1206         return subfilters
1208     def write_pretty_xml(self, node, file_path):
1209         xml_str = ET.tostring(node, encoding='unicode')
1210         pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
1211         with open(file_path, 'w') as f:
1212             f.write(pretty_str.decode())
1214     def add_nodes(self, files_node, module_dir, tag, project_files):
1215         ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
1216         filters = set()
1217         for project_file in project_files:
1218             file_node = ET.SubElement(files_node, tag, Include=project_file)
1219             if os.path.commonprefix([module_dir, project_file]) == module_dir:
1220                 project_filter = self.get_filter(module_dir, project_file)
1221                 filter_node = ET.SubElement(file_node, '{%s}Filter' % ns)
1222                 filter_node.text = project_filter
1223                 filters |= self.get_subfilters(project_filter)
1224         return filters
1226     def write_filters(self, filters_path, module_dir, cxx_files, c_files, include_files):
1227         ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
1228         ET.register_namespace('', ns)
1229         proj_node = ET.Element('{%s}Project' % ns, ToolsVersion='4.0')
1230         filters = set()
1231         compiles_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1232         filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % ns, cxx_files)
1233         filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % ns, c_files)
1234         include_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1235         filters |= self.add_nodes(include_node, module_dir, '{%s}ClInclude' % ns, include_files)
1237         filters_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1238         for proj_filter in filters:
1239             filter_node = ET.SubElement(filters_node, '{%s}Filter' % ns, Include=proj_filter)
1240         self.write_pretty_xml(proj_node, filters_path)
1243 class QtCreatorIntegrationGenerator(IdeIntegrationGenerator):
1245     def __init__(self, gbuildparser, ide):
1246         IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
1247         self.target_by_location = {}
1248         for target in set(self.gbuildparser.libs) | set(self.gbuildparser.exes) | set(self.gbuildparser.tests):
1249             if target.location not in self.target_by_location:
1250                 self.target_by_location[target.location] = set()
1251             self.target_by_location[target.location] |= set([target])
1253         self._do_log = False  # set to 'True' to activate log of QtCreatorIntegrationGenerator
1254         if self._do_log:
1255             qtlog_path = os.path.abspath('../qtlog_.txt')
1256             self.qtlog = open(qtlog_path, 'w')
1258     def _log(self, message):
1259         if self._do_log:
1260             self.qtlog.write(message)
1262     def log_close(self):
1263         if self._do_log:
1264             self.qtlog.close()
1266     def generate_build_configs(self, lib_folder):
1267         module_folder = os.path.join(self.base_folder, lib_folder)
1268         xml = ""
1269         # In QtCreator UI, build configs are listed alphabetically,
1270         # so it can be different from the creation order.
1271         # So we prefix the names with the index.
1272         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1273             'index': '0',
1274             'base_folder': module_folder,
1275             'arg': "",
1276             'name': "1-Build %s" % lib_folder,
1277         }
1278         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1279             'index': '1',
1280             'base_folder': module_folder,
1281             'arg': "unitcheck",
1282             'name': "2-Local tests -- quick tests (unitcheck)",
1283         }
1284         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1285             'index': '2',
1286             'base_folder': module_folder,
1287             'arg': "unitcheck slowcheck screenshot",
1288             'name': "3-Local tests -- slow tests (unitcheck, slowcheck, screenshot)",
1289         }
1290         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1291             'index': '3',
1292             'base_folder': module_folder,
1293             'arg': "unitcheck slowcheck screenshot subsequentcheck",
1294             'name': "4-Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1295         }
1296         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1297             'index': '4',
1298             'base_folder': self.base_folder,
1299             'arg': "unitcheck",
1300             'name': "5-Global tests -- quick tests (unitcheck)",
1301         }
1302         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1303             'index': '5',
1304             'base_folder': self.base_folder,
1305             'arg': "unitcheck slowcheck screenshot",
1306             'name': "6-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
1307         }
1308         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1309             'index': '6',
1310             'base_folder': self.base_folder,
1311             'arg': "unitcheck slowcheck screenshot subsequentcheck",
1312             'name': "7-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1313         }
1314         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1315             'index': '7',
1316             'base_folder': self.base_folder,
1317             'arg': "build-nocheck",
1318             'name': "8-Global build -- nocheck",
1319         }
1320         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1321             'index': '8',
1322             'base_folder': self.base_folder,
1323             'arg': "",
1324             'name': "9-Global build",
1325         }
1327         xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
1328             'nb': '9',
1329         }
1330         return xml
1332     def generate_meta_build_configs(self):
1333         xml = ""
1334         # In QtCreator UI, build configs are listed alphabetically,
1335         # so it can be different from the creation order.
1336         # So we prefix the names with the index.
1337         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1338             'index': '0',
1339             'base_folder': self.base_folder,
1340             'arg': "",
1341             'name': "01-Global Build",
1342         }
1343         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1344             'index': '1',
1345             'base_folder': self.base_folder,
1346             'arg': "unitcheck",
1347             'name': "02-Global tests -- quick tests (unitcheck)",
1348         }
1349         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1350             'index': '2',
1351             'base_folder': self.base_folder,
1352             'arg': "unitcheck slowcheck screenshot",
1353             'name': "03-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
1354         }
1355         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1356             'index': '3',
1357             'base_folder': self.base_folder,
1358             'arg': "unitcheck slowcheck screenshot subsequentcheck",
1359             'name': "04-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1360         }
1361         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1362             'index': '4',
1363             'base_folder': self.base_folder,
1364             'arg': "perfcheck",
1365             'name': "05-Global tests -- performance tests (perfcheck)",
1366         }
1367         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1368             'index': '5',
1369             'base_folder': self.base_folder,
1370             'arg': "check",
1371             'name': "06-Global tests -- tests (check)",
1372         }
1373         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1374             'index': '6',
1375             'base_folder': self.base_folder,
1376             'arg': "build-nocheck",
1377             'name': "07-Global build -- nocheck",
1378         }
1379         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1380             'index': '7',
1381             'base_folder': self.base_folder,
1382             'arg': "build-l10n-only",
1383             'name': "08-Global build -- build-l10n-only",
1384         }
1385         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1386             'index': '8',
1387             'base_folder': self.base_folder,
1388             'arg': "build-non-l10n-only",
1389             'name': "09-Global build -- build-non-l10n-only",
1390         }
1391         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1392             'index': '9',
1393             'base_folder': self.base_folder,
1394             'arg': "clean",
1395             'name': "10-Global build -- clean",
1396         }
1397         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1398             'index': '10',
1399             'base_folder': self.base_folder,
1400             'arg': "clean-build",
1401             'name': "11-Global build -- clean-build",
1402         }
1403         xml += QtCreatorIntegrationGenerator.build_configs_template % {
1404             'index': '11',
1405             'base_folder': self.base_folder,
1406             'arg': "clean-host",
1407             'name': "12-Global build -- clean-host",
1408         }
1409         xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
1410             'nb': '12',
1411         }
1412         return xml
1414     # By default, QtCreator creates 2 BuildStepList : "Build" and "Clean"
1415     # but the "clean" can be empty.
1416     build_configs_template = """
1417    <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.%(index)s">
1418     <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">%(base_folder)s</value>
1419     <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
1420      <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
1421       <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
1422       <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
1423       <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1424       <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
1425       <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
1426        <value type="QString">-w</value>
1427        <value type="QString">-r</value>
1428       </valuelist>
1429       <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
1430       <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">%(arg)s</value>
1431       <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
1432      </valuemap>
1433      <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
1434      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
1435      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1436      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
1437     </valuemap>
1438     <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
1439     <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
1440     <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
1441     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">%(name)s</value>
1442     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
1443     <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">%(index)s</value>
1444     <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
1445    </valuemap>
1446    """
1448     build_configs_count_template = """
1449    <!-- nb build configurations -->
1450    <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">%(nb)s</value>
1451    """
1453     def generate_deploy_configs(self, lib_folder):
1454         xml = QtCreatorIntegrationGenerator.deploy_configs_template % {}
1455         return xml
1457     deploy_configs_template = """
1458    <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
1459     <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
1460      <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
1461      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
1462      <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1463      <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
1464     </valuemap>
1465     <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
1466     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
1467     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1468     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
1469    </valuemap>
1470    <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
1471     """
1473     def generate_run_configs(self, lib_folder):
1475         # If we use 'soffice', it's ok only for "Run", not for "Debug".
1476         # So we put "soffice.bin" that is ok for both.
1477         loexec = "%s/instdir/program/soffice.bin" % self.base_folder
1478         xml = QtCreatorIntegrationGenerator.run_configs_template % {
1479             'loexec': loexec,
1480             'workdir': self.base_folder
1481         }
1482         return xml
1484     run_configs_template = """
1485    <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
1486     <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
1487     <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
1488     <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
1489     <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
1490     <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
1491     <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
1492     <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
1493     <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
1494     <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
1495     <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
1496     <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
1497     <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
1498     <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
1499     <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
1500     <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
1501     <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
1502     <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
1503     <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
1504      <value type="int">0</value>
1505      <value type="int">1</value>
1506      <value type="int">2</value>
1507      <value type="int">3</value>
1508      <value type="int">4</value>
1509      <value type="int">5</value>
1510      <value type="int">6</value>
1511      <value type="int">7</value>
1512      <value type="int">8</value>
1513      <value type="int">9</value>
1514      <value type="int">10</value>
1515      <value type="int">11</value>
1516      <value type="int">12</value>
1517      <value type="int">13</value>
1518      <value type="int">14</value>
1519     </valuelist>
1520     <value type="int" key="PE.EnvironmentAspect.Base">2</value>
1521     <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
1523     <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
1524     <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%(loexec)s</value>
1525     <value type="bool" key="ProjectExplorer.CustomExecutableRunConfiguration.UseTerminal">false</value>
1526     <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">%(workdir)s</value>
1527     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run libreoffice/instdir/program/soffice</value>
1528     <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1529     <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
1530     <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
1531     <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
1532     <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
1533     <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
1534     <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
1535     <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
1537    </valuemap>
1538    <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
1539     """
1541     def generate_pro_shared_content(self, lib_folder):
1543         build_configs = self.generate_build_configs(lib_folder)
1544         deploy_configs = self.generate_deploy_configs(lib_folder)
1545         run_configs = self.generate_run_configs(lib_folder)
1547         xml = QtCreatorIntegrationGenerator.pro_shared_template % {
1548             'build_configs': build_configs,
1549             'deploy_configs': deploy_configs,
1550             'run_configs': run_configs,
1551         }
1552         return xml
1554     def generate_meta_pro_shared_content(self):
1556         build_configs = self.generate_meta_build_configs()
1557         deploy_configs = self.generate_deploy_configs("")
1558         run_configs = self.generate_run_configs("")
1560         xml = QtCreatorIntegrationGenerator.pro_shared_template % {
1561             'build_configs': build_configs,
1562             'deploy_configs': deploy_configs,
1563             'run_configs': run_configs,
1564         }
1565         return xml
1567     pro_shared_template = """<?xml version="1.0" encoding="UTF-8"?>
1568 <!DOCTYPE QtCreatorProject>
1569 <!-- Written by QtCreator 3.1.1, 2015-05-14T15:54:34. -->
1570 <qtcreator>
1571  <data>
1572   <variable>ProjectExplorer.Project.ActiveTarget</variable>
1573   <value type="int">0</value>
1574  </data>
1576  <!-- editor settings -->
1577  <data>
1578   <variable>ProjectExplorer.Project.EditorSettings</variable>
1579   <valuemap type="QVariantMap">
1580    <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
1581    <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
1582    <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
1583    <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
1584     <value type="QString" key="language">Cpp</value>
1585     <valuemap type="QVariantMap" key="value">
1586      <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
1587     </valuemap>
1588    </valuemap>
1589    <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
1590     <value type="QString" key="language">QmlJS</value>
1591     <valuemap type="QVariantMap" key="value">
1592      <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
1593     </valuemap>
1594    </valuemap>
1595    <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
1596    <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
1597    <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
1598    <value type="int" key="EditorConfiguration.IndentSize">4</value>
1599    <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
1600    <value type="int" key="EditorConfiguration.MarginColumn">80</value>
1601    <value type="bool" key="EditorConfiguration.MouseHiding">true</value>
1602    <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
1603    <value type="int" key="EditorConfiguration.PaddingMode">1</value>
1604    <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
1605    <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
1606    <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
1607    <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
1608    <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
1609    <value type="int" key="EditorConfiguration.TabSize">8</value>
1610    <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
1611    <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
1612    <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
1613    <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
1614    <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
1615    <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
1616   </valuemap>
1617  </data>
1619  <data>
1620   <variable>ProjectExplorer.Project.PluginSettings</variable>
1621   <valuemap type="QVariantMap"/>
1622  </data>
1624  <!-- target -->
1625  <data>
1626   <variable>ProjectExplorer.Project.Target.0</variable>
1627   <valuemap type="QVariantMap">
1628    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
1629    <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
1630    <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{0701de51-c96e-4e4f-85c3-e70b223c5076}</value>
1631    <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
1632    <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
1633    <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
1635    <!-- build configurations -->
1636    %(build_configs)s
1638    <!-- deploy configurations -->
1639    %(deploy_configs)s
1641    <!-- plugin settings -->
1642    <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
1644    <!-- run configurations -->
1645    %(run_configs)s
1647   </valuemap>
1648  </data>
1649  <!-- nb targets : 1 -->
1650  <data>
1651   <variable>ProjectExplorer.Project.TargetCount</variable>
1652   <value type="int">1</value>
1653  </data>
1654  <data>
1655   <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
1656   <value type="QByteArray">{5abcafed-86f6-49f6-b1cb-380fadd21211}</value>
1657  </data>
1658  <data>
1659   <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
1660   <value type="int">15</value>
1661  </data>
1662 </qtcreator>
1665     def get_file_path(self, src_file, ext_choices):
1666         path = os.path.join(self.gbuildparser.srcdir, src_file)
1667         for ext in ext_choices:
1668             full_path = path + ext
1669             if os.path.isfile(full_path):
1670                 return full_path
1671         return ""
1673     def get_source_path(self, src_file):
1674         return self.get_file_path(src_file, (".cxx", ".cpp", ".c", ".mm"))
1676     def get_header_path(self, src_file):
1677         return self.get_file_path(src_file, (".hxx", ".hpp", ".h"))
1679     def build_data_libs(self):
1681         self.data_libs = {}
1683         all_libs = set(self.gbuildparser.libs) | set(self.gbuildparser.exes) | set(self.gbuildparser.tests)
1684         for lib in all_libs:
1685             self._log("\nlibrary : %s, loc=%s" % (lib.short_name(), lib.location))
1686             lib_name = os.path.basename(lib.location)
1687             lib_folder = os.path.relpath(lib.location, self.base_folder)
1689             def lopath(path):
1690                 if platform == "cygwin":
1691                     # absolute paths from GbuildToJson are Windows paths,
1692                     # so convert everything to such ones
1693                     abs_path = path
1694                     if not ntpath.isabs(abs_path):
1695                         abs_path = ntpath.join(self.gbuildparser.srcdir, path)
1696                     return abs_path.replace('\\', '/')
1698                 return os.path.abspath(path)
1700             defines_list = []
1701             sources_list = []
1702             includepath_list = []
1703             # The explicit headers list is not mandatory :
1704             # QtCreator just needs 'include_path_list' to find all headers files.
1705             # But files listed in 'header_list' will be shown
1706             # in a specific "Headers" folder in QtCreator's Project panel.
1707             # We will list here only headers files of current lib.
1708             headers_list = []
1709             for file_ in lib.cxxobjects:
1710                 # the file has no extension : search it
1711                 # self._log("\n    file : %s" % file_)
1712                 path = self.get_source_path(file_)
1713                 if path:
1714                     sources_list.append(lopath(path))
1716                 # few cxxobject files have a header beside
1717                 path = self.get_header_path(file_)
1718                 if path:
1719                     headers_list.append(lopath(path))
1721             cxxflags_list = []
1722             for cxxflag in lib.cxxflags:
1723                 # extract flag for C++ standard version
1724                 if cxxflag.startswith('-std'):
1725                     cxxflags_list.append(cxxflag)
1727             # List all include paths
1728             for hdir in (lib.include + lib.include_sys):
1729                 hf_lopath = lopath(hdir)
1730                 includepath_list.append(hf_lopath)
1732             # List headers files from current lib
1733             for hdir in lib.include:
1734                 if hdir.startswith(lib.location):
1735                     for dirpath, _, files in os.walk(hdir):
1736                         for hf in files:
1737                             if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
1738                                 hf_lopath = lopath(os.path.join(dirpath, hf))
1739                                 headers_list.append(hf_lopath)
1741             # List defines
1742             for key, value in lib.defs.items():
1743                 define = key
1744                 if value is not None:
1745                     define += '=' + value
1746                 defines_list.append(define)
1748             # All data are prepared, store them for the lib.
1749             if lib_folder in self.data_libs:
1750                 self.data_libs[lib_folder]['sources'] |= set(sources_list)
1751                 self.data_libs[lib_folder]['headers'] |= set(headers_list)
1752                 self.data_libs[lib_folder]['cxxflags'] |= set(cxxflags_list)
1753                 self.data_libs[lib_folder]['includepath'] |= set(includepath_list)
1754                 self.data_libs[lib_folder]['defines'] |= set(defines_list)
1755             else:
1756                 self.data_libs[lib_folder] = {
1757                     'sources': set(sources_list),
1758                     'headers': set(headers_list),
1759                     'cxxflags': set(cxxflags_list),
1760                     'includepath': set(includepath_list),
1761                     'defines': set(defines_list),
1762                     'loc': lib.location,
1763                     'name': lib_name
1764                 }
1766     def emit(self):
1768         mode = 'w+'
1769         self.base_folder = self.gbuildparser.builddir
1771         # for .pro files, we must explicitly list all files (.c, .h)
1772         # so we can't reuse directly the same method than for kde integration.
1773         self.build_data_libs()
1775         # subdirs for the meta .pro file
1776         subdirs_meta_pro = []
1777         subdirs_list = self.data_libs.keys()
1778         # Now we can create Qt files
1779         for lib_folder in subdirs_list:
1780             sources_list = sorted(self.data_libs[lib_folder]['sources'])
1781             headers_list = sorted(self.data_libs[lib_folder]['headers'])
1782             cxxflags_list = sorted(self.data_libs[lib_folder]['cxxflags'])
1783             includepath_list = sorted(self.data_libs[lib_folder]['includepath'])
1784             defines_list = sorted(self.data_libs[lib_folder]['defines'])
1785             lib_loc = self.data_libs[lib_folder]['loc']
1786             lib_name = self.data_libs[lib_folder]['name']
1788             sources = " \\\n".join(sources_list)
1789             headers = " \\\n".join(headers_list)
1790             cxxflags = " \\\n".join(cxxflags_list)
1791             includepath = " \\\n".join(includepath_list)
1792             defines = " \\\n".join(defines_list)
1794             # create .pro file
1795             subdirs_meta_pro.append(lib_name)
1796             qt_pro_file = os.path.join(self.base_folder, lib_name, lib_name + '.pro')
1797             try:
1798                 content = QtCreatorIntegrationGenerator.pro_template % {'sources': sources, 'headers': headers,
1799                                                                         'cxxflags': cxxflags, 'includepath': includepath, 'defines': defines}
1800                 with open(qt_pro_file, mode) as fpro:
1801                     fpro.write(content)
1802                 self._log("created %s\n" % qt_pro_file)
1804             except Exception as e:
1805                 print("ERROR : creating pro file=" + qt_pro_file, file=sys.stderr)
1806                 print(e, file=sys.stderr)
1807                 temp = traceback.format_exc()  # .decode('utf8')
1808                 print(temp, file=sys.stderr)
1809                 print("\n\n", file=sys.stderr)
1811             # create .pro.shared file
1812             qt_pro_shared_file = os.path.join(self.base_folder, lib_name, lib_name + '.pro.shared')
1813             try:
1814                 with open(qt_pro_shared_file, mode) as fproshared:
1815                     fproshared.write(self.generate_pro_shared_content(lib_folder))
1816                 self._log("created %s\n" % qt_pro_shared_file)
1818             except Exception as e:
1819                 print("ERROR : creating pro.shared file=" + qt_pro_shared_file, file=sys.stderr)
1820                 print(e, file=sys.stderr)
1821                 temp = traceback.format_exc()
1822                 print(temp, file=sys.stderr)
1823                 print("\n\n", file=sys.stderr)
1825         # create meta .pro file (lists all sub projects)
1826         qt_meta_pro_file = os.path.join(self.base_folder, 'lo.pro')
1827         try:
1828             subdirs = " \\\n".join(sorted(subdirs_meta_pro))
1829             content = QtCreatorIntegrationGenerator.pro_meta_template % {'subdirs': subdirs}
1830             with open(qt_meta_pro_file, 'w+') as fmpro:
1831                 fmpro.write(content)
1833         except Exception as e:
1834             print("ERROR : creating lo.pro file=" + qt_meta_pro_file, file=sys.stderr)
1835             print(e, file=sys.stderr)
1836             temp = traceback.format_exc()
1837             print(temp, file=sys.stderr)
1838             print("\n\n", file=sys.stderr)
1840         # create meta .pro.shared file
1841         qt_meta_pro_shared_file = os.path.join(self.base_folder, 'lo.pro.shared')
1842         try:
1843             with open(qt_meta_pro_shared_file, mode) as fmproshared:
1844                 fmproshared.write(self.generate_meta_pro_shared_content())
1845             self._log("created %s\n" % qt_meta_pro_shared_file)
1847         except Exception as e:
1848             print("ERROR : creating lo.pro.shared file=" + qt_meta_pro_shared_file, file=sys.stderr)
1849             print(e, file=sys.stderr)
1850             temp = traceback.format_exc()
1851             print(temp, file=sys.stderr)
1852             print("\n\n", file=sys.stderr)
1854         self.log_close()
1856     pro_template = """TEMPLATE = lib
1857 CONFIG += console
1858 CONFIG -= app_bundle
1859 CONFIG -= qt
1861 QMAKE_CXXFLAGS += %(cxxflags)s
1863 INCLUDEPATH += %(includepath)s
1865 SOURCES += %(sources)s
1867 HEADERS += %(headers)s
1869 DEFINES += %(defines)s
1872     pro_meta_template = """TEMPLATE = subdirs
1874 SUBDIRS = %(subdirs)s
1878 def get_options():
1879     parser = argparse.ArgumentParser(
1880         description='LibreOffice gbuild IDE project generator')
1881     parser.add_argument('--ide', dest='ide', required=True,
1882                         help='the IDE to generate project files for')
1883     parser.add_argument('--make', dest='makecmd', required=True,
1884                         help='the command to execute make')
1885     return parser.parse_args()
1888 if __name__ == '__main__':
1889     args = get_options()
1890     # FIXME: Hack
1891     if args.makecmd == 'make':
1892         args.makecmd = '/usr/bin/make'
1894     paths = {}
1895     generators = {
1896         'codelite': CodeliteIntegrationGenerator,
1897         'eclipsecdt': EclipseCDTIntegrationGenerator,
1898         'kdevelop': KdevelopIntegrationGenerator,
1899         'xcode': XcodeIntegrationGenerator,
1900         'vs': VisualStudioIntegrationGenerator,
1901         'vim': VimIntegrationGenerator,
1902         'debug': DebugIntegrationGenerator,
1903         'qtcreator': QtCreatorIntegrationGenerator,
1904     }
1906     if args.ide not in generators.keys():
1907         print("Invalid ide. valid values are %s" % ','.join(generators.keys()))
1908         sys.exit(1)
1910     gbuildparser = GbuildParser(args.makecmd).parse()
1912     generators[args.ide](gbuildparser, args.ide).emit()
1913     print("Successfully created the project files.")
1915 # Local Variables:
1916 # indent-tabs-mode: nil
1917 # End:
1919 # vim: set et sw=4 ts=4: