|  | #!/usr/bin/env python | 
|  | # | 
|  | # Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | # 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 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)) |