[Libreoffice-commits] core.git: bin/gbuild-to-ide .gitignore Makefile.in

Bjoern Michaelsen bjoern.michaelsen at canonical.com
Tue Nov 19 03:32:55 PST 2013


 .gitignore        |    2 
 Makefile.in       |   10 +
 bin/gbuild-to-ide |  295 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 307 insertions(+)

New commits:
commit ba99e296077e6bc6d6a153d01a45bd9ebe1a1d35
Author: Bjoern Michaelsen <bjoern.michaelsen at canonical.com>
Date:   Fri Nov 15 18:39:46 2013 +0100

    related fdo#70414 gbuild to ide: kdevelop
    
    This provides kdevelop integration and generates one project file for each
    old-style module (top level dir). This project file has:
    
    - has four build configurations:
      - build the module of the project or build all of LibreOffice
      - for each of the above a debug and a nondebug build
    - has seven launch targets:
      - running the unitchecks, the slowchecks and subsequentchecks
      - for each of the above once for the module and once for all
      - running LibreOffice interactively
    - has custom include paths and thus provides full autocompletion
    
    Change-Id: I6dd51133147d019fc403e3bd814bc6103df94cac
    Reviewed-on: https://gerrit.libreoffice.org/6694
    Reviewed-by: Björn Michaelsen <bjoern.michaelsen at canonical.com>
    Tested-by: Björn Michaelsen <bjoern.michaelsen at canonical.com>

diff --git a/.gitignore b/.gitignore
index 4680de1..0de9054 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,8 @@
 *~
 .*sw?
 \#*
+*.kdev4
+.kdev_include_paths
 
 # things below this point are targeted for elimination
 
diff --git a/Makefile.in b/Makefile.in
index 95bf5b3..443f758 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -400,6 +400,16 @@ subsequentcheck :| $(if $(filter-out subsequentcheck,$(MAKECMDGOALS)),build)
 debugrun help slowcheck translations unitcheck :
 	$(GNUMAKE) -j $(PARALLELISM) $(GMAKE_OPTIONS) -f $(SRCDIR)/Makefile.gbuild $@
 
+define GbuildToIdeIntegration
+$(1)-ide-integration:
+	cd $(SRCDIR) && (make cmd -npf Makefile.gbuild all || true) | $(SRCDIR)/bin/gbuild-to-ide --ide $(1)
+
+endef
+
+$(foreach ide,\
+	kdevelop, \
+$(eval $(call GbuildToIdeIntegration,$(ide))))
+
 endif # MAKE_RESTARTS
 
 # vim: set noet sw=4 ts=4:
diff --git a/bin/gbuild-to-ide b/bin/gbuild-to-ide
new file mode 100755
index 0000000..d18ee84
--- /dev/null
+++ b/bin/gbuild-to-ide
@@ -0,0 +1,295 @@
+#! /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 inspect
+import os
+import os.path
+import shutil
+import re
+import sys
+
+class GbuildParserState:
+    def __init__(self):
+        self.include = []
+        self.defs = {}
+        self.cxxobjects = []
+        self.linked_libs = []
+
+class GbuildLinkTarget:
+    def __init__(self, name, location, include, defs, cxxobjects, linked_libs):
+        (self.name, self.location, self.include, self.defs, self.cxxobjects, self.linked_libs) = (name, location, include, defs, cxxobjects, linked_libs)
+    def short_name(self):
+        return self.name
+    def __str__(self):
+        return '%s at %s with include path: %s, defines %s, objects: %s and linked libs: %s' % (self.short_name(), self.location, self.include, self.defs, self.cxxobjects, self.linked_libs)
+
+class GbuildLib(GbuildLinkTarget):
+    def __init__(self, name, location, include, defs, cxxobjects, linked_libs):
+        GbuildLinkTarget.__init__(self, name, location, include, defs, cxxobjects, linked_libs)
+    def short_name(self):
+        return 'Library %s' % self.name
+
+class GbuildExe(GbuildLinkTarget):
+    def __init__(self, name, location, include, defs, cxxobjects, linked_libs):
+        GbuildLinkTarget.__init__(self, name, location, include, defs, cxxobjects, linked_libs)
+    def short_name(self):
+        return 'Executable %s' % self.name
+
+class GbuildParser:
+    makecmdpattern = re.compile('^MAKE_COMMAND := (.*)')
+    srcdirpattern = re.compile('^SRCDIR = (.*)')
+    builddirpattern = re.compile('^BUILDDIR = (.*)')
+    instdirpattern = re.compile('^INSTDIR = (.*)')
+    libpattern = re.compile('#  [a-z]+ to execute \(from `(.*)/Library_(.*)\.mk\', line [0-9]*\):')
+    exepattern = re.compile('#  [a-z]+ to execute \(from `(.*)/Executable_(.*)\.mk\', line [0-9]*\):')
+    includepattern = re.compile('# INCLUDE := (.*)')
+    defspattern = re.compile('# DEFS := (.*)')
+    cxxpattern = re.compile('# CXXOBJECTS := (.*)')
+    linkedlibspattern = re.compile('# LINKED_LIBS := (.*)')
+    def __init__(self):
+        (self.makecmd, self.srcdir, self.builddir, self.instdir, self.libs, self.exes) = ('', '', '', '', [], [])
+    def parse(self, gbuildstate):
+        state = GbuildParserState()
+        for line in gbuildstate:
+            if not line.startswith('#'):
+                makecmdmatch = GbuildParser.makecmdpattern.match(line)
+                if makecmdmatch:
+                    self.makecmd = makecmdmatch.group(1)
+                    # FIXME: Hack
+                    if self.makecmd == 'make':
+                        self.makecmd = '/usr/bin/make'
+                    continue
+                srcdirmatch = GbuildParser.srcdirpattern.match(line)
+                if srcdirmatch:
+                    self.srcdir = srcdirmatch.group(1)
+                    continue
+                builddirmatch = GbuildParser.builddirpattern.match(line)
+                if builddirmatch:
+                    self.builddir = builddirmatch.group(1)
+                    continue
+                instdirmatch = GbuildParser.instdirpattern.match(line)
+                if instdirmatch:
+                    self.instdir = instdirmatch.group(1)
+                    continue
+                state = GbuildParserState()
+                continue
+            libmatch = GbuildParser.libpattern.match(line)
+            if libmatch:
+                self.libs.append(GbuildLib(libmatch.group(2), libmatch.group(1), state.include, state.defs, state.cxxobjects, state.linked_libs))
+                state = GbuildParserState()
+                continue
+            exematch = GbuildParser.exepattern.match(line)
+            if exematch:
+                self.exes.append(GbuildExe(exematch.group(2), exematch.group(1), state.include, state.defs, state.cxxobjects, state.linked_libs))
+                state = GbuildParserState()
+                continue
+            includematch = GbuildParser.includepattern.match(line)
+            if includematch:
+                state.include = [includeswitch.strip()[2:] for includeswitch in includematch.group(1).split(' ') if len(includeswitch) > 2]
+                continue
+            defsmatch = GbuildParser.defspattern.match(line)
+            if defsmatch:
+                alldefs = [defswitch.strip()[2:] for defswitch in defsmatch.group(1).split(' ') if len(defswitch) >2]
+                for d in alldefs:
+                    defparts = d.split('=')
+                    if len(defparts) == 1:
+                        defparts.append(None)
+                    state.defs[defparts[0]] = defparts[1]
+                continue
+            cxxmatch = GbuildParser.cxxpattern.match(line)
+            if cxxmatch:
+                state.cxxobjects = [obj for obj in cxxmatch.group(1).split(' ') if len(obj) > 0]
+                continue
+            linkedlibsmatch = GbuildParser.linkedlibspattern.match(line)
+            if linkedlibsmatch:
+                state.linked_libs = linkedlibsmatch.group(1).strip().split(' ')
+                continue
+            #we could match a lot of other stuff here if needed for integration rpaths etc.
+        return self
+
+class IdeIntegrationGenerator:
+    def __init__(self, gbuildparser):
+        self.gbuildparser = gbuildparser
+    def emit(self):
+        pass
+
+class DebugIntegrationGenerator(IdeIntegrationGenerator):
+    def __init__(self, gbuildparser):
+        IdeIntegrationGenerator.__init__(self, gbuildparser)
+    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)
+
+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 }
+        pathid = 0
+        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)', self.gbuildparser.makecmd, 'unitcheck slowcheck', moduledir) 
+        result += self.generate_launch(2, 'Local tests -- integration tests (unitcheck, slowcheck, subsequentcheck)', self.gbuildparser.makecmd, 'unitcheck slowcheck 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)', self.gbuildparser.makecmd, 'unitcheck slowcheck', self.gbuildparser.builddir) 
+        result += self.generate_launch(5, 'Global tests -- integration tests (unitcheck, slowcheck, subsequentcheck)', self.gbuildparser.makecmd, 'unitcheck slowcheck 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')
+        fullpath = '%s/%s' % (self.gbuildparser.srcdir, path)
+        include = set()
+        for target in self.target_by_path[path]:
+            include |= set(target.include)
+        includedirfile.write('\n'.join(include))
+        includedirfile.close()
+    def __init__(self, gbuildparser):
+        IdeIntegrationGenerator.__init__(self, gbuildparser)
+        self.target_by_location = {}
+        self.target_by_path = {}
+        for target in set(self.gbuildparser.libs) | set(self.gbuildparser.exes):
+            if not target.location 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 not path in self.target_by_path:
+                    self.target_by_path[path] = set()
+                self.target_by_path[path] |= set([target])
+        for path in self.target_by_path:
+            if len(self.target_by_path[path]) > 1:
+                print('fdo#70422: multiple target use dir %s: %s' % (path, ', '.join([target.short_name() for target in self.target_by_path[path]])))
+    def emit(self):
+        for path in self.target_by_path:
+            self.write_includepaths(path)
+        for location in self.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.target_by_location:
+            modulename = os.path.split(location)[1]
+            self.write_modulestub(location, modulename)
+            self.write_modulebeef(location, modulename)
+
+if __name__ == '__main__':
+    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')
+    args = parser.parse_args()
+    paths = {}
+    gbuildparser = GbuildParser().parse(sys.stdin)
+    #DebugIntegrationGenerator(gbuildparser).emit()
+    if args.ide == 'kdevelop':
+        KdevelopIntegrationGenerator(gbuildparser).emit()
+    else:
+        parser.print_help()
+        sys.exit(1)
+
+# vim: set noet sw=4 ts=4:


More information about the Libreoffice-commits mailing list