#!/usr/bin/env python
#
# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generates XML file which can be imported into an Eclipse CDT project.
The XML file contains the include directories and defines that all applications
which use the clang compiler inherit. Should be used in conjunction with the
XML file generated by "gn gen out/Release --ide=eclipse"
"""
from __future__ import print_function
from xml.sax.saxutils import escape
import os
import subprocess
import sys
def GetClangIncludeDirectories(compiler_path):
"""Gets the system include directories as determined by the clang compiler.
Returns:
The list of include directories.
"""
includes_set = set()
command = [compiler_path, '-E', '-xc++', '-v', '-']
proc = subprocess.Popen(args=command, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = proc.communicate()[1]
# Extract the list of include dirs from the output, which has this format:
# ...
# #include "..." search starts here:
# #include <...> search starts here:
# /usr/include/c++/4.6
# /usr/local/include
# End of search list.
# ...
in_includes_list = False
for line in output.splitlines():
if line.startswith('#include'):
in_includes_list = True
continue
if line.startswith('End of search list.'):
break
if in_includes_list:
includes_set.add(line.strip())
return sorted(includes_set)
def GetClangDefines(compiler_path):
"""Gets the system defines as determined by the clang compiler.
Returns:
The dict of defines.
"""
all_defines = {}
command = [compiler_path, '-E', '-dM', '-']
proc = subprocess.Popen(args=command, stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
# Extract the list of defines from the output, which has this format:
# #define __SIZEOF_INT__ 4
# ...
# #define unix 1
output = proc.communicate()[0]
for line in output.splitlines():
if not line.strip():
continue
line_parts = line.split(' ', 2)
key = line_parts[1]
if len(line_parts) >= 3:
val = line_parts[2]
else:
val = '1'
all_defines[key] = val
return all_defines
def WriteIncludePaths(out, eclipse_langs, include_dirs):
"""Write the includes section of a CDT settings export file."""
out.write(' <section name="org.eclipse.cdt.internal.ui.wizards.' \
'settingswizards.IncludePaths">\n')
out.write(' <language name="holder for library settings"></language>\n')
for lang in eclipse_langs:
out.write(' <language name="%s">\n' % lang)
for include_dir in include_dirs:
out.write(' <includepath workspace_path="false">%s</includepath>\n' %
include_dir)
out.write(' </language>\n')
out.write(' </section>\n')
def WriteMacros(out, eclipse_langs, defines):
"""Write the macros section of a CDT settings export file."""
out.write(' <section name="org.eclipse.cdt.internal.ui.wizards.' \
'settingswizards.Macros">\n')
out.write(' <language name="holder for library settings"></language>\n')
for lang in eclipse_langs:
out.write(' <language name="%s">\n' % lang)
for key in sorted(defines.iterkeys()):
out.write(' <macro><name>%s</name><value>%s</value></macro>\n' %
(escape(key), escape(defines[key])))
out.write(' </language>\n')
out.write(' </section>\n')
def main(argv):
if len(argv) != 2:
print("Usage: generate_cdt_clang_settings.py destination_file")
return
compiler_path = os.path.abspath(
'third_party/llvm-build/Release+Asserts/bin/clang')
if not os.path.exists(compiler_path):
print('Please run this script from the Chromium src/ directory.')
return
include_dirs = GetClangIncludeDirectories(compiler_path)
if not include_dirs:
print('ERROR: Could not extract include dirs from %s.' % compiler_path)
return
defines = GetClangDefines(compiler_path)
if not defines:
print('ERROR: Could not extract defines from %s.' % compiler_path)
destination_file = os.path.abspath(argv[1])
destination_dir = os.path.dirname(destination_file)
if not os.path.exists(destination_dir):
os.makedirs(destination_dir)
with open(destination_file, 'w') as out:
eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File',
'GNU C++', 'GNU C', 'Assembly']
out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
out.write('<cdtprojectproperties>\n')
WriteIncludePaths(out, eclipse_langs, include_dirs)
WriteMacros(out, eclipse_langs, defines)
out.write('</cdtprojectproperties>\n')
if __name__ == '__main__':
sys.exit(main(sys.argv))