double ".ccx" for each source files in the .filters in the testVS2013Ide. this patch fix that. Change-Id: Ic06800c260800f72254038e30119db40fe048037 Reviewed-on: https://gerrit.libreoffice.org/33892 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: jan iversen <jani@documentfoundation.org>
2186 lines
101 KiB
Python
Executable File
2186 lines
101 KiB
Python
Executable File
#! /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 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 collections
|
|
import subprocess
|
|
|
|
|
|
|
|
class GbuildParser:
|
|
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.modules = collections.OrderedDict()
|
|
|
|
_includepattern = re.compile('-I(\S+)')
|
|
_isystempattern = re.compile('-isystem\s*(\S+)')
|
|
_warningpattern = re.compile('-W\S+')
|
|
_buildpattern = {'Library': re.compile('Library_(.*)\.mk'),
|
|
'Executable': re.compile('Executable_(.*)\.mk'),
|
|
'CppunitTest': re.compile('CppunitTest_(.*)\.mk')}
|
|
_allheaders=[]
|
|
|
|
def __split_includes(json_srcdir,includes):
|
|
foundisystem = GbuildParser._isystempattern.findall(includes)
|
|
foundincludes=[]
|
|
for includeswitch in GbuildParser._includepattern.findall(includes):
|
|
if len(includeswitch) > 2:
|
|
if includeswitch.strip()[:len(json_srcdir)] == json_srcdir:
|
|
foundincludes.append(includeswitch.strip()[len(json_srcdir)+1:])
|
|
else:
|
|
foundincludes.append(includeswitch.strip())
|
|
return (foundincludes, foundisystem)
|
|
|
|
def __split_objs(module,objsline, ext):
|
|
retObj = []
|
|
for obj in objsline.strip().split(' '):
|
|
if module in obj:
|
|
obj = obj[len(module)+1:]
|
|
if len(obj) > 0 and obj != 'CXXOBJECTS' and obj != '+=':
|
|
retObj.append(obj + ext)
|
|
return sorted(retObj)
|
|
|
|
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:
|
|
defparts = d.split('=')
|
|
if len(defparts) == 1:
|
|
defparts.append(None)
|
|
defs[defparts[0]] = defparts[1]
|
|
defs["LIBO_INTERNAL_ONLY"] = None
|
|
return defs
|
|
|
|
def __split_flags(flagsline, flagslineappend):
|
|
return [cxxflag.strip() for cxxflag in GbuildParser._warningpattern.sub('', '%s %s' % (flagsline, flagslineappend)).split(' ') if len(cxxflag) > 1]
|
|
|
|
|
|
def parse(self):
|
|
# current json blacklist, this is just for reference:
|
|
# bridges
|
|
# connectivity compilerplugins cli_ure cppu cppuhelper cpputools
|
|
# dictionaries
|
|
# extensions external
|
|
# helpcompiler helpcontent2
|
|
# i18npool icon-themes
|
|
# javaunohelper jurt
|
|
# lingucomponent
|
|
# odk
|
|
# sal scaddins shell solenv stoc
|
|
# tools translations
|
|
# udkapi unoid
|
|
# Add handling of BLACKLIST
|
|
|
|
# Relation between json object and file extension
|
|
jsonSrc = {
|
|
'CXXOBJECTS': '.cxx', 'OBJCOBJECTS': '.m', 'OBJCXXOBJECTS': '.mm', 'COBJECTS': '.c',
|
|
'LEXOBJECTS': '.l', 'YACCOBJECTS': '.y',
|
|
|
|
'GENCXXOBJECTS': '.cxx', # remark is in workdir/GenCxxObject
|
|
'ASMOBJECTS': '.s', #not in json, due to Blacklist ?
|
|
'GENCOBJECTS': '.c', #not in json, due to Blacklist ?
|
|
'JAVAOBJECTS': '.java', #not in json, due to Blacklist ?
|
|
'PYTHONOBJECTS': '.py' #not in json, due to Blacklist ?
|
|
}
|
|
|
|
|
|
moduleDict = {}
|
|
self.find_all_headers()
|
|
for jsontype in ['Library', 'Executable', 'CppunitTest']:
|
|
for jsonfilename in os.listdir(os.path.join(self.workdir, 'GbuildToJson', jsontype)):
|
|
with open(os.path.join(self.workdir, 'GbuildToJson', jsontype, jsonfilename), 'r') as f:
|
|
jsondata = json.load(f)
|
|
match = GbuildParser._buildpattern[jsontype].match(os.path.basename(jsondata['MAKEFILE'])).group(1)
|
|
jsondata['location'] = os.path.dirname(jsondata['MAKEFILE'])
|
|
module = jsondata['location'].split('/')[-1]
|
|
json_srcdir=jsondata['location'][:-(len(module)+1)]
|
|
jsondata['MAKEFILE']=jsondata['MAKEFILE'][len(jsondata['location'])+1:]
|
|
jsondata['ILIBTARGET']='../' + jsondata['ILIBTARGET'][len(json_srcdir)+1:]
|
|
|
|
(jsondata['include'], jsondata['include_sys']) = GbuildParser.__split_includes(json_srcdir, jsondata['INCLUDE'])
|
|
jsondata['name'] = match
|
|
jsondata['build_type'] = jsontype
|
|
jsondata['target_name'] = module + '_' + jsontype + '_' + match
|
|
jsondata['DEFS'] = GbuildParser.__split_defs(jsondata['DEFS'])
|
|
jsondata['LINKED_LIBS'] = jsondata['LINKED_LIBS'].strip().split(' ')
|
|
jsondata['CXXFLAGS'] += ' -DLIBO_INTERNAL_ONLY'
|
|
for i in ['CXXFLAGS', 'CFLAGS', 'OBJCFLAGS', 'OBJCXXFLAGS']:
|
|
jsondata[i] = GbuildParser.__split_flags(jsondata[i], jsondata[i+'APPEND'])
|
|
for i in jsonSrc:
|
|
if not i in jsondata:
|
|
jsondata[i] = ''
|
|
jsondata[i] = GbuildParser.__split_objs(module, jsondata[i], jsonSrc[i])
|
|
|
|
if not module in moduleDict:
|
|
moduleDict[module] = {'targets': [],'headers':{}}
|
|
moduleDict[module]['targets'].append(jsondata)
|
|
moduleDict[module]['headers'] =self.headers_of(module)
|
|
|
|
moduleDict['include']={ 'targets': [], 'headers':self.headers_of('include')}
|
|
|
|
for i in sorted(moduleDict):
|
|
module = moduleDict[i]
|
|
src = []
|
|
for target in module['targets']:
|
|
target['module'] = i
|
|
for ext in jsonSrc:
|
|
src.extend(target[ext])
|
|
module['sources'] = sorted(src)
|
|
self.modules[i] = module
|
|
return self
|
|
|
|
|
|
|
|
def find_all_headers(self):
|
|
|
|
cmdResult=subprocess.check_output(['git', 'ls-files','--','*.h','*.hxx', '*.hpp'], cwd=self.srcdir, stderr=subprocess.PIPE,)
|
|
|
|
|
|
allfiles={}
|
|
for file in cmdResult.splitlines():
|
|
strfile=file.decode()
|
|
modulename=strfile.split('/')[0]
|
|
if not modulename in allfiles:
|
|
allfiles[modulename]=[]
|
|
modulename_len=len(modulename)
|
|
allfiles[modulename].append(strfile[modulename_len + 1:])
|
|
|
|
self._allheaders = allfiles
|
|
|
|
def headers_of(self,modulename):
|
|
if modulename in self._allheaders: #for the modules that not have headers
|
|
headersof = self._allheaders[modulename]
|
|
else:
|
|
headersof=[]
|
|
return headersof
|
|
|
|
|
|
|
|
class IdeIntegrationGenerator:
|
|
|
|
def __init__(self, gbuildparser, ide):
|
|
(self.gbuildparser, self.ide) = (gbuildparser, ide)
|
|
|
|
def emit(self):
|
|
pass
|
|
|
|
|
|
|
|
class testVS2013Ide(IdeIntegrationGenerator):
|
|
|
|
def __init__(self, gbuildparser, ide):
|
|
IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
|
|
self.toolset = self.retrieve_toolset()
|
|
self.solution_directory = './windows'
|
|
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 retrieve_toolset(self):
|
|
return {'vs2013': 'v120', 'vs2015': 'v140'}.get(self.ide, None)
|
|
|
|
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 module in self.gbuildparser.modules:
|
|
projects = []
|
|
module_directory = os.path.join(self.solution_directory, module)
|
|
if module != 'include': # FIXME
|
|
for target in self.gbuildparser.modules[module]['targets']:
|
|
|
|
project_path = os.path.join(module_directory, '%s.vcxproj' % target['target_name'])
|
|
|
|
project_guid = self.twrite_project(project_path, target)
|
|
#self.twrite_project(project_path,target)
|
|
p = VisualStudioIntegrationGenerator.Project(project_guid, target, project_path)
|
|
self.write_filters(project_path + '.filters',target,self.gbuildparser.modules[module]['headers'])
|
|
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)
|
|
|
|
nmake_project_guid = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
|
|
|
|
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['name'] == linked_lib:
|
|
dependency_libs[library_project.guid] = library_project
|
|
return dependency_libs
|
|
|
|
def write_solution(self, solution_path, projects):
|
|
library_projects = [project for project in projects if project.target['build_type'] == 'Library']
|
|
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
|
|
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['target_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('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')
|
|
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')
|
|
|
|
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 = str(uuid.uuid4()).upper()
|
|
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['target_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'
|
|
# VS2012: I need to have this otherwise the names of projects will contain text Visual Studio 2010 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')
|
|
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('../..', 'program', 'soffice.exe')
|
|
nmake_defs_node = ET.SubElement(conf_node, '{%s}NMakePreprocessorDefinitions' % ns)
|
|
nmake_defs_node.text = ';'.join(list(target['DEFS']) + ['$(NMakePreprocessorDefinitions)'])
|
|
include_path_node = ET.SubElement(conf_node, '{%s}IncludePath' % ns)
|
|
includes=[os.path.join('../..',elem) if elem[1] != ':' else elem for elem in target['include'] ]
|
|
include_path_node.text = ';'.join(includes + ['$(IncludePath)'])
|
|
|
|
ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % ns)
|
|
|
|
cxxobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
|
|
for cxxobject in target['CXXOBJECTS']:
|
|
cxxrelpath= os.path.join('../..',target['location'].split('/')[-1], cxxobject)
|
|
cxxabspath = os.path.join(self.gbuildparser.srcdir,target['location'].split('/')[-1], cxxobject)
|
|
cxxfile = cxxabspath
|
|
if os.path.isfile(cxxfile):
|
|
ET.SubElement(cxxobjects_node, '{%s}ClCompile' % ns, Include=cxxrelpath)
|
|
else:
|
|
print('Source %s in project %s does not exist' % (cxxfile, target['target_name']))
|
|
|
|
includes_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
|
|
for cxxobject in target['CXXOBJECTS']:
|
|
include_rel_path = os.path.join('../..',target['location'].split('/')[-1], cxxobject)
|
|
include_abs_path = os.path.join(self.gbuildparser.srcdir,target['location'].split('/')[-1], cxxobject)
|
|
hxxfile = include_abs_path
|
|
if os.path.isfile(hxxfile):
|
|
ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=include_rel_path)
|
|
# Few files have corresponding .h files
|
|
hfile = include_abs_path
|
|
if os.path.isfile(hfile):
|
|
ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=include_rel_path)
|
|
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)
|
|
|
|
return project_guid
|
|
|
|
def twrite_project(self, project_path, target):
|
|
folder = os.path.dirname(project_path)
|
|
if not os.path.exists(folder):
|
|
os.makedirs(folder)
|
|
project_guid = str(uuid.uuid4()).upper()
|
|
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
|
|
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_root_namespace=ET.SubElement(globals_node, '{%s}RootNamespace' % ns)
|
|
proj_root_namespace.text = target['target_name']
|
|
|
|
|
|
ET.SubElement(proj_node, '{%s}Import' % ns, Project='$(VCTargetsPath)\Microsoft.Cpp.Default.props')
|
|
for configuration in self.configurations:
|
|
property_group_node=ET.SubElement(proj_node,'{%s}PropertyGroup' % ns, Label="Configuration", Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration,platform))
|
|
conf_type=ET.SubElement(property_group_node,'{%s}ConfigurationType' % ns)
|
|
conf_type.text='Application'
|
|
use_dbg_lib=ET.SubElement(property_group_node,'{%s}UseDebugLibraries' % ns)
|
|
use_dbg_lib.text='true'
|
|
platform_toolset_node = ET.SubElement(property_group_node, '{%s}PlatformToolset' % ns)
|
|
platform_toolset_node.text = self.toolset
|
|
char_set_node=ET.SubElement(property_group_node,'{%s}CharacterSet' %ns)
|
|
char_set_node.text='MultiByte'
|
|
#on debug there ist a whole programoptimization
|
|
|
|
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=ET.SubElement(proj_node,'{%s}ImportGroup' % ns, Label='PropertySheets',Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration,platform))
|
|
ET.SubElement(prop_sheets,'{%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')
|
|
for configuration in self.configurations:
|
|
item_def_group=ET.SubElement(proj_node,'{%s}ItemDefinitionGroup' % ns,Condition="'$(Configuration)|$(Platform)'=='%s|%s'" % (configuration,platform))
|
|
#compiler options
|
|
cl_compile=ET.SubElement(item_def_group,'{%s}ClCompile' % ns)
|
|
warn_lvl=ET.SubElement(cl_compile,'{%s}WarningLevel' % ns)
|
|
warn_lvl.text='Level 4'
|
|
opt_node=ET.SubElement(cl_compile,'{%s}Optimization' % ns)
|
|
opt_node.text='Disabled'
|
|
sdl_check=ET.SubElement(cl_compile,'{%s}SDLCheck' % ns)
|
|
sdl_check.text='true'
|
|
add_incl_dir=ET.SubElement(cl_compile,'{%s}AdditionalIncludeDirectories' % ns)
|
|
add_incl_dir.text=self.get_include_dirs(target)
|
|
add_incl_def_flag=ET.SubElement(cl_compile,'{%s}AdditionalOptions' % ns)
|
|
add_incl_def_flag.text=self.get_flags_defs(target)
|
|
dgb_info_form=ET.SubElement(cl_compile,'{%s}DebugInformationFormat' % ns)
|
|
dgb_info_form.text='ProgramDatabase'
|
|
warn_as_error=ET.SubElement(cl_compile,'{%s}TreatWarningAsError' % ns)
|
|
warn_as_error.text='true'
|
|
run_libs=ET.SubElement(cl_compile,'{%s}RuntimeLibrary' % ns)
|
|
run_libs.text='MultiThreadedDLL'
|
|
|
|
#linker options
|
|
#linker_node=ET.SubElement(item_def_group,'{%s}Link' % ns)
|
|
|
|
#gen_dbg_info=ET.SubElement(linker_node,'{%s}GenerateDebugInformation}' % ns)
|
|
#gen_dbg_info.text='true'
|
|
#add_lib_dirs=ET.SubElement(linker_node,'{%s}AdditionalLibraryDirectories}' % ns)
|
|
#libname=target['ILIBTARGET'].split('/')[-1]
|
|
#libpath='../' + target['ILIBTARGET'][:-(len(libname)+1)]
|
|
#add_lib_dirs.text= libpath
|
|
#add_dep=ET.SubElement(linker_node,'{%s}AdditionalDependencies}' % ns)
|
|
#add_dep.text= libname +';kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)'
|
|
|
|
#proj_ref_node=ET.SubElement(item_def_group,'{%s}ProjectReference' % ns)
|
|
#use_lib_dep=ET.SubElement(proj_ref_node,'{%s}UseLibraryDependencyInputs}' % ns)
|
|
#use_lib_dep.text='true'
|
|
|
|
#cxx files
|
|
cxx_node=ET.SubElement(proj_node,'{%s}ItemGroup' % ns)
|
|
for cxx_elem in target['CXXOBJECTS']:
|
|
cxx_cl_node=ET.SubElement(cxx_node,'{%s}ClCompile' % ns,Include='../../' + cxx_elem)
|
|
#miss headers
|
|
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)
|
|
return project_guid
|
|
|
|
def get_flags_defs(self,target):
|
|
flags=' '.join(target['CXXFLAGS']).replace('-','/')
|
|
mdefs=''
|
|
for elem_defs,elem_value in target['DEFS'].items():
|
|
mdefs += '/D' + elem_defs
|
|
if elem_value != None:
|
|
mdefs += '=' + elem_value
|
|
mdefs += ' '
|
|
return flags + ' ' + mdefs + '-arch:SSE -DEXCEPTIONS_ON -EHs -Od -FS -Zi -DLIBO_INTERNAL_ONLY -WX'
|
|
|
|
def get_include_dirs(self,target):
|
|
includes=''
|
|
for elem in target['include']:
|
|
if elem[1] == ':':
|
|
tmp_inc=elem
|
|
else:
|
|
tmp_inc ='../../' + elem
|
|
tmp_inc +=';'
|
|
includes +=tmp_inc
|
|
return includes[:-1]
|
|
|
|
|
|
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 write_filters(self,filters_path,target,headers):
|
|
ns = 'http://schemas.microsoft.com/developer/msbuild/2003'
|
|
ET.register_namespace('', ns)
|
|
proj_node = ET.Element('{%s}Project' % ns, ToolsVersion='4.0')
|
|
|
|
filters_node=ET.SubElement(proj_node,'{%s}ItemGroup' % ns)
|
|
filters={'sources' : 'c;cxx;cpp','headers':'h;hxx;hpp'}
|
|
for filter_key,filter_value in filters.items():
|
|
filter_node = ET.SubElement(filters_node,'{%s}Filter' % ns, Include='%s' % filter_key)
|
|
filter_id_node = ET.SubElement(filter_node,'{%s}UniqueIdentifier' % ns)
|
|
filter_id_node.text='{%s}' % str(uuid.uuid4())
|
|
filter_ext_node = ET.SubElement(filter_node,'{%s}Extensions' % ns)
|
|
filter_ext_node.text = '{%s}' % filter_value
|
|
sources_node=ET.SubElement(proj_node,'{%s}ItemGroup' % ns)
|
|
for cxxfile in target['CXXOBJECTS']:
|
|
cxx_file_name = cxxfile.split('/')[-1]
|
|
clinclude_node=ET.SubElement(sources_node,'{%s}ClInclude' % ns, Include='%s' % cxx_file_name)
|
|
header_filter=ET.SubElement(clinclude_node,'{%s}Filter' % ns)
|
|
header_filter.text="sources"
|
|
|
|
headers_node=ET.SubElement(proj_node,'{%s}ItemGroup' % ns)
|
|
for header in headers:
|
|
header_file_name=header.split('/')[-1]
|
|
|
|
clinclude_node=ET.SubElement(headers_node,'{%s}ClInclude' % ns, Include='%s' % header_file_name)
|
|
header_filter=ET.SubElement(clinclude_node,'{%s}Filter' % ns)
|
|
header_filter.text="headers"
|
|
|
|
self.write_pretty_xml(proj_node, filters_path)
|
|
|
|
class XcodeIntegrationGenerator(IdeIntegrationGenerator):
|
|
def __init__(self, gbuildparser, ide):
|
|
IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
|
|
|
|
typeCounter = {'PBXProject' : 000000,
|
|
'PBXGroup' : 100000,
|
|
'PBXFileReference' : 200000,
|
|
'PBXNativeTarget' : 300000,
|
|
'XCConfigurationList' : 400000,
|
|
'PBXSourcesBuildPhase' : 500000,
|
|
'XCBuildConfiguration' : 600000,
|
|
'PBXBuildFile' : 700000}
|
|
|
|
def emit(self):
|
|
mainGroupId, mainGroup = self.generate_PBXGroup(None)
|
|
rootId = self.generate_id('PBXProject')
|
|
self.rootObj = {'attributes': {'LastUpgradeCheck': '0820',
|
|
'ORGANIZATIONNAME': 'LibreOffice',
|
|
'TargetAttributes': {}},
|
|
'compatibilityVersion': 'Xcode 3.2',
|
|
'developmentRegion': 'English',
|
|
'isa': 'PBXProject',
|
|
'hasScannedForEncodings': 0,
|
|
'knownRegions': ['en'],
|
|
'mainGroup': mainGroupId,
|
|
'projectDirPath': self.gbuildparser.srcdir,
|
|
'projectRoot': '',
|
|
'buildConfigurationList': '',
|
|
'targets': []}
|
|
pbxproj = {'archiveVersion': 1,
|
|
'classes': {},
|
|
'objectVersion': 46,
|
|
'objects': {rootId: self.rootObj,
|
|
mainGroupId: mainGroup},
|
|
'rootObject': rootId}
|
|
for module in self.gbuildparser.modules:
|
|
if module == 'include':
|
|
continue
|
|
moduleId, moduleObj = self.generate_PBXGroup(module)
|
|
sourceId, sourceObj = self.generate_PBXGroup('Sources')
|
|
includeId, includeObj = self.generate_PBXGroup('Headers')
|
|
targetId, targetObj = self.generate_PBXGroup('Targets')
|
|
|
|
moduleObj['children'] = [sourceId, includeId, targetId]
|
|
pbxproj['objects'].update({sourceId: sourceObj,
|
|
includeId: includeObj,
|
|
moduleId: moduleObj,
|
|
targetId: targetObj})
|
|
mainGroup['children'].append(moduleId)
|
|
|
|
for i in self.gbuildparser.modules[module]['headers']:
|
|
ref = self.generate_id('PBXFileReference')
|
|
pbxproj['objects'][ref] = self.generate_PBXFileReference(module, i)
|
|
includeObj['children'].append(ref)
|
|
for i in self.gbuildparser.modules[module]['sources']:
|
|
ref = self.generate_id('PBXFileReference')
|
|
pbxproj['objects'][ref] = self.generate_PBXFileReference(module, i)
|
|
sourceObj['children'].append(ref)
|
|
for target in self.gbuildparser.modules[module]['targets']:
|
|
pbxproj['objects'].update(self.generate_target(target, module, targetObj, sourceObj['children']))
|
|
|
|
xcodeprojdir = './osx/libreoffice.xcodeproj'
|
|
try:
|
|
os.mkdir(xcodeprojdir)
|
|
except:
|
|
pass
|
|
with open(os.path.join(xcodeprojdir, 'project.pbxproj'), 'w') as f:
|
|
f.write('// !$*UTF8*$!\n')
|
|
self.write_object(pbxproj, f, 0)
|
|
|
|
def indent(self, file, level):
|
|
if level != 0:
|
|
for i in range(0, level):
|
|
file.write('\t')
|
|
|
|
def write_object(self, object, file, indent):
|
|
if isinstance(object, int):
|
|
file.write('%d' % object)
|
|
elif isinstance(object, str):
|
|
if object == '':
|
|
file.write('""')
|
|
elif not re.search('[^A-Za-z0-9_]', object):
|
|
file.write('%s' % object)
|
|
else:
|
|
file.write('"%s"' % object)
|
|
elif isinstance(object, dict):
|
|
file.write('{')
|
|
file.write('\n')
|
|
for key in sorted(object.keys()):
|
|
self.indent(file, indent + 1)
|
|
file.write('%s = ' % key)
|
|
self.write_object(object[key], file, indent + 1)
|
|
file.write(';\n')
|
|
self.indent(file, indent)
|
|
file.write('}')
|
|
elif isinstance(object, list):
|
|
file.write('(')
|
|
for key in object:
|
|
self.write_object(key, file, 1)
|
|
file.write(',')
|
|
file.write(')')
|
|
|
|
def generate_id(self, id):
|
|
self.typeCounter[id] += 1
|
|
return str('X%06d' % self.typeCounter[id])
|
|
|
|
def generate_target(self, target, module, targetObj, sourceObj):
|
|
targetId = self.generate_id('PBXNativeTarget')
|
|
configurationListId = self.generate_id('XCConfigurationList')
|
|
configurationDebugId = self.generate_id('XCBuildConfiguration')
|
|
fileId = self.generate_id('PBXFileReference')
|
|
objects = {configurationListId: self.generate_XCBuildConfiguration(target, configurationDebugId),
|
|
#MAKE targetId: self.generate_PBXLegacyTarget(target, configurationListId),
|
|
targetId: self.generate_PBXNativeTarget(target, configurationListId),
|
|
configurationDebugId: self.generate_XCBuildConfiguration(target, configurationDebugId, debug=True),
|
|
fileId : self.generate_PBXFileReference(module, target['LINKTARGET'], explicit=target['build_type'])
|
|
}
|
|
self.rootObj['attributes']['TargetAttributes'].update(
|
|
{targetId: {'CreatedOnToolsVersion': '8.2', 'ProvisioningStyle': 'Automatic'}})
|
|
self.rootObj['buildConfigurationList'] = configurationListId
|
|
self.rootObj['targets'].append(targetId)
|
|
targetObj['children'].append(fileId)
|
|
return objects
|
|
|
|
def generate_PBXGroup(self, name):
|
|
obj = {'isa': 'PBXGroup', 'children': [], 'sourceTree': '<group>'}
|
|
if not name is None:
|
|
obj['name'] = name
|
|
return self.generate_id('PBXGroup'), obj
|
|
|
|
def generate_PBXLegacyTarget(self, modulename, configurationListId):
|
|
if modulename['build_type'] == 'Library':
|
|
product = 'com.apple.product-type.library.dynamic'
|
|
elif modulename['build_type'] == 'Executable':
|
|
product = 'com.apple.product-type.executable'
|
|
elif modulename['build_type'] == 'CppunitTest':
|
|
product = 'com.apple.product-type.cppunit'
|
|
else:
|
|
product = 'com.apple.product-type.something'
|
|
|
|
return {'isa': 'PBXLegacyTarget',
|
|
'buildConfigurationList': configurationListId,
|
|
'buildArgumentsString': modulename['target_name'],
|
|
'buildPhases': [],
|
|
'dependencies': [],
|
|
'buildToolPath': 'make',
|
|
'buildWorkingDirectory': self.gbuildparser.builddir,
|
|
'name': modulename['target_name'],
|
|
'productName': modulename['name'],
|
|
'passBuildSettingsEnvironment': 1}
|
|
|
|
def generate_PBXNativeTarget(self, modulename, configurationListId):
|
|
if modulename['build_type'] == 'Library':
|
|
product = 'com.apple.product-type.library.dynamic'
|
|
elif modulename['build_type'] == 'Executable':
|
|
product = 'com.apple.product-type.tool'
|
|
elif modulename['build_type'] == 'CppunitTest':
|
|
product = 'com.apple.product-type.cppunit'
|
|
else:
|
|
product = 'com.apple.product-type.something'
|
|
|
|
return {'isa': 'PBXNativeTarget',
|
|
'buildRules': [],
|
|
'dependencies': [],
|
|
'name': modulename['target_name'],
|
|
'productName': modulename['name'],
|
|
'productType': product,
|
|
'buildConfigurationList': configurationListId,
|
|
'buildPhases': [],
|
|
'productReference': ''}
|
|
|
|
def generate_XCBuildConfiguration(self, modulename, configurationDebugId, debug=False):
|
|
if debug:
|
|
result = {'isa': 'XCBuildConfiguration',
|
|
'buildSettings': {
|
|
'ALWAYS_SEARCH_USER_PATHS': 'NO',
|
|
'CLANG_ANALYZER_NONNULL': 'YES',
|
|
'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++0x',
|
|
'CLANG_CXX_LIBRARY': 'libc++',
|
|
'CLANG_ENABLE_MODULES': 'YES',
|
|
'CLANG_ENABLE_OBJC_ARC': 'YES',
|
|
'CLANG_WARN_BOOL_CONVERSION': 'YES',
|
|
'CLANG_WARN_CONSTANT_CONVERSION': 'YES',
|
|
'CLANG_WARN_DIRECT_OBJC_ISA_USAGE': 'YES_ERROR',
|
|
'CLANG_WARN_DOCUMENTATION_COMMENTS': 'YES',
|
|
'CLANG_WARN_EMPTY_BODY': 'YES',
|
|
'CLANG_WARN_ENUM_CONVERSION': 'YES',
|
|
'CLANG_WARN_INFINITE_RECURSION': 'YES',
|
|
'CLANG_WARN_INT_CONVERSION': 'YES',
|
|
'CLANG_WARN_OBJC_ROOT_CLASS': 'YES_ERROR',
|
|
'CLANG_WARN_SUSPICIOUS_MOVE': 'YES',
|
|
'CLANG_WARN_UNREACHABLE_CODE': 'YES',
|
|
'CLANG_WARN__DUPLICATE_METHOD_MATCH': 'YES',
|
|
'CODE_SIGN_IDENTITY': '-',
|
|
'COPY_PHASE_STRIP': 'NO',
|
|
'DEBUG_INFORMATION_FORMAT': 'dwarf',
|
|
'ENABLE_STRICT_OBJC_MSGSEND': 'YES',
|
|
'ENABLE_TESTABILITY': 'YES',
|
|
'GCC_C_LANGUAGE_STANDARD': 'gnu99',
|
|
'GCC_DYNAMIC_NO_PIC': 'NO',
|
|
'GCC_NO_COMMON_BLOCKS': 'YES',
|
|
'GCC_OPTIMIZATION_LEVEL': 0,
|
|
'GCC_PREPROCESSOR_DEFINITIONS': ['DEBUG=1', '$(inherited)'],
|
|
'GCC_WARN_64_TO_32_BIT_CONVERSION': 'YES',
|
|
'GCC_WARN_ABOUT_RETURN_TYPE': 'YES_ERROR',
|
|
'GCC_WARN_UNDECLARED_SELECTOR': 'YES',
|
|
'GCC_WARN_UNINITIALIZED_AUTOS': 'YES_AGGRESSIVE',
|
|
'GCC_WARN_UNUSED_FUNCTION': 'YES',
|
|
'GCC_WARN_UNUSED_VARIABLE': 'YES',
|
|
'MACOSX_DEPLOYMENT_TARGET': '10.12',
|
|
'MTL_ENABLE_DEBUG_INFO': 'YES',
|
|
'ONLY_ACTIVE_ARCH': 'YES',
|
|
'PRODUCT_NAME': '$(TARGET_NAME)',
|
|
'SDKROOT': 'macosx',
|
|
'HEADER_SEARCH_PATHS': modulename['include']},
|
|
'name': 'Debug'}
|
|
else:
|
|
result = {'isa': 'XCConfigurationList',
|
|
'buildConfigurations': [configurationDebugId],
|
|
'defaultConfigurationIsVisible': 0,
|
|
'defaultConfigurationName': 'Debug'}
|
|
return result
|
|
|
|
def generate_PBXFileReference(self, module, filepath, explicit=None):
|
|
obj = {'isa': 'PBXFileReference',
|
|
'path': module + '/' + filepath,
|
|
'name': filepath,
|
|
'sourceTree': '<group>'}
|
|
if not explicit is None:
|
|
if explicit == 'Library':
|
|
obj['explicitFileType'] = 'compiled.mach-o.dylib'
|
|
else:
|
|
obj['explicitFileType'] = 'compiled.executable'
|
|
obj['includeInIndex'] = 0
|
|
obj['path'] = filepath
|
|
else:
|
|
obj['path'] = module + '/' + filepath
|
|
return obj
|
|
|
|
|
|
|
|
class VisualStudioIntegrationGenerator(IdeIntegrationGenerator):
|
|
|
|
def __init__(self, gbuildparser, ide):
|
|
IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
|
|
self.toolset = self.retrieve_toolset()
|
|
self.solution_directory = './windows'
|
|
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 retrieve_toolset(self):
|
|
return {'vs2013': 'v120', 'vs2015': 'v140'}.get(self.ide, None)
|
|
|
|
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 module in self.gbuildparser.modules:
|
|
projects = []
|
|
module_directory = os.path.join(self.solution_directory, module)
|
|
if module != 'include': #FIXME
|
|
for target in self.gbuildparser.modules[module]['targets']:
|
|
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)
|
|
|
|
nmake_project_guid = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
|
|
|
|
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['name'] == linked_lib:
|
|
dependency_libs[library_project.guid] = library_project
|
|
return dependency_libs
|
|
|
|
def write_solution(self, solution_path, projects):
|
|
library_projects = [project for project in projects if project.target['build_type'] == 'Library']
|
|
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
|
|
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['target_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('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')
|
|
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')
|
|
|
|
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 = str(uuid.uuid4()).upper()
|
|
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['target_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'
|
|
# VS2012: I need to have this otherwise the names of projects will contain text Visual Studio 2010 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')
|
|
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('../..', 'program', 'soffice.exe')
|
|
nmake_defs_node = ET.SubElement(conf_node, '{%s}NMakePreprocessorDefinitions' % ns)
|
|
nmake_defs_node.text = ';'.join(list(target['DEFS']) + ['$(NMakePreprocessorDefinitions)'])
|
|
include_path_node = ET.SubElement(conf_node, '{%s}IncludePath' % ns)
|
|
includes = [os.path.join('../..', elem) if elem[1] != ':' else elem for elem in target['include']]
|
|
include_path_node.text = ';'.join(includes + ['$(IncludePath)'])
|
|
|
|
ET.SubElement(proj_node, '{%s}ItemDefinitionGroup' % ns)
|
|
|
|
cxxobjects_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
|
|
for cxxobject in target['CXXOBJECTS']:
|
|
cxxrelpath = os.path.join('../..', target['location'].split('/')[-1], cxxobject)
|
|
cxxabspath = os.path.join(self.gbuildparser.srcdir, target['location'].split('/')[-1], cxxobject)
|
|
cxxfile = cxxabspath
|
|
if os.path.isfile(cxxfile):
|
|
ET.SubElement(cxxobjects_node, '{%s}ClCompile' % ns, Include=cxxrelpath)
|
|
else:
|
|
print('Source %s in project %s does not exist' % (cxxfile, target['target_name']))
|
|
|
|
includes_node = ET.SubElement(proj_node, '{%s}ItemGroup' % ns)
|
|
for cxxobject in target['CXXOBJECTS']:
|
|
include_rel_path = os.path.join('../..',target['location'].split('/')[-1], cxxobject)
|
|
include_abs_path = os.path.join(self.gbuildparser.srcdir,target['location'].split('/')[-1], cxxobject)
|
|
hxxfile = include_abs_path
|
|
if os.path.isfile(hxxfile):
|
|
ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=include_rel_path)
|
|
# Few files have corresponding .h files
|
|
hfile = include_abs_path
|
|
if os.path.isfile(hfile):
|
|
ET.SubElement(includes_node, '{%s}ClInclude' % ns, Include=include_rel_path)
|
|
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)],
|
|
[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])
|
|
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, compile_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, compile_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)
|
|
filter_id_node = ET.SubElement(filter_node, '{%s}UniqueIdentifier' % ns)
|
|
filter_id_node.text = '{%s}' % str(uuid.uuid4())
|
|
self.write_pretty_xml(proj_node, filters_path)
|
|
|
|
|
|
class DebugIntegrationGenerator(IdeIntegrationGenerator):
|
|
|
|
def __init__(self, gbuildparser, ide):
|
|
IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
|
|
|
|
def emit(self):
|
|
print(self.gbuildparser.srcdir)
|
|
print(self.gbuildparser.builddir)
|
|
print("testWinIde test:")
|
|
testWinIde(self.gbuildparser, self.ide).emit()
|
|
print("VisualStudioIntegrationGenerator test:")
|
|
VisualStudioIntegrationGenerator(self.gbuildparser, self.ide).emit()
|
|
print("XcodeIntegrationGenerator test:")
|
|
XcodeIntegrationGenerator(self.gbuildparser, self.ide).emit()
|
|
print("EclipseCDTIntegrationGenerator test:")
|
|
EclipseCDTIntegrationGenerator(self.gbuildparser, self.ide).emit()
|
|
print("KdevelopIntegrationGenerator test:")
|
|
KdevelopIntegrationGenerator(self.gbuildparser, self.ide).emit()
|
|
print("VimIntegrationGenerator test:")
|
|
VimIntegrationGenerator(self.gbuildparser, self.ide).emit()
|
|
print("QtCreatorIntegrationGenerator test:")
|
|
QtCreatorIntegrationGenerator(self.gbuildparser, self.ide).emit()
|
|
|
|
|
|
|
|
# ---- Classes below this point are not actively maintained -------
|
|
|
|
|
|
|
|
class EclipseCDTIntegrationGenerator(IdeIntegrationGenerator):
|
|
|
|
def __init__(self, gbuildparser, ide):
|
|
IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
|
|
|
|
def create_include_path(self):
|
|
for module in self.gbuildparser.modules:
|
|
if module == 'include':
|
|
continue
|
|
modulepath = os.path.join(self.gbuildparser.builddir, module)
|
|
includedirfile = open(os.path.join(modulepath, '.eclipsesettingfile'), 'w')
|
|
modulelibs = []
|
|
for lib in self.target_path.keys():
|
|
if lib.startswith(module+'/'):
|
|
modulelibs.append(lib)
|
|
include = []
|
|
for lib in modulelibs:
|
|
for target in self.target_path[lib]:
|
|
include.extend(target[0]['include'])
|
|
includedirfile.write('\n'.join(include))
|
|
includedirfile.close()
|
|
|
|
|
|
def create_macros(self):
|
|
for module in self.gbuildparser.modules:
|
|
if module == 'include':
|
|
continue
|
|
modulepath = os.path.join(self.gbuildparser.builddir, module)
|
|
macrofile = open(os.path.join(modulepath, '.macros'), 'w')
|
|
modulelibs = []
|
|
for lib in self.target_path.keys():
|
|
if lib.startswith(module+'/'):
|
|
modulelibs.append(lib)
|
|
define = []
|
|
defineset = set()
|
|
for lib in modulelibs:
|
|
for target in self.target_path[lib]:
|
|
for i in target[0]['DEFS'].keys():
|
|
tmp = str(i) +','+str(target[0]['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.modules:
|
|
if module == 'include':
|
|
continue
|
|
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.target_path = {}
|
|
for m in self.gbuildparser.modules:
|
|
if m == 'include':
|
|
continue
|
|
for target in self.gbuildparser.modules[m]['targets']:
|
|
for cxx in target['CXXOBJECTS']:
|
|
path = '/'.join(cxx.split('/')[:-1])
|
|
if path not in self.target_path:
|
|
self.target_path[path] = []
|
|
self.target_path[path].append([target])
|
|
self.create_include_path()
|
|
self.create_macros()
|
|
self.create_settings_file()
|
|
|
|
|
|
|
|
class VimIntegrationGenerator(IdeIntegrationGenerator):
|
|
|
|
def __init__(self, gbuildparser, ide):
|
|
IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
|
|
|
|
def emit(self):
|
|
global_list = []
|
|
for m in self.gbuildparser.modules:
|
|
for lib in self.gbuildparser.modules[m]['targets']:
|
|
entries = []
|
|
for file in lib['CXXOBJECTS']:
|
|
xFile = lib['module'] + '/' + file
|
|
filePath = os.path.join(self.gbuildparser.srcdir, xFile)
|
|
entry = {'directory': lib['location'], 'file': filePath, 'command': self.generateCommand(lib, filePath)}
|
|
entries.append(entry)
|
|
global_list.extend(entries)
|
|
export_file = open('compile_commands.json', 'w')
|
|
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
|
|
|
|
# The directory of the file is missing from lib's include list, as that
|
|
# one is not the same for all source files in the lib.
|
|
command += ' -I' + os.path.dirname(file)
|
|
|
|
for include in lib['include']:
|
|
command += ' -I'
|
|
command += os.path.abspath(include)
|
|
for isystem in lib['include_sys']:
|
|
command += ' -isystem '
|
|
command += isystem
|
|
for cxxflag in lib['CXXFLAGS']:
|
|
command += ' '
|
|
command += cxxflag
|
|
command += ' -c '
|
|
command += file
|
|
# Help clang when the tree is configured for gcc.
|
|
for gnu in ('-std=gnu++11', '-std=gnu++1y'):
|
|
command = command.replace(gnu, '-std=c++11')
|
|
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.target_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):
|
|
self.target_path = {}
|
|
for m in self.gbuildparser.modules:
|
|
for target in self.gbuildparser.modules[m]['targets']:
|
|
for cxx in target['CXXOBJECTS']:
|
|
path = '/'.join(cxx.split('/')[:-1])
|
|
path = target['module'] + '/' + path
|
|
if path not in self.target_path:
|
|
self.target_path[path] = []
|
|
self.target_path[path].append(target)
|
|
|
|
for path in self.target_path:
|
|
self.write_includepaths(path)
|
|
for modulename in self.gbuildparser.modules:
|
|
if modulename=='include':
|
|
continue
|
|
location = self.gbuildparser.srcdir + '/' + modulename
|
|
self.write_modulestub(location, modulename)
|
|
self.write_modulebeef(location, modulename)
|
|
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))
|
|
|
|
|
|
|
|
class QtCreatorIntegrationGenerator(IdeIntegrationGenerator):
|
|
|
|
def __init__(self, gbuildparser, ide):
|
|
IdeIntegrationGenerator.__init__(self, gbuildparser, ide)
|
|
self.target_by_location = {}
|
|
for m in self.gbuildparser.modules:
|
|
for target in self.gbuildparser.modules[m]['targets']:
|
|
if target['location'] not in self.target_by_location:
|
|
self.target_by_location[target['location']] = []
|
|
self.target_by_location[target['location']].append(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': "build-nocheck",
|
|
'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': "build-nocheck",
|
|
'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" et "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.DefaultDisplayName">%(name)s</value>
|
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></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_user_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_user_template % {
|
|
'build_configs': build_configs,
|
|
'deploy_configs': deploy_configs,
|
|
'run_configs': run_configs,
|
|
}
|
|
return xml
|
|
|
|
def generate_meta_pro_user_content(self):
|
|
|
|
build_configs = self.generate_meta_build_configs()
|
|
deploy_configs = self.generate_deploy_configs("")
|
|
run_configs = self.generate_run_configs("")
|
|
|
|
xml = QtCreatorIntegrationGenerator.pro_user_template % {
|
|
'build_configs': build_configs,
|
|
'deploy_configs': deploy_configs,
|
|
'run_configs': run_configs,
|
|
}
|
|
return xml
|
|
|
|
pro_user_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 remove_qt_files(self):
|
|
|
|
def do_remove_file(loc, afile):
|
|
try:
|
|
os.remove(os.path.join(loc, afile))
|
|
self._log("removed %s\n" % afile)
|
|
except OSError:
|
|
self._log("unable to remove %s\n" % afile)
|
|
|
|
do_remove_file(self.base_folder, "lo.pro")
|
|
do_remove_file(self.base_folder, "lo.pro.user")
|
|
for location in self.target_by_location:
|
|
for f in os.listdir(location):
|
|
if f.endswith('.pro') or f.endswith('.pro.user'):
|
|
do_remove_file(location, f)
|
|
|
|
def get_source_extension(self, src_file):
|
|
path = os.path.join(self.base_folder, src_file)
|
|
for ext in (".cxx", ".cpp", ".c", ".mm"):
|
|
if os.path.isfile(path):
|
|
return ext
|
|
return ""
|
|
|
|
def get_header_extension(self, src_file):
|
|
path = os.path.join(self.base_folder, src_file)
|
|
for ext in (".hxx", ".hpp", ".h"):
|
|
if os.path.isfile(path + ext):
|
|
return ext
|
|
return ""
|
|
|
|
def build_data_libs(self):
|
|
|
|
self.data_libs = {}
|
|
|
|
all_libs = []
|
|
for m in self.gbuildparser.modules:
|
|
for f in self.gbuildparser.modules[m]['targets']:
|
|
all_libs.append(f)
|
|
for lib in all_libs:
|
|
self._log("\nlibrary : %s, loc=%s" % (lib['target_name'], lib['location']))
|
|
lib_name = os.path.basename(lib['location'])
|
|
lib_folder = os.path.relpath(lib['location'], self.base_folder)
|
|
|
|
def lopath(path):
|
|
return os.path.relpath(path, lib['location'])
|
|
|
|
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_)
|
|
ext = self.get_source_extension(file_)
|
|
if ext:
|
|
sources_list.append(lopath(file_ + ext))
|
|
|
|
# few cxxobject files have a header beside
|
|
ext = self.get_header_extension(file_)
|
|
if ext:
|
|
headers_list.append(lopath(file_ + ext))
|
|
|
|
# List all include paths
|
|
for hdir in lib['include']:
|
|
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 hf in os.listdir(hdir):
|
|
if hf.endswith(('.h', '.hxx', '.hpp', '.hrc')):
|
|
hf_lopath = lopath(os.path.join(hdir, 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 datas 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]['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),
|
|
'includepath': set(includepath_list),
|
|
'defines': set(defines_list),
|
|
'loc': lib['location'],
|
|
'name': lib_name
|
|
}
|
|
|
|
def emit(self):
|
|
|
|
self.base_folder = self.gbuildparser.builddir
|
|
|
|
# we remove existing '.pro' and '.pro.user' files
|
|
self.remove_qt_files()
|
|
|
|
# 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_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'])
|
|
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)
|
|
includepath = " \\\n".join(includepath_list)
|
|
defines = " \\\n".join(defines_list)
|
|
|
|
# create .pro file
|
|
qt_pro_file = '%s/%s.pro' % (lib_loc, lib_name)
|
|
try:
|
|
content = QtCreatorIntegrationGenerator.pro_template % {'sources': sources, 'headers': headers, 'includepath': includepath, 'defines': defines}
|
|
mode = 'w+'
|
|
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.user file
|
|
qt_pro_user_file = '%s/%s.pro.user' % (lib_loc, lib_name)
|
|
try:
|
|
with open(qt_pro_user_file, mode) as fprouser:
|
|
fprouser.write(self.generate_pro_user_content(lib_folder))
|
|
self._log("created %s\n" % qt_pro_user_file)
|
|
|
|
except Exception as e:
|
|
print("ERROR : creating pro.user file=" + qt_pro_user_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 = 'lo.pro'
|
|
try:
|
|
subdirs = " \\\n".join(subdirs_list)
|
|
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.user file
|
|
qt_meta_pro_user_file = 'lo.pro.user'
|
|
try:
|
|
with open(qt_meta_pro_user_file, mode) as fmprouser:
|
|
fmprouser.write(self.generate_meta_pro_user_content())
|
|
self._log("created %s\n" % qt_meta_pro_user_file)
|
|
|
|
except Exception as e:
|
|
print("ERROR : creating lo.pro.user file=" + qt_meta_pro_user_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 = app
|
|
CONFIG += console
|
|
CONFIG -= app_bundle
|
|
CONFIG -= qt
|
|
|
|
INCLUDEPATH += %(includepath)s
|
|
|
|
SOURCES += %(sources)s
|
|
|
|
HEADERS += %(headers)s
|
|
|
|
DEFINES += %(defines)s
|
|
|
|
"""
|
|
pro_meta_template = """TEMPLATE = subdirs
|
|
|
|
SUBDIRS = %(subdirs)s
|
|
"""
|
|
|
|
|
|
|
|
class CodeliteIntegrationGenerator(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):
|
|
if target.location not in self.target_by_location:
|
|
self.target_by_location[target.location] = set()
|
|
self.target_by_location[target.location] |= set([target])
|
|
|
|
|
|
def emit(self):
|
|
# create main workspace file
|
|
codelite_workspace_file = 'lo.workspace1'
|
|
with open(codelite_workspace_file, 'w+') as f:
|
|
f.write(self.generate_workspace_content())
|
|
|
|
def generate_workspace_content(self):
|
|
projects1 = ''
|
|
projects2 = ''
|
|
projects3 = ''
|
|
for module in self.gbuildparser.modulenamelist:
|
|
projects1 += CodeliteIntegrationGenerator.codelite_projects1_template.format(
|
|
name = module
|
|
)
|
|
projects2 += CodeliteIntegrationGenerator.codelite_projects2_template.format(
|
|
name = module,
|
|
config = 'Debug'
|
|
)
|
|
projects3 += CodeliteIntegrationGenerator.codelite_projects2_template.format(
|
|
name = module,
|
|
config = 'Release'
|
|
)
|
|
xml = CodeliteIntegrationGenerator.codelite_workspace_template.format(
|
|
projects1,
|
|
projects2,
|
|
projects3
|
|
)
|
|
return xml
|
|
|
|
|
|
codelite_workspace_template = """<?xml version="1.0" encoding="UTF-8"?>
|
|
<CodeLite_Workspace Name="lo" Database="" SWTLW="Yes">
|
|
<WorkspaceParserMacros/>
|
|
<WorkspaceParserPaths>
|
|
<Include Path="${{WorkspacePath}}/include"/>
|
|
</WorkspaceParserPaths>
|
|
{0}
|
|
<BuildMatrix>
|
|
<WorkspaceConfiguration Name="Debug" Selected="yes">
|
|
<Environment/>
|
|
{1}
|
|
</WorkspaceConfiguration>
|
|
<WorkspaceConfiguration Name="Release" Selected="yes">
|
|
<Environment/>
|
|
{2}
|
|
</WorkspaceConfiguration>
|
|
</BuildMatrix>
|
|
</CodeLite_Workspace>
|
|
"""
|
|
codelite_projects1_template = """<Project Name="{name}" Path="{name}/{name}.project" Active="No"/>
|
|
"""
|
|
|
|
codelite_projects2_template = """<Project Name="{name}" ConfigName="{config}"/>
|
|
"""
|
|
|
|
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')
|
|
#add to debug a new functions in the project keeping contributors
|
|
parser.add_argument('--debug',dest='debug',required=False,
|
|
help='debug the new functions')
|
|
return parser.parse_args()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
args = get_options()
|
|
# FIXME: Hack
|
|
if args.makecmd == 'make':
|
|
args.makecmd = '/usr/bin/make'
|
|
if args.debug=='test':
|
|
|
|
pass
|
|
paths = {}
|
|
generators = {
|
|
# Supported platforms
|
|
'vs2013': VisualStudioIntegrationGenerator,
|
|
'xcode': XcodeIntegrationGenerator,
|
|
'debug': DebugIntegrationGenerator,
|
|
'testIde': testVS2013Ide,
|
|
|
|
# Old platforms
|
|
'eclipsecdt': EclipseCDTIntegrationGenerator,
|
|
'kdevelop': KdevelopIntegrationGenerator,
|
|
'vs2015': VisualStudioIntegrationGenerator,
|
|
'vim': VimIntegrationGenerator,
|
|
'qtcreator': QtCreatorIntegrationGenerator,
|
|
'codelite' : CodeliteIntegrationGenerator,
|
|
}
|
|
|
|
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:
|