Apply ASLR for send-booting-done and wait-target-done
[platform/upstream/systemd.git] / .ycm_extra_conf.py
1 #!/usr/bin/env python
2
3 # SPDX-License-Identifier: Unlicense
4 #
5 # Based on the template file provided by the 'YCM-Generator' project authored by
6 # Reuben D'Netto.
7 # Jiahui Xie has re-reformatted and expanded the original script in accordance
8 # to the requirements of the PEP 8 style guide and 'systemd' project,
9 # respectively.
10 #
11 # The original license is preserved as it is.
12 #
13 #
14 # This is free and unencumbered software released into the public domain.
15 #
16 # Anyone is free to copy, modify, publish, use, compile, sell, or
17 # distribute this software, either in source code form or as a compiled
18 # binary, for any purpose, commercial or non-commercial, and by any
19 # means.
20 #
21 # In jurisdictions that recognize copyright laws, the author or authors
22 # of this software dedicate any and all copyright interest in the
23 # software to the public domain. We make this dedication for the benefit
24 # of the public at large and to the detriment of our heirs and
25 # successors. We intend this dedication to be an overt act of
26 # relinquishment in perpetuity of all present and future rights to this
27 # software under copyright law.
28 #
29 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32 # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
33 # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34 # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35 # OTHER DEALINGS IN THE SOFTWARE.
36 #
37 # For more information, please refer to <http://unlicense.org/>
38
39 """
40 YouCompleteMe configuration file tailored to support the 'meson' build system
41 used by the 'systemd' project.
42 """
43
44 import glob
45 import os
46 import ycm_core
47
48
49 SOURCE_EXTENSIONS = (".C", ".cpp", ".cxx", ".cc", ".c", ".m", ".mm")
50 HEADER_EXTENSIONS = (".H", ".h", ".hxx", ".hpp", ".hh")
51
52
53 def DirectoryOfThisScript():
54     """
55     Return the absolute path of the parent directory containing this
56     script.
57     """
58     return os.path.dirname(os.path.abspath(__file__))
59
60
61 def GuessBuildDirectory():
62     """
63     Guess the build directory using the following heuristics:
64
65     1. Returns the current directory of this script plus 'build'
66     subdirectory in absolute path if this subdirectory exists.
67
68     2. Otherwise, probes whether there exists any directory
69     containing '.ninja_log' file two levels above the current directory;
70     returns this single directory only if there is one candidate.
71     """
72     result = os.path.join(DirectoryOfThisScript(), "build")
73
74     if os.path.exists(result):
75         return result
76
77     result = glob.glob(os.path.join(DirectoryOfThisScript(),
78                                     "..", "..", "*", ".ninja_log"))
79
80     if not result:
81         return ""
82
83     if 1 != len(result):
84         return ""
85
86     return os.path.split(result[0])[0]
87
88
89 def TraverseByDepth(root, include_extensions):
90     """
91     Return a set of child directories of the 'root' containing file
92     extensions specified in 'include_extensions'.
93
94     NOTE:
95         1. The 'root' directory itself is excluded from the result set.
96         2. No subdirectories would be excluded if 'include_extensions' is left
97            to 'None'.
98         3. Each entry in 'include_extensions' must begin with string '.'.
99     """
100     is_root = True
101     result = set()
102     # Perform a depth first top down traverse of the given directory tree.
103     for root_dir, subdirs, file_list in os.walk(root):
104         if not is_root:
105             # print("Relative Root: ", root_dir)
106             # print(subdirs)
107             if include_extensions:
108                 get_ext = os.path.splitext
109                 subdir_extensions = {
110                     get_ext(f)[-1] for f in file_list if get_ext(f)[-1]
111                 }
112                 if subdir_extensions & include_extensions:
113                     result.add(root_dir)
114             else:
115                 result.add(root_dir)
116         else:
117             is_root = False
118
119     return result
120
121
122 _project_src_dir = os.path.join(DirectoryOfThisScript(), "src")
123 _include_dirs_set = TraverseByDepth(_project_src_dir, frozenset({".h"}))
124 flags = [
125     "-x",
126     "c"
127     # The following flags are partially redundant due to the existence of
128     # 'compile_commands.json'.
129     #    '-Wall',
130     #    '-Wextra',
131     #    '-Wfloat-equal',
132     #    '-Wpointer-arith',
133     #    '-Wshadow',
134     #    '-std=gnu99',
135 ]
136
137 for include_dir in _include_dirs_set:
138     flags.append("-I" + include_dir)
139
140 # Set this to the absolute path to the folder (NOT the file!) containing the
141 # compile_commands.json file to use that instead of 'flags'. See here for
142 # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
143 #
144 # You can get CMake to generate this file for you by adding:
145 #   set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
146 # to your CMakeLists.txt file.
147 #
148 # Most projects will NOT need to set this to anything; you can just change the
149 # 'flags' list of compilation flags. Notice that YCM itself uses that approach.
150 compilation_database_folder = GuessBuildDirectory()
151
152 if os.path.exists(compilation_database_folder):
153     database = ycm_core.CompilationDatabase(compilation_database_folder)
154 else:
155     database = None
156
157
158 def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
159     """
160     Iterate through 'flags' and replace the relative paths prefixed by
161     '-isystem', '-I', '-iquote', '--sysroot=' with absolute paths
162     start with 'working_directory'.
163     """
164     if not working_directory:
165         return list(flags)
166     new_flags = []
167     make_next_absolute = False
168     path_flags = ["-isystem", "-I", "-iquote", "--sysroot="]
169     for flag in flags:
170         new_flag = flag
171
172         if make_next_absolute:
173             make_next_absolute = False
174             if not flag.startswith("/"):
175                 new_flag = os.path.join(working_directory, flag)
176
177         for path_flag in path_flags:
178             if flag == path_flag:
179                 make_next_absolute = True
180                 break
181
182             if flag.startswith(path_flag):
183                 path = flag[len(path_flag):]
184                 new_flag = path_flag + os.path.join(working_directory, path)
185                 break
186
187         if new_flag:
188             new_flags.append(new_flag)
189     return new_flags
190
191
192 def IsHeaderFile(filename):
193     """
194     Check whether 'filename' is considered as a header file.
195     """
196     extension = os.path.splitext(filename)[1]
197     return extension in HEADER_EXTENSIONS
198
199
200 def GetCompilationInfoForFile(filename):
201     """
202     Helper function to look up compilation info of 'filename' in the 'database'.
203     """
204     # The compilation_commands.json file generated by CMake does not have
205     # entries for header files. So we do our best by asking the db for flags for
206     # a corresponding source file, if any. If one exists, the flags for that
207     # file should be good enough.
208     if not database:
209         return None
210
211     if IsHeaderFile(filename):
212         basename = os.path.splitext(filename)[0]
213         for extension in SOURCE_EXTENSIONS:
214             replacement_file = basename + extension
215             if os.path.exists(replacement_file):
216                 compilation_info = \
217                     database.GetCompilationInfoForFile(replacement_file)
218                 if compilation_info.compiler_flags_:
219                     return compilation_info
220         return None
221     return database.GetCompilationInfoForFile(filename)
222
223
224 def FlagsForFile(filename, **kwargs):
225     """
226     Callback function to be invoked by YouCompleteMe in order to get the
227     information necessary to compile 'filename'.
228
229     It returns a dictionary with a single element 'flags'. This element is a
230     list of compiler flags to pass to libclang for the file 'filename'.
231     """
232     if database:
233         # Bear in mind that compilation_info.compiler_flags_ does NOT return a
234         # python list, but a "list-like" StringVec object
235         compilation_info = GetCompilationInfoForFile(filename)
236         if not compilation_info:
237             return None
238
239         final_flags = MakeRelativePathsInFlagsAbsolute(
240             compilation_info.compiler_flags_,
241             compilation_info.compiler_working_dir_)
242
243     else:
244         relative_to = DirectoryOfThisScript()
245         final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to)
246
247     return {
248         "flags": final_flags,
249         "do_cache": True
250     }