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/.
19 import xml.etree.ElementTree as ET
20 import xml.dom.minidom as minidom
23 from sys import platform
26 class GbuildLinkTarget:
27 def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, linked_libs):
28 (self.name, self.location, self.include, self.include_sys, self.defs, self.cxxobjects, self.cxxflags, self.linked_libs) = (
29 name, location, include, include_sys, defs, cxxobjects, cxxflags, linked_libs)
35 return not self.include and not self.defs and not self.cxxobjects and not self.linked_libs
38 return '%s at %s with include path: %s, isystem includes: %s, defines: %s, objects: %s, cxxflags: %s and linked libs: %s' % (
39 self.short_name(), self.location, self.include, self.include_sys, self.defs, self.cxxobjects,
40 self.cxxflags, self.linked_libs)
43 class GbuildLib(GbuildLinkTarget):
44 def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, linked_libs):
45 GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, linked_libs)
48 """Return the short name of target based on the Library_* makefile name"""
49 return 'Library %s' % self.name
51 def target_name(self):
52 return 'Library_%s' % self.name
54 def library_name(self):
57 class GbuildTest(GbuildLinkTarget):
58 def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, linked_libs):
59 GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, linked_libs)
62 """Return the short name of target based n the CppunitTest_* makefile names"""
63 return 'CppunitTest %s' % self.name
65 def target_name(self):
66 return 'CppunitTest_%s' % self.name
68 class GbuildExe(GbuildLinkTarget):
69 def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, linked_libs):
70 GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, linked_libs)
73 """Return the short name of target based on the Executable_* makefile name"""
74 return 'Executable %s' % self.name
76 def target_name(self):
77 return 'Executable_%s' % self.name
81 def __init__(self, makecmd):
82 self.makecmd = makecmd
83 self.binpath = os.path.dirname(os.environ['GPERF']) # woha, this is quite a hack
84 (self.srcdir, self.builddir, self.instdir, self.workdir) = (os.environ['SRCDIR'], os.environ['BUILDDIR'], os.environ['INSTDIR'], os.environ['WORKDIR'])
85 (self.libs, self.exes, self.tests, self.modulenamelist) = ([], [], [], [])
86 (self.target_by_path, self.target_by_location) = ({}, {})
88 includepattern = re.compile('-I(\S+)')
89 isystempattern = re.compile('-isystem\s*(\S+)')
90 warningpattern = re.compile('-W\S+')
91 libpattern = re.compile('Library_(.*)\.mk')
92 exepattern = re.compile('Executable_(.*)\.mk')
93 testpattern = re.compile('CppunitTest_(.*)\.mk')
96 def __split_includes(includes):
97 foundisystem = GbuildParser.isystempattern.findall(includes)
98 foundincludes = [includeswitch.strip() for includeswitch in GbuildParser.includepattern.findall(includes) if
99 len(includeswitch) > 2]
100 return (foundincludes, foundisystem)
103 def __split_objs(objsline):
104 return [obj for obj in objsline.strip().split(' ') if len(obj) > 0 and obj != 'CXXOBJECTS' and obj != '+=']
107 def __split_defs(defsline):
109 alldefs = [defswitch.strip() for defswitch in defsline.strip().lstrip('-D').split(' -D') if len(defswitch) > 2]
111 dparts = d.split(' -U')
112 """after dparts.pop(0), dparts will contain only undefs"""
113 defparts = dparts.pop(0).strip().split('=')
114 if len(defparts) == 1:
115 defparts.append(None)
116 defs[defparts[0]] = defparts[1]
117 """Drop undefed items (if any) from previous defs"""
119 defs.pop(u.strip(), '')
120 defs["LIBO_INTERNAL_ONLY"] = None
124 def __split_flags(flagsline, flagslineappend):
125 return [cxxflag.strip() for cxxflag in GbuildParser.warningpattern.sub('', '%s %s' % (flagsline, flagslineappend)).split(' ') if len(cxxflag) > 1]
128 def __lib_from_json(json):
129 (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
131 GbuildParser.libpattern.match(os.path.basename(json['MAKEFILE'])).group(1),
132 os.path.dirname(json['MAKEFILE']),
135 GbuildParser.__split_defs(json['DEFS']),
136 GbuildParser.__split_objs(json['CXXOBJECTS']),
137 GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
138 json['LINKED_LIBS'].strip().split(' '))
141 def __test_from_json(json):
142 (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
143 testname_match = GbuildParser.testpattern.match(os.path.basename(json['MAKEFILE']))
145 # Workaround strange writer test makefile setup
146 if testname_match is None:
147 testname = "StrangeWriterMakefiles"
149 testname = testname_match.group(1)
153 os.path.dirname(json['MAKEFILE']),
156 GbuildParser.__split_defs(json['DEFS']),
157 GbuildParser.__split_objs(json['CXXOBJECTS']),
158 GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
159 json['LINKED_LIBS'].strip().split(' '))
162 def __exe_from_json(json):
163 (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
165 GbuildParser.exepattern.match(os.path.basename(json['MAKEFILE'])).group(1),
166 os.path.dirname(json['MAKEFILE']),
169 GbuildParser.__split_defs(json['DEFS']),
170 GbuildParser.__split_objs(json['CXXOBJECTS']),
171 GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
172 json['LINKED_LIBS'].strip().split(' '))
175 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Library')):
176 with open(os.path.join(self.workdir, 'GbuildToJson', 'Library', jsonfilename), 'r') as f:
177 lib = self.__lib_from_json(json.load(f))
178 self.libs.append(lib)
179 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Executable')):
180 with open(os.path.join(self.workdir, 'GbuildToJson', 'Executable', jsonfilename), 'r') as f:
181 exe = self.__exe_from_json(json.load(f))
182 self.exes.append(exe)
183 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest')):
184 with open(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest', jsonfilename), 'r') as f:
185 test = self.__test_from_json(json.load(f))
186 self.tests.append(test)
187 for target in set(self.libs) | set(self.exes) | set(self.tests):
188 if target.location not in self.target_by_location:
189 self.target_by_location[target.location] = set()
190 self.target_by_location[target.location] |= set([target])
191 for cxx in target.cxxobjects:
192 path = '/'.join(cxx.split('/')[:-1])
193 if path not in self.target_by_path:
194 self.target_by_path[path] = set()
195 self.target_by_path[path] |= set([target])
196 for location in self.target_by_location:
197 self.modulenamelist.append(os.path.split(location)[1])
201 class IdeIntegrationGenerator:
203 def __init__(self, gbuildparser, ide):
204 self.gbuildparser = gbuildparser
210 class EclipseCDTIntegrationGenerator(IdeIntegrationGenerator):
212 def __init__(self, gbuildparser, ide):
213 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
215 def create_include_paths(self):
216 for module in self.gbuildparser.modulenamelist:
217 modulepath = os.path.join(self.gbuildparser.builddir, module)
218 includedirfile = open(os.path.join(modulepath, '.eclipsesettingfile'), 'w')
220 for lib in self.gbuildparser.target_by_path.keys():
221 if lib.startswith(module+'/'):
222 modulelibs.append(lib)
224 for lib in modulelibs:
225 for target in self.gbuildparser.target_by_path[lib]:
226 include |= set(target.include)
227 includedirfile.write('\n'.join(include))
228 includedirfile.close()
231 def create_macros(self):
232 for module in self.gbuildparser.modulenamelist:
233 modulepath = os.path.join(self.gbuildparser.builddir, module)
234 macrofile = open(os.path.join(modulepath, '.macros'), 'w')
236 for lib in self.gbuildparser.target_by_path.keys():
237 if lib.startswith(module+'/'):
238 modulelibs.append(lib)
241 for lib in modulelibs:
242 for target in self.gbuildparser.target_by_path[lib]:
243 for i in target.defs.keys():
244 tmp = str(i) +','+str(target.defs[i])
245 if tmp not in defineset:
247 macrofile.write('\n'.join(defineset))
251 def create_settings_file(self):
253 settingsfiletemplate = """\
254 <?xml version="1.0" encoding="UTF-8"?>
255 <cdtprojectproperties>
256 <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths">
257 <language name="C++ Source File">
261 <language name="C Source File">
264 <language name="Object File">
267 <language name="Assembly Source File">
271 <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros">
272 <language name="C++ Source File">
275 <language name="C Source File">
278 <language name="Object File">
281 <language name="Assembly Source File">
285 </cdtprojectproperties>
288 for module in self.gbuildparser.modulenamelist:
290 modulepath = os.path.join(self.gbuildparser.builddir, module)
292 settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
293 settingsfile.write(settingsfiletemplate)
296 settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'r')
297 tempxml = settingsfile.readlines()
298 tempinclude = open(os.path.join(modulepath, '.eclipsesettingfile'), 'r')
299 tempmacro = open(os.path.join(modulepath, '.macros'), 'r')
300 for includepath in tempinclude:
301 if includepath[-1:] == "\n":
302 includepath = includepath[:-1]
303 templine = "<includepath>%s</includepath>\n" % includepath
304 tempxml.insert(5, templine)
306 for line in tempmacro:
307 macroskeyvalue = line.split(',')
308 macrokey = macroskeyvalue[0]
309 macrovalue = macroskeyvalue[1]
310 if macrovalue[-1:] == "\n":
311 macrovalue = macrovalue[:-1]
312 templine = "<macro><name>%s</name><value>%s</value></macro>\n" %(macrokey, macrovalue)
313 tempxml.insert(-13, templine)
314 tempxml="".join(tempxml)
317 settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
318 settingsfile.write(tempxml)
320 os.remove(os.path.join(modulepath, '.eclipsesettingfile'))
321 os.remove(os.path.join(modulepath, '.macros'))
324 self.create_include_paths()
326 self.create_settings_file()
328 class DebugIntegrationGenerator(IdeIntegrationGenerator):
330 def __init__(self, gbuildparser, ide):
331 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
334 print(self.gbuildparser.srcdir)
335 print(self.gbuildparser.builddir)
336 for lib in self.gbuildparser.libs:
338 for exe in self.gbuildparser.exes:
340 for test in self.gbuildparser.tests:
344 class VimIntegrationGenerator(IdeIntegrationGenerator):
346 def __init__(self, gbuildparser, ide):
347 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
351 for lib in set(self.gbuildparser.libs) | set(self.gbuildparser.tests) | set(self.gbuildparser.exes):
353 for file in lib.cxxobjects:
354 filePath = os.path.join(self.gbuildparser.srcdir, file) + ".cxx"
355 entry = {'directory': lib.location, 'file': filePath, 'command': self.generateCommand(lib, filePath)}
356 entries.append(entry)
357 global_list.extend(entries)
358 export_file = open('compile_commands.json', 'w')
359 json.dump(global_list, export_file)
361 def generateCommand(self, lib, file):
362 command = 'clang++ -Wall'
363 for key, value in lib.defs.items():
366 if value is not None:
370 for include in lib.include:
373 for isystem in lib.include_sys:
374 command += ' -isystem '
376 for cxxflag in lib.cxxflags:
381 # Help clang when the tree is configured for gcc.
382 for gnu in ('-std=gnu++11', '-std=gnu++1y'):
383 command = command.replace(gnu, '-std=c++11')
387 class KdevelopIntegrationGenerator(IdeIntegrationGenerator):
389 def encode_int(self, i):
391 return '\\x%s\\x%s\\x%s\\x%s' % (temp[0:2], temp[2:4], temp[4:6], temp[6:8])
393 def encode_string(self, string):
394 result = self.encode_int(len(string) * 2)
395 for c in string.encode('utf-16-be'):
396 if c in range(32, 126):
399 result += '\\x%02x' % c
402 def generate_buildsystemconfigtool(self, configid, tool, args, exe, typenr):
403 return KdevelopIntegrationGenerator.buildsystemconfigtooltemplate % {'configid': configid, 'tool': tool,
404 'args': args, 'exe': exe, 'typenr': typenr}
406 buildsystemconfigtooltemplate = """
407 [CustomBuildSystem][BuildConfig%(configid)d][Tool%(tool)s]
416 def generate_buildsystemconfig(self, configid, moduledir, builddir, title, buildparms=''):
417 result = KdevelopIntegrationGenerator.buildsystemconfigtemplate % {'configid': configid, 'builddir': builddir,
419 result += self.generate_buildsystemconfigtool(configid, 'Clean', 'clean %s' % buildparms,
420 self.gbuildparser.makecmd, 3)
421 result += self.generate_buildsystemconfigtool(configid, 'Build', 'all %s' % buildparms,
422 self.gbuildparser.makecmd, 0)
425 buildsystemconfigtemplate = """
426 [CustomBuildSystem][BuildConfig%(configid)d]
427 BuildDir=file://%(builddir)s
432 def generate_buildsystem(self, moduledir):
433 result = KdevelopIntegrationGenerator.buildsystemtemplate % {'defaultconfigid': 0}
434 result += self.generate_buildsystemconfig(0, moduledir, moduledir, 'Module Build -- Release')
435 result += self.generate_buildsystemconfig(1, moduledir, self.gbuildparser.builddir, 'Full Build -- Release')
436 result += self.generate_buildsystemconfig(2, moduledir, moduledir, 'Module Build -- Debug', 'debug=T')
437 result += self.generate_buildsystemconfig(3, moduledir, self.gbuildparser.builddir, 'Full Build -- Debug',
441 buildsystemtemplate = """
443 CurrentConfiguration=BuildConfig%(defaultconfigid)d
447 def generate_launch(self, launchid, launchname, executablepath, args, workdir):
448 return KdevelopIntegrationGenerator.launchtemplate % {'launchid': launchid, 'launchname': launchname,
449 'executablepath': executablepath, 'args': args,
453 [Launch][Launch Configuration %(launchid)d]
454 Configured Launch Modes=execute
455 Configured Launchers=nativeAppLauncher
457 Type=Native Application
459 [Launch][Launch Configuration %(launchid)d][Data]
461 Dependencies=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x00)
462 Dependency Action=Nothing
463 EnvironmentGroup=default
464 Executable=file://%(executablepath)s
465 External Terminal=konsole --noclose --workdir %%workdir -e %%exe
467 Use External Terminal=false
468 Working Directory=file://%(workdir)s
473 def generate_launches(self, moduledir):
474 launches = ','.join(['Launch Configuration %d' % i for i in range(7)])
475 result = KdevelopIntegrationGenerator.launchestemplate % {'launches': launches}
476 result += self.generate_launch(0, 'Local tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
477 'unitcheck', moduledir)
478 result += self.generate_launch(1, 'Local tests -- slow tests (unitcheck, slowcheck, screenshot)', self.gbuildparser.makecmd,
479 'unitcheck slowcheck screenshot', moduledir)
480 result += self.generate_launch(2, 'Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
481 self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck', moduledir)
482 result += self.generate_launch(3, 'Global tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
483 'unitcheck', self.gbuildparser.builddir)
484 result += self.generate_launch(4, 'Global tests -- slow tests (unitcheck, slowcheck, screenshot)',
485 self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot', self.gbuildparser.builddir)
486 result += self.generate_launch(5, 'Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
487 self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck',
488 self.gbuildparser.builddir)
489 result += self.generate_launch(6, 'Run LibreOffice',
490 os.path.join(self.gbuildparser.instdir, 'program/soffice.bin'), '',
491 self.gbuildparser.instdir)
494 launchestemplate = """
496 Launch Configurations=%(launches)s
500 def write_modulebeef(self, moduledir, modulename):
501 beefdir = os.path.join(moduledir, '.kdev4')
503 beeffile = open(os.path.join(beefdir, 'Module_%s.kdev4' % modulename), 'w')
504 beeffile.write(self.generate_buildsystem(moduledir))
505 beeffile.write(self.generate_launches(moduledir))
508 def write_modulestub(self, moduledir, modulename):
509 stubfile = open(os.path.join(moduledir, 'Module_%s.kdev4' % modulename), 'w')
510 stubfile.write(KdevelopIntegrationGenerator.modulestubtemplate % {'modulename': modulename,
511 'builditem': self.encode_string(
512 'Module_%s' % modulename)})
515 modulestubtemplate = """
517 BuildItems=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x0b\\x00\\x00\\x00\\x00\\x01%(builditem)s)
520 Name=Module_%(modulename)s
521 Manager=KDevCustomBuildSystem
522 VersionControl=kdevgit
525 def write_includepaths(self, path):
526 includedirfile = open(os.path.join(path, '.kdev_include_paths'), 'w')
528 for target in self.gbuildparser.target_by_path[path]:
529 include |= set(target.include)
530 includedirfile.write('\n'.join(include))
531 includedirfile.close()
533 def __init__(self, gbuildparser, ide):
534 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
537 for path in self.gbuildparser.target_by_path:
538 self.write_includepaths(path)
539 for location in self.gbuildparser.target_by_location:
540 for f in os.listdir(location):
541 if f.endswith('.kdev4'):
543 os.remove(os.path.join(location, f))
545 shutil.rmtree(os.path.join(location, f))
546 for location in self.gbuildparser.target_by_location:
547 modulename = os.path.split(location)[1]
548 self.write_modulestub(location, modulename)
549 self.write_modulebeef(location, modulename)
552 class XcodeIntegrationGenerator(IdeIntegrationGenerator):
554 def indent(self, file, level):
557 for i in range(0, level):
560 def write_object(self, object, file, indent):
561 if isinstance(object, int):
562 file.write('%d' % object)
563 elif isinstance(object, str) and not re.search('[^A-Za-z0-9_]', object):
564 file.write('%s' % object)
565 elif isinstance(object, str):
566 file.write('"%s"' % object)
567 elif isinstance(object, dict):
568 self.write_dict(object, file, indent)
570 # Write a dictionary out as an "old-style (NeXT) ASCII plist"
571 def write_dict(self, dict, file, indent):
574 for key in sorted(dict.keys()):
575 self.indent(file, indent + 1)
576 file.write('%s = ' % key)
577 self.write_object(dict[key], file, indent + 1)
579 self.indent(file, indent)
582 def write_dict_to_plist(self, dict, file):
583 file.write('// !$*UTF8*$!\n')
584 self.write_dict(dict, file, 0)
586 def get_product_type(self, modulename):
587 if modulename in self.gbuildparser.libs:
588 return 'com.apple.product-type.library.dynamic'
589 elif modulename in self.gbuildparser.exes:
590 return 'com.apple.product-type.something'
594 def generate_id(self):
595 XcodeIntegrationGenerator.counter = XcodeIntegrationGenerator.counter + 1
596 return str('X%07x' % XcodeIntegrationGenerator.counter)
598 def generate_build_phases(self, modulename):
599 result = [self.sourcesBuildPhaseId]
602 def generate_root_object(self, modulename):
603 result = {'isa': 'PBXProject',
604 'attributes': {'LastUpgradeCheck': '0500',
605 'ORGANIZATIONNAME': 'LibreOffice'},
606 'buildConfigurationList': self.generate_id(),
607 'compatibilityVersion': 'Xcode 3.2',
608 'hasScannedForEncodings': 0,
609 'knownRegions': ['en'],
610 'mainGroup': self.mainGroupId,
611 'productRefGroup': self.productRefGroupId,
612 'projectDirPath': '',
614 'targets': self.targetId}
617 def generate_target(self, modulename):
618 result = {'isa': 'PBXNativeTarget',
619 'buildConfigurationList': self.generate_id(),
620 'buildPhases': self.generate_build_phases(modulename),
624 'productName': modulename,
625 'productReference': self.productReferenceId,
626 'productType': self.get_product_type(modulename)}
629 def generate_main_group(self, modulename):
630 result = {'isa': 'PBXGroup',
631 'children': [self.subMainGroupId, self.productGroupId],
632 'sourceTree': '<group>'}
635 def generate_sub_main_children(self, modulename):
638 def generate_sub_main_group(self, modulename):
639 result = {'isa': 'PBXGroup',
640 'children': self.generate_sub_main_children(modulename),
642 'sourceTree': '<group>'}
645 def generate_product_group(self, modulename):
646 result = {'isa': 'PBXGroup',
647 'children': [self.productReferenceId],
649 'sourceTree': '<group>'}
652 def build_source_list(self, module):
653 self.sourceRefList = {}
656 for i in module.cxxobjects:
657 ref = self.generate_id()
658 self.sourceList[self.generate_id()] = ref
659 self.sourceRefList[ref] = {'lastKnownFileType': 'sourcecode.cpp.cpp',
661 'sourceTree': '<group>'}
663 def generate_sources_build_phase(self, modulename):
664 result = {'isa': 'PBXSourcesBuildPhase',
665 'buildActionMask': 2147483647,
666 'files': self.sourceList.keys(),
667 'runOnlyForDeploymentPostprocessing': 0}
670 def generate_project(self, target):
671 self.rootObjectId = self.generate_id()
672 self.mainGroupId = self.generate_id()
673 self.subMainGroupId = self.generate_id()
674 self.productReferenceId = self.generate_id()
675 self.productRefGroupId = self.generate_id()
676 self.productGroupId = self.generate_id()
677 self.targetId = self.generate_id()
678 self.build_source_list(target)
679 self.sourcesBuildPhaseId = self.generate_id()
680 objects = {self.rootObjectId: self.generate_root_object(target),
681 self.targetId: self.generate_target(target),
682 self.mainGroupId: self.generate_main_group(target),
683 self.subMainGroupId: self.generate_sub_main_group(target),
684 self.productGroupId: self.generate_product_group(target),
685 self.sourcesBuildPhaseId: self.generate_sources_build_phase(target)
687 for i in self.sourceList.keys():
688 ref = self.sourceList[i]
689 objects[i] = {'isa': 'PBXBuildFile',
691 objects[ref] = {'isa': 'PBXFileReference',
692 'lastKnownFileType': self.sourceRefList[ref]['lastKnownFileType'],
693 'path': self.sourceRefList[ref]['path']}
694 project = {'archiveVersion': 1,
698 'rootObject': self.rootObjectId}
701 # For some reverse-engineered documentation on the project.pbxproj format,
702 # see http://www.monobjc.net/xcode-project-file-format.html .
703 def write_xcodeproj(self, moduledir, target):
704 xcodeprojdir = os.path.join(moduledir, '%s.xcodeproj' % target.target_name())
706 os.mkdir(xcodeprojdir)
709 self.write_dict_to_plist(self.generate_project(target),
710 open(os.path.join(xcodeprojdir, 'project.pbxproj'), 'w'))
712 def __init__(self, gbuildparser, ide):
713 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
716 self.rootlocation = './'
717 for location in self.gbuildparser.target_by_location:
718 # module = location.split('/')[-1]
719 # module_directory = os.path.join(self.rootlocation, module)
720 for target in self.gbuildparser.target_by_location[location]:
721 # project_path = os.path.join(module_directory, '%s.pbxroj' % target.target_name())
722 self.write_xcodeproj(location, target)
725 class VisualStudioIntegrationGenerator(IdeIntegrationGenerator):
727 def __init__(self, gbuildparser, ide):
728 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
729 self.toolset = self.retrieve_toolset(ide)
730 self.solution_directory = './'
731 self.configurations = {
733 'build': self.module_make_command('%(target)s'),
734 'clean': self.module_make_command('%(target)s.clean'),
735 'rebuild': self.module_make_command('%(target)s.clean %(target)s')
738 'build': self.module_make_command('unitcheck'),
739 'clean': self.module_make_command('clean'),
740 'rebuild': self.module_make_command('clean unitcheck'),
742 'Integration tests': {
743 'build': self.module_make_command('unitcheck slowcheck screenshot subsequentcheck'),
744 'clean': self.module_make_command('clean'),
745 'rebuild': self.module_make_command('clean unitcheck slowcheck screenshot subsequentcheck')
749 def retrieve_toolset(self, ide):
750 ide_toolset_map = {'vs2015': 'v140'}
751 return ide_toolset_map[ide]
753 def module_make_command(self, targets):
754 return '%(sh)s -c "PATH=\\"/bin:$PATH\\";BUILDDIR=\\"%(builddir)s\\" %(makecmd)s -rsC %(location)s ' + targets + '"'
758 def __init__(self, guid, target, project_path):
761 self.path = project_path
765 for location in self.gbuildparser.target_by_location:
767 module = location.split('/')[-1]
768 module_directory = os.path.join(self.solution_directory, module)
769 for target in self.gbuildparser.target_by_location[location]:
770 project_path = os.path.join(module_directory, '%s.vcxproj' % target.target_name())
771 project_guid = self.write_project(project_path, target)
772 p = VisualStudioIntegrationGenerator.Project(project_guid, target, project_path)
774 self.write_solution(os.path.join(module_directory, '%s.sln' % module), projects)
775 all_projects += projects
777 self.write_solution(os.path.join(self.solution_directory, 'LibreOffice.sln'), all_projects)
779 nmake_project_guid = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
781 def get_dependency_libs(self, linked_libs, library_projects):
783 for linked_lib in linked_libs:
784 for library_project in library_projects:
785 if library_project.target.library_name() == linked_lib:
786 dependency_libs[library_project.guid] = library_project
787 return dependency_libs
789 def write_solution(self, solution_path, projects):
790 print('Solution %s:' % os.path.splitext(os.path.basename(solution_path))[0], end='')
791 library_projects = [project for project in projects if project.target in self.gbuildparser.libs]
792 with open(solution_path, 'w') as f:
793 f.write('Microsoft Visual Studio Solution File, Format Version 12.00\n')
794 for project in projects:
795 target = project.target
796 print(' %s' % target.target_name(), end='')
797 proj_path = os.path.relpath(project.path, os.path.abspath(os.path.dirname(solution_path)))
798 f.write('Project("{%s}") = "%s", "%s", "{%s}"\n' %
799 (VisualStudioIntegrationGenerator.nmake_project_guid,
800 target.short_name(), proj_path, project.guid))
801 libs_in_solution = self.get_dependency_libs(target.linked_libs,
804 f.write('\tProjectSection(ProjectDependencies) = postProject\n')
805 for lib_guid in libs_in_solution.keys():
806 f.write('\t\t{%(guid)s} = {%(guid)s}\n' % {'guid': lib_guid})
807 f.write('\tEndProjectSection\n')
808 f.write('EndProject\n')
809 f.write('Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B9292527-A979-4D13-A598-C75A33222174}"\n')
810 f.write('\tProjectSection(SolutionItems) = preProject\n')
811 f.write('\t\tsolenv/vs/LibreOffice.natvis = solenv/vs/LibreOffice.natvis\n')
812 f.write('\tEndProjectSection\n')
813 f.write('EndProject\n')
816 f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
817 for cfg in self.configurations:
818 f.write('\t\t%(cfg)s|%(platform)s = %(cfg)s|%(platform)s\n' % {'cfg': cfg, 'platform': platform})
819 f.write('\tEndGlobalSection\n')
820 f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
821 # Specifies project configurations for solution configuration
822 for project in projects:
823 for cfg in self.configurations:
824 params = {'guid': project.guid, 'sol_cfg': cfg, 'proj_cfg': cfg, 'platform': platform}
825 f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.ActiveCfg = %(proj_cfg)s|%(platform)s\n' % params)
826 # Build.0 is basically 'Build checkbox' in configuration manager
827 f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.Build.0 = %(proj_cfg)s|%(platform)s\n' % params)
828 f.write('\tEndGlobalSection\n')
829 f.write('EndGlobal\n')
833 def to_long_names(shortnames):
834 if platform == "cygwin":
835 return (subprocess.check_output(["cygpath", "-wal"] + shortnames).decode("utf-8", "strict").rstrip()).split("\n")
843 for key, value in defs.items():
845 if value is not None:
846 define += '=' + value
847 defines_list.append(define)
850 def write_project(self, project_path, target):
851 # See info at http://blogs.msdn.com/b/visualstudio/archive/2010/05/14/a-guide-to-vcxproj-and-props-file-structure.aspx
852 folder = os.path.dirname(project_path)
853 if not os.path.exists(folder):
855 project_guid = str(uuid.uuid4()).upper()
856 ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
857 ET.register_namespace('', ns)
858 proj_node = ET.Element('{%s}Project' % ns, DefaultTargets='Build', ToolsVersion='4.0')
859 proj_confs_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns, Label='ProjectConfigurations')
861 for configuration in self.configurations:
862 proj_conf_node = ET.SubElement(proj_confs_node,
863 '{%s}ProjectConfiguration' % ns,
864 Include='%s|%s' % (configuration, platform))
865 conf_node = ET.SubElement(proj_conf_node, '{%s}Configuration' % ns)
866 conf_node.text = configuration
867 platform_node = ET.SubElement(proj_conf_node, '{%s}Platform' % ns)
868 platform_node.text = platform
870 globals_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='Globals')
871 proj_guid_node = ET.SubElement(globals_node, '{%s}ProjectGuid' % ns)
872 proj_guid_node.text = '{%s}' % project_guid
873 proj_keyword_node = ET.SubElement(globals_node, '{%s}Keyword' % ns)
874 proj_keyword_node.text = 'MakeFileProj'
875 proj_name_node = ET.SubElement(globals_node, '{%s}ProjectName' % ns)
876 proj_name_node.text = target.short_name()
878 ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
879 for configuration in self.configurations:
880 conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label="Configuration",
881 Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
882 # Type of project used by the MSBuild to determine build process, see Microsoft.Makefile.targets
883 conf_type_node = ET.SubElement(conf_node, '{%s}ConfigurationType' % ns)
884 conf_type_node.text = 'Makefile'
885 # VS2012: I need to have this otherwise the names of projects will contain text Visual Studio 2010 in the Solution Explorer
886 platform_toolset_node = ET.SubElement(conf_node, '{%s}PlatformToolset' % ns)
887 platform_toolset_node.text = self.toolset
889 ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.props')
890 ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionSettings')
891 for configuration in self.configurations:
892 prop_sheets_node = ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='Configuration',
893 Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
894 ET.SubElement(prop_sheets_node, '{%s}Import' % ns,
895 Project='$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props',
896 Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')",
897 Label='LocalAppDataPlatform')
899 ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='UserMacros')
900 # VS IDE (at least "Peek definition") is allergic to paths like "C:/PROGRA~2/WI3CF2~1/10/Include/10.0.14393.0/um"; see
901 # https://developercommunity.visualstudio.com/content/problem/139659/vc-peek-definition-fails-to-navigate-to-windows-ki.html
902 # We need to convert to long paths here. Do this once, since it's time-consuming operation.
903 include_path_node_text = ';'.join(self.to_long_names(target.include))
904 for cfg_name, cfg_targets in self.configurations.items():
905 conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns,
906 Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (cfg_name, platform))
908 'sh': os.path.join(self.gbuildparser.binpath, 'dash.exe'),
909 'builddir': self.gbuildparser.builddir,
910 'location': target.location,
911 'makecmd': self.gbuildparser.makecmd,
912 'target': target.target_name()}
913 nmake_build_node = ET.SubElement(conf_node, '{%s}NMakeBuildCommandLine' % ns)
914 nmake_build_node.text = cfg_targets['build'] % nmake_params
915 nmake_clean_node = ET.SubElement(conf_node, '{%s}NMakeCleanCommandLine' % ns)
916 nmake_clean_node.text = cfg_targets['clean'] % nmake_params
917 nmake_rebuild_node = ET.SubElement(conf_node, '{%s}NMakeReBuildCommandLine' % ns)
918 nmake_rebuild_node.text = cfg_targets['rebuild'] % nmake_params
919 nmake_output_node = ET.SubElement(conf_node, '{%s}NMakeOutput' % ns)
920 nmake_output_node.text = os.path.join(self.gbuildparser.instdir, 'program', 'soffice.bin')
921 nmake_defs_node = ET.SubElement(conf_node, '{%s}NMakePreprocessorDefinitions' % ns)
922 nmake_defs_node.text = ';'.join(self.defs_list(target.defs) + ['$(NMakePreprocessorDefinitions)'])
923 include_path_node = ET.SubElement(conf_node, '{%s}IncludePath' % ns)
924 include_path_node.text = include_path_node_text
926 ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % ns)
928 cxxobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
929 for cxxobject in target.cxxobjects:
930 cxxabspath = os.path.join(self.gbuildparser.srcdir, cxxobject)
931 cxxfile = cxxabspath + '.cxx'
932 if os.path.isfile(cxxfile):
933 ET.SubElement(cxxobjects_node, '{%s}ClCompile' % ns, Include=cxxfile)
935 print('Source %s in project %s does not exist' % (cxxfile, target.target_name()))
937 includes_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
938 for cxxobject in target.cxxobjects:
939 include_abs_path = os.path.join(self.gbuildparser.srcdir, cxxobject)
940 hxxfile = include_abs_path + '.hxx'
941 if os.path.isfile(hxxfile):
942 ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hxxfile)
943 # Few files have corresponding .h files
944 hfile = include_abs_path + '.h'
945 if os.path.isfile(hfile):
946 ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hfile)
947 ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.targets')
948 ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionTargets')
949 self.write_pretty_xml(proj_node, project_path)
950 self.write_filters(project_path + '.filters',
951 os.path.join(self.gbuildparser.srcdir, os.path.basename(target.location)),
952 [cxx_node.get('Include') for cxx_node in cxxobjects_node.findall('{%s}ClCompile' % ns)],
953 [include_node.get('Include') for include_node in includes_node.findall('{%s}ClInclude' % ns)])
956 def get_filter(self, module_dir, proj_file):
957 return '\\'.join(os.path.relpath(proj_file, module_dir).split('/')[:-1])
959 def get_subfilters(self, proj_filter):
960 parts = proj_filter.split('\\')
961 subfilters = set([proj_filter]) if proj_filter else set()
962 for i in range(1, len(parts)):
963 subfilters.add('\\'.join(parts[:i]))
966 def write_pretty_xml(self, node, file_path):
967 xml_str = ET.tostring(node, encoding='unicode')
968 pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
969 with open(file_path, 'w') as f:
970 f.write(pretty_str.decode())
972 def add_nodes(self, files_node, module_dir, tag, project_files):
973 ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
975 for project_file in project_files:
976 file_node = ET.SubElement(files_node, tag, Include=project_file)
977 if os.path.commonprefix([module_dir, project_file]) == module_dir:
978 project_filter = self.get_filter(module_dir, project_file)
979 filter_node = ET.SubElement(file_node, '{%s}Filter' % ns)
980 filter_node.text = project_filter
981 filters |= self.get_subfilters(project_filter)
984 def write_filters(self, filters_path, module_dir, compile_files, include_files):
985 ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
986 ET.register_namespace('', ns)
987 proj_node = ET.Element('{%s}Project' % ns, ToolsVersion='4.0')
989 compiles_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
990 filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % ns, compile_files)
991 include_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
992 filters |= self.add_nodes(include_node, module_dir, '{%s}ClInclude' % ns, include_files)
994 filters_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
995 for proj_filter in filters:
996 filter_node = ET.SubElement(filters_node, '{%s}Filter' % ns, Include=proj_filter)
997 filter_id_node = ET.SubElement(filter_node, '{%s}UniqueIdentifier' % ns)
998 filter_id_node.text = '{%s}' % str(uuid.uuid4())
999 self.write_pretty_xml(proj_node, filters_path)
1002 class QtCreatorIntegrationGenerator(IdeIntegrationGenerator):
1004 def __init__(self, gbuildparser, ide):
1005 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
1006 self.target_by_location = {}
1007 for target in set(self.gbuildparser.libs) | set(self.gbuildparser.exes):
1008 if target.location not in self.target_by_location:
1009 self.target_by_location[target.location] = set()
1010 self.target_by_location[target.location] |= set([target])
1012 self._do_log = False # set to 'True' to activate log of QtCreatorIntegrationGenerator
1014 qtlog_path = os.path.abspath('../qtlog_.txt')
1015 self.qtlog = open(qtlog_path, 'w')
1017 def _log(self, message):
1019 self.qtlog.write(message)
1021 def log_close(self):
1025 def generate_build_configs(self, lib_folder):
1026 module_folder = os.path.join(self.base_folder, lib_folder)
1028 # In QtCreator UI, build configs are listed alphabetically,
1029 # so it can be different from the creation order.
1030 # So we prefix the names with the index.
1031 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1033 'base_folder': module_folder,
1035 'name': "1-Build %s" % lib_folder,
1037 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1039 'base_folder': module_folder,
1041 'name': "2-Local tests -- quick tests (unitcheck)",
1043 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1045 'base_folder': module_folder,
1046 'arg': "unitcheck slowcheck screenshot",
1047 'name': "3-Local tests -- slow tests (unitcheck, slowcheck, screenshot)",
1049 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1051 'base_folder': module_folder,
1052 'arg': "unitcheck slowcheck screenshot subsequentcheck",
1053 'name': "4-Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1055 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1057 'base_folder': self.base_folder,
1059 'name': "5-Global tests -- quick tests (unitcheck)",
1061 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1063 'base_folder': self.base_folder,
1064 'arg': "unitcheck slowcheck screenshot",
1065 'name': "6-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
1067 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1069 'base_folder': self.base_folder,
1070 'arg': "unitcheck slowcheck screenshot subsequentcheck",
1071 'name': "7-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1073 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1075 'base_folder': self.base_folder,
1076 'arg': "build-nocheck",
1077 'name': "8-Global build -- nocheck",
1079 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1081 'base_folder': self.base_folder,
1083 'name': "9-Global build",
1086 xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
1091 def generate_meta_build_configs(self):
1093 # In QtCreator UI, build configs are listed alphabetically,
1094 # so it can be different from the creation order.
1095 # So we prefix the names with the index.
1096 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1098 'base_folder': self.base_folder,
1100 'name': "01-Global Build",
1102 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1104 'base_folder': self.base_folder,
1106 'name': "02-Global tests -- quick tests (unitcheck)",
1108 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1110 'base_folder': self.base_folder,
1111 'arg': "unitcheck slowcheck screenshot",
1112 'name': "03-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
1114 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1116 'base_folder': self.base_folder,
1117 'arg': "unitcheck slowcheck screenshot subsequentcheck",
1118 'name': "04-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1120 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1122 'base_folder': self.base_folder,
1124 'name': "05-Global tests -- performance tests (perfcheck)",
1126 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1128 'base_folder': self.base_folder,
1130 'name': "06-Global tests -- tests (check)",
1132 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1134 'base_folder': self.base_folder,
1135 'arg': "build-nocheck",
1136 'name': "07-Global build -- nocheck",
1138 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1140 'base_folder': self.base_folder,
1141 'arg': "build-l10n-only",
1142 'name': "08-Global build -- build-l10n-only",
1144 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1146 'base_folder': self.base_folder,
1147 'arg': "build-non-l10n-only",
1148 'name': "09-Global build -- build-non-l10n-only",
1150 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1152 'base_folder': self.base_folder,
1154 'name': "10-Global build -- clean",
1156 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1158 'base_folder': self.base_folder,
1159 'arg': "clean-build",
1160 'name': "11-Global build -- clean-build",
1162 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1164 'base_folder': self.base_folder,
1165 'arg': "clean-host",
1166 'name': "12-Global build -- clean-host",
1168 xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
1173 # By default, QtCreator creates 2 BuildStepList : "Build" et "Clean"
1174 # but the "clean" can be empty.
1175 build_configs_template = """
1176 <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.%(index)s">
1177 <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">%(base_folder)s</value>
1179 <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
1181 <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
1182 <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
1183 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
1184 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1185 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
1186 <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
1187 <value type="QString">-w</value>
1188 <value type="QString">-r</value>
1190 <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
1191 <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">%(arg)s</value>
1192 <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
1195 <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
1196 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
1197 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1198 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
1201 <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
1202 <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
1203 <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
1204 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">%(name)s</value>
1205 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1206 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
1207 <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">%(index)s</value>
1208 <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
1212 build_configs_count_template = """
1213 <!-- nb build configurations -->
1214 <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">%(nb)s</value>
1217 def generate_deploy_configs(self, lib_folder):
1218 xml = QtCreatorIntegrationGenerator.deploy_configs_template % {}
1221 deploy_configs_template = """
1222 <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
1223 <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
1224 <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
1225 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
1226 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1227 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
1229 <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
1230 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
1231 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1232 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
1234 <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
1237 def generate_run_configs(self, lib_folder):
1239 # If we use 'soffice', it's ok only for "Run", not for "Debug".
1240 # So we put "soffice.bin" that is ok for both.
1241 loexec = "%s/instdir/program/soffice.bin" % self.base_folder
1242 xml = QtCreatorIntegrationGenerator.run_configs_template % {
1244 'workdir': self.base_folder
1248 run_configs_template = """
1249 <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
1250 <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
1251 <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
1252 <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
1253 <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
1254 <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
1255 <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
1256 <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
1257 <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
1258 <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
1259 <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
1260 <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
1261 <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
1262 <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
1263 <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
1264 <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
1265 <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
1266 <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
1267 <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
1268 <value type="int">0</value>
1269 <value type="int">1</value>
1270 <value type="int">2</value>
1271 <value type="int">3</value>
1272 <value type="int">4</value>
1273 <value type="int">5</value>
1274 <value type="int">6</value>
1275 <value type="int">7</value>
1276 <value type="int">8</value>
1277 <value type="int">9</value>
1278 <value type="int">10</value>
1279 <value type="int">11</value>
1280 <value type="int">12</value>
1281 <value type="int">13</value>
1282 <value type="int">14</value>
1284 <value type="int" key="PE.EnvironmentAspect.Base">2</value>
1285 <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
1287 <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
1288 <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%(loexec)s</value>
1289 <value type="bool" key="ProjectExplorer.CustomExecutableRunConfiguration.UseTerminal">false</value>
1290 <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">%(workdir)s</value>
1291 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run libreoffice/instdir/program/soffice</value>
1292 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1293 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
1294 <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
1295 <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
1296 <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
1297 <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
1298 <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
1299 <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
1302 <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
1305 def generate_pro_user_content(self, lib_folder):
1307 build_configs = self.generate_build_configs(lib_folder)
1308 deploy_configs = self.generate_deploy_configs(lib_folder)
1309 run_configs = self.generate_run_configs(lib_folder)
1311 xml = QtCreatorIntegrationGenerator.pro_user_template % {
1312 'build_configs': build_configs,
1313 'deploy_configs': deploy_configs,
1314 'run_configs': run_configs,
1318 def generate_meta_pro_user_content(self):
1320 build_configs = self.generate_meta_build_configs()
1321 deploy_configs = self.generate_deploy_configs("")
1322 run_configs = self.generate_run_configs("")
1324 xml = QtCreatorIntegrationGenerator.pro_user_template % {
1325 'build_configs': build_configs,
1326 'deploy_configs': deploy_configs,
1327 'run_configs': run_configs,
1331 pro_user_template = """<?xml version="1.0" encoding="UTF-8"?>
1332 <!DOCTYPE QtCreatorProject>
1333 <!-- Written by QtCreator 3.1.1, 2015-05-14T15:54:34. -->
1336 <variable>ProjectExplorer.Project.ActiveTarget</variable>
1337 <value type="int">0</value>
1340 <!-- editor settings -->
1342 <variable>ProjectExplorer.Project.EditorSettings</variable>
1343 <valuemap type="QVariantMap">
1344 <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
1345 <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
1346 <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
1347 <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
1348 <value type="QString" key="language">Cpp</value>
1349 <valuemap type="QVariantMap" key="value">
1350 <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
1353 <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
1354 <value type="QString" key="language">QmlJS</value>
1355 <valuemap type="QVariantMap" key="value">
1356 <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
1359 <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
1360 <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
1361 <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
1362 <value type="int" key="EditorConfiguration.IndentSize">4</value>
1363 <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
1364 <value type="int" key="EditorConfiguration.MarginColumn">80</value>
1365 <value type="bool" key="EditorConfiguration.MouseHiding">true</value>
1366 <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
1367 <value type="int" key="EditorConfiguration.PaddingMode">1</value>
1368 <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
1369 <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
1370 <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
1371 <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
1372 <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
1373 <value type="int" key="EditorConfiguration.TabSize">8</value>
1374 <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
1375 <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
1376 <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
1377 <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
1378 <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
1379 <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
1384 <variable>ProjectExplorer.Project.PluginSettings</variable>
1385 <valuemap type="QVariantMap"/>
1390 <variable>ProjectExplorer.Project.Target.0</variable>
1391 <valuemap type="QVariantMap">
1392 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
1393 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
1394 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{0701de51-c96e-4e4f-85c3-e70b223c5076}</value>
1395 <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
1396 <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
1397 <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
1399 <!-- build configurations -->
1402 <!-- deploy configurations -->
1405 <!-- plugin settings -->
1406 <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
1408 <!-- run configurations -->
1413 <!-- nb targets : 1 -->
1415 <variable>ProjectExplorer.Project.TargetCount</variable>
1416 <value type="int">1</value>
1419 <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
1420 <value type="QByteArray">{5abcafed-86f6-49f6-b1cb-380fadd21211}</value>
1423 <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
1424 <value type="int">15</value>
1429 def remove_qt_files(self):
1431 def do_remove_file(loc, afile):
1433 os.remove(os.path.join(loc, afile))
1434 self._log("removed %s\n" % afile)
1436 self._log("unable to remove %s\n" % afile)
1438 do_remove_file(self.base_folder, "lo.pro")
1439 do_remove_file(self.base_folder, "lo.pro.user")
1440 for location in self.target_by_location:
1441 for f in os.listdir(location):
1442 if f.endswith('.pro') or f.endswith('.pro.user'):
1443 do_remove_file(location, f)
1445 def get_source_extension(self, src_file):
1446 path = os.path.join(self.base_folder, src_file)
1447 for ext in (".cxx", ".cpp", ".c", ".mm"):
1448 if os.path.isfile(path + ext):
1452 def get_header_extension(self, src_file):
1453 path = os.path.join(self.base_folder, src_file)
1454 for ext in (".hxx", ".hpp", ".h"):
1455 if os.path.isfile(path + ext):
1459 def build_data_libs(self):
1463 all_libs = set(self.gbuildparser.libs) | set(self.gbuildparser.exes)
1464 for lib in all_libs:
1465 self._log("\nlibrary : %s, loc=%s" % (lib.short_name(), lib.location))
1466 lib_name = os.path.basename(lib.location)
1467 lib_folder = os.path.relpath(lib.location, self.base_folder)
1470 return os.path.relpath(path, lib.location)
1474 includepath_list = []
1475 # The explicit headers list is not mandatory :
1476 # QtCreator just needs 'include_path_list' to find all headers files.
1477 # But files listed in 'header_list' will be shown
1478 # in a specific "Headers" folder in QtCreator's Project panel.
1479 # We will list here only headers files of current lib.
1481 for file_ in lib.cxxobjects:
1482 # the file has no extension : search it
1483 # self._log("\n file : %s" % file_)
1484 ext = self.get_source_extension(file_)
1486 sources_list.append(lopath(file_ + ext))
1488 # few cxxobject files have a header beside
1489 ext = self.get_header_extension(file_)
1491 headers_list.append(lopath(file_ + ext))
1493 # List all include paths
1494 for hdir in lib.include:
1495 hf_lopath = lopath(hdir)
1496 includepath_list.append(hf_lopath)
1498 # List headers files from current lib
1499 for hdir in lib.include:
1500 if hdir.startswith(lib.location):
1501 for hf in os.listdir(hdir):
1502 if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
1503 hf_lopath = lopath(os.path.join(hdir, hf))
1504 headers_list.append(hf_lopath)
1507 for key, value in lib.defs.items():
1509 if value is not None:
1510 define += '=' + value
1511 defines_list.append(define)
1513 # All datas are prepared, store them for the lib.
1514 if lib_folder in self.data_libs:
1515 self.data_libs[lib_folder]['sources'] |= set(sources_list)
1516 self.data_libs[lib_folder]['headers'] |= set(headers_list)
1517 self.data_libs[lib_folder]['includepath'] |= set(includepath_list)
1518 self.data_libs[lib_folder]['defines'] |= set(defines_list)
1520 self.data_libs[lib_folder] = {
1521 'sources': set(sources_list),
1522 'headers': set(headers_list),
1523 'includepath': set(includepath_list),
1524 'defines': set(defines_list),
1525 'loc': lib.location,
1531 self.base_folder = self.gbuildparser.builddir
1533 # we remove existing '.pro' and '.pro.user' files
1534 self.remove_qt_files()
1536 # for .pro files, we must explicitly list all files (.c, .h)
1537 # so we can't reuse directly the same method than for kde integration.
1538 self.build_data_libs()
1540 subdirs_list = self.data_libs.keys()
1541 # Now we can create Qt files
1542 for lib_folder in subdirs_list:
1543 sources_list = sorted(self.data_libs[lib_folder]['sources'])
1544 headers_list = sorted(self.data_libs[lib_folder]['headers'])
1545 includepath_list = sorted(self.data_libs[lib_folder]['includepath'])
1546 defines_list = sorted(self.data_libs[lib_folder]['defines'])
1547 lib_loc = self.data_libs[lib_folder]['loc']
1548 lib_name = self.data_libs[lib_folder]['name']
1550 sources = " \\\n".join(sources_list)
1551 headers = " \\\n".join(headers_list)
1552 includepath = " \\\n".join(includepath_list)
1553 defines = " \\\n".join(defines_list)
1556 qt_pro_file = '%s/%s.pro' % (lib_loc, lib_name)
1558 content = QtCreatorIntegrationGenerator.pro_template % {'sources': sources, 'headers': headers, 'includepath': includepath, 'defines': defines}
1560 with open(qt_pro_file, mode) as fpro:
1562 self._log("created %s\n" % qt_pro_file)
1564 except Exception as e:
1565 print("ERROR : creating pro file=" + qt_pro_file, file=sys.stderr)
1566 print(e, file=sys.stderr)
1567 temp = traceback.format_exc() # .decode('utf8')
1568 print(temp, file=sys.stderr)
1569 print("\n\n", file=sys.stderr)
1571 # create .pro.user file
1572 qt_pro_user_file = '%s/%s.pro.user' % (lib_loc, lib_name)
1574 with open(qt_pro_user_file, mode) as fprouser:
1575 fprouser.write(self.generate_pro_user_content(lib_folder))
1576 self._log("created %s\n" % qt_pro_user_file)
1578 except Exception as e:
1579 print("ERROR : creating pro.user file=" + qt_pro_user_file, file=sys.stderr)
1580 print(e, file=sys.stderr)
1581 temp = traceback.format_exc()
1582 print(temp, file=sys.stderr)
1583 print("\n\n", file=sys.stderr)
1585 # create meta .pro file (lists all sub projects)
1586 qt_meta_pro_file = 'lo.pro'
1588 subdirs = " \\\n".join(subdirs_list)
1589 content = QtCreatorIntegrationGenerator.pro_meta_template % {'subdirs': subdirs}
1590 with open(qt_meta_pro_file, 'w+') as fmpro:
1591 fmpro.write(content)
1593 except Exception as e:
1594 print("ERROR : creating lo.pro file=" + qt_meta_pro_file, file=sys.stderr)
1595 print(e, file=sys.stderr)
1596 temp = traceback.format_exc()
1597 print(temp, file=sys.stderr)
1598 print("\n\n", file=sys.stderr)
1600 # create meta .pro.user file
1601 qt_meta_pro_user_file = 'lo.pro.user'
1603 with open(qt_meta_pro_user_file, mode) as fmprouser:
1604 fmprouser.write(self.generate_meta_pro_user_content())
1605 self._log("created %s\n" % qt_meta_pro_user_file)
1607 except Exception as e:
1608 print("ERROR : creating lo.pro.user file=" + qt_meta_pro_user_file, file=sys.stderr)
1609 print(e, file=sys.stderr)
1610 temp = traceback.format_exc()
1611 print(temp, file=sys.stderr)
1612 print("\n\n", file=sys.stderr)
1616 pro_template = """TEMPLATE = app
1618 CONFIG -= app_bundle
1621 INCLUDEPATH += %(includepath)s
1623 SOURCES += %(sources)s
1625 HEADERS += %(headers)s
1627 DEFINES += %(defines)s
1630 pro_meta_template = """TEMPLATE = subdirs
1632 SUBDIRS = %(subdirs)s
1637 parser = argparse.ArgumentParser(
1638 description='LibreOffice gbuild IDE project generator')
1639 parser.add_argument('--ide', dest='ide', required=True,
1640 help='the IDE to generate project files for')
1641 parser.add_argument('--make', dest='makecmd', required=True,
1642 help='the command to execute make')
1643 return parser.parse_args()
1646 if __name__ == '__main__':
1647 args = get_options()
1649 if args.makecmd == 'make':
1650 args.makecmd = '/usr/bin/make'
1654 'eclipsecdt': EclipseCDTIntegrationGenerator,
1655 'kdevelop': KdevelopIntegrationGenerator,
1656 'xcode': XcodeIntegrationGenerator,
1657 'vs2015': VisualStudioIntegrationGenerator,
1658 'vim': VimIntegrationGenerator,
1659 'debug': DebugIntegrationGenerator,
1660 'qtcreator': QtCreatorIntegrationGenerator,
1663 if args.ide not in generators.keys():
1664 print("Invalid ide. valid values are %s" % ','.join(generators.keys()))
1667 gbuildparser = GbuildParser(args.makecmd).parse()
1669 generators[args.ide](gbuildparser, args.ide).emit()
1670 print("Successfully created the project files.")
1673 # indent-tabs-mode: nil
1676 # vim: set et sw=4 ts=4: