0
|
1 import argparse
|
|
2 import logging
|
|
3 import os.path
|
|
4 import sys
|
|
5
|
|
6
|
|
7 if True: # 'vim' in sys.modules:
|
|
8 sys.path.append(os.path.dirname(__file__))
|
|
9
|
|
10
|
|
11 from logutil import setup_logging
|
|
12 from vsutil import SolutionCache
|
|
13
|
|
14
|
|
15 logger = logging.getLogger(__name__)
|
|
16
|
|
17
|
|
18 def _build_cflags(filename, solution, buildenv=None, slncache=None):
|
|
19 # Load the solution.
|
|
20 if not solution:
|
|
21 raise Exception(
|
|
22 "No solution path was provided in the client data!")
|
|
23
|
|
24 cache, loaded = SolutionCache.load_or_rebuild(solution, slncache)
|
|
25 if not loaded:
|
|
26 cache.build_cache()
|
|
27
|
|
28 # Find the current file in the solution.
|
|
29 filename_lower = filename.lower()
|
|
30 projpath = None
|
|
31 for pp, pi in cache.index.items():
|
|
32 if filename_lower in pi:
|
|
33 projpath = pp
|
|
34 break
|
|
35 else:
|
|
36 raise Exception("File doesn't belong to the solution: %s" % filename)
|
|
37
|
|
38 # Find the project that our file belongs to.
|
|
39 proj = cache.slnobj.find_project_by_path(projpath)
|
|
40 if not proj:
|
|
41 raise Exception("Can't find project in solution: %s" % projpath)
|
|
42 logger.debug("Found project %s: %s" % (proj.name, proj.abspath))
|
|
43
|
|
44 # Get the provided config/platform combo, which represent a solution
|
|
45 # configuration, and find the corresponding project configuration.
|
|
46 # For instance, a solution configuration of "Debug|Win64" could map
|
|
47 # to a "MyDebug|AnyCPU" configuration on a specific project.
|
|
48 sln_config_platform = '%s|%s' % (buildenv['Configuration'],
|
|
49 buildenv['Platform'])
|
|
50 proj_config_platform = cache.slnobj.find_project_configuration(
|
|
51 proj.guid, sln_config_platform)
|
|
52 if not proj_config_platform:
|
|
53 raise Exception("Can't find project configuration and platform for "
|
|
54 "solution configuration and platform: %s" %
|
|
55 sln_config_platform)
|
|
56
|
|
57 # Make a build environment for the project, and figure out what
|
|
58 # kind of project it is.
|
|
59 proj_config, proj_platform = proj_config_platform.split('|')
|
|
60
|
|
61 proj_buildenv = buildenv.copy()
|
|
62 proj_buildenv['Configuration'] = proj_config
|
|
63 proj_buildenv['Platform'] = proj_platform
|
|
64
|
|
65 cfggroup = proj.propertygroup('Configuration', proj_buildenv)
|
|
66 cfgtype = cfggroup.get('ConfigurationType')
|
|
67 if not cfgtype:
|
|
68 raise Exception("Can't find configuration type. Did you specify a "
|
|
69 "configuration name and platform? Got: %s" %
|
|
70 proj_buildenv)
|
|
71 logger.debug("Found configuration type: %s" % cfgtype)
|
|
72
|
|
73 # Let's prepare a list of standard stuff for C++.
|
|
74 preproc = []
|
|
75 incpaths = []
|
|
76 projdir = os.path.dirname(proj.abspath)
|
|
77
|
|
78 if cfgtype == 'Makefile':
|
|
79 # It's a 'Makefile' project, which means we know as little about
|
|
80 # compiler flags as whatever information was given to VS. As
|
|
81 # such, if the solution setup doesn't give enough info, VS
|
|
82 # intellisense won't work, and neither will YouCompleteMe.
|
|
83 defaultpropgroup = proj.defaultpropertygroup(proj_buildenv)
|
|
84
|
|
85 nmake_preproc = defaultpropgroup.get('NMakePreprocessorDefinitions')
|
|
86 preproc += nmake_preproc.strip(';').split(';')
|
|
87
|
|
88 nmake_incpaths = defaultpropgroup.get('NMakeIncludeSearchPath')
|
|
89 incpaths += [os.path.abspath(os.path.join(projdir, p))
|
|
90 for p in nmake_incpaths.strip(';').split(';')]
|
|
91
|
|
92 else:
|
|
93 # We should definitely support standard VC++ projects here but
|
|
94 # I don't need it yet :)
|
|
95 raise Exception("Don't know how to handle configuration type: %s" %
|
|
96 cfgtype)
|
|
97
|
|
98 # Build the clang/YCM flags with what we found.
|
|
99 flags = ['-x', 'c++'] # TODO: check language type from project file.
|
|
100
|
|
101 for symbol in preproc:
|
|
102 flags.append('-D%s' % symbol)
|
|
103 for path in incpaths:
|
|
104 if path.startswith("C:\\Program Files"):
|
|
105 flags.append('-isystem')
|
|
106 else:
|
|
107 flags.append('-I')
|
|
108 flags.append(path)
|
|
109
|
|
110 return {'flags': flags}
|
|
111
|
|
112
|
|
113 def _build_env_from_vim(client_data):
|
|
114 buildenv = {}
|
|
115 buildenv['Configuration'] = client_data.get('g:vimcrosoft_current_config', '')
|
|
116 buildenv['Platform'] = client_data.get('g:vimcrosoft_current_platform', '')
|
|
117 return buildenv
|
|
118
|
|
119
|
|
120 def Settings(**kwargs):
|
|
121 language = kwargs.get('language')
|
|
122 filename = kwargs.get('filename')
|
|
123
|
|
124 client_data = kwargs.get('client_data', {})
|
|
125 from_cli = kwargs.get('from_cli', False)
|
|
126 if from_cli:
|
|
127 solution = client_data.get('solution')
|
|
128 slncache = client_data.get('slncache')
|
|
129 buildenv = client_data.get('env', {})
|
|
130 else:
|
|
131 solution = client_data.get('g:vimcrosoft_current_sln')
|
|
132 slncache = client_data.get('g:vimcrosoft_current_sln_cache')
|
|
133 buildenv = _build_env_from_vim(client_data)
|
|
134
|
|
135 flags = None
|
|
136
|
|
137 if language == 'cfamily':
|
|
138 try:
|
|
139 flags = _build_cflags(filename, solution,
|
|
140 buildenv=buildenv, slncache=slncache)
|
|
141 except Exception as exc:
|
|
142 if from_cli:
|
|
143 raise
|
|
144 flags = {'error': str(exc)}
|
|
145 else:
|
|
146 flags = {'error': f"Unknown language: {language}"}
|
|
147
|
|
148 with open("D:\\P4\\DevEditor\\debug.txt", 'w') as fp:
|
|
149 fp.write("kwargs:")
|
|
150 fp.write(str(kwargs))
|
|
151 fp.write("client_data:")
|
|
152 fp.write(str(list(kwargs['client_data'].items())))
|
|
153 fp.write("flags:")
|
|
154 fp.write(str(flags))
|
|
155 return flags
|
|
156
|
|
157
|
|
158 languages = {
|
|
159 'cfamily': ['h', 'c', 'hpp', 'cpp', 'inl']
|
|
160 }
|
|
161
|
|
162
|
|
163 def _get_language(filename):
|
|
164 _, ext = os.path.splitext(filename)
|
|
165 ext = ext.lstrip('.')
|
|
166 for lang, exts in languages.items():
|
|
167 if ext in exts:
|
|
168 return lang
|
|
169 return None
|
|
170
|
|
171
|
|
172 def main():
|
|
173 parser = argparse.ArgumentParser()
|
|
174 parser.add_argument('solution',
|
|
175 help="The solution file")
|
|
176 parser.add_argument('filename',
|
|
177 help="The filename for which to get flags")
|
|
178 parser.add_argument('-p', '--property',
|
|
179 action="append",
|
|
180 help="Specifies a build property")
|
|
181 parser.add_argument('-c', '--cache',
|
|
182 help="The solution cache to use")
|
|
183 parser.add_argument('-v', '--verbose',
|
|
184 action='store_true',
|
|
185 help="Show debugging information")
|
|
186 args = parser.parse_args()
|
|
187 setup_logging(args.verbose)
|
|
188
|
|
189 lang = _get_language(args.filename)
|
|
190 logger.debug(f"Got language {lang} for {args.filename}")
|
|
191
|
|
192 build_env = {}
|
|
193 if args.property:
|
|
194 for p in args.property:
|
|
195 pname, pval = p.split('=', 1)
|
|
196 build_env[pname] = pval
|
|
197 logger.debug(f"Got build environment: {build_env}")
|
|
198 client_data = {'solution': args.solution,
|
|
199 'slncache': args.cache,
|
|
200 'env': build_env}
|
|
201
|
|
202 params = {'from_cli': True,
|
|
203 'language': lang,
|
|
204 'filename': args.filename,
|
|
205 'client_data': client_data
|
|
206 }
|
|
207 flags = Settings(**params)
|
|
208 logger.info("Flags:")
|
|
209 import pprint
|
|
210 pp = pprint.PrettyPrinter(indent=2)
|
|
211 pp.pprint(flags)
|
|
212
|
|
213
|
|
214 if __name__ == '__main__':
|
|
215 main()
|