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 includepattern = re.compile(r'-I(\S+)')
30 isystempattern = re.compile(r'-isystem\s*(\S+)')
31 warningpattern = re.compile(r'-W\S+')
34 def __split_includes(includes):
35 foundisystem = GbuildLinkTarget.isystempattern.findall(includes)
36 foundincludes = [includeswitch.strip() for includeswitch in GbuildLinkTarget.includepattern.findall(includes) if
37 len(includeswitch) > 2]
38 return (foundincludes, foundisystem)
41 def __split_objs(objsline):
42 return [obj for obj in objsline.strip().split(' ') if obj not in { '', 'CXXOBJECTS', 'COBJECTS', 'OBJCXXOBJECTS', 'CXXCLROBJECTS', '+=' }]
45 def __split_defs(defsline):
47 alldefs = [defswitch.strip() for defswitch in defsline.strip().lstrip('-D').split(' -D') if len(defswitch) > 2]
49 dparts = d.split(' -U')
50 """after dparts.pop(0), dparts will contain only undefs"""
51 defparts = dparts.pop(0).strip().split('=')
52 if len(defparts) == 1:
54 defs[defparts[0]] = defparts[1]
55 """Drop undefed items (if any) from previous defs"""
57 defs.pop(u.strip(), '')
58 defs["LIBO_INTERNAL_ONLY"] = None
62 def __split_flags(flagsline, flagslineappend):
63 return [cxxflag.strip() for cxxflag in GbuildLinkTarget.warningpattern.sub('', '%s %s' % (flagsline, flagslineappend)).split(' ') if len(cxxflag) > 1]
65 def __init__(self, json):
66 (foundincludes, foundisystem) = GbuildLinkTarget.__split_includes(json['INCLUDE'])
67 (self.name, self.location, self.include, self.include_sys, self.defs, self.cxxobjects, self.objcxxobjects, self.cxxflags, self.cobjects, self.cflags, self.cxxclrobjects, self.cxxclrflags, self.linked_libs, self.linked_static_libs, self.link_target) = (
68 type(self).targetpattern.match(os.path.basename(json['MAKEFILE'])).group(1),
69 os.path.dirname(json['MAKEFILE']),
72 GbuildLinkTarget.__split_defs(json['DEFS']),
73 GbuildLinkTarget.__split_objs(json['CXXOBJECTS']),
74 GbuildLinkTarget.__split_objs(json['OBJCXXOBJECTS']),
75 GbuildLinkTarget.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
76 GbuildLinkTarget.__split_objs(json['COBJECTS']),
77 GbuildLinkTarget.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
78 GbuildLinkTarget.__split_objs(json['CXXCLROBJECTS']),
79 GbuildLinkTarget.__split_flags(json['CXXCLRFLAGS'], json['CXXCLRFLAGSAPPEND']),
80 json['LINKED_LIBS'].strip().split(' '),
81 json['LINKED_STATIC_LIBS'].strip().split(' '),
82 json['LINKTARGET'].strip())
85 """Return the short name of target based on the Foo_* makefile name"""
86 return '%s %s' % (type(self).targetprefix, self.name)
88 def target_name(self):
89 return '%s_%s' % (type(self).targetprefix, self.name)
92 return '%s at %s with include path: %s, isystem includes: %s, defines: %s, objects: %s, cxxflags: %s, cobjects: %s, cflags: %s, linked libs: %s and linked static libs: %s' % (
93 self.short_name(), self.location, self.include, self.include_sys, self.defs, self.cxxobjects,
94 self.cxxflags, self.cobjects, self.cflags, self.linked_libs, self.linked_static_libs)
97 class GbuildLib(GbuildLinkTarget):
98 targetpattern = re.compile(r'Library_(.*)\.mk')
99 targetprefix = "Library"
101 class GbuildStaticLib(GbuildLinkTarget):
102 targetpattern = re.compile(r'StaticLibrary_(.*)\.mk')
103 targetprefix = "StaticLibrary"
105 class GbuildTest(GbuildLinkTarget):
106 targetpattern = re.compile(r'CppunitTest_(.*)\.mk')
107 targetprefix = "CppunitTest"
109 class GbuildExe(GbuildLinkTarget):
110 targetpattern = re.compile(r'Executable_(.*)\.mk')
111 targetprefix = "Executable"
115 """Main data model object.
118 target_by_path : dict[path:string, set(target)]
119 where target is one of the GbuildLinkTarget subclasses
120 target_by_location : dict[path:string, set(target)]
121 where target is one of the GbuildLinkTarget subclasses
123 def __init__(self, makecmd):
124 self.makecmd = makecmd
125 self.binpath = os.path.dirname(os.environ['GPERF']) # woha, this is quite a hack
126 (self.srcdir, self.builddir, self.instdir, self.workdir) = (os.environ['SRCDIR'], os.environ['BUILDDIR'], os.environ['INSTDIR'], os.environ['WORKDIR'])
127 (self.libs, self.static_libs, self.exes, self.tests, self.modulenamelist) = (set(), set(), set(), set(), [])
128 (self.target_by_path, self.target_by_location) = ({}, {})
131 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Library')):
132 with open(os.path.join(self.workdir, 'GbuildToJson', 'Library', jsonfilename), 'r') as f:
133 lib = GbuildLib(json.load(f))
135 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'StaticLibrary')):
136 with open(os.path.join(self.workdir, 'GbuildToJson', 'StaticLibrary', jsonfilename), 'r') as f:
137 static_lib = GbuildStaticLib(json.load(f))
138 self.static_libs.add(static_lib)
139 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Executable')):
140 with open(os.path.join(self.workdir, 'GbuildToJson', 'Executable', jsonfilename), 'r') as f:
141 exe = GbuildExe(json.load(f))
143 for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest')):
144 with open(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest', jsonfilename), 'r') as f:
145 test = GbuildTest(json.load(f))
147 for target in self.libs | self.static_libs | self.exes | self.tests:
148 if target.location not in self.target_by_location:
149 self.target_by_location[target.location] = set()
150 self.target_by_location[target.location] |= set([target])
151 for cxx in target.cxxobjects:
152 path = '/'.join(cxx.split('/')[:-1])
153 if path not in self.target_by_path:
154 self.target_by_path[path] = set()
155 self.target_by_path[path] |= set([target])
156 for c in target.cobjects:
157 path = '/'.join(c.split('/')[:-1])
158 if path not in self.target_by_path:
159 self.target_by_path[path] = set()
160 self.target_by_path[path] |= set([target])
161 for location in self.target_by_location:
162 self.modulenamelist.append(os.path.split(location)[1])
166 class IdeIntegrationGenerator:
168 def __init__(self, gbuildparser, ide):
169 self.gbuildparser = gbuildparser
175 class EclipseCDTIntegrationGenerator(IdeIntegrationGenerator):
177 def __init__(self, gbuildparser, ide):
178 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
180 def create_include_paths(self):
181 for module in self.gbuildparser.modulenamelist:
182 modulepath = os.path.join(self.gbuildparser.builddir, module)
183 includedirfile = open(os.path.join(modulepath, '.eclipsesettingfile'), 'w')
185 for lib in self.gbuildparser.target_by_path.keys():
186 if lib.startswith(module+'/'):
187 modulelibs.append(lib)
189 for lib in modulelibs:
190 for target in self.gbuildparser.target_by_path[lib]:
191 include |= set(target.include)
192 includedirfile.write('\n'.join(include))
193 includedirfile.close()
196 def create_macros(self):
197 for module in self.gbuildparser.modulenamelist:
198 modulepath = os.path.join(self.gbuildparser.builddir, module)
199 macrofile = open(os.path.join(modulepath, '.macros'), 'w')
201 for lib in self.gbuildparser.target_by_path.keys():
202 if lib.startswith(module+'/'):
203 modulelibs.append(lib)
206 for lib in modulelibs:
207 for target in self.gbuildparser.target_by_path[lib]:
208 for i in target.defs.keys():
209 tmp = str(i) +','+str(target.defs[i])
210 if tmp not in defineset:
212 macrofile.write('\n'.join(defineset))
216 def create_settings_file(self):
218 settingsfiletemplate = """\
219 <?xml version="1.0" encoding="UTF-8"?>
220 <cdtprojectproperties>
221 <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths">
222 <language name="C++ Source File">
226 <language name="C Source File">
229 <language name="Object File">
232 <language name="Assembly Source File">
236 <section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros">
237 <language name="C++ Source File">
240 <language name="C Source File">
243 <language name="Object File">
246 <language name="Assembly Source File">
250 </cdtprojectproperties>
253 for module in self.gbuildparser.modulenamelist:
255 modulepath = os.path.join(self.gbuildparser.builddir, module)
257 settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
258 settingsfile.write(settingsfiletemplate)
261 settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'r')
262 tempxml = settingsfile.readlines()
263 tempinclude = open(os.path.join(modulepath, '.eclipsesettingfile'), 'r')
264 tempmacro = open(os.path.join(modulepath, '.macros'), 'r')
265 for includepath in tempinclude:
266 if includepath[-1:] == "\n":
267 includepath = includepath[:-1]
268 templine = "<includepath>%s</includepath>\n" % includepath
269 tempxml.insert(5, templine)
271 for line in tempmacro:
272 macroskeyvalue = line.split(',')
273 macrokey = macroskeyvalue[0]
274 macrovalue = macroskeyvalue[1]
275 if macrovalue[-1:] == "\n":
276 macrovalue = macrovalue[:-1]
277 templine = "<macro><name>%s</name><value>%s</value></macro>\n" %(macrokey, macrovalue)
278 tempxml.insert(-13, templine)
279 tempxml="".join(tempxml)
282 settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
283 settingsfile.write(tempxml)
285 os.remove(os.path.join(modulepath, '.eclipsesettingfile'))
286 os.remove(os.path.join(modulepath, '.macros'))
289 self.create_include_paths()
291 self.create_settings_file()
293 class CodeliteIntegrationGenerator(IdeIntegrationGenerator):
295 def __init__(self, gbuildparser, ide):
296 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
299 self.create_workspace_file()
300 for module in self.gbuildparser.modulenamelist:
301 if os.path.exists(module): # ignore external modules
302 self.create_project_file(module)
303 #self.create_project_file('vcl')
305 def create_workspace_file(self):
306 root_node = ET.Element('CodeLite_Workspace', Name='libo2', Database='./libo2.tags', Version='10.0.0')
307 for module in self.gbuildparser.modulenamelist:
308 if os.path.exists(module): # ignore external modules
309 ET.SubElement(root_node, 'Project', Name=module, Path='%s/%s.project' % (module, module), Active='No')
310 build_matrix_node = ET.SubElement(root_node, 'BuildMatrix')
311 workspace_config_node = ET.SubElement(build_matrix_node, 'WorkspaceConfiguration', Name='Debug', Selected='yes')
312 ET.SubElement(workspace_config_node, 'Environment')
313 for module in self.gbuildparser.modulenamelist:
314 if os.path.exists(module): # ignore external modules
315 ET.SubElement(workspace_config_node, 'Project', Name=module, ConfigName='Debug')
316 workspace_config_node = ET.SubElement(build_matrix_node, 'WorkspaceConfiguration', Name='Release', Selected='yes')
317 ET.SubElement(workspace_config_node, 'Environment')
318 for module in self.gbuildparser.modulenamelist:
319 if os.path.exists(module): # ignore external modules
320 ET.SubElement(workspace_config_node, 'Project', Name=module, ConfigName='Release')
322 self.write_pretty_xml(root_node, os.path.join(self.gbuildparser.builddir, 'libo2.workspace'))
324 def create_project_file(self, module_name):
325 root_node = ET.Element('CodeLite_Project', Name=module_name, InternalType='')
326 ET.SubElement(root_node, 'Plugins')
329 virtual_dirs = collections.defaultdict(set)
330 for target_path in self.gbuildparser.target_by_path.keys():
331 if target_path.startswith(module_name+'/'):
332 for target in self.gbuildparser.target_by_path[target_path]:
333 for file in target.cxxobjects:
334 relative_file = '/'.join(file.split('/')[1:])
335 path = '/'.join(file.split('/')[1:-1])
336 virtual_dirs[path].add(relative_file + '.cxx')
338 all_libs = self.gbuildparser.libs | self.gbuildparser.exes
340 if lib.name == module_name:
341 for hdir in lib.include:
342 # only want the module-internal ones
343 if hdir.startswith(module_name+'/'):
344 for hf in os.listdir(hdir):
345 if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
346 path = '/'.join(hf.split('/')[1:-1])
347 virtual_dirs[path].add(hf)
348 # add HXX files from the root/include/** folders
349 module_include = os.path.join(self.gbuildparser.builddir, 'include', module_name)
350 if os.path.exists(module_include):
351 for hf in os.listdir(module_include):
352 if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
353 path = '../include/' + ('/'.join(hf.split('/')[1:-1]))
354 virtual_dirs['include/' + module_name].add('../include/' + module_name + '/' + hf)
356 for vd_name in sorted(virtual_dirs.keys()):
357 vd_files = sorted(virtual_dirs[vd_name])
358 parent_node = root_node
359 for subname in vd_name.split('/'):
360 parent_node = ET.SubElement(parent_node, 'VirtualDirectory', Name=subname)
361 for file in vd_files:
362 ET.SubElement(parent_node, 'File', Name=file)
364 ET.SubElement(root_node, 'Description')
365 ET.SubElement(root_node, 'Dependencies')
366 ET.SubElement(root_node, 'Dependencies', Name='Debug')
367 ET.SubElement(root_node, 'Dependencies', Name='Release')
369 settingstemplate = """\
370 <Settings Type="Dynamic Library">
372 <Compiler Options="" C_Options="" Assembler="">
373 <IncludePath Value="."/>
376 <LibraryPath Value="."/>
378 <ResourceCompiler Options=""/>
380 <Configuration Name="Debug" CompilerType="clang( based on LLVM 3.5.0 )" DebuggerType="GNU gdb debugger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
381 <Compiler Options="-g" C_Options="-g" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
382 <IncludePath Value="."/>
384 <Linker Options="" Required="yes"/>
385 <ResourceCompiler Options="" Required="no"/>
386 <General OutputFile="" IntermediateDirectory="./Debug" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
387 <BuildSystem Name="Default"/>
388 <Environment EnvVarSetName="<Use Defaults>" DbgSetName="<Use Defaults>">
391 <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
392 <DebuggerSearchPaths/>
393 <PostConnectCommands/>
398 <CustomBuild Enabled="yes">
400 <CleanCommand>make %s.clean</CleanCommand>
401 <BuildCommand>make %s.build</BuildCommand>
402 <PreprocessFileCommand/>
404 <MakefileGenerationCommand/>
405 <ThirdPartyToolName>None</ThirdPartyToolName>
406 <WorkingDirectory>$(WorkspacePath)</WorkingDirectory>
412 <Completion EnableCpp11="no" EnableCpp14="no">
419 <Configuration Name="Release" CompilerType="clang( based on LLVM 3.5.0 )" DebuggerType="GNU gdb debugger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
420 <Compiler Options="" C_Options="" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
421 <IncludePath Value="."/>
423 <Linker Options="-O2" Required="yes"/>
424 <ResourceCompiler Options="" Required="no"/>
425 <General OutputFile="" IntermediateDirectory="./Release" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
426 <BuildSystem Name="Default"/>
427 <Environment EnvVarSetName="<Use Defaults>" DbgSetName="<Use Defaults>">
430 <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
431 <DebuggerSearchPaths/>
432 <PostConnectCommands/>
437 <CustomBuild Enabled="yes">
439 <CleanCommand>make %s.clean</CleanCommand>
440 <BuildCommand>make %s.build</BuildCommand>
441 <PreprocessFileCommand/>
443 <MakefileGenerationCommand/>
444 <ThirdPartyToolName>None</ThirdPartyToolName>
445 <WorkingDirectory>$(WorkspacePath)</WorkingDirectory>
451 <Completion EnableCpp11="no" EnableCpp14="no">
460 root_node.append(ET.fromstring(settingstemplate % (module_name, module_name, module_name, module_name)))
462 self.write_pretty_xml(root_node, os.path.join(self.gbuildparser.builddir, module_name, '%s.project' % module_name))
464 def write_pretty_xml(self, node, file_path):
465 xml_str = ET.tostring(node, encoding='unicode')
466 pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
467 with open(file_path, 'w') as f:
468 f.write(pretty_str.decode())
470 class DebugIntegrationGenerator(IdeIntegrationGenerator):
472 def __init__(self, gbuildparser, ide):
473 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
476 print(self.gbuildparser.srcdir)
477 print(self.gbuildparser.builddir)
478 for lib in self.gbuildparser.libs:
480 for exe in self.gbuildparser.exes:
482 for test in self.gbuildparser.tests:
486 class VimIntegrationGenerator(IdeIntegrationGenerator):
488 def __init__(self, gbuildparser, ide):
489 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
493 for lib in self.gbuildparser.libs | self.gbuildparser.tests | self.gbuildparser.exes:
495 for file in lib.cxxobjects:
496 filePath = os.path.join(self.gbuildparser.srcdir, file) + ".cxx"
497 entry = {'directory': lib.location, 'file': filePath, 'command': self.generateCommand(lib, filePath)}
498 entries.append(entry)
499 global_list.extend(entries)
500 with open(os.path.join(self.gbuildparser.builddir, 'compile_commands.json'), 'w') as export_file:
501 json.dump(global_list, export_file)
503 def generateCommand(self, lib, file):
504 command = 'clang++ -Wall'
505 for key, value in lib.defs.items():
508 if value is not None:
512 for include in lib.include:
515 for isystem in lib.include_sys:
516 command += ' -isystem '
518 for cxxflag in lib.cxxflags:
526 class KdevelopIntegrationGenerator(IdeIntegrationGenerator):
528 def encode_int(self, i):
530 return '\\x%s\\x%s\\x%s\\x%s' % (temp[0:2], temp[2:4], temp[4:6], temp[6:8])
532 def encode_string(self, string):
533 result = self.encode_int(len(string) * 2)
534 for c in string.encode('utf-16-be'):
535 if c in range(32, 126):
538 result += '\\x%02x' % c
541 def generate_buildsystemconfigtool(self, configid, tool, args, exe, typenr):
542 return KdevelopIntegrationGenerator.buildsystemconfigtooltemplate % {'configid': configid, 'tool': tool,
543 'args': args, 'exe': exe, 'typenr': typenr}
545 buildsystemconfigtooltemplate = """
546 [CustomBuildSystem][BuildConfig%(configid)d][Tool%(tool)s]
555 def generate_buildsystemconfig(self, configid, moduledir, builddir, title, buildparms=''):
556 result = KdevelopIntegrationGenerator.buildsystemconfigtemplate % {'configid': configid, 'builddir': builddir,
558 result += self.generate_buildsystemconfigtool(configid, 'Clean', 'clean %s' % buildparms,
559 self.gbuildparser.makecmd, 3)
560 result += self.generate_buildsystemconfigtool(configid, 'Build', 'all %s' % buildparms,
561 self.gbuildparser.makecmd, 0)
564 buildsystemconfigtemplate = """
565 [CustomBuildSystem][BuildConfig%(configid)d]
566 BuildDir=file://%(builddir)s
571 def generate_buildsystem(self, moduledir):
572 result = KdevelopIntegrationGenerator.buildsystemtemplate % {'defaultconfigid': 0}
573 result += self.generate_buildsystemconfig(0, moduledir, moduledir, 'Module Build -- Release')
574 result += self.generate_buildsystemconfig(1, moduledir, self.gbuildparser.builddir, 'Full Build -- Release')
575 result += self.generate_buildsystemconfig(2, moduledir, moduledir, 'Module Build -- Debug', 'debug=T')
576 result += self.generate_buildsystemconfig(3, moduledir, self.gbuildparser.builddir, 'Full Build -- Debug',
580 buildsystemtemplate = """
582 CurrentConfiguration=BuildConfig%(defaultconfigid)d
586 def generate_launch(self, launchid, launchname, executablepath, args, workdir):
587 return KdevelopIntegrationGenerator.launchtemplate % {'launchid': launchid, 'launchname': launchname,
588 'executablepath': executablepath, 'args': args,
592 [Launch][Launch Configuration %(launchid)d]
593 Configured Launch Modes=execute
594 Configured Launchers=nativeAppLauncher
596 Type=Native Application
598 [Launch][Launch Configuration %(launchid)d][Data]
600 Dependencies=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x00)
601 Dependency Action=Nothing
602 EnvironmentGroup=default
603 Executable=file://%(executablepath)s
604 External Terminal=konsole --noclose --workdir %%workdir -e %%exe
606 Use External Terminal=false
607 Working Directory=file://%(workdir)s
612 def generate_launches(self, moduledir):
613 launches = ','.join(['Launch Configuration %d' % i for i in range(7)])
614 result = KdevelopIntegrationGenerator.launchestemplate % {'launches': launches}
615 result += self.generate_launch(0, 'Local tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
616 'unitcheck', moduledir)
617 result += self.generate_launch(1, 'Local tests -- slow tests (unitcheck, slowcheck, screenshot)', self.gbuildparser.makecmd,
618 'unitcheck slowcheck screenshot', moduledir)
619 result += self.generate_launch(2, 'Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
620 self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck', moduledir)
621 result += self.generate_launch(3, 'Global tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
622 'unitcheck', self.gbuildparser.builddir)
623 result += self.generate_launch(4, 'Global tests -- slow tests (unitcheck, slowcheck, screenshot)',
624 self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot', self.gbuildparser.builddir)
625 result += self.generate_launch(5, 'Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
626 self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck',
627 self.gbuildparser.builddir)
628 result += self.generate_launch(6, 'Run LibreOffice',
629 os.path.join(self.gbuildparser.instdir, 'program/soffice.bin'), '',
630 self.gbuildparser.instdir)
633 launchestemplate = """
635 Launch Configurations=%(launches)s
639 def write_modulebeef(self, moduledir, modulename):
640 beefdir = os.path.join(moduledir, '.kdev4')
642 beeffile = open(os.path.join(beefdir, 'Module_%s.kdev4' % modulename), 'w')
643 beeffile.write(self.generate_buildsystem(moduledir))
644 beeffile.write(self.generate_launches(moduledir))
647 def write_modulestub(self, moduledir, modulename):
648 stubfile = open(os.path.join(moduledir, 'Module_%s.kdev4' % modulename), 'w')
649 stubfile.write(KdevelopIntegrationGenerator.modulestubtemplate % {'modulename': modulename,
650 'builditem': self.encode_string(
651 'Module_%s' % modulename)})
654 modulestubtemplate = """
656 BuildItems=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x0b\\x00\\x00\\x00\\x00\\x01%(builditem)s)
659 Name=Module_%(modulename)s
660 Manager=KDevCustomBuildSystem
661 VersionControl=kdevgit
664 def write_includepaths(self, path):
665 includedirfile = open(os.path.join(path, '.kdev_include_paths'), 'w')
667 for target in self.gbuildparser.target_by_path[path]:
668 include |= set(target.include)
669 includedirfile.write('\n'.join(include))
670 includedirfile.close()
672 def __init__(self, gbuildparser, ide):
673 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
676 for path in self.gbuildparser.target_by_path:
677 self.write_includepaths(path)
678 for location in self.gbuildparser.target_by_location:
679 for f in os.listdir(location):
680 if f.endswith('.kdev4'):
682 os.remove(os.path.join(location, f))
684 shutil.rmtree(os.path.join(location, f))
685 for location in self.gbuildparser.target_by_location:
686 modulename = os.path.split(location)[1]
687 self.write_modulestub(location, modulename)
688 self.write_modulebeef(location, modulename)
691 class XcodeIntegrationGenerator(IdeIntegrationGenerator):
693 def indent(self, file, level):
696 for i in range(0, level):
699 def write_object(self, object, file, indent):
700 if isinstance(object, int):
701 file.write('%d' % object)
702 elif isinstance(object, str) and not re.search('[^A-Za-z0-9_]', object):
703 file.write('%s' % object)
704 elif isinstance(object, str):
705 file.write('"%s"' % object)
706 elif isinstance(object, dict):
707 self.write_dict(object, file, indent)
709 # Write a dictionary out as an "old-style (NeXT) ASCII plist"
710 def write_dict(self, dict, file, indent):
713 for key in sorted(dict.keys()):
714 self.indent(file, indent + 1)
715 file.write('%s = ' % key)
716 self.write_object(dict[key], file, indent + 1)
718 self.indent(file, indent)
721 def write_dict_to_plist(self, dict, file):
722 file.write('// !$*UTF8*$!\n')
723 self.write_dict(dict, file, 0)
725 def get_product_type(self, modulename):
726 if modulename in self.gbuildparser.libs:
727 return 'com.apple.product-type.library.dynamic'
728 elif modulename in self.gbuildparser.exes:
729 return 'com.apple.product-type.something'
733 def generate_id(self):
734 XcodeIntegrationGenerator.counter = XcodeIntegrationGenerator.counter + 1
735 return str('X%07x' % XcodeIntegrationGenerator.counter)
737 def generate_build_phases(self, modulename):
738 result = [self.sourcesBuildPhaseId]
741 def generate_root_object(self, modulename):
742 result = {'isa': 'PBXProject',
743 'attributes': {'LastUpgradeCheck': '0500',
744 'ORGANIZATIONNAME': 'LibreOffice'},
745 'buildConfigurationList': self.generate_id(),
746 'compatibilityVersion': 'Xcode 3.2',
747 'hasScannedForEncodings': 0,
748 'knownRegions': ['en'],
749 'mainGroup': self.mainGroupId,
750 'productRefGroup': self.productRefGroupId,
751 'projectDirPath': '',
753 'targets': self.targetId}
756 def generate_target(self, modulename):
757 result = {'isa': 'PBXNativeTarget',
758 'buildConfigurationList': self.generate_id(),
759 'buildPhases': self.generate_build_phases(modulename),
763 'productName': modulename,
764 'productReference': self.productReferenceId,
765 'productType': self.get_product_type(modulename)}
768 def generate_main_group(self, modulename):
769 result = {'isa': 'PBXGroup',
770 'children': [self.subMainGroupId, self.productGroupId],
771 'sourceTree': '<group>'}
774 def generate_sub_main_children(self, modulename):
777 def generate_sub_main_group(self, modulename):
778 result = {'isa': 'PBXGroup',
779 'children': self.generate_sub_main_children(modulename),
781 'sourceTree': '<group>'}
784 def generate_product_group(self, modulename):
785 result = {'isa': 'PBXGroup',
786 'children': [self.productReferenceId],
788 'sourceTree': '<group>'}
791 def build_source_list(self, module):
792 self.sourceRefList = {}
795 for i in module.cxxobjects:
796 ref = self.generate_id()
797 self.sourceList[self.generate_id()] = ref
798 self.sourceRefList[ref] = {'lastKnownFileType': 'sourcecode.cpp.cpp',
800 'sourceTree': '<group>'}
802 def generate_sources_build_phase(self, modulename):
803 result = {'isa': 'PBXSourcesBuildPhase',
804 'buildActionMask': 2147483647,
805 'files': self.sourceList.keys(),
806 'runOnlyForDeploymentPostprocessing': 0}
809 def generate_project(self, target):
810 self.rootObjectId = self.generate_id()
811 self.mainGroupId = self.generate_id()
812 self.subMainGroupId = self.generate_id()
813 self.productReferenceId = self.generate_id()
814 self.productRefGroupId = self.generate_id()
815 self.productGroupId = self.generate_id()
816 self.targetId = self.generate_id()
817 self.build_source_list(target)
818 self.sourcesBuildPhaseId = self.generate_id()
819 objects = {self.rootObjectId: self.generate_root_object(target),
820 self.targetId: self.generate_target(target),
821 self.mainGroupId: self.generate_main_group(target),
822 self.subMainGroupId: self.generate_sub_main_group(target),
823 self.productGroupId: self.generate_product_group(target),
824 self.sourcesBuildPhaseId: self.generate_sources_build_phase(target)
826 for i in self.sourceList.keys():
827 ref = self.sourceList[i]
828 objects[i] = {'isa': 'PBXBuildFile',
830 objects[ref] = {'isa': 'PBXFileReference',
831 'lastKnownFileType': self.sourceRefList[ref]['lastKnownFileType'],
832 'path': self.sourceRefList[ref]['path']}
833 project = {'archiveVersion': 1,
837 'rootObject': self.rootObjectId}
840 # For some reverse-engineered documentation on the project.pbxproj format,
841 # see http://www.monobjc.net/xcode-project-file-format.html .
842 def write_xcodeproj(self, moduledir, target):
843 xcodeprojdir = os.path.join(moduledir, '%s.xcodeproj' % target.target_name())
845 os.mkdir(xcodeprojdir)
848 self.write_dict_to_plist(self.generate_project(target),
849 open(os.path.join(xcodeprojdir, 'project.pbxproj'), 'w'))
851 def __init__(self, gbuildparser, ide):
852 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
855 self.rootlocation = './'
856 for location in self.gbuildparser.target_by_location:
857 # module = location.split('/')[-1]
858 # module_directory = os.path.join(self.rootlocation, module)
859 for target in self.gbuildparser.target_by_location[location]:
860 # project_path = os.path.join(module_directory, '%s.pbxroj' % target.target_name())
861 self.write_xcodeproj(location, target)
864 class VisualStudioIntegrationGenerator(IdeIntegrationGenerator):
866 def __init__(self, gbuildparser, ide):
867 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
868 self.toolset = os.environ['VCTOOLSET']
869 self.solution_directory = self.gbuildparser.builddir
870 self.configurations = {
872 'build': self.module_make_command('%(target)s'),
873 'clean': self.module_make_command('%(target)s.clean'),
874 'rebuild': self.module_make_command('%(target)s.clean %(target)s')
877 'build': self.module_make_command('unitcheck'),
878 'clean': self.module_make_command('clean'),
879 'rebuild': self.module_make_command('clean unitcheck'),
881 'Integration tests': {
882 'build': self.module_make_command('unitcheck slowcheck screenshot subsequentcheck'),
883 'clean': self.module_make_command('clean'),
884 'rebuild': self.module_make_command('clean unitcheck slowcheck screenshot subsequentcheck')
888 def module_make_command(self, targets):
889 return '%(sh)s -c "PATH=\\"/bin:$PATH\\";BUILDDIR=\\"%(builddir)s\\" %(makecmd)s -rsC %(location)s ' + targets + '"'
893 def __init__(self, guid, target, project_path):
896 self.path = project_path
898 # Check if the target is empty (no source files would be added to project file)
900 def should_skip(target):
901 return not target.cxxobjects and not target.cxxclrobjects and not target.cobjects
905 for location, targets in self.gbuildparser.target_by_location.items():
907 module = location.split('/')[-1]
908 module_directory = os.path.join(self.solution_directory, module)
909 for target in targets:
910 if self.should_skip(target):
911 print(' %s: no files to add, skipping' % target.target_name())
913 project_path = os.path.join(module_directory, '%s.vcxproj' % target.target_name())
914 project_guid = self.write_project(project_path, target)
915 p = VisualStudioIntegrationGenerator.Project(project_guid, target, project_path)
917 self.write_solution(os.path.join(module_directory, '%s.sln' % module), projects)
918 all_projects += projects
920 self.write_solution(os.path.join(self.solution_directory, 'LibreOffice.sln'), all_projects)
921 # this enables Python GDB pretty printers when debugging a WSL Linux build from VS
922 MIEngine_options_path = os.path.join(gbuildparser.srcdir, 'solenv/vs/Microsoft.MIEngine.Options.xml')
923 shutil.copy(MIEngine_options_path, self.solution_directory)
926 def gen_guid(category, name):
927 return str(uuid.uuid5(uuid.NAMESPACE_URL, 'vnd.libreoffice.vs-ide-integration:' + category + '/' + urllib.parse.quote(name))).upper()
929 nmake_project_guid = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
930 nmake_folder_guid = '2150E333-8FDC-42A3-9474-1A3956D46DE8'
932 def get_dependency_libs(self, linked_libs, library_projects):
934 for linked_lib in linked_libs:
935 for library_project in library_projects:
936 if library_project.target.name == linked_lib:
937 dependency_libs[library_project.guid] = library_project
938 return dependency_libs
940 def write_solution(self, solution_path, projects):
941 print('Solution %s:' % os.path.splitext(os.path.basename(solution_path))[0], end='')
943 print(' no projects, skipping')
945 library_projects = [project for project in projects if project.target in self.gbuildparser.libs]
946 static_library_projects = [project for project in projects if project.target in self.gbuildparser.static_libs]
947 test_projects = [project for project in projects if project.target in self.gbuildparser.tests]
948 executable_projects = [project for project in projects if project.target in self.gbuildparser.exes]
949 with open(solution_path, 'w') as f:
950 f.write('Microsoft Visual Studio Solution File, Format Version 12.00\n')
951 for project in projects:
952 target = project.target
953 print(' %s' % target.target_name(), end='')
954 proj_path = os.path.relpath(project.path, os.path.abspath(os.path.dirname(solution_path)))
955 f.write('Project("{%s}") = "%s", "%s", "{%s}"\n' %
956 (VisualStudioIntegrationGenerator.nmake_project_guid,
957 target.short_name(), proj_path, project.guid))
958 libs_in_solution = self.get_dependency_libs(target.linked_libs,
960 libs_in_solution |= self.get_dependency_libs(target.linked_static_libs,
961 static_library_projects)
963 f.write('\tProjectSection(ProjectDependencies) = postProject\n')
964 for lib_guid in libs_in_solution.keys():
965 f.write('\t\t{%(guid)s} = {%(guid)s}\n' % {'guid': lib_guid})
966 f.write('\tEndProjectSection\n')
967 f.write('EndProject\n')
968 f.write('Project("{%s}") = "Utility", "Utility", "{6778240E-8B6B-47A0-AC31-7E7A257B97E6}"\n' %
969 (VisualStudioIntegrationGenerator.nmake_folder_guid))
970 f.write('\tProjectSection(SolutionItems) = preProject\n')
971 # The natvis file gives pretty-printed variable values when debugging
972 natvis_path = os.path.join(gbuildparser.srcdir, 'solenv/vs/LibreOffice.natvis')
973 f.write('\t\t%(natvis)s = %(natvis)s\n' % {'natvis': natvis_path})
974 # The natstepfilter file allows to skip specific functions when stepping into in debugging
975 natstepfilter_path = os.path.join(gbuildparser.srcdir, 'solenv/vs/LibreOffice.natstepfilter')
976 f.write('\t\t%(natstepfilter)s = %(natstepfilter)s\n' % {'natstepfilter': natstepfilter_path})
977 f.write('\tEndProjectSection\n')
978 f.write('EndProject\n')
979 # Folders to group tests/libraries/executables
980 nmake_tests_guid = 'CF544F7B-9D02-4D83-8370-5887851209B7'
981 nmake_libraries_guid = 'C624F43D-616C-4627-B58F-F5C2047B7BDC'
982 nmake_static_libraries_guid = 'EB2CD1D4-7C29-4232-9B1E-9FB1FE62D61C'
983 nmake_executables_guid = '1CD80999-9FA9-4BA9-B4D9-6E33035CF648'
984 f.write('Project("{%s}") = "Tests", "Tests", "{%s}"\n' %
985 (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_tests_guid))
986 f.write('EndProject\n')
987 f.write('Project("{%s}") = "Libraries", "Libraries", "{%s}"\n' %
988 (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_libraries_guid))
989 f.write('EndProject\n')
990 f.write('Project("{%s}") = "StaticLibraries", "StaticLibraries", "{%s}"\n' %
991 (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_static_libraries_guid))
992 f.write('EndProject\n')
993 f.write('Project("{%s}") = "Executables", "Executables", "{%s}"\n' %
994 (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_executables_guid))
995 f.write('EndProject\n')
996 # end Folders to group tests/libraries/executables
999 f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
1000 for cfg in self.configurations:
1001 f.write('\t\t%(cfg)s|%(platform)s = %(cfg)s|%(platform)s\n' % {'cfg': cfg, 'platform': platform})
1002 f.write('\tEndGlobalSection\n')
1003 # Group projects to folders
1004 f.write('\tGlobalSection(NestedProjects) = preSolution\n')
1005 for project in test_projects:
1006 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_tests_guid))
1007 for project in library_projects:
1008 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_libraries_guid))
1009 for project in static_library_projects:
1010 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_static_libraries_guid))
1011 for project in executable_projects:
1012 f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_executables_guid))
1013 f.write('\tEndGlobalSection\n')
1014 # end Group projects to folders
1015 f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
1016 # Specifies project configurations for solution configuration
1017 for project in projects:
1018 for cfg in self.configurations:
1019 params = {'guid': project.guid, 'sol_cfg': cfg, 'proj_cfg': cfg, 'platform': platform}
1020 f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.ActiveCfg = %(proj_cfg)s|%(platform)s\n' % params)
1021 # Build.0 is basically 'Build checkbox' in configuration manager
1022 f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.Build.0 = %(proj_cfg)s|%(platform)s\n' % params)
1023 f.write('\tEndGlobalSection\n')
1024 f.write('EndGlobal\n')
1028 def to_long_names(shortnames):
1029 if platform == "cygwin":
1030 return (subprocess.check_output(["cygpath", "-wal"] + shortnames).decode("utf-8", "strict").rstrip()).split("\n")
1034 # Unescape the values: \"tklo.dll\" => "tklo.dll"
1035 escapepattern = re.compile(r'\\(.)')
1038 def defs_list(defs):
1041 for key, value in defs.items():
1043 if value is not None:
1044 define += '=' + VisualStudioIntegrationGenerator.escapepattern.sub(r'\1', value).replace('""', '"')
1045 defines_list.append(define)
1048 ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
1051 def add_objects(cls, objects, root_path, ext, target, parent_node, flags = ''):
1053 objfile = os.path.join(root_path, obj) + ext
1054 if os.path.isfile(objfile):
1055 obj_node = ET.SubElement(parent_node, '{%s}ClCompile' % cls.ns, Include=objfile)
1057 obj_additional_options_node = ET.SubElement(obj_node, '{%s}AdditionalOptions' % cls.ns)
1058 obj_additional_options_node.text = flags
1060 print('Source %s in project %s does not exist' % (objfile, target.target_name()))
1062 def write_project(self, project_path, target):
1063 # See info at http://blogs.msdn.com/b/visualstudio/archive/2010/05/14/a-guide-to-vcxproj-and-props-file-structure.aspx
1064 folder = os.path.dirname(project_path)
1065 if not os.path.exists(folder):
1067 project_guid = self.gen_guid('project', target.short_name())
1068 cxxflags = ' '.join(target.cxxflags)
1069 cxxclrflags = ' '.join(target.cxxclrflags)
1070 cflags = ' '.join(target.cflags)
1071 ET.register_namespace('', self.ns)
1072 proj_node = ET.Element('{%s}Project' % self.ns, DefaultTargets='Build', ToolsVersion='4.0')
1073 proj_confs_node = ET.SubElement(proj_node, '{%s}ItemGroup' % self.ns, Label='ProjectConfigurations')
1075 for configuration in self.configurations:
1076 proj_conf_node = ET.SubElement(proj_confs_node,
1077 '{%s}ProjectConfiguration' % self.ns,
1078 Include='%s|%s' % (configuration, platform))
1079 conf_node = ET.SubElement(proj_conf_node, '{%s}Configuration' % self.ns)
1080 conf_node.text = configuration
1081 platform_node = ET.SubElement(proj_conf_node, '{%s}Platform' % self.ns)
1082 platform_node.text = platform
1084 globals_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % self.ns, Label='Globals')
1085 proj_guid_node = ET.SubElement(globals_node, '{%s}ProjectGuid' % self.ns)
1086 proj_guid_node.text = '{%s}' % project_guid
1087 proj_keyword_node = ET.SubElement(globals_node, '{%s}Keyword' % self.ns)
1088 proj_keyword_node.text = 'MakeFileProj'
1089 proj_name_node = ET.SubElement(globals_node, '{%s}ProjectName' % self.ns)
1090 proj_name_node.text = target.short_name()
1092 ET.SubElement(proj_node, '{%s}Import' % self.ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.Default.props')
1093 for configuration in self.configurations:
1094 conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % self.ns, Label="Configuration",
1095 Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
1096 # Type of project used by the MSBuild to determine build process, see Microsoft.Makefile.targets
1097 conf_type_node = ET.SubElement(conf_node, '{%s}ConfigurationType' % self.ns)
1098 conf_type_node.text = 'Makefile'
1099 # This defines the version of Visual Studio which can show next to project names in the Solution Explorer
1100 platform_toolset_node = ET.SubElement(conf_node, '{%s}PlatformToolset' % self.ns)
1101 platform_toolset_node.text = self.toolset
1103 ET.SubElement(proj_node, '{%s}Import' % self.ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.props')
1104 ET.SubElement(proj_node, '{%s}ImportGroup' % self.ns, Label='ExtensionSettings')
1105 for configuration in self.configurations:
1106 prop_sheets_node = ET.SubElement(proj_node, '{%s}ImportGroup' % self.ns, Label='Configuration',
1107 Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
1108 ET.SubElement(prop_sheets_node, '{%s}Import' % self.ns,
1109 Project='$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props',
1110 Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')",
1111 Label='LocalAppDataPlatform')
1113 ET.SubElement(proj_node, '{%s}PropertyGroup' % self.ns, Label='UserMacros')
1114 # VS IDE (at least "Peek definition") is allergic to paths like "C:/PROGRA~2/WI3CF2~1/10/Include/10.0.14393.0/um"; see
1115 # https://developercommunity.visualstudio.com/content/problem/139659/vc-peek-definition-fails-to-navigate-to-windows-ki.html
1116 # We need to convert to long paths here. Do this once, since it's time-consuming operation.
1117 include_path_node_text = ';'.join(self.to_long_names(target.include))
1118 for cfg_name, cfg_targets in self.configurations.items():
1119 conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % self.ns,
1120 Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (cfg_name, platform))
1122 'sh': os.path.join(self.gbuildparser.binpath, 'dash.exe'),
1123 'builddir': self.gbuildparser.builddir,
1124 'location': target.location,
1125 'makecmd': self.gbuildparser.makecmd,
1126 'target': target.target_name()}
1127 nmake_build_node = ET.SubElement(conf_node, '{%s}NMakeBuildCommandLine' % self.ns)
1128 nmake_build_node.text = cfg_targets['build'] % nmake_params
1129 nmake_clean_node = ET.SubElement(conf_node, '{%s}NMakeCleanCommandLine' % self.ns)
1130 nmake_clean_node.text = cfg_targets['clean'] % nmake_params
1131 nmake_rebuild_node = ET.SubElement(conf_node, '{%s}NMakeReBuildCommandLine' % self.ns)
1132 nmake_rebuild_node.text = cfg_targets['rebuild'] % nmake_params
1133 nmake_output_node = ET.SubElement(conf_node, '{%s}NMakeOutput' % self.ns)
1134 nmake_output_node.text = os.path.join(self.gbuildparser.workdir, 'LinkTarget', target.link_target)
1135 nmake_defs_node = ET.SubElement(conf_node, '{%s}NMakePreprocessorDefinitions' % self.ns)
1136 nmake_defs_node.text = ';'.join(self.defs_list(target.defs) + ['$(NMakePreprocessorDefinitions)'])
1137 nmake_debug_command_node = ET.SubElement(conf_node, '{%s}LocalDebuggerCommand' % self.ns)
1138 nmake_debug_command_node.text = os.path.join(self.gbuildparser.instdir, 'program', 'soffice.bin')
1139 nmake_debug_flavor_node = ET.SubElement(conf_node, '{%s}DebuggerFlavor' % self.ns)
1140 nmake_debug_flavor_node.text = 'WindowsLocalDebugger'
1141 include_path_node = ET.SubElement(conf_node, '{%s}IncludePath' % self.ns)
1142 include_path_node.text = include_path_node_text
1143 additional_options_node = ET.SubElement(conf_node, '{%s}AdditionalOptions' % self.ns)
1144 additional_options_node.text = cxxflags
1146 ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % self.ns)
1148 cxxobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % self.ns)
1149 self.add_objects(target.cxxobjects, self.gbuildparser.srcdir, '.cxx', target, cxxobjects_node)
1150 self.add_objects(target.cxxclrobjects, self.gbuildparser.srcdir, '.cxx', target, cxxobjects_node, cxxclrflags)
1152 cobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % self.ns)
1153 self.add_objects(target.cobjects, self.gbuildparser.srcdir, '.c', target, cobjects_node, cflags)
1155 ET.SubElement(proj_node, '{%s}Import' % self.ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.targets')
1156 ET.SubElement(proj_node, '{%s}ImportGroup' % self.ns, Label='ExtensionTargets')
1157 self.write_pretty_xml(proj_node, project_path)
1158 self.write_filters(project_path + '.filters',
1159 os.path.join(self.gbuildparser.srcdir, os.path.basename(target.location)),
1160 [cxx_node.get('Include') for cxx_node in cxxobjects_node.findall('{%s}ClCompile' % self.ns)],
1161 [c_node.get('Include') for c_node in cobjects_node.findall('{%s}ClCompile' % self.ns)])
1164 def get_filter(self, module_dir, proj_file):
1165 return '\\'.join(os.path.relpath(proj_file, module_dir).split('/')[:-1])
1167 def get_subfilters(self, proj_filter):
1168 parts = proj_filter.split('\\')
1169 subfilters = set([proj_filter]) if proj_filter else set()
1170 for i in range(1, len(parts)):
1171 subfilters.add('\\'.join(parts[:i]))
1174 def write_pretty_xml(self, node, file_path):
1175 xml_str = ET.tostring(node, encoding='unicode')
1176 pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
1177 with open(file_path, 'w') as f:
1178 f.write(pretty_str.decode())
1180 def add_nodes(self, files_node, module_dir, tag, project_files):
1182 for project_file in project_files:
1183 file_node = ET.SubElement(files_node, tag, Include=project_file)
1184 if os.path.commonprefix([module_dir, project_file]) == module_dir:
1185 project_filter = self.get_filter(module_dir, project_file)
1186 filter_node = ET.SubElement(file_node, '{%s}Filter' % self.ns)
1187 filter_node.text = project_filter
1188 filters |= self.get_subfilters(project_filter)
1191 def write_filters(self, filters_path, module_dir, cxx_files, c_files):
1192 ET.register_namespace('', self.ns)
1193 proj_node = ET.Element('{%s}Project' % self.ns, ToolsVersion='4.0')
1195 compiles_node = ET.SubElement(proj_node, '{%s}ItemGroup' % self.ns)
1196 filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % self.ns, cxx_files)
1197 filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % self.ns, c_files)
1199 filters_node = ET.SubElement(proj_node, '{%s}ItemGroup' % self.ns)
1200 for proj_filter in filters:
1201 filter_node = ET.SubElement(filters_node, '{%s}Filter' % self.ns, Include=proj_filter)
1202 self.write_pretty_xml(proj_node, filters_path)
1205 class QtCreatorIntegrationGenerator(IdeIntegrationGenerator):
1207 def __init__(self, gbuildparser, ide):
1208 IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
1209 self.target_by_location = {}
1210 for target in self.gbuildparser.libs | self.gbuildparser.exes | self.gbuildparser.tests:
1211 if target.location not in self.target_by_location:
1212 self.target_by_location[target.location] = set()
1213 self.target_by_location[target.location] |= set([target])
1215 self._do_log = False # set to 'True' to activate log of QtCreatorIntegrationGenerator
1217 qtlog_path = os.path.abspath('../qtlog_.txt')
1218 self.qtlog = open(qtlog_path, 'w')
1220 def _log(self, message):
1222 self.qtlog.write(message)
1224 def log_close(self):
1228 def generate_build_configs(self, lib_folder):
1229 module_folder = os.path.join(self.base_folder, lib_folder)
1231 # In QtCreator UI, build configs are listed alphabetically,
1232 # so it can be different from the creation order.
1233 # So we prefix the names with the index.
1234 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1236 'base_folder': module_folder,
1238 'name': "1-Build %s" % lib_folder,
1240 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1242 'base_folder': module_folder,
1244 'name': "2-Local tests -- quick tests (unitcheck)",
1246 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1248 'base_folder': module_folder,
1249 'arg': "unitcheck slowcheck screenshot",
1250 'name': "3-Local tests -- slow tests (unitcheck, slowcheck, screenshot)",
1252 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1254 'base_folder': module_folder,
1255 'arg': "unitcheck slowcheck screenshot subsequentcheck",
1256 'name': "4-Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1258 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1260 'base_folder': self.base_folder,
1262 'name': "5-Global tests -- quick tests (unitcheck)",
1264 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1266 'base_folder': self.base_folder,
1267 'arg': "unitcheck slowcheck screenshot",
1268 'name': "6-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
1270 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1272 'base_folder': self.base_folder,
1273 'arg': "unitcheck slowcheck screenshot subsequentcheck",
1274 'name': "7-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1276 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1278 'base_folder': self.base_folder,
1280 'name': "8-Global build -- nocheck",
1282 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1284 'base_folder': self.base_folder,
1286 'name': "9-Global build",
1289 xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
1294 def generate_meta_build_configs(self):
1296 # In QtCreator UI, build configs are listed alphabetically,
1297 # so it can be different from the creation order.
1298 # So we prefix the names with the index.
1299 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1301 'base_folder': self.base_folder,
1303 'name': "01-Global Build",
1305 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1307 'base_folder': self.base_folder,
1309 'name': "02-Global tests -- quick tests (unitcheck)",
1311 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1313 'base_folder': self.base_folder,
1314 'arg': "unitcheck slowcheck screenshot",
1315 'name': "03-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
1317 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1319 'base_folder': self.base_folder,
1320 'arg': "unitcheck slowcheck screenshot subsequentcheck",
1321 'name': "04-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
1323 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1325 'base_folder': self.base_folder,
1327 'name': "05-Global tests -- performance tests (perfcheck)",
1329 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1331 'base_folder': self.base_folder,
1333 'name': "06-Global tests -- tests (check)",
1335 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1337 'base_folder': self.base_folder,
1339 'name': "07-Global build -- nocheck",
1341 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1343 'base_folder': self.base_folder,
1344 'arg': "build-l10n-only",
1345 'name': "08-Global build -- build-l10n-only",
1347 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1349 'base_folder': self.base_folder,
1350 'arg': "build-non-l10n-only",
1351 'name': "09-Global build -- build-non-l10n-only",
1353 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1355 'base_folder': self.base_folder,
1357 'name': "10-Global build -- clean",
1359 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1361 'base_folder': self.base_folder,
1362 'arg': "clean-build",
1363 'name': "11-Global build -- clean-build",
1365 xml += QtCreatorIntegrationGenerator.build_configs_template % {
1367 'base_folder': self.base_folder,
1368 'arg': "clean-host",
1369 'name': "12-Global build -- clean-host",
1371 xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
1376 # By default, QtCreator creates 2 BuildStepList : "Build" and "Clean"
1377 # but the "clean" can be empty.
1378 build_configs_template = """
1379 <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.%(index)s">
1380 <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">%(base_folder)s</value>
1381 <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
1382 <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
1383 <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
1384 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
1385 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1386 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
1387 <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
1388 <value type="QString">-w</value>
1389 <value type="QString">-r</value>
1391 <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
1392 <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">%(arg)s</value>
1393 <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
1395 <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
1396 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
1397 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1398 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
1400 <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
1401 <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
1402 <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
1403 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">%(name)s</value>
1404 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
1405 <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">%(index)s</value>
1406 <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
1410 build_configs_count_template = """
1411 <!-- nb build configurations -->
1412 <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">%(nb)s</value>
1415 def generate_deploy_configs(self, lib_folder):
1416 xml = QtCreatorIntegrationGenerator.deploy_configs_template % {}
1419 deploy_configs_template = """
1420 <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
1421 <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
1422 <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
1423 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
1424 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1425 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
1427 <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
1428 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
1429 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1430 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
1432 <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
1435 def generate_run_configs(self, lib_folder):
1437 if platform == 'darwin':
1438 loexec = "%s/instdir/LibreOfficeDev.app/Contents/MacOS/soffice" % self.base_folder
1440 loexec = "%s/instdir/program/soffice.bin" % self.base_folder
1441 xml = QtCreatorIntegrationGenerator.run_configs_template % {
1443 'workdir': self.base_folder
1447 run_configs_template = """
1448 <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
1449 <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
1450 <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
1451 <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
1452 <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
1453 <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
1454 <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
1455 <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
1456 <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
1457 <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
1458 <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
1459 <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
1460 <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
1461 <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
1462 <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
1463 <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
1464 <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
1465 <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
1466 <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
1467 <value type="int">0</value>
1468 <value type="int">1</value>
1469 <value type="int">2</value>
1470 <value type="int">3</value>
1471 <value type="int">4</value>
1472 <value type="int">5</value>
1473 <value type="int">6</value>
1474 <value type="int">7</value>
1475 <value type="int">8</value>
1476 <value type="int">9</value>
1477 <value type="int">10</value>
1478 <value type="int">11</value>
1479 <value type="int">12</value>
1480 <value type="int">13</value>
1481 <value type="int">14</value>
1483 <value type="int" key="PE.EnvironmentAspect.Base">2</value>
1484 <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
1486 <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
1487 <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%(loexec)s</value>
1488 <value type="bool" key="ProjectExplorer.CustomExecutableRunConfiguration.UseTerminal">false</value>
1489 <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">%(workdir)s</value>
1490 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run libreoffice/instdir/program/soffice</value>
1491 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
1492 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
1493 <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
1494 <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
1495 <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
1496 <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
1497 <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
1498 <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
1501 <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
1504 def generate_pro_shared_content(self, lib_folder):
1506 build_configs = self.generate_build_configs(lib_folder)
1507 deploy_configs = self.generate_deploy_configs(lib_folder)
1508 run_configs = self.generate_run_configs(lib_folder)
1510 xml = QtCreatorIntegrationGenerator.pro_shared_template % {
1511 'build_configs': build_configs,
1512 'deploy_configs': deploy_configs,
1513 'run_configs': run_configs,
1517 def generate_meta_pro_shared_content(self):
1519 build_configs = self.generate_meta_build_configs()
1520 deploy_configs = self.generate_deploy_configs("")
1521 run_configs = self.generate_run_configs("")
1523 xml = QtCreatorIntegrationGenerator.pro_shared_template % {
1524 'build_configs': build_configs,
1525 'deploy_configs': deploy_configs,
1526 'run_configs': run_configs,
1530 pro_shared_template = """<?xml version="1.0" encoding="UTF-8"?>
1531 <!DOCTYPE QtCreatorProject>
1532 <!-- Written by QtCreator 3.1.1, 2015-05-14T15:54:34. -->
1535 <variable>ProjectExplorer.Project.ActiveTarget</variable>
1536 <value type="int">0</value>
1539 <!-- editor settings -->
1541 <variable>ProjectExplorer.Project.EditorSettings</variable>
1542 <valuemap type="QVariantMap">
1543 <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
1544 <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
1545 <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
1546 <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
1547 <value type="QString" key="language">Cpp</value>
1548 <valuemap type="QVariantMap" key="value">
1549 <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
1552 <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
1553 <value type="QString" key="language">QmlJS</value>
1554 <valuemap type="QVariantMap" key="value">
1555 <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
1558 <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
1559 <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
1560 <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
1561 <value type="int" key="EditorConfiguration.IndentSize">4</value>
1562 <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
1563 <value type="int" key="EditorConfiguration.MarginColumn">80</value>
1564 <value type="bool" key="EditorConfiguration.MouseHiding">true</value>
1565 <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
1566 <value type="int" key="EditorConfiguration.PaddingMode">1</value>
1567 <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
1568 <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
1569 <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
1570 <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
1571 <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
1572 <value type="int" key="EditorConfiguration.TabSize">8</value>
1573 <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
1574 <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
1575 <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
1576 <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
1577 <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
1578 <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
1583 <variable>ProjectExplorer.Project.PluginSettings</variable>
1584 <valuemap type="QVariantMap"/>
1589 <variable>ProjectExplorer.Project.Target.0</variable>
1590 <valuemap type="QVariantMap">
1591 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
1592 <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
1593 <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{0701de51-c96e-4e4f-85c3-e70b223c5076}</value>
1594 <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
1595 <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
1596 <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
1598 <!-- build configurations -->
1601 <!-- deploy configurations -->
1604 <!-- plugin settings -->
1605 <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
1607 <!-- run configurations -->
1612 <!-- nb targets : 1 -->
1614 <variable>ProjectExplorer.Project.TargetCount</variable>
1615 <value type="int">1</value>
1618 <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
1619 <value type="QByteArray">{5abcafed-86f6-49f6-b1cb-380fadd21211}</value>
1622 <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
1623 <value type="int">15</value>
1628 def get_file_path(self, src_file, ext_choices):
1629 path = os.path.join(self.gbuildparser.srcdir, src_file)
1630 for ext in ext_choices:
1631 full_path = path + ext
1632 if os.path.isfile(full_path):
1636 def get_source_path(self, src_file):
1637 return self.get_file_path(src_file, (".cxx", ".cpp", ".c", ".mm"))
1639 def get_header_path(self, src_file):
1640 return self.get_file_path(src_file, (".hxx", ".hpp", ".h"))
1642 def build_data_libs(self):
1646 all_libs = self.gbuildparser.libs | self.gbuildparser.exes | self.gbuildparser.tests
1647 for lib in all_libs:
1648 self._log("\nlibrary : %s, loc=%s" % (lib.short_name(), lib.location))
1649 lib_name = os.path.basename(lib.location)
1650 lib_folder = os.path.relpath(lib.location, self.base_folder)
1653 if platform == "cygwin":
1654 # absolute paths from GbuildToJson are Windows paths,
1655 # so convert everything to such ones
1657 if not ntpath.isabs(abs_path):
1658 abs_path = ntpath.join(self.gbuildparser.srcdir, path)
1659 return abs_path.replace('\\', '/')
1661 return os.path.abspath(path)
1665 objcxx_sources_list = []
1666 includepath_list = []
1667 # The explicit headers list is not mandatory :
1668 # QtCreator just needs 'include_path_list' to find all headers files.
1669 # But files listed in 'header_list' will be shown
1670 # in a specific "Headers" folder in QtCreator's Project panel.
1671 # We will list here only headers files of current lib.
1673 objcxx_headers_list = []
1674 for file_ in lib.cxxobjects:
1675 # the file has no extension : search it
1676 # self._log("\n file : %s" % file_)
1677 path = self.get_source_path(file_)
1679 sources_list.append(lopath(path))
1681 # few cxxobject files have a header beside
1682 path = self.get_header_path(file_)
1684 headers_list.append(lopath(path))
1686 for file_ in lib.objcxxobjects:
1687 # the file has no extension: search it
1688 path = self.get_source_path(file_)
1690 objcxx_sources_list.append(lopath(path))
1692 # several objcxxobject files have a header beside
1693 path = self.get_header_path(file_)
1695 objcxx_headers_list.append(lopath(path))
1697 cxxstdversionflag = ''
1698 for cxxflag in lib.cxxflags:
1699 # extract flag for C++ standard version
1700 if cxxflag.startswith('-std'):
1701 cxxstdversionflag = cxxflag
1703 # List all include paths
1704 for hdir in (lib.include + lib.include_sys):
1705 hf_lopath = lopath(hdir)
1706 includepath_list.append(hf_lopath)
1708 # List headers files from current lib
1709 for hdir in lib.include:
1710 if hdir.startswith(lib.location):
1711 for dirpath, _, files in os.walk(hdir):
1713 if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
1714 hf_lopath = lopath(os.path.join(dirpath, hf))
1715 headers_list.append(hf_lopath)
1718 for key, value in lib.defs.items():
1720 if value is not None:
1721 define += '=' + value
1722 defines_list.append(define)
1724 # All data are prepared, store them for the lib.
1725 if lib_folder in self.data_libs:
1726 self.data_libs[lib_folder]['sources'] |= set(sources_list)
1727 self.data_libs[lib_folder]['headers'] |= set(headers_list)
1728 self.data_libs[lib_folder]['objcxx_sources'] |= set(objcxx_sources_list)
1729 self.data_libs[lib_folder]['objcxx_headers'] |= set(objcxx_headers_list)
1730 self.data_libs[lib_folder]['cxxstdversionflag'] = cxxstdversionflag
1731 self.data_libs[lib_folder]['includepath'] |= set(includepath_list)
1732 self.data_libs[lib_folder]['defines'] |= set(defines_list)
1734 self.data_libs[lib_folder] = {
1735 'sources': set(sources_list),
1736 'headers': set(headers_list),
1737 'objcxx_sources': set(objcxx_sources_list),
1738 'objcxx_headers': set(objcxx_headers_list),
1739 'cxxstdversionflag': cxxstdversionflag,
1740 'includepath': set(includepath_list),
1741 'defines': set(defines_list),
1742 'loc': lib.location,
1749 self.base_folder = self.gbuildparser.builddir
1751 # for .pro files, we must explicitly list all files (.c, .h)
1752 # so we can't reuse directly the same method than for kde integration.
1753 self.build_data_libs()
1755 # subdirs for the meta .pro file
1756 subdirs_meta_pro = []
1757 subdirs_list = self.data_libs.keys()
1758 # Now we can create Qt files
1759 for lib_folder in subdirs_list:
1760 sources_list = sorted(self.data_libs[lib_folder]['sources'])
1761 headers_list = sorted(self.data_libs[lib_folder]['headers'])
1762 objcxx_sources_list = sorted(self.data_libs[lib_folder]['objcxx_sources'])
1763 objcxx_headers_list = sorted(self.data_libs[lib_folder]['objcxx_headers'])
1764 cxxstdversionflag = self.data_libs[lib_folder]['cxxstdversionflag']
1765 includepath_list = sorted(self.data_libs[lib_folder]['includepath'])
1766 defines_list = sorted(self.data_libs[lib_folder]['defines'])
1767 lib_loc = self.data_libs[lib_folder]['loc']
1768 lib_name = self.data_libs[lib_folder]['name']
1770 sources = " \\\n".join(sources_list)
1771 headers = " \\\n".join(headers_list)
1772 objcxx_sources = " \\\n".join(objcxx_sources_list)
1773 objcxx_headers = " \\\n".join(objcxx_headers_list)
1774 includepath = " \\\n".join(includepath_list)
1775 defines = " \\\n".join(defines_list)
1776 # strip '-std=' or '-std:' prefix
1777 assert(isinstance(cxxstdversionflag, str) and cxxstdversionflag.startswith('-std'))
1778 cxxstdversion = cxxstdversionflag[5:]
1781 relative_subdir_path = os.path.relpath(lib_loc, self.gbuildparser.srcdir)
1782 subdirs_meta_pro.append(relative_subdir_path)
1783 qt_pro_file = os.path.join(self.base_folder, relative_subdir_path, lib_name + '.pro')
1785 content = QtCreatorIntegrationGenerator.pro_template % {'sources': sources, 'headers': headers, 'cxxstdversionflag': cxxstdversionflag,
1786 'cxxstdversion': cxxstdversion, 'objcxx_sources': objcxx_sources,
1787 'objcxx_headers': objcxx_headers, 'includepath': includepath, 'defines': defines}
1788 with open(qt_pro_file, mode) as fpro:
1790 self._log("created %s\n" % qt_pro_file)
1792 except Exception as e:
1793 print("ERROR : creating pro file=" + qt_pro_file, file=sys.stderr)
1794 print(e, file=sys.stderr)
1795 temp = traceback.format_exc() # .decode('utf8')
1796 print(temp, file=sys.stderr)
1797 print("\n\n", file=sys.stderr)
1799 # create .pro.shared file
1800 qt_pro_shared_file = os.path.join(self.base_folder, relative_subdir_path, lib_name + '.pro.shared')
1802 with open(qt_pro_shared_file, mode) as fproshared:
1803 fproshared.write(self.generate_pro_shared_content(lib_folder))
1804 self._log("created %s\n" % qt_pro_shared_file)
1806 except Exception as e:
1807 print("ERROR : creating pro.shared file=" + qt_pro_shared_file, file=sys.stderr)
1808 print(e, file=sys.stderr)
1809 temp = traceback.format_exc()
1810 print(temp, file=sys.stderr)
1811 print("\n\n", file=sys.stderr)
1813 # create meta .pro file (lists all sub projects)
1814 qt_meta_pro_file = os.path.join(self.base_folder, 'lo.pro')
1816 subdirs = " \\\n".join(sorted(subdirs_meta_pro))
1817 content = QtCreatorIntegrationGenerator.pro_meta_template % {'subdirs': subdirs}
1818 with open(qt_meta_pro_file, 'w+') as fmpro:
1819 fmpro.write(content)
1821 except Exception as e:
1822 print("ERROR : creating lo.pro file=" + qt_meta_pro_file, file=sys.stderr)
1823 print(e, file=sys.stderr)
1824 temp = traceback.format_exc()
1825 print(temp, file=sys.stderr)
1826 print("\n\n", file=sys.stderr)
1828 # create meta .pro.shared file
1829 qt_meta_pro_shared_file = os.path.join(self.base_folder, 'lo.pro.shared')
1831 with open(qt_meta_pro_shared_file, mode) as fmproshared:
1832 fmproshared.write(self.generate_meta_pro_shared_content())
1833 self._log("created %s\n" % qt_meta_pro_shared_file)
1835 except Exception as e:
1836 print("ERROR : creating lo.pro.shared file=" + qt_meta_pro_shared_file, file=sys.stderr)
1837 print(e, file=sys.stderr)
1838 temp = traceback.format_exc()
1839 print(temp, file=sys.stderr)
1840 print("\n\n", file=sys.stderr)
1844 pro_template = """TEMPLATE = lib
1846 CONFIG -= app_bundle
1848 CONFIG += %(cxxstdversion)s
1850 QMAKE_CXXFLAGS += %(cxxstdversionflag)s
1852 INCLUDEPATH += %(includepath)s
1854 SOURCES += %(sources)s
1856 HEADERS += %(headers)s
1858 OBJECTIVE_SOURCES += %(objcxx_sources)s
1860 OBJECTIVE_HEADERS += %(objcxx_headers)s
1862 DEFINES += %(defines)s
1865 pro_meta_template = """TEMPLATE = subdirs
1867 SUBDIRS = %(subdirs)s
1872 parser = argparse.ArgumentParser(
1873 description='LibreOffice gbuild IDE project generator')
1874 parser.add_argument('--ide', dest='ide', required=True,
1875 help='the IDE to generate project files for')
1876 parser.add_argument('--make', dest='makecmd', required=True,
1877 help='the command to execute make')
1878 return parser.parse_args()
1881 if __name__ == '__main__':
1882 args = get_options()
1884 if args.makecmd == 'make':
1885 args.makecmd = '/usr/bin/make'
1889 'codelite': CodeliteIntegrationGenerator,
1890 'eclipsecdt': EclipseCDTIntegrationGenerator,
1891 'kdevelop': KdevelopIntegrationGenerator,
1892 'xcode': XcodeIntegrationGenerator,
1893 'vs': VisualStudioIntegrationGenerator,
1894 'vim': VimIntegrationGenerator,
1895 'debug': DebugIntegrationGenerator,
1896 'qtcreator': QtCreatorIntegrationGenerator,
1899 if args.ide not in generators.keys():
1900 print("Invalid ide. valid values are %s" % ','.join(generators.keys()))
1903 gbuildparser = GbuildParser(args.makecmd).parse()
1905 generators[args.ide](gbuildparser, args.ide).emit()
1906 print("Successfully created the project files.")
1909 # indent-tabs-mode: nil
1912 # vim: set et sw=4 ts=4: