mirror of https://github.com/microsoft/clang.git
134 lines
4.2 KiB
Python
134 lines
4.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# The LLVM Compiler Infrastructure
|
|
#
|
|
# This file is distributed under the University of Illinois Open Source
|
|
# License. See LICENSE.TXT for details.
|
|
""" This module is responsible for to parse a compiler invocation. """
|
|
|
|
import re
|
|
import os
|
|
|
|
__all__ = ['Action', 'classify_parameters', 'classify_source']
|
|
|
|
|
|
class Action(object):
|
|
""" Enumeration class for compiler action. """
|
|
|
|
Link, Compile, Ignored = range(3)
|
|
|
|
|
|
def classify_parameters(command):
|
|
""" Parses the command line arguments of the given invocation. """
|
|
|
|
# result value of this method.
|
|
# some value are preset, some will be set only when found.
|
|
result = {
|
|
'action': Action.Link,
|
|
'files': [],
|
|
'output': None,
|
|
'compile_options': [],
|
|
'c++': is_cplusplus_compiler(command[0])
|
|
# archs_seen
|
|
# language
|
|
}
|
|
|
|
# data structure to ignore compiler parameters.
|
|
# key: parameter name, value: number of parameters to ignore afterwards.
|
|
ignored = {
|
|
'-g': 0,
|
|
'-fsyntax-only': 0,
|
|
'-save-temps': 0,
|
|
'-install_name': 1,
|
|
'-exported_symbols_list': 1,
|
|
'-current_version': 1,
|
|
'-compatibility_version': 1,
|
|
'-init': 1,
|
|
'-e': 1,
|
|
'-seg1addr': 1,
|
|
'-bundle_loader': 1,
|
|
'-multiply_defined': 1,
|
|
'-sectorder': 3,
|
|
'--param': 1,
|
|
'--serialize-diagnostics': 1
|
|
}
|
|
|
|
args = iter(command[1:])
|
|
for arg in args:
|
|
# compiler action parameters are the most important ones...
|
|
if arg in {'-E', '-S', '-cc1', '-M', '-MM', '-###'}:
|
|
result.update({'action': Action.Ignored})
|
|
elif arg == '-c':
|
|
result.update({'action': max(result['action'], Action.Compile)})
|
|
# arch flags are taken...
|
|
elif arg == '-arch':
|
|
archs = result.get('archs_seen', [])
|
|
result.update({'archs_seen': archs + [next(args)]})
|
|
# explicit language option taken...
|
|
elif arg == '-x':
|
|
result.update({'language': next(args)})
|
|
# output flag taken...
|
|
elif arg == '-o':
|
|
result.update({'output': next(args)})
|
|
# warning disable options are taken...
|
|
elif re.match(r'^-Wno-', arg):
|
|
result['compile_options'].append(arg)
|
|
# warning options are ignored...
|
|
elif re.match(r'^-[mW].+', arg):
|
|
pass
|
|
# some preprocessor parameters are ignored...
|
|
elif arg in {'-MD', '-MMD', '-MG', '-MP'}:
|
|
pass
|
|
elif arg in {'-MF', '-MT', '-MQ'}:
|
|
next(args)
|
|
# linker options are ignored...
|
|
elif arg in {'-static', '-shared', '-s', '-rdynamic'} or \
|
|
re.match(r'^-[lL].+', arg):
|
|
pass
|
|
elif arg in {'-l', '-L', '-u', '-z', '-T', '-Xlinker'}:
|
|
next(args)
|
|
# some other options are ignored...
|
|
elif arg in ignored.keys():
|
|
for _ in range(ignored[arg]):
|
|
next(args)
|
|
# parameters which looks source file are taken...
|
|
elif re.match(r'^[^-].+', arg) and classify_source(arg):
|
|
result['files'].append(arg)
|
|
# and consider everything else as compile option.
|
|
else:
|
|
result['compile_options'].append(arg)
|
|
|
|
return result
|
|
|
|
|
|
def classify_source(filename, cplusplus=False):
|
|
""" Return the language from file name extension. """
|
|
|
|
mapping = {
|
|
'.c': 'c++' if cplusplus else 'c',
|
|
'.i': 'c++-cpp-output' if cplusplus else 'c-cpp-output',
|
|
'.ii': 'c++-cpp-output',
|
|
'.m': 'objective-c',
|
|
'.mi': 'objective-c-cpp-output',
|
|
'.mm': 'objective-c++',
|
|
'.mii': 'objective-c++-cpp-output',
|
|
'.C': 'c++',
|
|
'.cc': 'c++',
|
|
'.CC': 'c++',
|
|
'.cp': 'c++',
|
|
'.cpp': 'c++',
|
|
'.cxx': 'c++',
|
|
'.c++': 'c++',
|
|
'.C++': 'c++',
|
|
'.txx': 'c++'
|
|
}
|
|
|
|
__, extension = os.path.splitext(os.path.basename(filename))
|
|
return mapping.get(extension)
|
|
|
|
|
|
def is_cplusplus_compiler(name):
|
|
""" Returns true when the compiler name refer to a C++ compiler. """
|
|
|
|
match = re.match(r'^([^/]*/)*(\w*-)*(\w+\+\+)(-(\d+(\.\d+){0,3}))?$', name)
|
|
return False if match is None else True
|