-
Notifications
You must be signed in to change notification settings - Fork 0
/
global_ycm_extra_conf.py
143 lines (124 loc) · 4.31 KB
/
global_ycm_extra_conf.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import os
from pathlib import Path
from pathlib import PosixPath
import ycm_core
flags = [
'-Wall',
'-Wextra',
'-Wpedantic',
'-Werror',
'-Wno-long-long',
'-Wno-padded',
'-Wno-variadic-macros',
'-fexceptions',
'-DNDEBUG',
'-std=c++1z',
'-x',
'c++', # For a C project, you would set this to 'c' instead of 'c++'.
]
# Find matching file/dir directly inside the given directory, or recursively in
# parent directories
def find_outer_dir_with_file(curdir, file_to_find):
assert os.path.isdir(curdir), "curdir is not a dir"
while curdir != None and curdir != '' and curdir != '/': # disallow root
if os.path.exists(os.path.join(curdir, file_to_find)):
return curdir
curdir = os.path.dirname(curdir)
return None
def get_basedir(filedir):
cmldir = find_outer_dir_with_file(filedir, 'CMakeLists.txt')
if cmldir != None:
return cmldir
gitdir = find_outer_dir_with_file(filedir, '.git')
if gitdir != None:
return gitdir
return None
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
if not working_directory:
return list( flags )
new_flags = []
make_next_absolute = False
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
for flag in flags:
new_flag = flag
if make_next_absolute:
make_next_absolute = False
if not flag.startswith( '/' ):
new_flag = os.path.join( working_directory, flag )
for path_flag in path_flags:
if flag == path_flag:
make_next_absolute = True
break
if flag.startswith( path_flag ):
path = flag[ len( path_flag ): ]
new_flag = path_flag + os.path.join( working_directory, path )
break
if new_flag:
new_flags.append( new_flag )
return new_flags
HEADER_EXTENSIONS = [ '.h', '.hxx', '.hpp', '.hh', '.ipp', '.ixx' ]
def is_header_file(filename):
extension = os.path.splitext( filename )[ 1 ]
return extension in HEADER_EXTENSIONS
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c' ]
def is_source_file(filename):
extension = os.path.splitext(filename)[1]
return extension in SOURCE_EXTENSIONS
def get_compile_info_from_db(db, filename):
if None == db:
return None
if is_header_file(filename):
# First, try related source files
basename = os.path.splitext(filename)[0]
for extension in SOURCE_EXTENSIONS:
source_file = basename + extension
if os.path.exists(source_file):
compilation_info = db.GetCompilationInfoForFile(source_file)
if compilation_info.compiler_flags_:
return compilation_info
# Then try the first source file in the same folder... meh
for sibling in Path(filename).parents[0].iterdir():
if not sibling.is_dir():
sibling_ext = sibling.suffix
if sibling_ext in SOURCE_EXTENSIONS:
raw = os.path.abspath(bytes(sibling))
compilation_info = db.GetCompilationInfoForFile(raw)
if compilation_info.compiler_flags_:
return compilation_info
else:
# Don't keep trying others
return None
return None
return db.GetCompilationInfoForFile(filename)
def flags_with_abs_paths(flags, relative_to):
return {
'flags': MakeRelativePathsInFlagsAbsolute(flags, relative_to),
'do_cache': True
}
def get_db_folder(filedir):
if None == filedir:
return None
DB_RELPATHS = ['target', 'target/debug', 'target/release', 'build', 'build/debug', 'build/release']
for dbrel in DB_RELPATHS:
dbdir = os.path.join(filedir, dbrel)
dbfile = os.path.join(dbdir, 'compile_commands.json')
if os.path.exists(dbfile):
return os.path.abspath(dbdir)
return None
def FlagsForFile(filename, **kwargs):
assert not os.path.isdir(filename)
filedir = os.path.dirname(os.path.abspath(filename))
assert os.path.exists(filedir)
basedir = get_basedir(filedir)
db_folder = get_db_folder(basedir)
if None == db_folder:
db_folder = get_db_folder(filedir)
if None != db_folder and os.path.exists(db_folder):
db = ycm_core.CompilationDatabase(db_folder)
db_compile_info = get_compile_info_from_db(db, filename)
if None != db_compile_info:
return flags_with_abs_paths(db_compile_info.compiler_flags_, db_compile_info.compiler_working_dir_)
more_flags = flags + ['-I' + filedir]
if None != basedir:
return flags_with_abs_paths(more_flags, basedir)
return flags_with_abs_paths(more_flags, filedir)