diff options
author | Bjoern Michaelsen <bjoern.michaelsen@canonical.com> | 2013-11-15 18:39:46 +0100 |
---|---|---|
committer | Björn Michaelsen <bjoern.michaelsen@canonical.com> | 2013-11-19 05:32:30 -0600 |
commit | ba99e296077e6bc6d6a153d01a45bd9ebe1a1d35 (patch) | |
tree | b0ba8b7a2edba0e075c4ceb8e85d905e2b6c0c35 /bin | |
parent | 3773201d5973d40f0b6a67930adeaed36f1494c9 (diff) |
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@canonical.com>
Tested-by: Björn Michaelsen <bjoern.michaelsen@canonical.com>
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/gbuild-to-ide | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/bin/gbuild-to-ide b/bin/gbuild-to-ide new file mode 100755 index 000000000000..d18ee84eb519 --- /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: |