| #!/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)) |