summaryrefslogtreecommitdiffstats
path: root/bin/gbuild-to-ide
diff options
context:
space:
mode:
Diffstat (limited to 'bin/gbuild-to-ide')
-rwxr-xr-xbin/gbuild-to-ide1919
1 files changed, 1919 insertions, 0 deletions
diff --git a/bin/gbuild-to-ide b/bin/gbuild-to-ide
new file mode 100755
index 000000000..b56cff858
--- /dev/null
+++ b/bin/gbuild-to-ide
@@ -0,0 +1,1919 @@
+#! /usr/bin/env python3
+# -*- Mode: python; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import argparse
+import ntpath
+import os
+import os.path
+import shutil
+import re
+import sys
+import uuid
+import json
+import xml.etree.ElementTree as ET
+import xml.dom.minidom as minidom
+import traceback
+import subprocess
+from sys import platform
+import collections
+import urllib.parse
+
+class GbuildLinkTarget:
+ def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs):
+ (self.name, self.location, self.include, self.include_sys, self.defs, self.cxxobjects, self.cxxflags, self.cobjects, self.cflags, self.linked_libs) = (
+ name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs)
+
+ def short_name(self):
+ return self.name
+
+ def is_empty(self):
+ return not self.include and not self.defs and not self.cxxobjects and not self.cobjects and not self.linked_libs
+
+ def __str__(self):
+ return '%s at %s with include path: %s, isystem includes: %s, defines: %s, objects: %s, cxxflags: %s, cobjects: %s, cflags: %s and linked libs: %s' % (
+ self.short_name(), self.location, self.include, self.include_sys, self.defs, self.cxxobjects,
+ self.cxxflags, self.cobjects, self.cflags, self.linked_libs)
+
+
+class GbuildLib(GbuildLinkTarget):
+ def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs):
+ GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs)
+
+ def short_name(self):
+ """Return the short name of target based on the Library_* makefile name"""
+ return 'Library %s' % self.name
+
+ def target_name(self):
+ return 'Library_%s' % self.name
+
+ def library_name(self):
+ return self.name
+
+class GbuildTest(GbuildLinkTarget):
+ def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs):
+ GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs)
+
+ def short_name(self):
+ """Return the short name of target based n the CppunitTest_* makefile names"""
+ return 'CppunitTest %s' % self.name
+
+ def target_name(self):
+ return 'CppunitTest_%s' % self.name
+
+class GbuildExe(GbuildLinkTarget):
+ def __init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs):
+ GbuildLinkTarget.__init__(self, name, location, include, include_sys, defs, cxxobjects, cxxflags, cobjects, cflags, linked_libs)
+
+ def short_name(self):
+ """Return the short name of target based on the Executable_* makefile name"""
+ return 'Executable %s' % self.name
+
+ def target_name(self):
+ return 'Executable_%s' % self.name
+
+
+class GbuildParser:
+ """Main data model object.
+
+ Attributes:
+ target_by_path : dict[path:string, set(target)]
+ where target is one of the GbuildLinkTarget subclasses
+ target_by_location : dict[path:string, set(target)]
+ where target is one of the GbuildLinkTarget subclasses
+ """
+ def __init__(self, makecmd):
+ self.makecmd = makecmd
+ self.binpath = os.path.dirname(os.environ['GPERF']) # woha, this is quite a hack
+ (self.srcdir, self.builddir, self.instdir, self.workdir) = (os.environ['SRCDIR'], os.environ['BUILDDIR'], os.environ['INSTDIR'], os.environ['WORKDIR'])
+ (self.libs, self.exes, self.tests, self.modulenamelist) = ([], [], [], [])
+ (self.target_by_path, self.target_by_location) = ({}, {})
+
+ includepattern = re.compile(r'-I(\S+)')
+ isystempattern = re.compile(r'-isystem\s*(\S+)')
+ warningpattern = re.compile(r'-W\S+')
+ libpattern = re.compile(r'Library_(.*)\.mk')
+ exepattern = re.compile(r'Executable_(.*)\.mk')
+ testpattern = re.compile(r'CppunitTest_(.*)\.mk')
+
+ @staticmethod
+ def __split_includes(includes):
+ foundisystem = GbuildParser.isystempattern.findall(includes)
+ foundincludes = [includeswitch.strip() for includeswitch in GbuildParser.includepattern.findall(includes) if
+ len(includeswitch) > 2]
+ return (foundincludes, foundisystem)
+
+ @staticmethod
+ def __split_objs(objsline):
+ return [obj for obj in objsline.strip().split(' ') if len(obj) > 0 and obj != 'CXXOBJECTS' and obj != 'COBJECTS' and obj != '+=']
+
+ @staticmethod
+ def __split_defs(defsline):
+ defs = {}
+ alldefs = [defswitch.strip() for defswitch in defsline.strip().lstrip('-D').split(' -D') if len(defswitch) > 2]
+ for d in alldefs:
+ dparts = d.split(' -U')
+ """after dparts.pop(0), dparts will contain only undefs"""
+ defparts = dparts.pop(0).strip().split('=')
+ if len(defparts) == 1:
+ defparts.append(None)
+ defs[defparts[0]] = defparts[1]
+ """Drop undefed items (if any) from previous defs"""
+ for u in dparts:
+ defs.pop(u.strip(), '')
+ defs["LIBO_INTERNAL_ONLY"] = None
+ return defs
+
+ @staticmethod
+ def __split_flags(flagsline, flagslineappend):
+ return [cxxflag.strip() for cxxflag in GbuildParser.warningpattern.sub('', '%s %s' % (flagsline, flagslineappend)).split(' ') if len(cxxflag) > 1]
+
+ @staticmethod
+ def __lib_from_json(json):
+ (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
+ return GbuildLib(
+ GbuildParser.libpattern.match(os.path.basename(json['MAKEFILE'])).group(1),
+ os.path.dirname(json['MAKEFILE']),
+ foundincludes,
+ foundisystem,
+ GbuildParser.__split_defs(json['DEFS']),
+ GbuildParser.__split_objs(json['CXXOBJECTS']),
+ GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
+ GbuildParser.__split_objs(json['COBJECTS']),
+ GbuildParser.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
+ json['LINKED_LIBS'].strip().split(' '))
+
+ @staticmethod
+ def __test_from_json(json):
+ (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
+ testname_match = GbuildParser.testpattern.match(os.path.basename(json['MAKEFILE']))
+
+ # Workaround strange writer test makefile setup
+ if testname_match is None:
+ testname = "StrangeWriterMakefiles"
+ else:
+ testname = testname_match.group(1)
+
+ return GbuildTest(
+ testname,
+ os.path.dirname(json['MAKEFILE']),
+ foundincludes,
+ foundisystem,
+ GbuildParser.__split_defs(json['DEFS']),
+ GbuildParser.__split_objs(json['CXXOBJECTS']),
+ GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
+ GbuildParser.__split_objs(json['COBJECTS']),
+ GbuildParser.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
+ json['LINKED_LIBS'].strip().split(' '))
+
+ @staticmethod
+ def __exe_from_json(json):
+ (foundincludes, foundisystem) = GbuildParser.__split_includes(json['INCLUDE'])
+ return GbuildExe(
+ GbuildParser.exepattern.match(os.path.basename(json['MAKEFILE'])).group(1),
+ os.path.dirname(json['MAKEFILE']),
+ foundincludes,
+ foundisystem,
+ GbuildParser.__split_defs(json['DEFS']),
+ GbuildParser.__split_objs(json['CXXOBJECTS']),
+ GbuildParser.__split_flags(json['CXXFLAGS'], json['CXXFLAGSAPPEND']),
+ GbuildParser.__split_objs(json['COBJECTS']),
+ GbuildParser.__split_flags(json['CFLAGS'], json['CFLAGSAPPEND']),
+ json['LINKED_LIBS'].strip().split(' '))
+
+ def parse(self):
+ for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Library')):
+ with open(os.path.join(self.workdir, 'GbuildToJson', 'Library', jsonfilename), 'r') as f:
+ lib = self.__lib_from_json(json.load(f))
+ self.libs.append(lib)
+ for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'Executable')):
+ with open(os.path.join(self.workdir, 'GbuildToJson', 'Executable', jsonfilename), 'r') as f:
+ exe = self.__exe_from_json(json.load(f))
+ self.exes.append(exe)
+ for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest')):
+ with open(os.path.join(self.workdir, 'GbuildToJson', 'CppunitTest', jsonfilename), 'r') as f:
+ test = self.__test_from_json(json.load(f))
+ self.tests.append(test)
+ for target in set(self.libs) | set(self.exes) | set(self.tests):
+ if target.location not in self.target_by_location:
+ self.target_by_location[target.location] = set()
+ self.target_by_location[target.location] |= set([target])
+ for cxx in target.cxxobjects:
+ path = '/'.join(cxx.split('/')[:-1])
+ if path not in self.target_by_path:
+ self.target_by_path[path] = set()
+ self.target_by_path[path] |= set([target])
+ for c in target.cobjects:
+ path = '/'.join(c.split('/')[:-1])
+ if path not in self.target_by_path:
+ self.target_by_path[path] = set()
+ self.target_by_path[path] |= set([target])
+ for location in self.target_by_location:
+ self.modulenamelist.append(os.path.split(location)[1])
+ return self
+
+
+class IdeIntegrationGenerator:
+
+ def __init__(self, gbuildparser, ide):
+ self.gbuildparser = gbuildparser
+ self.ide = ide
+
+ def emit(self):
+ pass
+
+class EclipseCDTIntegrationGenerator(IdeIntegrationGenerator):
+
+ def __init__(self, gbuildparser, ide):
+ IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
+
+ def create_include_paths(self):
+ for module in self.gbuildparser.modulenamelist:
+ modulepath = os.path.join(self.gbuildparser.builddir, module)
+ includedirfile = open(os.path.join(modulepath, '.eclipsesettingfile'), 'w')
+ modulelibs = []
+ for lib in self.gbuildparser.target_by_path.keys():
+ if lib.startswith(module+'/'):
+ modulelibs.append(lib)
+ include = set()
+ for lib in modulelibs:
+ for target in self.gbuildparser.target_by_path[lib]:
+ include |= set(target.include)
+ includedirfile.write('\n'.join(include))
+ includedirfile.close()
+
+
+ def create_macros(self):
+ for module in self.gbuildparser.modulenamelist:
+ modulepath = os.path.join(self.gbuildparser.builddir, module)
+ macrofile = open(os.path.join(modulepath, '.macros'), 'w')
+ modulelibs = []
+ for lib in self.gbuildparser.target_by_path.keys():
+ if lib.startswith(module+'/'):
+ modulelibs.append(lib)
+ define = []
+ defineset = set()
+ for lib in modulelibs:
+ for target in self.gbuildparser.target_by_path[lib]:
+ for i in target.defs.keys():
+ tmp = str(i) +','+str(target.defs[i])
+ if tmp not in defineset:
+ defineset.add(tmp)
+ macrofile.write('\n'.join(defineset))
+ macrofile.close()
+
+
+ def create_settings_file(self):
+
+ settingsfiletemplate = """\
+<?xml version="1.0" encoding="UTF-8"?>
+<cdtprojectproperties>
+<section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths">
+<language name="C++ Source File">
+
+
+</language>
+<language name="C Source File">
+
+</language>
+<language name="Object File">
+
+</language>
+<language name="Assembly Source File">
+
+</language>
+</section>
+<section name="org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros">
+<language name="C++ Source File">
+
+</language>
+<language name="C Source File">
+
+</language>
+<language name="Object File">
+
+</language>
+<language name="Assembly Source File">
+
+</language>
+</section>
+</cdtprojectproperties>
+"""
+
+ for module in self.gbuildparser.modulenamelist:
+ tempxml = []
+ modulepath = os.path.join(self.gbuildparser.builddir, module)
+
+ settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
+ settingsfile.write(settingsfiletemplate)
+ settingsfile.close()
+
+ settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'r')
+ tempxml = settingsfile.readlines()
+ tempinclude = open(os.path.join(modulepath, '.eclipsesettingfile'), 'r')
+ tempmacro = open(os.path.join(modulepath, '.macros'), 'r')
+ for includepath in tempinclude:
+ if includepath[-1:] == "\n":
+ includepath = includepath[:-1]
+ templine = "<includepath>%s</includepath>\n" % includepath
+ tempxml.insert(5, templine)
+
+ for line in tempmacro:
+ macroskeyvalue = line.split(',')
+ macrokey = macroskeyvalue[0]
+ macrovalue = macroskeyvalue[1]
+ if macrovalue[-1:] == "\n":
+ macrovalue = macrovalue[:-1]
+ templine = "<macro><name>%s</name><value>%s</value></macro>\n" %(macrokey, macrovalue)
+ tempxml.insert(-13, templine)
+ tempxml="".join(tempxml)
+ settingsfile.close
+
+ settingsfile = open(os.path.join(modulepath, 'eclipsesettingfile.xml'), 'w')
+ settingsfile.write(tempxml)
+ settingsfile.close()
+ os.remove(os.path.join(modulepath, '.eclipsesettingfile'))
+ os.remove(os.path.join(modulepath, '.macros'))
+
+ def emit(self):
+ self.create_include_paths()
+ self.create_macros()
+ self.create_settings_file()
+
+class CodeliteIntegrationGenerator(IdeIntegrationGenerator):
+
+ def __init__(self, gbuildparser, ide):
+ IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
+
+ def emit(self):
+ self.create_workspace_file()
+ for module in self.gbuildparser.modulenamelist:
+ self.create_project_file(module)
+ #self.create_project_file('vcl')
+
+ def create_workspace_file(self):
+ root_node = ET.Element('CodeLite_Workspace', Name='libo2', Database='./libo2.tags', Version='10.0.0')
+ for module in self.gbuildparser.modulenamelist:
+ ET.SubElement(root_node, 'Project', Name=module, Path='%s/%s.project' % (module, module), Active='No')
+ build_matrix_node = ET.SubElement(root_node, 'BuildMatrix')
+ workspace_config_node = ET.SubElement(build_matrix_node, 'WorkspaceConfiguration', Name='Debug', Selected='yes')
+ ET.SubElement(workspace_config_node, 'Environment')
+ for module in self.gbuildparser.modulenamelist:
+ ET.SubElement(workspace_config_node, 'Project', Name=module, ConfigName='Debug')
+ workspace_config_node = ET.SubElement(build_matrix_node, 'WorkspaceConfiguration', Name='Release', Selected='yes')
+ ET.SubElement(workspace_config_node, 'Environment')
+ for module in self.gbuildparser.modulenamelist:
+ ET.SubElement(workspace_config_node, 'Project', Name=module, ConfigName='Release')
+
+ self.write_pretty_xml(root_node, os.path.join(self.gbuildparser.builddir, 'libo2.workspace'))
+
+ def create_project_file(self, module_name):
+ root_node = ET.Element('CodeLite_Project', Name=module_name, InternalType='')
+ ET.SubElement(root_node, 'Plugins')
+
+ # add CXX files
+ virtual_dirs = collections.defaultdict(set)
+ for target_path in self.gbuildparser.target_by_path.keys():
+ if target_path.startswith(module_name+'/'):
+ for target in self.gbuildparser.target_by_path[target_path]:
+ for file in target.cxxobjects:
+ relative_file = '/'.join(file.split('/')[1:])
+ path = '/'.join(file.split('/')[1:-1])
+ virtual_dirs[path].add(relative_file + '.cxx')
+ # add HXX files
+ all_libs = set(self.gbuildparser.libs) | set(self.gbuildparser.exes)
+ for lib in all_libs:
+ if lib.name == module_name:
+ for hdir in lib.include:
+ # only want the module-internal ones
+ if hdir.startswith(module_name+'/'):
+ for hf in os.listdir(hdir):
+ if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
+ path = '/'.join(hf.split('/')[1:-1])
+ virtual_dirs[path].add(hf)
+ # add HXX files from the root/include/** folders
+ module_include = os.path.join(self.gbuildparser.builddir, 'include', module_name)
+ if os.path.exists(module_include):
+ for hf in os.listdir(module_include):
+ if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
+ path = '../include/' + ('/'.join(hf.split('/')[1:-1]))
+ virtual_dirs['include/' + module_name].add('../include/' + module_name + '/' + hf)
+
+ for vd_name in sorted(virtual_dirs.keys()):
+ vd_files = sorted(virtual_dirs[vd_name])
+ parent_node = root_node
+ for subname in vd_name.split('/'):
+ parent_node = ET.SubElement(parent_node, 'VirtualDirectory', Name=subname)
+ for file in vd_files:
+ ET.SubElement(parent_node, 'File', Name=file)
+
+ ET.SubElement(root_node, 'Description')
+ ET.SubElement(root_node, 'Dependencies')
+ ET.SubElement(root_node, 'Dependencies', Name='Debug')
+ ET.SubElement(root_node, 'Dependencies', Name='Release')
+
+ settingstemplate = """\
+ <Settings Type="Dynamic Library">
+ <GlobalSettings>
+ <Compiler Options="" C_Options="" Assembler="">
+ <IncludePath Value="."/>
+ </Compiler>
+ <Linker Options="">
+ <LibraryPath Value="."/>
+ </Linker>
+ <ResourceCompiler Options=""/>
+ </GlobalSettings>
+ <Configuration Name="Debug" CompilerType="clang( based on LLVM 3.5.0 )" DebuggerType="GNU gdb debugger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
+ <Compiler Options="-g" C_Options="-g" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
+ <IncludePath Value="."/>
+ </Compiler>
+ <Linker Options="" Required="yes"/>
+ <ResourceCompiler Options="" Required="no"/>
+ <General OutputFile="" IntermediateDirectory="./Debug" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
+ <BuildSystem Name="Default"/>
+ <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
+ <![CDATA[]]>
+ </Environment>
+ <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
+ <DebuggerSearchPaths/>
+ <PostConnectCommands/>
+ <StartupCommands/>
+ </Debugger>
+ <PreBuild/>
+ <PostBuild/>
+ <CustomBuild Enabled="yes">
+ <RebuildCommand/>
+ <CleanCommand>make %s.clean</CleanCommand>
+ <BuildCommand>make %s.build</BuildCommand>
+ <PreprocessFileCommand/>
+ <SingleFileCommand/>
+ <MakefileGenerationCommand/>
+ <ThirdPartyToolName>None</ThirdPartyToolName>
+ <WorkingDirectory>$(WorkspacePath)</WorkingDirectory>
+ </CustomBuild>
+ <AdditionalRules>
+ <CustomPostBuild/>
+ <CustomPreBuild/>
+ </AdditionalRules>
+ <Completion EnableCpp11="no" EnableCpp14="no">
+ <ClangCmpFlagsC/>
+ <ClangCmpFlags/>
+ <ClangPP/>
+ <SearchPaths/>
+ </Completion>
+ </Configuration>
+ <Configuration Name="Release" CompilerType="clang( based on LLVM 3.5.0 )" DebuggerType="GNU gdb debugger" Type="Dynamic Library" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
+ <Compiler Options="" C_Options="" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
+ <IncludePath Value="."/>
+ </Compiler>
+ <Linker Options="-O2" Required="yes"/>
+ <ResourceCompiler Options="" Required="no"/>
+ <General OutputFile="" IntermediateDirectory="./Release" Command="" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
+ <BuildSystem Name="Default"/>
+ <Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
+ <![CDATA[]]>
+ </Environment>
+ <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="" IsExtended="no">
+ <DebuggerSearchPaths/>
+ <PostConnectCommands/>
+ <StartupCommands/>
+ </Debugger>
+ <PreBuild/>
+ <PostBuild/>
+ <CustomBuild Enabled="yes">
+ <RebuildCommand/>
+ <CleanCommand>make %s.clean</CleanCommand>
+ <BuildCommand>make %s.build</BuildCommand>
+ <PreprocessFileCommand/>
+ <SingleFileCommand/>
+ <MakefileGenerationCommand/>
+ <ThirdPartyToolName>None</ThirdPartyToolName>
+ <WorkingDirectory>$(WorkspacePath)</WorkingDirectory>
+ </CustomBuild>
+ <AdditionalRules>
+ <CustomPostBuild/>
+ <CustomPreBuild/>
+ </AdditionalRules>
+ <Completion EnableCpp11="no" EnableCpp14="no">
+ <ClangCmpFlagsC/>
+ <ClangCmpFlags/>
+ <ClangPP/>
+ <SearchPaths/>
+ </Completion>
+ </Configuration>
+ </Settings>
+"""
+ root_node.append(ET.fromstring(settingstemplate % (module_name, module_name, module_name, module_name)))
+
+ self.write_pretty_xml(root_node, os.path.join(self.gbuildparser.builddir, module_name, '%s.project' % module_name))
+
+ def write_pretty_xml(self, node, file_path):
+ xml_str = ET.tostring(node, encoding='unicode')
+ pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
+ with open(file_path, 'w') as f:
+ f.write(pretty_str.decode())
+
+class DebugIntegrationGenerator(IdeIntegrationGenerator):
+
+ def __init__(self, gbuildparser, ide):
+ IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
+
+ def emit(self):
+ print(self.gbuildparser.srcdir)
+ print(self.gbuildparser.builddir)
+ for lib in self.gbuildparser.libs:
+ print(lib)
+ for exe in self.gbuildparser.exes:
+ print(exe)
+ for test in self.gbuildparser.tests:
+ print(test)
+
+
+class VimIntegrationGenerator(IdeIntegrationGenerator):
+
+ def __init__(self, gbuildparser, ide):
+ IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
+
+ def emit(self):
+ global_list = []
+ for lib in set(self.gbuildparser.libs) | set(self.gbuildparser.tests) | set(self.gbuildparser.exes):
+ entries = []
+ for file in lib.cxxobjects:
+ filePath = os.path.join(self.gbuildparser.srcdir, file) + ".cxx"
+ entry = {'directory': lib.location, 'file': filePath, 'command': self.generateCommand(lib, filePath)}
+ entries.append(entry)
+ global_list.extend(entries)
+ with open(os.path.join(self.gbuildparser.builddir, 'compile_commands.json'), 'w') as export_file:
+ json.dump(global_list, export_file)
+
+ def generateCommand(self, lib, file):
+ command = 'clang++ -Wall'
+ for key, value in lib.defs.items():
+ command += ' -D'
+ command += key
+ if value is not None:
+ command += '='
+ command += value
+
+ for include in lib.include:
+ command += ' -I'
+ command += include
+ for isystem in lib.include_sys:
+ command += ' -isystem '
+ command += isystem
+ for cxxflag in lib.cxxflags:
+ command += ' '
+ command += cxxflag
+ command += ' -c '
+ command += file
+ return command
+
+
+class KdevelopIntegrationGenerator(IdeIntegrationGenerator):
+
+ def encode_int(self, i):
+ temp = '%08x' % i
+ return '\\x%s\\x%s\\x%s\\x%s' % (temp[0:2], temp[2:4], temp[4:6], temp[6:8])
+
+ def encode_string(self, string):
+ result = self.encode_int(len(string) * 2)
+ for c in string.encode('utf-16-be'):
+ if c in range(32, 126):
+ result += chr(c)
+ else:
+ result += '\\x%02x' % c
+ return result
+
+ def generate_buildsystemconfigtool(self, configid, tool, args, exe, typenr):
+ return KdevelopIntegrationGenerator.buildsystemconfigtooltemplate % {'configid': configid, 'tool': tool,
+ 'args': args, 'exe': exe, 'typenr': typenr}
+
+ buildsystemconfigtooltemplate = """
+[CustomBuildSystem][BuildConfig%(configid)d][Tool%(tool)s]
+Arguments=%(args)s
+Enabled=true
+Environment=
+Executable=%(exe)s
+Type=%(typenr)d
+
+"""
+
+ def generate_buildsystemconfig(self, configid, moduledir, builddir, title, buildparms=''):
+ result = KdevelopIntegrationGenerator.buildsystemconfigtemplate % {'configid': configid, 'builddir': builddir,
+ 'title': title}
+ result += self.generate_buildsystemconfigtool(configid, 'Clean', 'clean %s' % buildparms,
+ self.gbuildparser.makecmd, 3)
+ result += self.generate_buildsystemconfigtool(configid, 'Build', 'all %s' % buildparms,
+ self.gbuildparser.makecmd, 0)
+ return result
+
+ buildsystemconfigtemplate = """
+[CustomBuildSystem][BuildConfig%(configid)d]
+BuildDir=file://%(builddir)s
+Title=%(title)s
+
+"""
+
+ def generate_buildsystem(self, moduledir):
+ result = KdevelopIntegrationGenerator.buildsystemtemplate % {'defaultconfigid': 0}
+ result += self.generate_buildsystemconfig(0, moduledir, moduledir, 'Module Build -- Release')
+ result += self.generate_buildsystemconfig(1, moduledir, self.gbuildparser.builddir, 'Full Build -- Release')
+ result += self.generate_buildsystemconfig(2, moduledir, moduledir, 'Module Build -- Debug', 'debug=T')
+ result += self.generate_buildsystemconfig(3, moduledir, self.gbuildparser.builddir, 'Full Build -- Debug',
+ 'debug=T')
+ return result
+
+ buildsystemtemplate = """
+[CustomBuildSystem]
+CurrentConfiguration=BuildConfig%(defaultconfigid)d
+
+"""
+
+ def generate_launch(self, launchid, launchname, executablepath, args, workdir):
+ return KdevelopIntegrationGenerator.launchtemplate % {'launchid': launchid, 'launchname': launchname,
+ 'executablepath': executablepath, 'args': args,
+ 'workdir': workdir}
+
+ launchtemplate = """
+[Launch][Launch Configuration %(launchid)d]
+Configured Launch Modes=execute
+Configured Launchers=nativeAppLauncher
+Name=%(launchname)s
+Type=Native Application
+
+[Launch][Launch Configuration %(launchid)d][Data]
+Arguments=%(args)s
+Dependencies=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x00)
+Dependency Action=Nothing
+EnvironmentGroup=default
+Executable=file://%(executablepath)s
+External Terminal=konsole --noclose --workdir %%workdir -e %%exe
+Project Target=
+Use External Terminal=false
+Working Directory=file://%(workdir)s
+isExecutable=true
+
+"""
+
+ def generate_launches(self, moduledir):
+ launches = ','.join(['Launch Configuration %d' % i for i in range(7)])
+ result = KdevelopIntegrationGenerator.launchestemplate % {'launches': launches}
+ result += self.generate_launch(0, 'Local tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
+ 'unitcheck', moduledir)
+ result += self.generate_launch(1, 'Local tests -- slow tests (unitcheck, slowcheck, screenshot)', self.gbuildparser.makecmd,
+ 'unitcheck slowcheck screenshot', moduledir)
+ result += self.generate_launch(2, 'Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
+ self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck', moduledir)
+ result += self.generate_launch(3, 'Global tests -- quick tests (unitcheck)', self.gbuildparser.makecmd,
+ 'unitcheck', self.gbuildparser.builddir)
+ result += self.generate_launch(4, 'Global tests -- slow tests (unitcheck, slowcheck, screenshot)',
+ self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot', self.gbuildparser.builddir)
+ result += self.generate_launch(5, 'Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)',
+ self.gbuildparser.makecmd, 'unitcheck slowcheck screenshot subsequentcheck',
+ self.gbuildparser.builddir)
+ result += self.generate_launch(6, 'Run LibreOffice',
+ os.path.join(self.gbuildparser.instdir, 'program/soffice.bin'), '',
+ self.gbuildparser.instdir)
+ return result
+
+ launchestemplate = """
+[Launch]
+Launch Configurations=%(launches)s
+
+"""
+
+ def write_modulebeef(self, moduledir, modulename):
+ beefdir = os.path.join(moduledir, '.kdev4')
+ os.mkdir(beefdir)
+ beeffile = open(os.path.join(beefdir, 'Module_%s.kdev4' % modulename), 'w')
+ beeffile.write(self.generate_buildsystem(moduledir))
+ beeffile.write(self.generate_launches(moduledir))
+ beeffile.close()
+
+ def write_modulestub(self, moduledir, modulename):
+ stubfile = open(os.path.join(moduledir, 'Module_%s.kdev4' % modulename), 'w')
+ stubfile.write(KdevelopIntegrationGenerator.modulestubtemplate % {'modulename': modulename,
+ 'builditem': self.encode_string(
+ 'Module_%s' % modulename)})
+ stubfile.close()
+
+ modulestubtemplate = """
+[Buildset]
+BuildItems=@Variant(\\x00\\x00\\x00\\t\\x00\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x0b\\x00\\x00\\x00\\x00\\x01%(builditem)s)
+
+[Project]
+Name=Module_%(modulename)s
+Manager=KDevCustomBuildSystem
+VersionControl=kdevgit
+"""
+
+ def write_includepaths(self, path):
+ includedirfile = open(os.path.join(path, '.kdev_include_paths'), 'w')
+ include = set()
+ for target in self.gbuildparser.target_by_path[path]:
+ include |= set(target.include)
+ includedirfile.write('\n'.join(include))
+ includedirfile.close()
+
+ def __init__(self, gbuildparser, ide):
+ IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
+
+ def emit(self):
+ for path in self.gbuildparser.target_by_path:
+ self.write_includepaths(path)
+ for location in self.gbuildparser.target_by_location:
+ for f in os.listdir(location):
+ if f.endswith('.kdev4'):
+ try:
+ os.remove(os.path.join(location, f))
+ except OSError:
+ shutil.rmtree(os.path.join(location, f))
+ for location in self.gbuildparser.target_by_location:
+ modulename = os.path.split(location)[1]
+ self.write_modulestub(location, modulename)
+ self.write_modulebeef(location, modulename)
+
+
+class XcodeIntegrationGenerator(IdeIntegrationGenerator):
+
+ def indent(self, file, level):
+ if level == 0:
+ return
+ for i in range(0, level):
+ file.write(' ')
+
+ def write_object(self, object, file, indent):
+ if isinstance(object, int):
+ file.write('%d' % object)
+ elif isinstance(object, str) and not re.search('[^A-Za-z0-9_]', object):
+ file.write('%s' % object)
+ elif isinstance(object, str):
+ file.write('"%s"' % object)
+ elif isinstance(object, dict):
+ self.write_dict(object, file, indent)
+
+ # Write a dictionary out as an "old-style (NeXT) ASCII plist"
+ def write_dict(self, dict, file, indent):
+ file.write('{')
+ file.write('\n')
+ for key in sorted(dict.keys()):
+ self.indent(file, indent + 1)
+ file.write('%s = ' % key)
+ self.write_object(dict[key], file, indent + 1)
+ file.write(';\n')
+ self.indent(file, indent)
+ file.write('}')
+
+ def write_dict_to_plist(self, dict, file):
+ file.write('// !$*UTF8*$!\n')
+ self.write_dict(dict, file, 0)
+
+ def get_product_type(self, modulename):
+ if modulename in self.gbuildparser.libs:
+ return 'com.apple.product-type.library.dynamic'
+ elif modulename in self.gbuildparser.exes:
+ return 'com.apple.product-type.something'
+
+ counter = 0
+
+ def generate_id(self):
+ XcodeIntegrationGenerator.counter = XcodeIntegrationGenerator.counter + 1
+ return str('X%07x' % XcodeIntegrationGenerator.counter)
+
+ def generate_build_phases(self, modulename):
+ result = [self.sourcesBuildPhaseId]
+ return result
+
+ def generate_root_object(self, modulename):
+ result = {'isa': 'PBXProject',
+ 'attributes': {'LastUpgradeCheck': '0500',
+ 'ORGANIZATIONNAME': 'LibreOffice'},
+ 'buildConfigurationList': self.generate_id(),
+ 'compatibilityVersion': 'Xcode 3.2',
+ 'hasScannedForEncodings': 0,
+ 'knownRegions': ['en'],
+ 'mainGroup': self.mainGroupId,
+ 'productRefGroup': self.productRefGroupId,
+ 'projectDirPath': '',
+ 'projectRoot': '',
+ 'targets': self.targetId}
+ return result
+
+ def generate_target(self, modulename):
+ result = {'isa': 'PBXNativeTarget',
+ 'buildConfigurationList': self.generate_id(),
+ 'buildPhases': self.generate_build_phases(modulename),
+ 'buildRules': [],
+ 'dependencies': [],
+ 'name': modulename,
+ 'productName': modulename,
+ 'productReference': self.productReferenceId,
+ 'productType': self.get_product_type(modulename)}
+ return result
+
+ def generate_main_group(self, modulename):
+ result = {'isa': 'PBXGroup',
+ 'children': [self.subMainGroupId, self.productGroupId],
+ 'sourceTree': '<group>'}
+ return result
+
+ def generate_sub_main_children(self, modulename):
+ return {}
+
+ def generate_sub_main_group(self, modulename):
+ result = {'isa': 'PBXGroup',
+ 'children': self.generate_sub_main_children(modulename),
+ 'path': modulename,
+ 'sourceTree': '<group>'}
+ return result
+
+ def generate_product_group(self, modulename):
+ result = {'isa': 'PBXGroup',
+ 'children': [self.productReferenceId],
+ 'name': 'Products',
+ 'sourceTree': '<group>'}
+ return result
+
+ def build_source_list(self, module):
+ self.sourceRefList = {}
+ self.sourceList = {}
+
+ for i in module.cxxobjects:
+ ref = self.generate_id()
+ self.sourceList[self.generate_id()] = ref
+ self.sourceRefList[ref] = {'lastKnownFileType': 'sourcecode.cpp.cpp',
+ 'path': i + '.cxx',
+ 'sourceTree': '<group>'}
+
+ def generate_sources_build_phase(self, modulename):
+ result = {'isa': 'PBXSourcesBuildPhase',
+ 'buildActionMask': 2147483647,
+ 'files': self.sourceList.keys(),
+ 'runOnlyForDeploymentPostprocessing': 0}
+ return result
+
+ def generate_project(self, target):
+ self.rootObjectId = self.generate_id()
+ self.mainGroupId = self.generate_id()
+ self.subMainGroupId = self.generate_id()
+ self.productReferenceId = self.generate_id()
+ self.productRefGroupId = self.generate_id()
+ self.productGroupId = self.generate_id()
+ self.targetId = self.generate_id()
+ self.build_source_list(target)
+ self.sourcesBuildPhaseId = self.generate_id()
+ objects = {self.rootObjectId: self.generate_root_object(target),
+ self.targetId: self.generate_target(target),
+ self.mainGroupId: self.generate_main_group(target),
+ self.subMainGroupId: self.generate_sub_main_group(target),
+ self.productGroupId: self.generate_product_group(target),
+ self.sourcesBuildPhaseId: self.generate_sources_build_phase(target)
+ }
+ for i in self.sourceList.keys():
+ ref = self.sourceList[i]
+ objects[i] = {'isa': 'PBXBuildFile',
+ 'fileRef': ref}
+ objects[ref] = {'isa': 'PBXFileReference',
+ 'lastKnownFileType': self.sourceRefList[ref]['lastKnownFileType'],
+ 'path': self.sourceRefList[ref]['path']}
+ project = {'archiveVersion': 1,
+ 'classes': {},
+ 'objectVersion': 46,
+ 'objects': objects,
+ 'rootObject': self.rootObjectId}
+ return project
+
+ # For some reverse-engineered documentation on the project.pbxproj format,
+ # see http://www.monobjc.net/xcode-project-file-format.html .
+ def write_xcodeproj(self, moduledir, target):
+ xcodeprojdir = os.path.join(moduledir, '%s.xcodeproj' % target.target_name())
+ try:
+ os.mkdir(xcodeprojdir)
+ except:
+ pass
+ self.write_dict_to_plist(self.generate_project(target),
+ open(os.path.join(xcodeprojdir, 'project.pbxproj'), 'w'))
+
+ def __init__(self, gbuildparser, ide):
+ IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
+
+ def emit(self):
+ self.rootlocation = './'
+ for location in self.gbuildparser.target_by_location:
+ # module = location.split('/')[-1]
+ # module_directory = os.path.join(self.rootlocation, module)
+ for target in self.gbuildparser.target_by_location[location]:
+ # project_path = os.path.join(module_directory, '%s.pbxroj' % target.target_name())
+ self.write_xcodeproj(location, target)
+
+
+class VisualStudioIntegrationGenerator(IdeIntegrationGenerator):
+
+ def __init__(self, gbuildparser, ide):
+ IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
+ self.toolset = os.environ['VCTOOLSET']
+ self.solution_directory = self.gbuildparser.builddir
+ self.configurations = {
+ 'Build': {
+ 'build': self.module_make_command('%(target)s'),
+ 'clean': self.module_make_command('%(target)s.clean'),
+ 'rebuild': self.module_make_command('%(target)s.clean %(target)s')
+ },
+ 'Unit Tests': {
+ 'build': self.module_make_command('unitcheck'),
+ 'clean': self.module_make_command('clean'),
+ 'rebuild': self.module_make_command('clean unitcheck'),
+ },
+ 'Integration tests': {
+ 'build': self.module_make_command('unitcheck slowcheck screenshot subsequentcheck'),
+ 'clean': self.module_make_command('clean'),
+ 'rebuild': self.module_make_command('clean unitcheck slowcheck screenshot subsequentcheck')
+ }
+ }
+
+ def module_make_command(self, targets):
+ return '%(sh)s -c "PATH=\\"/bin:$PATH\\";BUILDDIR=\\"%(builddir)s\\" %(makecmd)s -rsC %(location)s ' + targets + '"'
+
+ class Project:
+
+ def __init__(self, guid, target, project_path):
+ self.guid = guid
+ self.target = target
+ self.path = project_path
+
+ def emit(self):
+ all_projects = []
+ for location in self.gbuildparser.target_by_location:
+ projects = []
+ module = location.split('/')[-1]
+ module_directory = os.path.join(self.solution_directory, module)
+ for target in self.gbuildparser.target_by_location[location]:
+ project_path = os.path.join(module_directory, '%s.vcxproj' % target.target_name())
+ project_guid = self.write_project(project_path, target)
+ p = VisualStudioIntegrationGenerator.Project(project_guid, target, project_path)
+ projects.append(p)
+ self.write_solution(os.path.join(module_directory, '%s.sln' % module), projects)
+ all_projects += projects
+
+ self.write_solution(os.path.join(self.solution_directory, 'LibreOffice.sln'), all_projects)
+
+ @staticmethod
+ def gen_guid(category, name):
+ return str(uuid.uuid5(uuid.NAMESPACE_URL, 'vnd.libreoffice.vs-ide-integration:' + category + '/' + urllib.parse.quote(name))).upper()
+
+ nmake_project_guid = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
+ nmake_folder_guid = '2150E333-8FDC-42A3-9474-1A3956D46DE8'
+
+ def get_dependency_libs(self, linked_libs, library_projects):
+ dependency_libs = {}
+ for linked_lib in linked_libs:
+ for library_project in library_projects:
+ if library_project.target.library_name() == linked_lib:
+ dependency_libs[library_project.guid] = library_project
+ return dependency_libs
+
+ def write_solution(self, solution_path, projects):
+ print('Solution %s:' % os.path.splitext(os.path.basename(solution_path))[0], end='')
+ library_projects = [project for project in projects if project.target in self.gbuildparser.libs]
+ test_projects = [project for project in projects if project.target in self.gbuildparser.tests]
+ executable_projects = [project for project in projects if project.target in self.gbuildparser.exes]
+ with open(solution_path, 'w') as f:
+ f.write('Microsoft Visual Studio Solution File, Format Version 12.00\n')
+ for project in projects:
+ target = project.target
+ print(' %s' % target.target_name(), end='')
+ proj_path = os.path.relpath(project.path, os.path.abspath(os.path.dirname(solution_path)))
+ f.write('Project("{%s}") = "%s", "%s", "{%s}"\n' %
+ (VisualStudioIntegrationGenerator.nmake_project_guid,
+ target.short_name(), proj_path, project.guid))
+ libs_in_solution = self.get_dependency_libs(target.linked_libs,
+ library_projects)
+ if libs_in_solution:
+ f.write('\tProjectSection(ProjectDependencies) = postProject\n')
+ for lib_guid in libs_in_solution.keys():
+ f.write('\t\t{%(guid)s} = {%(guid)s}\n' % {'guid': lib_guid})
+ f.write('\tEndProjectSection\n')
+ f.write('EndProject\n')
+ f.write('Project("{%s}") = "Utility", "Utility", "{6778240E-8B6B-47A0-AC31-7E7A257B97E6}"\n' %
+ (VisualStudioIntegrationGenerator.nmake_folder_guid))
+ f.write('\tProjectSection(SolutionItems) = preProject\n')
+ # The natvis file gives pretty-printed variable values when debugging
+ natvis_path = os.path.join(gbuildparser.srcdir, 'solenv/vs/LibreOffice.natvis')
+ f.write('\t\t%(natvis)s = %(natvis)s\n' % {'natvis': natvis_path})
+ f.write('\tEndProjectSection\n')
+ f.write('EndProject\n')
+ # Folders to group tests/libraries/executables
+ nmake_tests_guid = 'CF544F7B-9D02-4D83-8370-5887851209B7'
+ nmake_libraries_guid = 'C624F43D-616C-4627-B58F-F5C2047B7BDC'
+ nmake_executables_guid = '1CD80999-9FA9-4BA9-B4D9-6E33035CF648'
+ f.write('Project("{%s}") = "Tests", "Tests", "{%s}"\n' %
+ (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_tests_guid))
+ f.write('EndProject\n')
+ f.write('Project("{%s}") = "Libraries", "Libraries", "{%s}"\n' %
+ (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_libraries_guid))
+ f.write('EndProject\n')
+ f.write('Project("{%s}") = "Executables", "Executables", "{%s}"\n' %
+ (VisualStudioIntegrationGenerator.nmake_folder_guid, nmake_executables_guid))
+ f.write('EndProject\n')
+ # end Folders to group tests/libraries/executables
+ f.write('Global\n')
+ platform = 'Win32'
+ f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
+ for cfg in self.configurations:
+ f.write('\t\t%(cfg)s|%(platform)s = %(cfg)s|%(platform)s\n' % {'cfg': cfg, 'platform': platform})
+ f.write('\tEndGlobalSection\n')
+ # Group projects to folders
+ f.write('\tGlobalSection(NestedProjects) = preSolution\n')
+ for project in test_projects:
+ f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_tests_guid))
+ for project in library_projects:
+ f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_libraries_guid))
+ for project in executable_projects:
+ f.write('\t\t{%s} = {%s}\n' % (project.guid, nmake_executables_guid))
+ f.write('\tEndGlobalSection\n')
+ # end Group projects to folders
+ f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
+ # Specifies project configurations for solution configuration
+ for project in projects:
+ for cfg in self.configurations:
+ params = {'guid': project.guid, 'sol_cfg': cfg, 'proj_cfg': cfg, 'platform': platform}
+ f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.ActiveCfg = %(proj_cfg)s|%(platform)s\n' % params)
+ # Build.0 is basically 'Build checkbox' in configuration manager
+ f.write('\t\t{%(guid)s}.%(sol_cfg)s|%(platform)s.Build.0 = %(proj_cfg)s|%(platform)s\n' % params)
+ f.write('\tEndGlobalSection\n')
+ f.write('EndGlobal\n')
+ print('')
+
+ @staticmethod
+ def to_long_names(shortnames):
+ if platform == "cygwin":
+ return (subprocess.check_output(["cygpath", "-wal"] + shortnames).decode("utf-8", "strict").rstrip()).split("\n")
+ else:
+ return shortnames
+
+ # Unescape the values: \"tklo.dll\" => "tklo.dll"
+ escapepattern = re.compile(r'\\(.)')
+
+ @staticmethod
+ def defs_list(defs):
+ defines_list = []
+ # List defines
+ for key, value in defs.items():
+ define = key
+ if value is not None:
+ define += '=' + VisualStudioIntegrationGenerator.escapepattern.sub(r'\1', value)
+ defines_list.append(define)
+ return defines_list
+
+ def write_project(self, project_path, target):
+ # See info at http://blogs.msdn.com/b/visualstudio/archive/2010/05/14/a-guide-to-vcxproj-and-props-file-structure.aspx
+ folder = os.path.dirname(project_path)
+ if not os.path.exists(folder):
+ os.makedirs(folder)
+ project_guid = self.gen_guid('project', target.short_name())
+ cxxflags = ' '.join(target.cxxflags)
+ ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
+ ET.register_namespace('', ns)
+ proj_node = ET.Element('{%s}Project' % ns, DefaultTargets='Build', ToolsVersion='4.0')
+ proj_confs_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns, Label='ProjectConfigurations')
+ platform = 'Win32'
+ for configuration in self.configurations:
+ proj_conf_node = ET.SubElement(proj_confs_node,
+ '{%s}ProjectConfiguration' % ns,
+ Include='%s|%s' % (configuration, platform))
+ conf_node = ET.SubElement(proj_conf_node, '{%s}Configuration' % ns)
+ conf_node.text = configuration
+ platform_node = ET.SubElement(proj_conf_node, '{%s}Platform' % ns)
+ platform_node.text = platform
+
+ globals_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='Globals')
+ proj_guid_node = ET.SubElement(globals_node, '{%s}ProjectGuid' % ns)
+ proj_guid_node.text = '{%s}' % project_guid
+ proj_keyword_node = ET.SubElement(globals_node, '{%s}Keyword' % ns)
+ proj_keyword_node.text = 'MakeFileProj'
+ proj_name_node = ET.SubElement(globals_node, '{%s}ProjectName' % ns)
+ proj_name_node.text = target.short_name()
+
+ ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.Default.props')
+ for configuration in self.configurations:
+ conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label="Configuration",
+ Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
+ # Type of project used by the MSBuild to determine build process, see Microsoft.Makefile.targets
+ conf_type_node = ET.SubElement(conf_node, '{%s}ConfigurationType' % ns)
+ conf_type_node.text = 'Makefile'
+ # This defines the version of Visual Studio which can show next to project names in the Solution Explorer
+ platform_toolset_node = ET.SubElement(conf_node, '{%s}PlatformToolset' % ns)
+ platform_toolset_node.text = self.toolset
+
+ ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.props')
+ ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionSettings')
+ for configuration in self.configurations:
+ prop_sheets_node = ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='Configuration',
+ Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration, platform))
+ ET.SubElement(prop_sheets_node, '{%s}Import' % ns,
+ Project='$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props',
+ Condition="exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')",
+ Label='LocalAppDataPlatform')
+
+ ET.SubElement(proj_node, '{%s}PropertyGroup' % ns, Label='UserMacros')
+ # VS IDE (at least "Peek definition") is allergic to paths like "C:/PROGRA~2/WI3CF2~1/10/Include/10.0.14393.0/um"; see
+ # https://developercommunity.visualstudio.com/content/problem/139659/vc-peek-definition-fails-to-navigate-to-windows-ki.html
+ # We need to convert to long paths here. Do this once, since it's time-consuming operation.
+ include_path_node_text = ';'.join(self.to_long_names(target.include))
+ for cfg_name, cfg_targets in self.configurations.items():
+ conf_node = ET.SubElement(proj_node, '{%s}PropertyGroup' % ns,
+ Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (cfg_name, platform))
+ nmake_params = {
+ 'sh': os.path.join(self.gbuildparser.binpath, 'dash.exe'),
+ 'builddir': self.gbuildparser.builddir,
+ 'location': target.location,
+ 'makecmd': self.gbuildparser.makecmd,
+ 'target': target.target_name()}
+ nmake_build_node = ET.SubElement(conf_node, '{%s}NMakeBuildCommandLine' % ns)
+ nmake_build_node.text = cfg_targets['build'] % nmake_params
+ nmake_clean_node = ET.SubElement(conf_node, '{%s}NMakeCleanCommandLine' % ns)
+ nmake_clean_node.text = cfg_targets['clean'] % nmake_params
+ nmake_rebuild_node = ET.SubElement(conf_node, '{%s}NMakeReBuildCommandLine' % ns)
+ nmake_rebuild_node.text = cfg_targets['rebuild'] % nmake_params
+ nmake_output_node = ET.SubElement(conf_node, '{%s}NMakeOutput' % ns)
+ nmake_output_node.text = os.path.join(self.gbuildparser.instdir, 'program', 'soffice.bin')
+ nmake_defs_node = ET.SubElement(conf_node, '{%s}NMakePreprocessorDefinitions' % ns)
+ nmake_defs_node.text = ';'.join(self.defs_list(target.defs) + ['$(NMakePreprocessorDefinitions)'])
+ include_path_node = ET.SubElement(conf_node, '{%s}IncludePath' % ns)
+ include_path_node.text = include_path_node_text
+ additional_options_node = ET.SubElement(conf_node, '{%s}AdditionalOptions' % ns)
+ additional_options_node.text = cxxflags
+
+ ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % ns)
+
+ cxxobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
+ for cxxobject in target.cxxobjects:
+ cxxabspath = os.path.join(self.gbuildparser.srcdir, cxxobject)
+ cxxfile = cxxabspath + '.cxx'
+ if os.path.isfile(cxxfile):
+ ET.SubElement(cxxobjects_node, '{%s}ClCompile' % ns, Include=cxxfile)
+ else:
+ print('Source %s in project %s does not exist' % (cxxfile, target.target_name()))
+
+ cobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
+ for cobject in target.cobjects:
+ cabspath = os.path.join(self.gbuildparser.srcdir, cobject)
+ cfile = cabspath + '.c'
+ if os.path.isfile(cfile):
+ ET.SubElement(cobjects_node, '{%s}ClCompile' % ns, Include=cfile)
+ else:
+ print('Source %s in project %s does not exist' % (cfile, target.target_name()))
+
+ includes_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
+ for cxxobject in target.cxxobjects:
+ include_abs_path = os.path.join(self.gbuildparser.srcdir, cxxobject)
+ hxxfile = include_abs_path + '.hxx'
+ if os.path.isfile(hxxfile):
+ ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hxxfile)
+ # Few files have corresponding .h files
+ hfile = include_abs_path + '.h'
+ if os.path.isfile(hfile):
+ ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hfile)
+ for cobject in target.cobjects:
+ include_abs_path = os.path.join(self.gbuildparser.srcdir, cobject)
+ hfile = include_abs_path + '.h'
+ if os.path.isfile(hfile):
+ ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=hfile)
+ ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\\Microsoft.Cpp.targets')
+ ET.SubElement(proj_node, '{%s}ImportGroup' % ns, Label='ExtensionTargets')
+ self.write_pretty_xml(proj_node, project_path)
+ self.write_filters(project_path + '.filters',
+ os.path.join(self.gbuildparser.srcdir, os.path.basename(target.location)),
+ [cxx_node.get('Include') for cxx_node in cxxobjects_node.findall('{%s}ClCompile' % ns)],
+ [c_node.get('Include') for c_node in cobjects_node.findall('{%s}ClCompile' % ns)],
+ [include_node.get('Include') for include_node in includes_node.findall('{%s}ClInclude' % ns)])
+ return project_guid
+
+ def get_filter(self, module_dir, proj_file):
+ return '\\'.join(os.path.relpath(proj_file, module_dir).split('/')[:-1])
+
+ def get_subfilters(self, proj_filter):
+ parts = proj_filter.split('\\')
+ subfilters = set([proj_filter]) if proj_filter else set()
+ for i in range(1, len(parts)):
+ subfilters.add('\\'.join(parts[:i]))
+ return subfilters
+
+ def write_pretty_xml(self, node, file_path):
+ xml_str = ET.tostring(node, encoding='unicode')
+ pretty_str = minidom.parseString(xml_str).toprettyxml(encoding='utf-8')
+ with open(file_path, 'w') as f:
+ f.write(pretty_str.decode())
+
+ def add_nodes(self, files_node, module_dir, tag, project_files):
+ ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
+ filters = set()
+ for project_file in project_files:
+ file_node = ET.SubElement(files_node, tag, Include=project_file)
+ if os.path.commonprefix([module_dir, project_file]) == module_dir:
+ project_filter = self.get_filter(module_dir, project_file)
+ filter_node = ET.SubElement(file_node, '{%s}Filter' % ns)
+ filter_node.text = project_filter
+ filters |= self.get_subfilters(project_filter)
+ return filters
+
+ def write_filters(self, filters_path, module_dir, cxx_files, c_files, include_files):
+ ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
+ ET.register_namespace('', ns)
+ proj_node = ET.Element('{%s}Project' % ns, ToolsVersion='4.0')
+ filters = set()
+ compiles_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
+ filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % ns, cxx_files)
+ filters |= self.add_nodes(compiles_node, module_dir, '{%s}ClCompile' % ns, c_files)
+ include_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
+ filters |= self.add_nodes(include_node, module_dir, '{%s}ClInclude' % ns, include_files)
+
+ filters_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
+ for proj_filter in filters:
+ filter_node = ET.SubElement(filters_node, '{%s}Filter' % ns, Include=proj_filter)
+ self.write_pretty_xml(proj_node, filters_path)
+
+
+class QtCreatorIntegrationGenerator(IdeIntegrationGenerator):
+
+ def __init__(self, gbuildparser, ide):
+ IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
+ self.target_by_location = {}
+ for target in set(self.gbuildparser.libs) | set(self.gbuildparser.exes) | set(self.gbuildparser.tests):
+ if target.location not in self.target_by_location:
+ self.target_by_location[target.location] = set()
+ self.target_by_location[target.location] |= set([target])
+
+ self._do_log = False # set to 'True' to activate log of QtCreatorIntegrationGenerator
+ if self._do_log:
+ qtlog_path = os.path.abspath('../qtlog_.txt')
+ self.qtlog = open(qtlog_path, 'w')
+
+ def _log(self, message):
+ if self._do_log:
+ self.qtlog.write(message)
+
+ def log_close(self):
+ if self._do_log:
+ self.qtlog.close()
+
+ def generate_build_configs(self, lib_folder):
+ module_folder = os.path.join(self.base_folder, lib_folder)
+ xml = ""
+ # In QtCreator UI, build configs are listed alphabetically,
+ # so it can be different from the creation order.
+ # So we prefix the names with the index.
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '0',
+ 'base_folder': module_folder,
+ 'arg': "",
+ 'name': "1-Build %s" % lib_folder,
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '1',
+ 'base_folder': module_folder,
+ 'arg': "unitcheck",
+ 'name': "2-Local tests -- quick tests (unitcheck)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '2',
+ 'base_folder': module_folder,
+ 'arg': "unitcheck slowcheck screenshot",
+ 'name': "3-Local tests -- slow tests (unitcheck, slowcheck, screenshot)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '3',
+ 'base_folder': module_folder,
+ 'arg': "unitcheck slowcheck screenshot subsequentcheck",
+ 'name': "4-Local tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '4',
+ 'base_folder': self.base_folder,
+ 'arg': "unitcheck",
+ 'name': "5-Global tests -- quick tests (unitcheck)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '5',
+ 'base_folder': self.base_folder,
+ 'arg': "unitcheck slowcheck screenshot",
+ 'name': "6-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '6',
+ 'base_folder': self.base_folder,
+ 'arg': "unitcheck slowcheck screenshot subsequentcheck",
+ 'name': "7-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '7',
+ 'base_folder': self.base_folder,
+ 'arg': "",
+ 'name': "8-Global build -- nocheck",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '8',
+ 'base_folder': self.base_folder,
+ 'arg': "",
+ 'name': "9-Global build",
+ }
+
+ xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
+ 'nb': '9',
+ }
+ return xml
+
+ def generate_meta_build_configs(self):
+ xml = ""
+ # In QtCreator UI, build configs are listed alphabetically,
+ # so it can be different from the creation order.
+ # So we prefix the names with the index.
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '0',
+ 'base_folder': self.base_folder,
+ 'arg': "",
+ 'name': "01-Global Build",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '1',
+ 'base_folder': self.base_folder,
+ 'arg': "unitcheck",
+ 'name': "02-Global tests -- quick tests (unitcheck)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '2',
+ 'base_folder': self.base_folder,
+ 'arg': "unitcheck slowcheck screenshot",
+ 'name': "03-Global tests -- slow tests (unitcheck, slowcheck, screenshot)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '3',
+ 'base_folder': self.base_folder,
+ 'arg': "unitcheck slowcheck screenshot subsequentcheck",
+ 'name': "04-Global tests -- integration tests (unitcheck, slowcheck, screenshot, subsequentcheck)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '4',
+ 'base_folder': self.base_folder,
+ 'arg': "perfcheck",
+ 'name': "05-Global tests -- performance tests (perfcheck)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '5',
+ 'base_folder': self.base_folder,
+ 'arg': "check",
+ 'name': "06-Global tests -- tests (check)",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '6',
+ 'base_folder': self.base_folder,
+ 'arg': "",
+ 'name': "07-Global build -- nocheck",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '7',
+ 'base_folder': self.base_folder,
+ 'arg': "build-l10n-only",
+ 'name': "08-Global build -- build-l10n-only",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '8',
+ 'base_folder': self.base_folder,
+ 'arg': "build-non-l10n-only",
+ 'name': "09-Global build -- build-non-l10n-only",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '9',
+ 'base_folder': self.base_folder,
+ 'arg': "clean",
+ 'name': "10-Global build -- clean",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '10',
+ 'base_folder': self.base_folder,
+ 'arg': "clean-build",
+ 'name': "11-Global build -- clean-build",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_template % {
+ 'index': '11',
+ 'base_folder': self.base_folder,
+ 'arg': "clean-host",
+ 'name': "12-Global build -- clean-host",
+ }
+ xml += QtCreatorIntegrationGenerator.build_configs_count_template % {
+ 'nb': '12',
+ }
+ return xml
+
+ # By default, QtCreator creates 2 BuildStepList : "Build" and "Clean"
+ # but the "clean" can be empty.
+ build_configs_template = """
+ <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.%(index)s">
+ <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">%(base_folder)s</value>
+ <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+ <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
+ <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
+ <valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
+ <value type="QString">-w</value>
+ <value type="QString">-r</value>
+ </valuelist>
+ <value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
+ <value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">%(arg)s</value>
+ <value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
+ </valuemap>
+ <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
+ </valuemap>
+ <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
+ <value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
+ <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">%(name)s</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
+ <value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">%(index)s</value>
+ <value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
+ </valuemap>
+ """
+
+ build_configs_count_template = """
+ <!-- nb build configurations -->
+ <value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">%(nb)s</value>
+ """
+
+ def generate_deploy_configs(self, lib_folder):
+ xml = QtCreatorIntegrationGenerator.deploy_configs_template % {}
+ return xml
+
+ deploy_configs_template = """
+ <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
+ <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
+ <value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
+ </valuemap>
+ <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy locally</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
+ </valuemap>
+ <value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
+ """
+
+ def generate_run_configs(self, lib_folder):
+
+ # If we use 'soffice', it's ok only for "Run", not for "Debug".
+ # So we put "soffice.bin" that is ok for both.
+ loexec = "%s/instdir/program/soffice.bin" % self.base_folder
+ xml = QtCreatorIntegrationGenerator.run_configs_template % {
+ 'loexec': loexec,
+ 'workdir': self.base_folder
+ }
+ return xml
+
+ run_configs_template = """
+ <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
+ <valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
+ <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
+ <value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
+ <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
+ <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
+ <value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
+ <value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
+ <value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
+ <value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
+ <value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
+ <value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
+ <valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
+ <value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
+ <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
+ <value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
+ <value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
+ <value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
+ <valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
+ <value type="int">0</value>
+ <value type="int">1</value>
+ <value type="int">2</value>
+ <value type="int">3</value>
+ <value type="int">4</value>
+ <value type="int">5</value>
+ <value type="int">6</value>
+ <value type="int">7</value>
+ <value type="int">8</value>
+ <value type="int">9</value>
+ <value type="int">10</value>
+ <value type="int">11</value>
+ <value type="int">12</value>
+ <value type="int">13</value>
+ <value type="int">14</value>
+ </valuelist>
+ <value type="int" key="PE.EnvironmentAspect.Base">2</value>
+ <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
+
+ <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
+ <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">%(loexec)s</value>
+ <value type="bool" key="ProjectExplorer.CustomExecutableRunConfiguration.UseTerminal">false</value>
+ <value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">%(workdir)s</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run libreoffice/instdir/program/soffice</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
+ <value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
+ <value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
+ <value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
+ <value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
+ <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
+ <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
+
+ </valuemap>
+ <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
+ """
+
+ def generate_pro_shared_content(self, lib_folder):
+
+ build_configs = self.generate_build_configs(lib_folder)
+ deploy_configs = self.generate_deploy_configs(lib_folder)
+ run_configs = self.generate_run_configs(lib_folder)
+
+ xml = QtCreatorIntegrationGenerator.pro_shared_template % {
+ 'build_configs': build_configs,
+ 'deploy_configs': deploy_configs,
+ 'run_configs': run_configs,
+ }
+ return xml
+
+ def generate_meta_pro_shared_content(self):
+
+ build_configs = self.generate_meta_build_configs()
+ deploy_configs = self.generate_deploy_configs("")
+ run_configs = self.generate_run_configs("")
+
+ xml = QtCreatorIntegrationGenerator.pro_shared_template % {
+ 'build_configs': build_configs,
+ 'deploy_configs': deploy_configs,
+ 'run_configs': run_configs,
+ }
+ return xml
+
+ pro_shared_template = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE QtCreatorProject>
+<!-- Written by QtCreator 3.1.1, 2015-05-14T15:54:34. -->
+<qtcreator>
+ <data>
+ <variable>ProjectExplorer.Project.ActiveTarget</variable>
+ <value type="int">0</value>
+ </data>
+
+ <!-- editor settings -->
+ <data>
+ <variable>ProjectExplorer.Project.EditorSettings</variable>
+ <valuemap type="QVariantMap">
+ <value type="bool" key="EditorConfiguration.AutoIndent">true</value>
+ <value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
+ <value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
+ <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
+ <value type="QString" key="language">Cpp</value>
+ <valuemap type="QVariantMap" key="value">
+ <value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
+ </valuemap>
+ </valuemap>
+ <valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
+ <value type="QString" key="language">QmlJS</value>
+ <valuemap type="QVariantMap" key="value">
+ <value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
+ </valuemap>
+ </valuemap>
+ <value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
+ <value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
+ <value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
+ <value type="int" key="EditorConfiguration.IndentSize">4</value>
+ <value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
+ <value type="int" key="EditorConfiguration.MarginColumn">80</value>
+ <value type="bool" key="EditorConfiguration.MouseHiding">true</value>
+ <value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
+ <value type="int" key="EditorConfiguration.PaddingMode">1</value>
+ <value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
+ <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
+ <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
+ <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
+ <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
+ <value type="int" key="EditorConfiguration.TabSize">8</value>
+ <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
+ <value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
+ <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
+ <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
+ <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
+ <value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
+ </valuemap>
+ </data>
+
+ <data>
+ <variable>ProjectExplorer.Project.PluginSettings</variable>
+ <valuemap type="QVariantMap"/>
+ </data>
+
+ <!-- target -->
+ <data>
+ <variable>ProjectExplorer.Project.Target.0</variable>
+ <valuemap type="QVariantMap">
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
+ <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{0701de51-c96e-4e4f-85c3-e70b223c5076}</value>
+ <value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
+ <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
+ <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
+
+ <!-- build configurations -->
+ %(build_configs)s
+
+ <!-- deploy configurations -->
+ %(deploy_configs)s
+
+ <!-- plugin settings -->
+ <valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
+
+ <!-- run configurations -->
+ %(run_configs)s
+
+ </valuemap>
+ </data>
+ <!-- nb targets : 1 -->
+ <data>
+ <variable>ProjectExplorer.Project.TargetCount</variable>
+ <value type="int">1</value>
+ </data>
+ <data>
+ <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
+ <value type="QByteArray">{5abcafed-86f6-49f6-b1cb-380fadd21211}</value>
+ </data>
+ <data>
+ <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
+ <value type="int">15</value>
+ </data>
+</qtcreator>
+"""
+
+ def get_file_path(self, src_file, ext_choices):
+ path = os.path.join(self.gbuildparser.srcdir, src_file)
+ for ext in ext_choices:
+ full_path = path + ext
+ if os.path.isfile(full_path):
+ return full_path
+ return ""
+
+ def get_source_path(self, src_file):
+ return self.get_file_path(src_file, (".cxx", ".cpp", ".c", ".mm"))
+
+ def get_header_path(self, src_file):
+ return self.get_file_path(src_file, (".hxx", ".hpp", ".h"))
+
+ def build_data_libs(self):
+
+ self.data_libs = {}
+
+ all_libs = set(self.gbuildparser.libs) | set(self.gbuildparser.exes) | set(self.gbuildparser.tests)
+ for lib in all_libs:
+ self._log("\nlibrary : %s, loc=%s" % (lib.short_name(), lib.location))
+ lib_name = os.path.basename(lib.location)
+ lib_folder = os.path.relpath(lib.location, self.base_folder)
+
+ def lopath(path):
+ if platform == "cygwin":
+ # absolute paths from GbuildToJson are Windows paths,
+ # so convert everything to such ones
+ abs_path = path
+ if not ntpath.isabs(abs_path):
+ abs_path = ntpath.join(self.gbuildparser.srcdir, path)
+ return abs_path.replace('\\', '/')
+
+ return os.path.abspath(path)
+
+ defines_list = []
+ sources_list = []
+ includepath_list = []
+ # The explicit headers list is not mandatory :
+ # QtCreator just needs 'include_path_list' to find all headers files.
+ # But files listed in 'header_list' will be shown
+ # in a specific "Headers" folder in QtCreator's Project panel.
+ # We will list here only headers files of current lib.
+ headers_list = []
+ for file_ in lib.cxxobjects:
+ # the file has no extension : search it
+ # self._log("\n file : %s" % file_)
+ path = self.get_source_path(file_)
+ if path:
+ sources_list.append(lopath(path))
+
+ # few cxxobject files have a header beside
+ path = self.get_header_path(file_)
+ if path:
+ headers_list.append(lopath(path))
+
+ cxxflags_list = []
+ for cxxflag in lib.cxxflags:
+ # extract flag for C++ standard version
+ if cxxflag.startswith('-std'):
+ cxxflags_list.append(cxxflag)
+
+ # List all include paths
+ for hdir in (lib.include + lib.include_sys):
+ hf_lopath = lopath(hdir)
+ includepath_list.append(hf_lopath)
+
+ # List headers files from current lib
+ for hdir in lib.include:
+ if hdir.startswith(lib.location):
+ for dirpath, _, files in os.walk(hdir):
+ for hf in files:
+ if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
+ hf_lopath = lopath(os.path.join(dirpath, hf))
+ headers_list.append(hf_lopath)
+
+ # List defines
+ for key, value in lib.defs.items():
+ define = key
+ if value is not None:
+ define += '=' + value
+ defines_list.append(define)
+
+ # All data are prepared, store them for the lib.
+ if lib_folder in self.data_libs:
+ self.data_libs[lib_folder]['sources'] |= set(sources_list)
+ self.data_libs[lib_folder]['headers'] |= set(headers_list)
+ self.data_libs[lib_folder]['cxxflags'] |= set(cxxflags_list)
+ self.data_libs[lib_folder]['includepath'] |= set(includepath_list)
+ self.data_libs[lib_folder]['defines'] |= set(defines_list)
+ else:
+ self.data_libs[lib_folder] = {
+ 'sources': set(sources_list),
+ 'headers': set(headers_list),
+ 'cxxflags': set(cxxflags_list),
+ 'includepath': set(includepath_list),
+ 'defines': set(defines_list),
+ 'loc': lib.location,
+ 'name': lib_name
+ }
+
+ def emit(self):
+
+ mode = 'w+'
+ self.base_folder = self.gbuildparser.builddir
+
+ # for .pro files, we must explicitly list all files (.c, .h)
+ # so we can't reuse directly the same method than for kde integration.
+ self.build_data_libs()
+
+ # subdirs for the meta .pro file
+ subdirs_meta_pro = []
+ subdirs_list = self.data_libs.keys()
+ # Now we can create Qt files
+ for lib_folder in subdirs_list:
+ sources_list = sorted(self.data_libs[lib_folder]['sources'])
+ headers_list = sorted(self.data_libs[lib_folder]['headers'])
+ cxxflags_list = sorted(self.data_libs[lib_folder]['cxxflags'])
+ includepath_list = sorted(self.data_libs[lib_folder]['includepath'])
+ defines_list = sorted(self.data_libs[lib_folder]['defines'])
+ lib_loc = self.data_libs[lib_folder]['loc']
+ lib_name = self.data_libs[lib_folder]['name']
+
+ sources = " \\\n".join(sources_list)
+ headers = " \\\n".join(headers_list)
+ cxxflags = " \\\n".join(cxxflags_list)
+ includepath = " \\\n".join(includepath_list)
+ defines = " \\\n".join(defines_list)
+
+ # create .pro file
+ subdirs_meta_pro.append(lib_name)
+ qt_pro_file = os.path.join(self.base_folder, lib_name, lib_name + '.pro')
+ try:
+ content = QtCreatorIntegrationGenerator.pro_template % {'sources': sources, 'headers': headers,
+ 'cxxflags': cxxflags, 'includepath': includepath, 'defines': defines}
+ with open(qt_pro_file, mode) as fpro:
+ fpro.write(content)
+ self._log("created %s\n" % qt_pro_file)
+
+ except Exception as e:
+ print("ERROR : creating pro file=" + qt_pro_file, file=sys.stderr)
+ print(e, file=sys.stderr)
+ temp = traceback.format_exc() # .decode('utf8')
+ print(temp, file=sys.stderr)
+ print("\n\n", file=sys.stderr)
+
+ # create .pro.shared file
+ qt_pro_shared_file = os.path.join(self.base_folder, lib_name, lib_name + '.pro.shared')
+ try:
+ with open(qt_pro_shared_file, mode) as fproshared:
+ fproshared.write(self.generate_pro_shared_content(lib_folder))
+ self._log("created %s\n" % qt_pro_shared_file)
+
+ except Exception as e:
+ print("ERROR : creating pro.shared file=" + qt_pro_shared_file, file=sys.stderr)
+ print(e, file=sys.stderr)
+ temp = traceback.format_exc()
+ print(temp, file=sys.stderr)
+ print("\n\n", file=sys.stderr)
+
+ # create meta .pro file (lists all sub projects)
+ qt_meta_pro_file = os.path.join(self.base_folder, 'lo.pro')
+ try:
+ subdirs = " \\\n".join(sorted(subdirs_meta_pro))
+ content = QtCreatorIntegrationGenerator.pro_meta_template % {'subdirs': subdirs}
+ with open(qt_meta_pro_file, 'w+') as fmpro:
+ fmpro.write(content)
+
+ except Exception as e:
+ print("ERROR : creating lo.pro file=" + qt_meta_pro_file, file=sys.stderr)
+ print(e, file=sys.stderr)
+ temp = traceback.format_exc()
+ print(temp, file=sys.stderr)
+ print("\n\n", file=sys.stderr)
+
+ # create meta .pro.shared file
+ qt_meta_pro_shared_file = os.path.join(self.base_folder, 'lo.pro.shared')
+ try:
+ with open(qt_meta_pro_shared_file, mode) as fmproshared:
+ fmproshared.write(self.generate_meta_pro_shared_content())
+ self._log("created %s\n" % qt_meta_pro_shared_file)
+
+ except Exception as e:
+ print("ERROR : creating lo.pro.shared file=" + qt_meta_pro_shared_file, file=sys.stderr)
+ print(e, file=sys.stderr)
+ temp = traceback.format_exc()
+ print(temp, file=sys.stderr)
+ print("\n\n", file=sys.stderr)
+
+ self.log_close()
+
+ pro_template = """TEMPLATE = lib
+CONFIG += console
+CONFIG -= app_bundle
+CONFIG -= qt
+
+QMAKE_CXXFLAGS += %(cxxflags)s
+
+INCLUDEPATH += %(includepath)s
+
+SOURCES += %(sources)s
+
+HEADERS += %(headers)s
+
+DEFINES += %(defines)s
+
+"""
+ pro_meta_template = """TEMPLATE = subdirs
+
+SUBDIRS = %(subdirs)s
+"""
+
+
+def get_options():
+ parser = argparse.ArgumentParser(
+ description='LibreOffice gbuild IDE project generator')
+ parser.add_argument('--ide', dest='ide', required=True,
+ help='the IDE to generate project files for')
+ parser.add_argument('--make', dest='makecmd', required=True,
+ help='the command to execute make')
+ return parser.parse_args()
+
+
+if __name__ == '__main__':
+ args = get_options()
+ # FIXME: Hack
+ if args.makecmd == 'make':
+ args.makecmd = '/usr/bin/make'
+
+ paths = {}
+ generators = {
+ 'codelite': CodeliteIntegrationGenerator,
+ 'eclipsecdt': EclipseCDTIntegrationGenerator,
+ 'kdevelop': KdevelopIntegrationGenerator,
+ 'xcode': XcodeIntegrationGenerator,
+ 'vs': VisualStudioIntegrationGenerator,
+ 'vim': VimIntegrationGenerator,
+ 'debug': DebugIntegrationGenerator,
+ 'qtcreator': QtCreatorIntegrationGenerator,
+ }
+
+ if args.ide not in generators.keys():
+ print("Invalid ide. valid values are %s" % ','.join(generators.keys()))
+ sys.exit(1)
+
+ gbuildparser = GbuildParser(args.makecmd).parse()
+
+ generators[args.ide](gbuildparser, args.ide).emit()
+ print("Successfully created the project files.")
+
+# Local Variables:
+# indent-tabs-mode: nil
+# End:
+#
+# vim: set et sw=4 ts=4: