Adding a .ycm_extra_conf file for webkitGtk
[WebKit-https.git] / Tools / gtk / ycm_extra_conf.py
1 #!/usr/bin/env python
2 # Copyright (C) 2013 Danilo Cesar Lemes de Paula <danilo.eu@gmail.com>
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17
18 import os
19 import re
20 import subprocess
21 import sys
22
23 # It's very likely that this script is a symlink somewhere in the WebKit directory,
24 # so we try to find the actual script location so that we can locate the tools
25 # directory.
26 if os.path.islink(__file__):
27     __tools_directory = os.path.dirname(os.readlink(__file__))
28 else:
29     __tools_directory = os.path.dirname(__file__)
30 sys.path.insert(0, os.path.abspath(__tools_directory))
31 import common
32
33 MAKE_TRACE_FILE_NAME = "ycm-make-trace"
34 FLAGS_PRECEDING_PATHS = ['-isystem', '-I', '-iquote', '--sysroot=']
35
36
37 def transform_relative_paths_to_absolute_paths(arguments, build_path):
38     result = []
39
40     make_next_absolute = False
41     for argument in arguments:
42         if make_next_absolute:
43             make_next_absolute = False
44             if not argument.startswith('/'):
45                 argument = os.path.join(build_path, argument)
46         elif flag in FLAGS_PRECEDING_PATHS:
47             # Some flags precede the path in the list. For those we make the
48             # next argument absolute.
49             if argument == flag:
50                 make_next_absolute = True
51         else:
52             # Some argument contain the flag and the path together. For these
53             # we parse the argument out of the path.
54             for flag in FLAGS_PRECEDING_PATHS:
55                 if argument.startswith(flag):
56                     argument = flag + os.path.join(build_path, argument[len(flag):])
57                     break
58
59         result.append(argument)
60     return result
61
62
63 def create_make_trace_file(build_path):
64     print "Creating make trace file for YouCompleteMe, might take a few seconds"
65     os.chdir(build_path)
66     subprocess.call("make -n -s > %s" % MAKE_TRACE_FILE_NAME, shell=True)
67
68
69 def make_trace_file_up_to_date(build_path):
70     trace_file = os.path.join(build_path, MAKE_TRACE_FILE_NAME)
71     if not os.path.isfile(trace_file):
72         return False
73
74     makefile = os.path.join(build_path, 'GNUmakefile')
75     if os.path.getmtime(trace_file) < os.path.getctime(makefile):
76         return False
77
78     return True
79
80
81 def ensure_make_trace_file(build_path):
82     if make_trace_file_up_to_date(build_path):
83         return True
84     create_make_trace_file(build_path)
85     return make_trace_file_up_to_date(build_path)
86
87
88 def get_compilation_flags_from_build_commandline(command_line, build_path):
89     flags = re.findall("-[I,D,p,O][\w,\.,/,-]*(?:=\"?\w*\"?)?", command_line)
90     return transform_relative_paths_to_absolute_paths(flags, build_path)
91
92
93 def get_compilation_flags_for_file(build_path, filename):
94     trace_file_path = os.path.join(build_path, MAKE_TRACE_FILE_NAME)
95
96     try:
97         trace_file = open(trace_file_path)
98         lines = trace_file.readlines()
99         trace_file.close()
100     except:
101         print "==== Error reading %s file", trace_file_path
102         return []
103
104     basename = os.path.basename(filename)
105     for line in lines:
106         if line.find(basename) != -1 and line.find("CC") != -1 or line.find("CXX") != -1:
107             return get_compilation_flags_from_build_commandline(line, build_path)
108
109     print "Could not find flags for %s" % filename
110     return []
111
112
113 def FlagsForFile(filename, **kwargs):
114     """This is the main entry point for YCM. Its interface is fixed.
115
116     Args:
117       filename: (String) Path to source file being edited.
118
119     Returns:
120       (Dictionary)
121         'flags': (List of Strings) Command line flags.
122         'do_cache': (Boolean) True if the result should be cached.
123     """
124
125     result = {'flags': ['-std=c++11', '-x', 'c++'], 'do_cache': True}
126
127     # Headers can't be built, so we get the source file flags instead.
128     if filename.endswith('.h'):
129         filename = filename[:-2] + ".cpp"
130         if not os.path.exists(filename):
131             return result
132
133         # Force config.h file inclusion, for GLib macros.
134         result['flags'].append("-includeconfig.h")
135
136     build_path = common.get_build_path(fatal=False)
137     if not build_path:
138         print "Could not find WebKit build path."
139         return result
140
141     if not ensure_make_trace_file(build_path):
142         print "Could not create make trace file"
143         return result
144
145     result['flags'].extend(get_compilation_flags_for_file(build_path, filename))
146     return result
147
148 if __name__ == "__main__":
149     import sys
150     if len(sys.argv) >= 2:
151         print FlagsForFile(sys.argv[1])