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/.
20 import xml.etree.ElementTree as ET
21 import xml.dom.minidom as minidom
24 from sys import platform
28 class GbuildLinkTarget:
29 def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, objcxxobjects, cflags, linked_libs, link_target):
30 (self.name, self.location, self.include, self.include_sys, self.defs, self.cxxobjects, self.cxxflags, self.cobjects, self.objcxxobjects, self.cflags, self.linked_libs, self.link_target) = (
31 name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, objcxxobjects, cflags, linked_libs, link_target)
37 return not self.include and not self.defs and not self.cxxobjects and not self.cobjects and not self.linked_libs
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, objcxxobjects, cflags, linked_libs, link_target):
47 GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, objcxxobjects, cflags, linked_libs, link_target)
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):
59 class GbuildTest(GbuildLinkTarget):
60 def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, objcxxobjects, cflags, linked_libs, link_target):
61 GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, objcxxobjects, cflags, linked_libs, link_target)
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, objcxxobjects, cflags, linked_libs, link_target):
72 GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, objcxxobjects, cflags, linked_libs, link_target)
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
83 """Main data model object.
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
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')
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)
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 != 'OBJCXXOBJECTS' and obj != '+=']
117 def __split_defs(defsline):
119 alldefs = [defswitch.strip() for defswitch in defsline.strip().lstrip('-D').split(' -D') if len(defswitch) > 2]
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"""
129 defs.pop(u.strip(), '')
130 defs["LIBO_INTERNAL_ONLY"] = None
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]
138 def __lib_from_json(json):
139 (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
141 GbuildParser.libpattern.match(os.path.basename(json['MAKEFILE'])).group(1),
142 os.path.dirname(json['MAKEFILE']),
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_objs(json['OBJCXXOBJECTS']),
150 GbuildParser.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
151 json['LINKED_LIBS'].strip().split(' '),
152 json['LINKTARGET'].strip())
155 def __test_from_json(json):
156 (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
157 testname_match = GbuildParser.testpattern.match(os.path.basename(json['MAKEFILE']))
159 # Workaround strange writer test makefile setup
160 if testname_match is None:
161 testname = "StrangeWriterMakefiles"
163 testname = testname_match.group(1)
167 os.path.dirname(json['MAKEFILE']),
170 GbuildParser.__split_defs(json['DEFS']),
171 GbuildParser.__split_objs(json['CXXOBJECTS']),
172 GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
173 GbuildParser.__split_objs(json['COBJECTS']),
174 GbuildParser.__split_objs(json['OBJCXXOBJECTS']),
175 GbuildParser.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
176 json['LINKED_LIBS'].strip().split(' '),
177 json['LINKTARGET'].strip())
180 def __exe_from_json(json):
181 (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
183 GbuildParser.exepattern.match(os.path.basename(json['MAKEFILE'])).group(1),
184 os.path.dirname(json['MAKEFILE']),
187 GbuildParser.__split_defs(json['DEFS']),
188 GbuildParser.__split_objs(json['CXXOBJECTS']),
189 GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
190 GbuildParser.__split_objs(json['COBJECTS']),
191 GbuildParser.__split_objs(json['OBJCXXOBJECTS']),
192 GbuildParser.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
193 json['LINKED_LIBS'].strip().split(' '),
194 json['LINKTARGET'].strip())
197 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Library')):
198 with open(os.path.join(self.workdir, 'GbuildToJson', 'Library', jsonfilename), 'r') as f:
199 lib = self.__lib_from_json(json.load(f))
200 self.libs.append(lib)
201 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Executable')):
202 with open(os.path.join(self.workdir, 'GbuildToJson', 'Executable', jsonfilename), 'r') as f:
203 exe = self.__exe_from_json(json.load(f))
204 self.exes.append(exe)
205 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest')):
206 with open(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest', jsonfilename), 'r') as f:
207 test = self.__test_from_json(json.load(f))
208 self.tests.append(test)
209 for target in set(self.libs) | set(self.exes) | set(self.tests):
210 if target.location not in self.target_by_location:
211 self.target_by_location[target.location] = set()
212 self.target_by_location[target.location] |= set([target])
213 for cxx in target.cxxobjects:
214 path = '/'.join(cxx.split('/')[:-1])
215 if path not in self.target_by_path:
216 self.target_by_path[path] = set()
217 self.target_by_path[path] |= set([target])
218 for c in target.cobjects:
219 path = '/'.join(c.split('/')[:-1])
220 if path not in self.target_by_path:
221 self.target_by_path[path] = set()
222 self.target_by_path[path] |= set([target])
223 for location in self.target_by_location:
224 self.modulenamelist.append(os.path.split(location)[1])
228 class IdeIntegrationGenerator:
230 def __init__(self, gbuildparser, ide):
231 self.gbuildparser = gbuildparser
237 class EclipseCDTIntegrationGenerator(IdeIntegrationGenerator):
239 def __init__(self, gbuildparser, ide):
240 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
242 def create_include_paths(self):
243 for module in self.gbuildparser.modulenamelist:
244 modulepath = os.path.join(self.gbuildparser.builddir, module)
245 includedirfile = open(os.path.join(modulepath, '.eclipsesettingfile'), 'w')
247 for lib in self.gbuildparser.target_by_path.keys():
248 if lib.startswith(module+'/'):
249 modulelibs.append(lib)
251 for lib in modulelibs:
252 for target in self.gbuildparser.target_by_path[lib]:
253 include |= set(target.include)
254 includedirfile.write('\n'.join(include))
255 includedirfile.close()
258 def create_macros(self):
259 for module in self.gbuildparser.modulenamelist:
260 modulepath = os.path.join(self.gbuildparser.builddir, module)
261 macrofile = open(os.path.join(modulepath, '.macros'), 'w')
263 for lib in self.gbuildparser.target_by_path.keys():
264 if lib.startswith(module+'/'):
265 modulelibs.append(lib)
268 for lib in modulelibs:
269 for target in self.gbuildparser.target_by_path[lib]:
270 for i in target.defs.keys():
271 tmp = str(i) +','+str(target.defs[i])
272 if tmp not in defineset:
274 macrofile.write('\n'.join(defineset))
278 def create_settings_file(self):
280 settingsfiletemplate = """\
281 <?xml version="1.0" encoding="UTF-8"?>
282 <cdtprojectproperties>
283 <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths">
284 <language name="C++ Source File">
288 <language name="C Source File">
291 <language name="Object File">
294 <language name="Assembly Source File">
298 <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros">
299 <language name="C++ Source File">
302 <language name="C Source File">
305 <language name="Object File">
308 <language name="Assembly Source File">
312 </cdtprojectproperties>
315 for module in self.gbuildparser.modulenamelist:
317 modulepath = os.path.join(self.gbuildparser.builddir, module)
319 settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
320 settingsfile.write(settingsfiletemplate)
323 settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'r')
324 tempxml = settingsfile.readlines()
325 tempinclude = open(os.path.join(modulepath, '.eclipsesettingfile'), 'r')
326 tempmacro = open(os.path.join(modulepath, '.macros'), 'r')
327 for includepath in tempinclude:
328 if includepath[-1:] == "\n":
329 includepath = includepath[:-1]
330 templine = "<includepath>%s</includepath>\n" % includepath
331 tempxml.insert(5, templine)
333 for line in tempmacro:
334 macroskeyvalue = line.split(',')
335 macrokey = macroskeyvalue[0]
336 macrovalue = macroskeyvalue[1]
337 if macrovalue[-1:] == "\n":
338 macrovalue = macrovalue[:-1]
339 templine = "<macro><name>%s</name><value>%s</value></macro>\n" %(macrokey, macrovalue)
340 tempxml.insert(-13, templine)
341 tempxml="".join(tempxml)
344 settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
345 settingsfile.write(tempxml)
347 os.remove(os.path.join(modulepath, '.eclipsesettingfile'))
348 os.remove(os.path.join(modulepath, '.macros'))
351 self.create_include_paths()
353 self.create_settings_file()
355 class CodeliteIntegrationGenerator(IdeIntegrationGenerator):
357 def __init__(self, gbuildparser, ide):
358 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
361 self.create_workspace_file()
362 for module in self.gbuildparser.modulenamelist:
363 self.create_project_file(module)
364 #self.create_project_file('vcl')
366 def create_workspace_file(self):
367 root_node = ET.Element('CodeLite_Workspace', Name='libo2', Database='./libo2.tags', Version='10.0.0')
368 for module in self.gbuildparser.modulenamelist:
369 ET.SubElement(root_node, 'Project', Name=module, Path='%s/%s.project' % (module, module), Active='No')
370 build_matrix_node = ET.SubElement(root_node, 'BuildMatrix')
371 workspace_config_node = ET.SubElement(build_matrix_node, 'WorkspaceConfiguration', Name='Debug', Selected='yes')
372 ET.SubElement(workspace_config_node, 'Environment')
373 for module in self.gbuildparser.modulenamelist:
374 ET.SubElement(workspace_config_node, 'Project', Name=module, ConfigName='Debug')
375 workspace_config_node = ET.SubElement(build_matrix_node, 'WorkspaceConfiguration', Name='Release', Selected='yes')
376 ET.SubElement(workspace_config_node, 'Environment')
377 for module in self.gbuildparser.modulenamelist:
378 ET.SubElement(workspace_config_node, 'Project', Name=module, ConfigName='Release')
380 self.write_pretty_xml(root_node, os.path.join(self.gbuildparser.builddir, 'libo2.workspace'))
382 def create_project_file(self, module_name):
383 root_node = ET.Element('CodeLite_Project', Name=module_name, InternalType='')
384 ET.SubElement(root_node, 'Plugins')
387 virtual_dirs = collections.defaultdict(set)
388 for target_path in self.gbuildparser.target_by_path.keys():
389 if target_path.startswith(module_name+'/'):
390 for target in self.gbuildparser.target_by_path[target_path]:
391 for file in target.cxxobjects:
392 relative_file = '/'.join(file.split('/')[1:])
393 path = '/'.join(file.split('/')[1:-1])
394 virtual_dirs[path].add(relative_file + '.cxx')
396 all_libs = set(self.gbuildparser.libs) | set(self.gbuildparser.exes)
398 if lib.name == module_name:
399 for hdir in lib.include:
400 # only want the module-internal ones
401 if hdir.startswith(module_name+'/'):
402 for hf in os.listdir(hdir):
403 if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
404 path = '/'.join(hf.split('/')[1:-1])
405 virtual_dirs[path].add(hf)
406 # add HXX files from the root/include/** folders
407 module_include = os.path.join(self.gbuildparser.builddir, 'include', module_name)
408 if os.path.exists(module_include):
409 for hf in os.listdir(module_include):
410 if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
411 path = '../include/' + ('/'.join(hf.split('/')[1:-1]))
412 virtual_dirs['include/' + module_name].add('../include/' + module_name + '/' + hf)
414 for vd_name in sorted(virtual_dirs.keys()):
415 vd_files = sorted(virtual_dirs[vd_name])
416 parent_node = root_node
417 for subname in vd_name.split('/'):
418 parent_node = ET.SubElement(parent_node, 'VirtualDirectory', Name=subname)
419 for file in vd_files:
420 ET.SubElement(parent_node, 'File', Name=file)
422 ET.SubElement(root_node, 'Description')
423 ET.SubElement(root_node, 'Dependencies')
424 ET.SubElement(root_node, 'Dependencies', Name='Debug')
425 ET.SubElement(root_node, 'Dependencies', Name='Release')
427 settingstemplate = """\
428 <Settings Type="Dynamic Library">
430 <Compiler Options="" C_Options="" Assembler="">
431 <IncludePath Value="."/>
434 <LibraryPath Value="."/>
436 <ResourceCompiler Options=""/>
438 <Configuration Name="Debug" CompilerType="clang( based on LLVM 3.5.0 )" DebuggerType="GNU gdb debugger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
439 <Compiler Options="-g" C_Options="-g" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
440 <IncludePath Value="."/>
442 <Linker Options="" Required="yes"/>
443 <ResourceCompiler Options="" Required="no"/>
444 <General OutputFile="" IntermediateDirectory="./Debug" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
445 <BuildSystem Name="Default"/>
446 <Environment EnvVarSetName="<Use Defaults>" DbgSetName="<Use Defaults>">
449 <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
450 <DebuggerSearchPaths/>
451 <PostConnectCommands/>
456 <CustomBuild Enabled="yes">
458 <CleanCommand>make %s.clean</CleanCommand>
459 <BuildCommand>make %s.build</BuildCommand>
460 <PreprocessFileCommand/>
462 <MakefileGenerationCommand/>
463 <ThirdPartyToolName>None</ThirdPartyToolName>
464 <WorkingDirectory>$(WorkspacePath)</WorkingDirectory>
470 <Completion EnableCpp11="no" EnableCpp14="no">
477 <Configuration Name="Release" CompilerType="clang( based on LLVM 3.5.0 )" DebuggerType="GNU gdb debugger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
478 <Compiler Options="" C_Options="" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
479 <IncludePath Value="."/>
481 <Linker Options="-O2" Required="yes"/>
482 <ResourceCompiler Options="" Required="no"/>
483 <General OutputFile="" IntermediateDirectory="./Release" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
484 <BuildSystem Name="Default"/>
485 <Environment EnvVarSetName="<Use Defaults>" DbgSetName="<Use Defaults>">
488 <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
489 <DebuggerSearchPaths/>
490 <PostConnectCommands/>
495 <CustomBuild Enabled="yes">
497 <CleanCommand>make %s.clean</CleanCommand>
498 <BuildCommand>make %s.build</BuildCommand>
499 <PreprocessFileCommand/>
501 <MakefileGenerationCommand/>
502 <ThirdPartyToolName>None</ThirdPartyToolName>
503 <WorkingDirectory>$(WorkspacePath)</WorkingDirectory>
509 <Completion EnableCpp11="no" EnableCpp14="no">
518 root_node.append(ET.fromstring(settingstemplate % (module_name, module_name, module_name, module_name)))
520 self.write_pretty_xml(root_node, os.path.join(self.gbuildparser.builddir, module_name, '%s.project' % module_name))
522 def write_pretty_xml(self, node, file_path):
523 xml_str = ET.tostring(node, encoding='unicode')
524 pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
525 with open(file_path, 'w') as f:
526 f.write(pretty_str.decode())
528 class DebugIntegrationGenerator(IdeIntegrationGenerator):
530 def __init__(self, gbuildparser, ide):
531 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
534 print(self.gbuildparser.srcdir)
535 print(self.gbuildparser.builddir)
536 for lib in self.gbuildparser.libs:
538 for exe in self.gbuildparser.exes:
540 for test in self.gbuildparser.tests:
544 class VimIntegrationGenerator(IdeIntegrationGenerator):
546 def __init__(self, gbuildparser, ide):
547 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
551 for lib in set(self.gbuildparser.libs) | set(self.gbuildparser.tests) | set(self.gbuildparser.exes):
553 for file in lib.cxxobjects:
554 filePath = os.path.join(self.gbuildparser.srcdir, file) + ".cxx"
555 entry = {'directory': lib.location, 'file': filePath, 'command': self.generateCommand(lib, filePath)}
556 entries.append(entry)
557 global_list.extend(entries)
558 with open(os.path.join(self.gbuildparser.builddir, 'compile_commands.json'), 'w') as export_file:
559 json.dump(global_list, export_file)
561 def generateCommand(self, lib, file):
562 command = 'clang++ -Wall'
563 for key, value in lib.defs.items():
566 if value is not None:
570 for include in lib.include:
573 for isystem in lib.include_sys:
574 command += ' -isystem '
576 for cxxflag in lib.cxxflags:
584 class KdevelopIntegrationGenerator(IdeIntegrationGenerator):
586 def encode_int(self, i):
588 return '\\x%s\\x%s\\x%s\\x%s' % (temp[0:2], temp[2:4], temp[4:6], temp[6:8])
590 def encode_string(self, string):
591 result = self.encode_int(len(string) * 2)
592 for c in string.encode('utf-16-be'):
593 if c in range(32, 126):
596 result += '\\x%02x' % c
599 def generate_buildsystemconfigtool(self, configid, tool, args, exe, typenr):
600 return KdevelopIntegrationGenerator.buildsystemconfigtooltemplate % {'configid': configid, 'tool': tool,
601 'args': args, 'exe': exe, 'typenr': typenr}
603 buildsystemconfigtooltemplate = """
604 [CustomBuildSystem][BuildConfig%(configid)d][Tool%(tool)s]
613 def generate_buildsystemconfig(self, configid, moduledir, builddir, title, buildparms=''):
614 result = KdevelopIntegrationGenerator.buildsystemconfigtemplate % {'configid': configid, 'builddir': builddir,
616 result += self.generate_buildsystemconfigtool(configid, 'Clean', 'clean %s' % buildparms,
617 self.gbuildparser.makecmd, 3)
618 result += self.generate_buildsystemconfigtool(configid, 'Build', 'all %s' % buildparms,
619 self.gbuildparser.makecmd, 0)
622 buildsystemconfigtemplate = """
623 [CustomBuildSystem][BuildConfig%(configid)d]
624 BuildDir=file://%(builddir)s
629 def generate_buildsystem(self, moduledir):
630 result = KdevelopIntegrationGenerator.buildsystemtemplate % {'defaultconfigid': 0}
631 result += self.generate_buildsystemconfig(0, moduledir, moduledir, 'Module Build -- Release')
632 result += self.generate_buildsystemconfig(1, moduledir, self.gbuildparser.builddir, 'Full Build -- Release')
633 result += self.generate_buildsystemconfig(2, moduledir, moduledir, 'Module Build -- Debug', 'debug=T')
634 result += self.generate_buildsystemconfig(3, moduledir, self.gbuildparser.builddir, 'Full Build -- Debug',
638 buildsystemtemplate = """
640 CurrentConfiguration=BuildConfig%(defaultconfigid)d
644 def generate_launch(self, launchid, launchname, executablepath, args, workdir):
645 return KdevelopIntegrationGenerator.launchtemplate % {'launchid': launchid, 'launchname': launchname,
646 'executablepath': executablepath, 'args': args,
650 [Launch][Launch Configuration %(launchid)d]
651 Configured Launch Modes=execute
652 Configured Launchers=nativeAppLauncher
654 Type=Native Application
656 [Launch][Launch Configuration %(launchid)d][Data]
658 Dependencies=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x00)
659 Dependency Action=Nothing
660 EnvironmentGroup=default
661 Executable=file://%(executablepath)s
662 External Terminal=konsole --noclose --workdir %%workdir -e %%exe
664 Use External Terminal=false
665 Working Directory=file://%(workdir)s
670 def generate_launches(self, moduledir):
671 launches = ','.join(['Launch Configuration %d' % i for i in range(7)])
672 result = KdevelopIntegrationGenerator.launchestemplate % {'launches': launches}
673 result += self.generate_launch(0, 'Local tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
674 'unitcheck', moduledir)
675 result += self.generate_launch(1, 'Local tests -- slow tests (unitcheck, slowcheck, screenshot)', self.gbuildparser.makecmd,
676 'unitcheck slowcheck screenshot', moduledir)
677 result += self.generate_launch(2, 'Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
678 self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck', moduledir)
679 result += self.generate_launch(3, 'Global tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
680 'unitcheck', self.gbuildparser.builddir)
681 result += self.generate_launch(4, 'Global tests -- slow tests (unitcheck, slowcheck, screenshot)',
682 self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot', self.gbuildparser.builddir)
683 result += self.generate_launch(5, 'Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
684 self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck',
685 self.gbuildparser.builddir)
686 result += self.generate_launch(6, 'Run LibreOffice',
687 os.path.join(self.gbuildparser.instdir, 'program/soffice.bin'), '',
688 self.gbuildparser.instdir)
691 launchestemplate = """
693 Launch Configurations=%(launches)s
697 def write_modulebeef(self, moduledir, modulename):
698 beefdir = os.path.join(moduledir, '.kdev4')
700 beeffile = open(os.path.join(beefdir, 'Module_%s.kdev4' % modulename), 'w')
701 beeffile.write(self.generate_buildsystem(moduledir))
702 beeffile.write(self.generate_launches(moduledir))
705 def write_modulestub(self, moduledir, modulename):
706 stubfile = open(os.path.join(moduledir, 'Module_%s.kdev4' % modulename), 'w')
707 stubfile.write(KdevelopIntegrationGenerator.modulestubtemplate % {'modulename': modulename,
708 'builditem': self.encode_string(
709 'Module_%s' % modulename)})
712 modulestubtemplate = """
714 BuildItems=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x0b\\x00\\x00\\x00\\x00\\x01%(builditem)s)
717 Name=Module_%(modulename)s
718 Manager=KDevCustomBuildSystem
719 VersionControl=kdevgit
722 def write_includepaths(self, path):
723 includedirfile = open(os.path.join(path, '.kdev_include_paths'), 'w')
725 for target in self.gbuildparser.target_by_path[path]:
726 include |= set(target.include)
727 includedirfile.write('\n'.join(include))
728 includedirfile.close()
730 def __init__(self, gbuildparser, ide):
731 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
734 for path in self.gbuildparser.target_by_path:
735 self.write_includepaths(path)
736 for location in self.gbuildparser.target_by_location:
737 for f in os.listdir(location):
738 if f.endswith('.kdev4'):
740 os.remove(os.path.join(location, f))
742 shutil.rmtree(os.path.join(location, f))
743 for location in self.gbuildparser.target_by_location:
744 modulename = os.path.split(location)[1]
745 self.write_modulestub(location, modulename)
746 self.write_modulebeef(location, modulename)
749 class XcodeIntegrationGenerator(IdeIntegrationGenerator):
751 def indent(self, file, level):
754 for i in range(0, level):
757 def write_object(self, object, file, indent):
758 if isinstance(object, int):
759 file.write('%d' % object)
760 elif isinstance(object, str) and not re.search('[^A-Za-z0-9_]', object):
761 file.write('%s' % object)
762 elif isinstance(object, str):
763 file.write('"%s"' % object)
764 elif isinstance(object, dict):
765 self.write_dict(object, file, indent)
767 # Write a dictionary out as an "old-style (NeXT) ASCII plist"
768 def write_dict(self, dict, file, indent):
771 for key in sorted(dict.keys()):
772 self.indent(file, indent + 1)
773 file.write('%s = ' % key)
774 self.write_object(dict[key], file, indent + 1)
776 self.indent(file, indent)
779 def write_dict_to_plist(self, dict, file):
780 file.write('// !$*UTF8*$!\n')
781 self.write_dict(dict, file, 0)
783 def get_product_type(self, modulename):
784 if modulename in self.gbuildparser.libs:
785 return 'com.apple.product-type.library.dynamic'
786 elif modulename in self.gbuildparser.exes:
787 return 'com.apple.product-type.something'
791 def generate_id(self):
792 XcodeIntegrationGenerator.counter = XcodeIntegrationGenerator.counter + 1
793 return str('X%07x' % XcodeIntegrationGenerator.counter)
795 def generate_build_phases(self, modulename):
796 result = [self.sourcesBuildPhaseId]
799 def generate_root_object(self, modulename):
800 result = {'isa': 'PBXProject',
801 'attributes': {'LastUpgradeCheck': '0500',
802 'ORGANIZATIONNAME': 'LibreOffice'},
803 'buildConfigurationList': self.generate_id(),
804 'compatibilityVersion': 'Xcode 3.2',
805 'hasScannedForEncodings': 0,
806 'knownRegions': ['en'],
807 'mainGroup': self.mainGroupId,
808 'productRefGroup': self.productRefGroupId,
809 'projectDirPath': '',
811 'targets': self.targetId}
814 def generate_target(self, modulename):
815 result = {'isa': 'PBXNativeTarget',
816 'buildConfigurationList': self.generate_id(),
817 'buildPhases': self.generate_build_phases(modulename),
821 'productName': modulename,
822 'productReference': self.productReferenceId,
823 'productType': self.get_product_type(modulename)}
826 def generate_main_group(self, modulename):
827 result = {'isa': 'PBXGroup',
828 'children': [self.subMainGroupId, self.productGroupId],
829 'sourceTree': '<group>'}
832 def generate_sub_main_children(self, modulename):
835 def generate_sub_main_group(self, modulename):
836 result = {'isa': 'PBXGroup',
837 'children': self.generate_sub_main_children(modulename),
839 'sourceTree': '<group>'}
842 def generate_product_group(self, modulename):
843 result = {'isa': 'PBXGroup',
844 'children': [self.productReferenceId],
846 'sourceTree': '<group>'}
849 def build_source_list(self, module):
850 self.sourceRefList = {}
853 for i in module.cxxobjects:
854 ref = self.generate_id()
855 self.sourceList[self.generate_id()] = ref
856 self.sourceRefList[ref] = {'lastKnownFileType': 'sourcecode.cpp.cpp',
858 'sourceTree': '<group>'}
860 def generate_sources_build_phase(self, modulename):
861 result = {'isa': 'PBXSourcesBuildPhase',
862 'buildActionMask': 2147483647,
863 'files': self.sourceList.keys(),
864 'runOnlyForDeploymentPostprocessing': 0}
867 def generate_project(self, target):
868 self.rootObjectId = self.generate_id()
869 self.mainGroupId = self.generate_id()
870 self.subMainGroupId = self.generate_id()
871 self.productReferenceId = self.generate_id()
872 self.productRefGroupId = self.generate_id()
873 self.productGroupId = self.generate_id()
874 self.targetId = self.generate_id()
875 self.build_source_list(target)
876 self.sourcesBuildPhaseId = self.generate_id()
877 objects = {self.rootObjectId: self.generate_root_object(target),
878 self.targetId: self.generate_target(target),
879 self.mainGroupId: self.generate_main_group(target),
880 self.subMainGroupId: self.generate_sub_main_group(target),
881 self.productGroupId: self.generate_product_group(target),
882 self.sourcesBuildPhaseId: self.generate_sources_build_phase(target)
884 for i in self.sourceList.keys():
885 ref = self.sourceList[i]
886 objects[i] = {'isa': 'PBXBuildFile',
888 objects[ref] = {'isa': 'PBXFileReference',
889 'lastKnownFileType': self.sourceRefList[ref]['lastKnownFileType'],
890 'path': self.sourceRefList[ref]['path']}
891 project = {'archiveVersion': 1,
895 'rootObject': self.rootObjectId}
898 # For some reverse-engineered documentation on the project.pbxproj format,
899 # see http://www.monobjc.net/xcode-project-file-format.html .
900 def write_xcodeproj(self, moduledir, target):
901 xcodeprojdir = os.path.join(moduledir, '%s.xcodeproj' % target.target_name())
903 os.mkdir(xcodeprojdir)
906 self.write_dict_to_plist(self.generate_project(target),
907 open(os.path.join(xcodeprojdir, 'project.pbxproj'), 'w'))
909 def __init__(self, gbuildparser, ide):
910 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
913 self.rootlocation = './'
914 for location in self.gbuildparser.target_by_location:
915 # module = location.split('/')[-1]
916 # module_directory = os.path.join(self.rootlocation, module)
917 for target in self.gbuildparser.target_by_location[location]:
918 # project_path = os.path.join(module_directory, '%s.pbxroj' % target.target_name())
919 self.write_xcodeproj(location, target)
922 class VisualStudioIntegrationGenerator(IdeIntegrationGenerator):
924 def __init__(self, gbuildparser, ide):
925 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
926 self.toolset = os.environ['VCTOOLSET']
927 self.solution_directory = self.gbuildparser.builddir
928 self.configurations = {
930 'build': self.module_make_command('%(target)s'),
931 'clean': self.module_make_command('%(target)s.clean'),
932 'rebuild': self.module_make_command('%(target)s.clean %(target)s')
935 'build': self.module_make_command('unitcheck'),
936 'clean': self.module_make_command('clean'),
937 'rebuild': self.module_make_command('clean unitcheck'),
939 'Integration tests': {
940 'build': self.module_make_command('unitcheck slowcheck screenshot subsequentcheck'),
941 'clean': self.module_make_command('clean'),
942 'rebuild': self.module_make_command('clean unitcheck slowcheck screenshot subsequentcheck')
946 def module_make_command(self, targets):
947 return '%(sh)s -c "PATH=\\"/bin:$PATH\\";BUILDDIR=\\"%(builddir)s\\" %(makecmd)s -rsC %(location)s ' + targets + '"'
951 def __init__(self, guid, target, project_path):
954 self.path = project_path
958 for location in self.gbuildparser.target_by_location:
960 module = location.split('/')[-1]
961 module_directory = os.path.join(self.solution_directory, module)
962 for target in self.gbuildparser.target_by_location[location]:
963 project_path = os.path.join(module_directory, '%s.vcxproj' % target.target_name())
964 project_guid = self.write_project(project_path, target)
965 p = VisualStudioIntegrationGenerator.Project(project_guid, target, project_path)
967 self.write_solution(os.path.join(module_directory, '%s.sln' % module), projects)
968 all_projects += projects
970 self.write_solution(os.path.join(self.solution_directory, 'LibreOffice.sln'), all_projects)
971 # this enables Python GDB pretty printers when debugging a WSL Linux build from VS
972 MIEngine_options_path = os.path.join(gbuildparser.srcdir, 'solenv/vs/Microsoft.MIEngine.Options.xml')
973 shutil.copy(MIEngine_options_path, self.solution_directory)
976 def gen_guid(category, name):
977 return str(uuid.uuid5(uuid.NAMESPACE_URL, 'vnd.libreoffice.vs-ide-integration:' + category + '/' + urllib.parse.quote(name))).upper()
979 nmake_project_guid = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
980 nmake_folder_guid = '2150E333-8FDC-42A3-9474-1A3956D46DE8'
982 def get_dependency_libs(self, linked_libs, library_projects):
984 for linked_lib in linked_libs:
985 for library_project in library_projects:
986 if library_project.target.library_name() == linked_lib:
987 dependency_libs[library_project.guid] = library_project
988 return dependency_libs
990 def write_solution(self, solution_path, projects):
991 print('Solution %s:' % os.path.splitext(os.path.basename(solution_path))[0], end='')
992 library_projects = [project for project in projects if project.target in self.gbuildparser.libs]
993 test_projects = [project for project in projects if project.target in self.gbuildparser.tests]
994 executable_projects = [project for project in projects if project.target in self.gbuildparser.exes]
995 with open(solution_path, 'w') as f:
996 f.write('Microsoft Visual Studio Solution File, Format Version 12.00\n')
997 for project in projects:
998 target = project.target
999 print(' %s' % target.target_name(), end='')
1000 proj_path = os.path.relpath(project.path, os.path.abspath(os.path.dirname(solution_path)))
1001 f.write('Project("{%s}") = "%s", "%s", "{%s}"\n' %
1002 (VisualStudioIntegrationGenerator.nmake_project_guid,
1003 target.short_name(), proj_path, project.guid))
1004 libs_in_solution = self.get_dependency_libs(target.linked_libs,
1006 if libs_in_solution:
1007 f.write('\tProjectSection(ProjectDependencies) = postProject\n')
1008 for lib_guid in libs_in_solution.keys():
1009 f.write('\t\t{%(guid)s} = {%(guid)s}\n' % {'guid': lib_guid})
1010 f.write('\tEndProjectSection\n')
1011 f.write('EndProject\n')
1012 f.write('Project("{%s}") = "Utility", "Utility", "{6778240E-8B6B-47A0-AC31-7E7A257B97E6}"\n' %
1013 (VisualStudioIntegrationGenerator.nmake_folder_guid))
1014 f.write('\tProjectSection(SolutionItems) = preProject\n')
1015 # The natvis file gives pretty-printed variable values when debugging
1016 natvis_path = os.path.join(gbuildparser.srcdir, 'solenv/vs/LibreOffice.natvis')
1017 f.write('\t\t%(natvis)s = %(natvis)s\n' % {'natvis': natvis_path})
1018 f.write('\tEndProjectSection\n')
1019 f.write('EndProject\n')
1020 # Folders to group tests/libraries/executables
1021 nmake_tests_guid = 'CF544F7B-9D02-4D83-8370-5887851209B7'
1022 nmake_libraries_guid = 'C624F43D-616C-4627-B58F-F5C2047B7BDC'
1023 nmake_executables_guid = '1CD80999-9FA9-4BA9-B4D9-6E33035CF648'
1024 f.write('Project("{%s}") = "Tests", "Tests", "{%s}"\n' %
1025 (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_tests_guid))
1026 f.write('EndProject\n')
1027 f.write('Project("{%s}") = "Libraries", "Libraries", "{%s}"\n' %
1028 (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_libraries_guid))
1029 f.write('EndProject\n')
1030 f.write('Project("{%s}") = "Executables", "Executables", "{%s}"\n' %
1031 (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_executables_guid))
1032 f.write('EndProject\n')
1033 # end Folders to group tests/libraries/executables
1036 f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
1037 for cfg in self.configurations:
1038 f.write('\t\t%(cfg)s|%(platform)s = %(cfg)s|%(platform)s\n' % {'cfg': cfg, 'platform': platform})
1039 f.write('\tEndGlobalSection\n')
1040 # Group projects to folders
1041 f.write('\tGlobalSection(NestedProjects) = preSolution\n')
1042 for project in test_projects:
1043 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_tests_guid))
1044 for project in library_projects:
1045 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_libraries_guid))
1046 for project in executable_projects:
1047 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_executables_guid))
1048 f.write('\tEndGlobalSection\n')
1049 # end Group projects to folders
1050 f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
1051 # Specifies project configurations for solution configuration
1052 for project in projects:
1053 for cfg in self.configurations:
1054 params = {'guid': project.guid, 'sol_cfg': cfg, 'proj_cfg': cfg, 'platform': platform}
1055 f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.ActiveCfg = %(proj_cfg)s|%(platform)s\n' % params)
1056 # Build.0 is basically 'Build checkbox' in configuration manager
1057 f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.Build.0 = %(proj_cfg)s|%(platform)s\n' % params)
1058 f.write('\tEndGlobalSection\n')
1059 f.write('EndGlobal\n')
1063 def to_long_names(shortnames):
1064 if platform == "cygwin":
1065 return (subprocess.check_output(["cygpath", "-wal"] + shortnames).decode("utf-8", "strict").rstrip()).split("\n")
1069 # Unescape the values: \"tklo.dll\" => "tklo.dll"
1070 escapepattern = re.compile(r'\\(.)')
1073 def defs_list(defs):
1076 for key, value in defs.items():
1078 if value is not None:
1079 define += '=' + VisualStudioIntegrationGenerator.escapepattern.sub(r'\1', value)
1080 defines_list.append(define)
1083 def write_project(self, project_path, target):
1084 # See info at http://blogs.msdn.com/b/visualstudio/archive/2010/05/14/a-guide-to-vcxproj-and-props-file-structure.aspx
1085 folder = os.path.dirname(project_path)
1086 if not os.path.exists(folder):
1088 project_guid = self.gen_guid('project', target.short_name())
1089 cxxflags = ' '.join(target.cxxflags)
1090 ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
1091 ET.register_namespace('', ns)
1092 proj_node = ET.Element('{%s}Project' % ns, DefaultTargets='Build', ToolsVersion='4.0')
1093 proj_confs_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns, Label='ProjectConfigurations')
1095 for configuration in self.configurations:
1096 proj_conf_node = ET.SubElement(proj_confs_node,
1097 '{%s}ProjectConfiguration' % ns,
1098 Include='%s|%s' % (configuration, platform))
1099 conf_node = ET.SubElement(proj_conf_node, '{%s}Configuration' % ns)
1100 conf_node.text = configuration
1101 platform_node = ET.SubElement(proj_conf_node, '{%s}Platform' % ns)
1102 platform_node.text = platform
1104 globals_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='Globals')
1105 proj_guid_node = ET.SubElement(globals_node, '{%s}ProjectGuid' % ns)
1106 proj_guid_node.text = '{%s}' % project_guid
1107 proj_keyword_node = ET.SubElement(globals_node, '{%s}Keyword' % ns)
1108 proj_keyword_node.text = 'MakeFileProj'
1109 proj_name_node = ET.SubElement(globals_node, '{%s}ProjectName' % ns)
1110 proj_name_node.text = target.short_name()
1112 ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.Default.props')
1113 for configuration in self.configurations:
1114 conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label="Configuration",
1115 Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
1116 # Type of project used by the MSBuild to determine build process, see Microsoft.Makefile.targets
1117 conf_type_node = ET.SubElement(conf_node, '{%s}ConfigurationType' % ns)
1118 conf_type_node.text = 'Makefile'
1119 # This defines the version of Visual Studio which can show next to project names in the Solution Explorer
1120 platform_toolset_node = ET.SubElement(conf_node, '{%s}PlatformToolset' % ns)
1121 platform_toolset_node.text = self.toolset
1123 ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.props')
1124 ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionSettings')
1125 for configuration in self.configurations:
1126 prop_sheets_node = ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='Configuration',
1127 Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
1128 ET.SubElement(prop_sheets_node, '{%s}Import' % ns,
1129 Project='$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props',
1130 Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')",
1131 Label='LocalAppDataPlatform')
1133 ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='UserMacros')
1134 # VS IDE (at least "Peek definition") is allergic to paths like "C:/PROGRA~2/WI3CF2~1/10/Include/10.0.14393.0/um"; see
1135 # https://developercommunity.visualstudio.com/content/problem/139659/vc-peek-definition-fails-to-navigate-to-windows-ki.html
1136 # We need to convert to long paths here. Do this once, since it's time-consuming operation.
1137 include_path_node_text = ';'.join(self.to_long_names(target.include))
1138 for cfg_name, cfg_targets in self.configurations.items():
1139 conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns,
1140 Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (cfg_name, platform))
1142 'sh': os.path.join(self.gbuildparser.binpath, 'dash.exe'),
1143 'builddir': self.gbuildparser.builddir,
1144 'location': target.location,
1145 'makecmd': self.gbuildparser.makecmd,
1146 'target': target.target_name()}
1147 nmake_build_node = ET.SubElement(conf_node, '{%s}NMakeBuildCommandLine' % ns)
1148 nmake_build_node.text = cfg_targets['build'] % nmake_params
1149 nmake_clean_node = ET.SubElement(conf_node, '{%s}NMakeCleanCommandLine' % ns)
1150 nmake_clean_node.text = cfg_targets['clean'] % nmake_params
1151 nmake_rebuild_node = ET.SubElement(conf_node, '{%s}NMakeReBuildCommandLine' % ns)
1152 nmake_rebuild_node.text = cfg_targets['rebuild'] % nmake_params
1153 nmake_output_node = ET.SubElement(conf_node, '{%s}NMakeOutput' % ns)
1154 nmake_output_node.text = os.path.join(self.gbuildparser.workdir, 'LinkTarget', target.link_target)
1155 nmake_defs_node = ET.SubElement(conf_node, '{%s}NMakePreprocessorDefinitions' % ns)
1156 nmake_defs_node.text = ';'.join(self.defs_list(target.defs) + ['$(NMakePreprocessorDefinitions)'])
1157 nmake_debug_command_node = ET.SubElement(conf_node, '{%s}LocalDebuggerCommand' % ns)
1158 nmake_debug_command_node.text = os.path.join(self.gbuildparser.instdir, 'program', 'soffice.bin')
1159 nmake_debug_flavor_node = ET.SubElement(conf_node, '{%s}DebuggerFlavor' % ns)
1160 nmake_debug_flavor_node.text = 'WindowsLocalDebugger'
1161 include_path_node = ET.SubElement(conf_node, '{%s}IncludePath' % ns)
1162 include_path_node.text = include_path_node_text
1163 additional_options_node = ET.SubElement(conf_node, '{%s}AdditionalOptions' % ns)
1164 additional_options_node.text = cxxflags
1166 ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % ns)
1168 cxxobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1169 for cxxobject in target.cxxobjects:
1170 cxxabspath = os.path.join(self.gbuildparser.srcdir, cxxobject)
1171 cxxfile = cxxabspath + '.cxx'
1172 if os.path.isfile(cxxfile):
1173 ET.SubElement(cxxobjects_node, '{%s}ClCompile' % ns, Include=cxxfile)
1175 print('Source %s in project %s does not exist' % (cxxfile, target.target_name()))
1177 cobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1178 for cobject in target.cobjects:
1179 cabspath = os.path.join(self.gbuildparser.srcdir, cobject)
1180 cfile = cabspath + '.c'
1181 if os.path.isfile(cfile):
1182 ET.SubElement(cobjects_node, '{%s}ClCompile' % ns, Include=cfile)
1184 print('Source %s in project %s does not exist' % (cfile, target.target_name()))
1186 includes_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1187 for cxxobject in target.cxxobjects:
1188 include_abs_path = os.path.join(self.gbuildparser.srcdir, cxxobject)
1189 hxxfile = include_abs_path + '.hxx'
1190 if os.path.isfile(hxxfile):
1191 ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hxxfile)
1192 # Few files have corresponding .h files
1193 hfile = include_abs_path + '.h'
1194 if os.path.isfile(hfile):
1195 ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hfile)
1196 for cobject in target.cobjects:
1197 include_abs_path = os.path.join(self.gbuildparser.srcdir, cobject)
1198 hfile = include_abs_path + '.h'
1199 if os.path.isfile(hfile):
1200 ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hfile)
1201 ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.targets')
1202 ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionTargets')
1203 self.write_pretty_xml(proj_node, project_path)
1204 self.write_filters(project_path + '.filters',
1205 os.path.join(self.gbuildparser.srcdir, os.path.basename(target.location)),
1206 [cxx_node.get('Include') for cxx_node in cxxobjects_node.findall('{%s}ClCompile' % ns)],
1207 [c_node.get('Include') for c_node in cobjects_node.findall('{%s}ClCompile' % ns)],
1208 [include_node.get('Include') for include_node in includes_node.findall('{%s}ClInclude' % ns)])
1211 def get_filter(self, module_dir, proj_file):
1212 return '\\'.join(os.path.relpath(proj_file, module_dir).split('/')[:-1])
1214 def get_subfilters(self, proj_filter):
1215 parts = proj_filter.split('\\')
1216 subfilters = set([proj_filter]) if proj_filter else set()
1217 for i in range(1, len(parts)):
1218 subfilters.add('\\'.join(parts[:i]))
1221 def write_pretty_xml(self, node, file_path):
1222 xml_str = ET.tostring(node, encoding='unicode')
1223 pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
1224 with open(file_path, 'w') as f:
1225 f.write(pretty_str.decode())
1227 def add_nodes(self, files_node, module_dir, tag, project_files):
1228 ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
1230 for project_file in project_files:
1231 file_node = ET.SubElement(files_node, tag, Include=project_file)
1232 if os.path.commonprefix([module_dir, project_file]) == module_dir:
1233 project_filter = self.get_filter(module_dir, project_file)
1234 filter_node = ET.SubElement(file_node, '{%s}Filter' % ns)
1235 filter_node.text = project_filter
1236 filters |= self.get_subfilters(project_filter)
1239 def write_filters(self, filters_path, module_dir, cxx_files, c_files, include_files):
1240 ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
1241 ET.register_namespace('', ns)
1242 proj_node = ET.Element('{%s}Project' % ns, ToolsVersion='4.0')
1244 compiles_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1245 filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % ns, cxx_files)
1246 filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % ns, c_files)
1247 include_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1248 filters |= self.add_nodes(include_node, module_dir, '{%s}ClInclude' % ns, include_files)
1250 filters_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
1251 for proj_filter in filters:
1252 filter_node = ET.SubElement(filters_node, '{%s}Filter' % ns, Include=proj_filter)
1253 self.write_pretty_xml(proj_node, filters_path)
1256 class QtCreatorIntegrationGenerator(IdeIntegrationGenerator):
1258 def __init__(self, gbuildparser, ide):
1259 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
1260 self.target_by_location = {}
1261 for target in set(self.gbuildparser.libs) | set(self.gbuildparser.exes) | set(self.gbuildparser.tests):
1262 if target.location not in self.target_by_location:
1263 self.target_by_location[target.location] = set()
1264 self.target_by_location[target.location] |= set([target])
1266 self._do_log = False # set to 'True' to activate log of QtCreatorIntegrationGenerator
1268 qtlog_path = os.path.abspath('../qtlog_.txt')
1269 self.qtlog = open(qtlog_path, 'w')
1271 def _log(self, message):
1273 self.qtlog.write(message)
1275 def log_close(self):
1279 def generate_build_configs(self, lib_folder):
1280 module_folder = os.path.join(self.base_folder, lib_folder)
1282 # In QtCreator UI, build configs are listed alphabetically,
1283 # so it can be different from the creation order.
1284 # So we prefix the names with the index.
1285 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1287 'base_folder': module_folder,
1289 'name': "1-Build %s" % lib_folder,
1291 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1293 'base_folder': module_folder,
1295 'name': "2-Local tests -- quick tests (unitcheck)",
1297 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1299 'base_folder': module_folder,
1300 'arg': "unitcheck slowcheck screenshot",
1301 'name': "3-Local tests -- slow tests (unitcheck, slowcheck, screenshot)",
1303 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1305 'base_folder': module_folder,
1306 'arg': "unitcheck slowcheck screenshot subsequentcheck",
1307 'name': "4-Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1309 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1311 'base_folder': self.base_folder,
1313 'name': "5-Global tests -- quick tests (unitcheck)",
1315 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1317 'base_folder': self.base_folder,
1318 'arg': "unitcheck slowcheck screenshot",
1319 'name': "6-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
1321 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1323 'base_folder': self.base_folder,
1324 'arg': "unitcheck slowcheck screenshot subsequentcheck",
1325 'name': "7-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1327 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1329 'base_folder': self.base_folder,
1331 'name': "8-Global build -- nocheck",
1333 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1335 'base_folder': self.base_folder,
1337 'name': "9-Global build",
1340 xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
1345 def generate_meta_build_configs(self):
1347 # In QtCreator UI, build configs are listed alphabetically,
1348 # so it can be different from the creation order.
1349 # So we prefix the names with the index.
1350 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1352 'base_folder': self.base_folder,
1354 'name': "01-Global Build",
1356 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1358 'base_folder': self.base_folder,
1360 'name': "02-Global tests -- quick tests (unitcheck)",
1362 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1364 'base_folder': self.base_folder,
1365 'arg': "unitcheck slowcheck screenshot",
1366 'name': "03-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
1368 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1370 'base_folder': self.base_folder,
1371 'arg': "unitcheck slowcheck screenshot subsequentcheck",
1372 'name': "04-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1374 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1376 'base_folder': self.base_folder,
1378 'name': "05-Global tests -- performance tests (perfcheck)",
1380 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1382 'base_folder': self.base_folder,
1384 'name': "06-Global tests -- tests (check)",
1386 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1388 'base_folder': self.base_folder,
1390 'name': "07-Global build -- nocheck",
1392 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1394 'base_folder': self.base_folder,
1395 'arg': "build-l10n-only",
1396 'name': "08-Global build -- build-l10n-only",
1398 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1400 'base_folder': self.base_folder,
1401 'arg': "build-non-l10n-only",
1402 'name': "09-Global build -- build-non-l10n-only",
1404 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1406 'base_folder': self.base_folder,
1408 'name': "10-Global build -- clean",
1410 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1412 'base_folder': self.base_folder,
1413 'arg': "clean-build",
1414 'name': "11-Global build -- clean-build",
1416 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1418 'base_folder': self.base_folder,
1419 'arg': "clean-host",
1420 'name': "12-Global build -- clean-host",
1422 xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
1427 # By default, QtCreator creates 2 BuildStepList : "Build" and "Clean"
1428 # but the "clean" can be empty.
1429 build_configs_template = """
1430 <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.%(index)s">
1431 <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">%(base_folder)s</value>
1432 <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
1433 <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
1434 <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
1435 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
1436 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1437 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
1438 <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
1439 <value type="QString">-w</value>
1440 <value type="QString">-r</value>
1442 <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
1443 <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">%(arg)s</value>
1444 <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
1446 <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
1447 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
1448 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1449 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
1451 <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
1452 <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
1453 <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
1454 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">%(name)s</value>
1455 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
1456 <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">%(index)s</value>
1457 <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
1461 build_configs_count_template = """
1462 <!-- nb build configurations -->
1463 <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">%(nb)s</value>
1466 def generate_deploy_configs(self, lib_folder):
1467 xml = QtCreatorIntegrationGenerator.deploy_configs_template % {}
1470 deploy_configs_template = """
1471 <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
1472 <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
1473 <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
1474 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
1475 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1476 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
1478 <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
1479 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
1480 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1481 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
1483 <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
1486 def generate_run_configs(self, lib_folder):
1488 if platform == 'darwin':
1489 loexec = "%s/instdir/LibreOfficeDev.app/Contents/MacOS/soffice" % self.base_folder
1491 loexec = "%s/instdir/program/soffice.bin" % self.base_folder
1492 xml = QtCreatorIntegrationGenerator.run_configs_template % {
1494 'workdir': self.base_folder
1498 run_configs_template = """
1499 <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
1500 <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
1501 <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
1502 <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
1503 <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
1504 <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
1505 <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
1506 <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
1507 <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
1508 <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
1509 <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
1510 <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
1511 <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
1512 <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
1513 <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
1514 <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
1515 <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
1516 <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
1517 <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
1518 <value type="int">0</value>
1519 <value type="int">1</value>
1520 <value type="int">2</value>
1521 <value type="int">3</value>
1522 <value type="int">4</value>
1523 <value type="int">5</value>
1524 <value type="int">6</value>
1525 <value type="int">7</value>
1526 <value type="int">8</value>
1527 <value type="int">9</value>
1528 <value type="int">10</value>
1529 <value type="int">11</value>
1530 <value type="int">12</value>
1531 <value type="int">13</value>
1532 <value type="int">14</value>
1534 <value type="int" key="PE.EnvironmentAspect.Base">2</value>
1535 <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
1537 <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
1538 <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%(loexec)s</value>
1539 <value type="bool" key="ProjectExplorer.CustomExecutableRunConfiguration.UseTerminal">false</value>
1540 <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">%(workdir)s</value>
1541 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run libreoffice/instdir/program/soffice</value>
1542 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1543 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
1544 <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
1545 <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
1546 <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
1547 <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
1548 <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
1549 <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
1552 <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
1555 def generate_pro_shared_content(self, lib_folder):
1557 build_configs = self.generate_build_configs(lib_folder)
1558 deploy_configs = self.generate_deploy_configs(lib_folder)
1559 run_configs = self.generate_run_configs(lib_folder)
1561 xml = QtCreatorIntegrationGenerator.pro_shared_template % {
1562 'build_configs': build_configs,
1563 'deploy_configs': deploy_configs,
1564 'run_configs': run_configs,
1568 def generate_meta_pro_shared_content(self):
1570 build_configs = self.generate_meta_build_configs()
1571 deploy_configs = self.generate_deploy_configs("")
1572 run_configs = self.generate_run_configs("")
1574 xml = QtCreatorIntegrationGenerator.pro_shared_template % {
1575 'build_configs': build_configs,
1576 'deploy_configs': deploy_configs,
1577 'run_configs': run_configs,
1581 pro_shared_template = """<?xml version="1.0" encoding="UTF-8"?>
1582 <!DOCTYPE QtCreatorProject>
1583 <!-- Written by QtCreator 3.1.1, 2015-05-14T15:54:34. -->
1586 <variable>ProjectExplorer.Project.ActiveTarget</variable>
1587 <value type="int">0</value>
1590 <!-- editor settings -->
1592 <variable>ProjectExplorer.Project.EditorSettings</variable>
1593 <valuemap type="QVariantMap">
1594 <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
1595 <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
1596 <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
1597 <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
1598 <value type="QString" key="language">Cpp</value>
1599 <valuemap type="QVariantMap" key="value">
1600 <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
1603 <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
1604 <value type="QString" key="language">QmlJS</value>
1605 <valuemap type="QVariantMap" key="value">
1606 <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
1609 <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
1610 <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
1611 <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
1612 <value type="int" key="EditorConfiguration.IndentSize">4</value>
1613 <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
1614 <value type="int" key="EditorConfiguration.MarginColumn">80</value>
1615 <value type="bool" key="EditorConfiguration.MouseHiding">true</value>
1616 <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
1617 <value type="int" key="EditorConfiguration.PaddingMode">1</value>
1618 <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
1619 <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
1620 <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
1621 <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
1622 <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
1623 <value type="int" key="EditorConfiguration.TabSize">8</value>
1624 <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
1625 <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
1626 <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
1627 <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
1628 <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
1629 <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
1634 <variable>ProjectExplorer.Project.PluginSettings</variable>
1635 <valuemap type="QVariantMap"/>
1640 <variable>ProjectExplorer.Project.Target.0</variable>
1641 <valuemap type="QVariantMap">
1642 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
1643 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
1644 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{0701de51-c96e-4e4f-85c3-e70b223c5076}</value>
1645 <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
1646 <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
1647 <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
1649 <!-- build configurations -->
1652 <!-- deploy configurations -->
1655 <!-- plugin settings -->
1656 <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
1658 <!-- run configurations -->
1663 <!-- nb targets : 1 -->
1665 <variable>ProjectExplorer.Project.TargetCount</variable>
1666 <value type="int">1</value>
1669 <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
1670 <value type="QByteArray">{5abcafed-86f6-49f6-b1cb-380fadd21211}</value>
1673 <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
1674 <value type="int">15</value>
1679 def get_file_path(self, src_file, ext_choices):
1680 path = os.path.join(self.gbuildparser.srcdir, src_file)
1681 for ext in ext_choices:
1682 full_path = path + ext
1683 if os.path.isfile(full_path):
1687 def get_source_path(self, src_file):
1688 return self.get_file_path(src_file, (".cxx", ".cpp", ".c", ".mm"))
1690 def get_header_path(self, src_file):
1691 return self.get_file_path(src_file, (".hxx", ".hpp", ".h"))
1693 def build_data_libs(self):
1697 all_libs = set(self.gbuildparser.libs) | set(self.gbuildparser.exes) | set(self.gbuildparser.tests)
1698 for lib in all_libs:
1699 self._log("\nlibrary : %s, loc=%s" % (lib.short_name(), lib.location))
1700 lib_name = os.path.basename(lib.location)
1701 lib_folder = os.path.relpath(lib.location, self.base_folder)
1704 if platform == "cygwin":
1705 # absolute paths from GbuildToJson are Windows paths,
1706 # so convert everything to such ones
1708 if not ntpath.isabs(abs_path):
1709 abs_path = ntpath.join(self.gbuildparser.srcdir, path)
1710 return abs_path.replace('\\', '/')
1712 return os.path.abspath(path)
1716 objcxx_sources_list = []
1717 includepath_list = []
1718 # The explicit headers list is not mandatory :
1719 # QtCreator just needs 'include_path_list' to find all headers files.
1720 # But files listed in 'header_list' will be shown
1721 # in a specific "Headers" folder in QtCreator's Project panel.
1722 # We will list here only headers files of current lib.
1724 objcxx_headers_list = []
1725 for file_ in lib.cxxobjects:
1726 # the file has no extension : search it
1727 # self._log("\n file : %s" % file_)
1728 path = self.get_source_path(file_)
1730 sources_list.append(lopath(path))
1732 # few cxxobject files have a header beside
1733 path = self.get_header_path(file_)
1735 headers_list.append(lopath(path))
1737 for file_ in lib.objcxxobjects:
1738 # the file has no extension: search it
1739 path = self.get_source_path(file_)
1741 objcxx_sources_list.append(lopath(path))
1743 # several objcxxobject files have a header beside
1744 path = self.get_header_path(file_)
1746 objcxx_headers_list.append(lopath(path))
1748 cxxstdversionflag = ''
1749 for cxxflag in lib.cxxflags:
1750 # extract flag for C++ standard version
1751 if cxxflag.startswith('-std'):
1752 cxxstdversionflag = cxxflag
1754 # List all include paths
1755 for hdir in (lib.include + lib.include_sys):
1756 hf_lopath = lopath(hdir)
1757 includepath_list.append(hf_lopath)
1759 # List headers files from current lib
1760 for hdir in lib.include:
1761 if hdir.startswith(lib.location):
1762 for dirpath, _, files in os.walk(hdir):
1764 if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
1765 hf_lopath = lopath(os.path.join(dirpath, hf))
1766 headers_list.append(hf_lopath)
1769 for key, value in lib.defs.items():
1771 if value is not None:
1772 define += '=' + value
1773 defines_list.append(define)
1775 # All data are prepared, store them for the lib.
1776 if lib_folder in self.data_libs:
1777 self.data_libs[lib_folder]['sources'] |= set(sources_list)
1778 self.data_libs[lib_folder]['headers'] |= set(headers_list)
1779 self.data_libs[lib_folder]['objcxx_sources'] |= set(objcxx_sources_list)
1780 self.data_libs[lib_folder]['objcxx_headers'] |= set(objcxx_headers_list)
1781 self.data_libs[lib_folder]['cxxstdversionflag'] = cxxstdversionflag
1782 self.data_libs[lib_folder]['includepath'] |= set(includepath_list)
1783 self.data_libs[lib_folder]['defines'] |= set(defines_list)
1785 self.data_libs[lib_folder] = {
1786 'sources': set(sources_list),
1787 'headers': set(headers_list),
1788 'objcxx_sources': set(objcxx_sources_list),
1789 'objcxx_headers': set(objcxx_headers_list),
1790 'cxxstdversionflag': cxxstdversionflag,
1791 'includepath': set(includepath_list),
1792 'defines': set(defines_list),
1793 'loc': lib.location,
1800 self.base_folder = self.gbuildparser.builddir
1802 # for .pro files, we must explicitly list all files (.c, .h)
1803 # so we can't reuse directly the same method than for kde integration.
1804 self.build_data_libs()
1806 # subdirs for the meta .pro file
1807 subdirs_meta_pro = []
1808 subdirs_list = self.data_libs.keys()
1809 # Now we can create Qt files
1810 for lib_folder in subdirs_list:
1811 sources_list = sorted(self.data_libs[lib_folder]['sources'])
1812 headers_list = sorted(self.data_libs[lib_folder]['headers'])
1813 objcxx_sources_list = sorted(self.data_libs[lib_folder]['objcxx_sources'])
1814 objcxx_headers_list = sorted(self.data_libs[lib_folder]['objcxx_headers'])
1815 cxxstdversionflag = self.data_libs[lib_folder]['cxxstdversionflag']
1816 includepath_list = sorted(self.data_libs[lib_folder]['includepath'])
1817 defines_list = sorted(self.data_libs[lib_folder]['defines'])
1818 lib_loc = self.data_libs[lib_folder]['loc']
1819 lib_name = self.data_libs[lib_folder]['name']
1821 sources = " \\\n".join(sources_list)
1822 headers = " \\\n".join(headers_list)
1823 objcxx_sources = " \\\n".join(objcxx_sources_list)
1824 objcxx_headers = " \\\n".join(objcxx_headers_list)
1825 includepath = " \\\n".join(includepath_list)
1826 defines = " \\\n".join(defines_list)
1827 # strip '-std=' or '-std:' prefix
1828 assert(isinstance(cxxstdversionflag, str) and cxxstdversionflag.startswith('-std'))
1829 cxxstdversion = cxxstdversionflag[5:]
1832 subdirs_meta_pro.append(lib_name)
1833 qt_pro_file = os.path.join(self.base_folder, lib_name, lib_name + '.pro')
1835 content = QtCreatorIntegrationGenerator.pro_template % {'sources': sources, 'headers': headers, 'cxxstdversionflag': cxxstdversionflag,
1836 'cxxstdversion': cxxstdversion, 'objcxx_sources': objcxx_sources,
1837 'objcxx_headers': objcxx_headers, 'includepath': includepath, 'defines': defines}
1838 with open(qt_pro_file, mode) as fpro:
1840 self._log("created %s\n" % qt_pro_file)
1842 except Exception as e:
1843 print("ERROR : creating pro file=" + qt_pro_file, file=sys.stderr)
1844 print(e, file=sys.stderr)
1845 temp = traceback.format_exc() # .decode('utf8')
1846 print(temp, file=sys.stderr)
1847 print("\n\n", file=sys.stderr)
1849 # create .pro.shared file
1850 qt_pro_shared_file = os.path.join(self.base_folder, lib_name, lib_name + '.pro.shared')
1852 with open(qt_pro_shared_file, mode) as fproshared:
1853 fproshared.write(self.generate_pro_shared_content(lib_folder))
1854 self._log("created %s\n" % qt_pro_shared_file)
1856 except Exception as e:
1857 print("ERROR : creating pro.shared file=" + qt_pro_shared_file, file=sys.stderr)
1858 print(e, file=sys.stderr)
1859 temp = traceback.format_exc()
1860 print(temp, file=sys.stderr)
1861 print("\n\n", file=sys.stderr)
1863 # create meta .pro file (lists all sub projects)
1864 qt_meta_pro_file = os.path.join(self.base_folder, 'lo.pro')
1866 subdirs = " \\\n".join(sorted(subdirs_meta_pro))
1867 content = QtCreatorIntegrationGenerator.pro_meta_template % {'subdirs': subdirs}
1868 with open(qt_meta_pro_file, 'w+') as fmpro:
1869 fmpro.write(content)
1871 except Exception as e:
1872 print("ERROR : creating lo.pro file=" + qt_meta_pro_file, file=sys.stderr)
1873 print(e, file=sys.stderr)
1874 temp = traceback.format_exc()
1875 print(temp, file=sys.stderr)
1876 print("\n\n", file=sys.stderr)
1878 # create meta .pro.shared file
1879 qt_meta_pro_shared_file = os.path.join(self.base_folder, 'lo.pro.shared')
1881 with open(qt_meta_pro_shared_file, mode) as fmproshared:
1882 fmproshared.write(self.generate_meta_pro_shared_content())
1883 self._log("created %s\n" % qt_meta_pro_shared_file)
1885 except Exception as e:
1886 print("ERROR : creating lo.pro.shared file=" + qt_meta_pro_shared_file, file=sys.stderr)
1887 print(e, file=sys.stderr)
1888 temp = traceback.format_exc()
1889 print(temp, file=sys.stderr)
1890 print("\n\n", file=sys.stderr)
1894 pro_template = """TEMPLATE = lib
1896 CONFIG -= app_bundle
1898 CONFIG += %(cxxstdversion)s
1900 QMAKE_CXXFLAGS += %(cxxstdversionflag)s
1902 INCLUDEPATH += %(includepath)s
1904 SOURCES += %(sources)s
1906 HEADERS += %(headers)s
1908 OBJECTIVE_SOURCES += %(objcxx_sources)s
1910 OBJECTIVE_HEADERS += %(objcxx_headers)s
1912 DEFINES += %(defines)s
1915 pro_meta_template = """TEMPLATE = subdirs
1917 SUBDIRS = %(subdirs)s
1922 parser = argparse.ArgumentParser(
1923 description='LibreOffice gbuild IDE project generator')
1924 parser.add_argument('--ide', dest='ide', required=True,
1925 help='the IDE to generate project files for')
1926 parser.add_argument('--make', dest='makecmd', required=True,
1927 help='the command to execute make')
1928 return parser.parse_args()
1931 if __name__ == '__main__':
1932 args = get_options()
1934 if args.makecmd == 'make':
1935 args.makecmd = '/usr/bin/make'
1939 'codelite': CodeliteIntegrationGenerator,
1940 'eclipsecdt': EclipseCDTIntegrationGenerator,
1941 'kdevelop': KdevelopIntegrationGenerator,
1942 'xcode': XcodeIntegrationGenerator,
1943 'vs': VisualStudioIntegrationGenerator,
1944 'vim': VimIntegrationGenerator,
1945 'debug': DebugIntegrationGenerator,
1946 'qtcreator': QtCreatorIntegrationGenerator,
1949 if args.ide not in generators.keys():
1950 print("Invalid ide. valid values are %s" % ','.join(generators.keys()))
1953 gbuildparser = GbuildParser(args.makecmd).parse()
1955 generators[args.ide](gbuildparser, args.ide).emit()
1956 print("Successfully created the project files.")
1959 # indent-tabs-mode: nil
1962 # vim: set et sw=4 ts=4: