Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Side by Side Diff: pylib/gyp/generator/eclipse.py

Issue 9972015: Create a gyp generator for Eclipse CDT settings (Closed) Base URL: http://git.chromium.org/external/gyp.git@master
Patch Set: Cleanup Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright (c) 2012 Google Inc. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """GYP backend that generates Eclipse CDT settings files.
6
7 This backend DOES NOT generate Eclipse CDT projects. Instead, it generates XML
8 files that can be imported into an Eclipse CDT project. The XML file contains a
9 list of include paths and symbols (i.e. defines).
10
11 Because a full .cproject definition is not created by this generator, it's not
12 possible to properly define the include dirs and symbols for each file
13 individually. Instead, one set of includes/symbols is generated for the entire
14 project. This works fairly well (and is a vast improvement in general), but may
15 still result in a few indexer issues here and there.
16 """
17
18 import os.path
19 import subprocess
20 import gyp
21 import gyp.common
22 import shlex
23
24 generator_wants_static_library_dependencies_adjusted = False
25
26 generator_default_variables = {
27 }
28
29 for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']:
30 # Some gyp steps fail if these are empty(!).
31 generator_default_variables[dirname] = 'dir'
32
33 for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
34 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
35 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
36 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
37 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX']:
38 generator_default_variables[unused] = ''
39
40 # Include dirs will occasionaly use the SHARED_INTERMEDIATE_DIR variable as
41 # part of the path when dealing with generated headers. This value will be
42 # replaced dynamically for each configuration.
43 generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \
44 '$SHARED_INTERMEDIATES_DIR'
45
46
47 def CalculateVariables(default_variables, params):
48 generator_flags = params.get('generator_flags', {})
49 for key, val in generator_flags.items():
50 default_variables.setdefault(key, val)
51 default_variables.setdefault('OS', gyp.common.GetFlavor(params))
52
53
54 def CalculateGeneratorInputInfo(params):
55 """Calculate the generator specific info that gets fed to input (called by
56 gyp)."""
57 generator_flags = params.get('generator_flags', {})
58 if generator_flags.get('adjust_static_libraries', False):
59 global generator_wants_static_library_dependencies_adjusted
60 generator_wants_static_library_dependencies_adjusted = True
61
62
63 def GetAllIncludeDirs(target_list, target_dicts, shared_intermediates_dir,
Nico 2012/04/27 17:33:41 nit: style guide says no abbreviations. Use GetAll
Jesse Greenwald 2012/04/28 01:57:49 Done.
64 config_name):
65 """Calculate the set of include dirs to be used.
66
67 Returns:
68 A list including all the include_dir's specified for every target followed
69 by any include dirs that were added as cflag compiler options.
70 """
71
72 gyp_includes = []
73 compiler_includes = []
74
75 for target_name in target_list:
76 target = target_dicts[target_name]
77 if config_name in target['configurations']:
78 config = target['configurations'][config_name]
79
80 # Look for any include dirs that were explicitly added via cflags. This
81 # may be done in gyp files to force certain includes to come at the end.
Nico 2012/04/27 17:33:41 Can you at least put a "# TODO: Change the gyp fil
Jesse Greenwald 2012/04/28 01:57:49 Done.
82 cflags = config['cflags']
83 for cflag in cflags:
84 include_dir = ''
85 if cflag.startswith('-I'):
86 include_dir = cflag[2:]
87 if include_dir and not include_dir in compiler_includes:
88 compiler_includes.append(include_dir)
89
90 # Find standard gyp include dirs.
91 if config.has_key('include_dirs'):
92 include_dirs = config['include_dirs']
93 for include_dir in include_dirs:
94 include_dir = include_dir.replace('$SHARED_INTERMEDIATES_DIR',
95 shared_intermediates_dir)
96 if not os.path.isabs(include_dir):
97 base_dir = os.path.dirname(target_name)
98
99 include_dir = base_dir + '/' + include_dir
100 include_dir = os.path.abspath(include_dir)
101
102 if not include_dir in gyp_includes:
103 gyp_includes.append(include_dir)
104
105 gyp_includes.sort()
106
107 # Generate a list that has all the include dirs.
108 all_includes = list(gyp_includes)
Nico 2012/04/27 17:33:41 s/list/set/, else the loop below is O(n^2). (Also,
Jesse Greenwald 2012/04/28 01:57:49 To keep the ordering, I copied gyp_includes into a
109 for compiler_include in compiler_includes:
110 if not compiler_include in all_includes:
111 all_includes.append(compiler_include)
112
113 # All done.
114 return all_includes
115
116
117 def GetCompilerPath(target_list, target_dicts, data):
118 """Determine a command that can be used to invoke the compiler.
119
120 Returns:
121 If this is a gyp project that has explicit make settings, try to determine
122 the compiler from that. Otherwise, see if a compiler was specified via the
123 CC_target environment variable.
124 """
125
126 # First, see if the compiler is configured in make's settings.
127 build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
128 make_global_settings_dict = data[build_file].get('make_global_settings', {})
129 for key, value in make_global_settings_dict:
130 if key in ['CC', 'CXX']:
131 return value
132
133 # Check to see if the compiler was specified as an environment variable.
Nico 2012/04/27 17:33:41 I think ninja allows 'CC' and 'CXX' as env keys to
Jesse Greenwald 2012/04/28 01:57:49 Done.
134 cc_target = os.environ.get('CC_target')
135 if cc_target:
136 return cc_target
137
138 # Default.
Nico 2012/04/27 17:33:41 Nit: Comment doesn't add much, remove it.
Jesse Greenwald 2012/04/28 01:57:49 Done.
139 return 'gcc'
140
141
142 def GetAllDefines(target_list, target_dicts, data, config_name):
143 """Calculate the defines for a project.
144
145 Returns:
146 A dict that includes explict defines declared in gyp files along with all of
147 the default defines that the compiler uses.
148 """
149
150 # Get defines declared in the gyp files.
151 all_defines = {}
152 for target_name in target_list:
153 target = target_dicts[target_name]
154
155 if config_name in target['configurations']:
156 config = target['configurations'][config_name]
157 for define in config['defines']:
158 split_define = define.split('=', 1)
159 if len(split_define) == 1:
160 split_define.append('1')
161 if split_define[0].strip() in all_defines:
162 # Already defined
163 continue
164
165 all_defines[split_define[0].strip()] = split_define[1].strip()
166
167 # Get default compiler defines (if possible).
Nico 2012/04/27 17:33:41 I'm surprised this part is needed. Shouldn't Eclip
Jesse Greenwald 2012/04/28 01:57:49 Eclipse doesn't know what compiler is being used.
168 cc_target = GetCompilerPath(target_list, target_dicts, data)
169 if cc_target:
170 command = shlex.split(cc_target)
171 command.extend(['-E', '-dM', '-'])
172 cpp_proc = subprocess.Popen(args=command, cwd='.',
173 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
174 cpp_output = cpp_proc.communicate()[0]
175 cpp_lines = cpp_output.split('\n')
176 for cpp_line in cpp_lines:
177 if not cpp_line.strip():
178 continue
179 cpp_line_parts = cpp_line.split(' ', 2)
180 key = cpp_line_parts[1]
181 if len(cpp_line_parts) >= 3:
182 val = cpp_line_parts[2]
183 else:
184 val = '1'
185 all_defines[key] = val
186
187 return all_defines
188
189
190 def WriteIncludePaths(out, eclipse_langs, include_dirs):
191 """Write the includes section of a CDT settings export file."""
192
193 out.write(' <section name="org.eclipse.cdt.internal.ui.wizards.' \
194 'settingswizards.IncludePaths">\n')
195 out.write(' <language name="holder for library settings"></language>\n')
196 for lang in eclipse_langs:
197 out.write(' <language name="%s">\n' % lang)
198 for include_dir in include_dirs:
199 out.write(' <includepath workspace_path="false">%s</includepath>\n' %
200 include_dir)
201 out.write(' </language>\n')
202 out.write(' </section>\n')
203
204
205 def WriteMacros(out, eclipse_langs, defines):
206 """Write the macros section of a CDT settings export file."""
207
208 out.write(' <section name="org.eclipse.cdt.internal.ui.wizards.' \
209 'settingswizards.Macros">\n')
210 out.write(' <language name="holder for library settings"></language>\n')
211 for lang in eclipse_langs:
212 out.write(' <language name="%s">\n' % lang)
213 for key in sorted(defines.iterkeys()):
214 out.write(' <macro><name>%s</name><value>%s</value></macro>\n' %
215 (key, defines[key]))
216 out.write(' </language>\n')
217 out.write(' </section>\n')
218
219
220 def GenerateOutputForConfig(target_list, target_dicts, data, params,
221 config_name):
222 options = params['options']
223 generator_flags = params.get('generator_flags', {})
224
225 # build_dir: relative path from source root to our output files.
226 # e.g. "out/Debug"
227 build_dir = os.path.join(generator_flags.get('output_dir', 'out'),
228 config_name)
229
230 toplevel_build = os.path.join(options.toplevel_dir, build_dir)
231 shared_intermediate_dir = os.path.join(toplevel_build, 'obj', 'gen')
232
233 if not os.path.exists(toplevel_build):
234 os.makedirs(toplevel_build)
235 out = open(os.path.join(toplevel_build, 'eclipse-cdt-settings.xml'), 'w')
236
237 out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
238 out.write('<cdtprojectproperties>\n')
239
240 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File',
241 'GNU C++', 'GNU C', 'Assembly']
242 include_dirs = GetAllIncludeDirs(target_list, target_dicts,
243 shared_intermediate_dir, config_name)
244 WriteIncludePaths(out, eclipse_langs, include_dirs)
245 defines = GetAllDefines(target_list, target_dicts, data, config_name)
246 WriteMacros(out, eclipse_langs, defines)
247
248 out.write('</cdtprojectproperties>\n')
249 out.close()
250
251
252 def GenerateOutput(target_list, target_dicts, data, params):
253 """Generate an XML settings file that can be imported into a CDT project."""
254
255 if params['options'].generator_output:
256 raise NotImplementedError, "--generator_output not implemented for eclipse"
257
258 user_config = params.get('generator_flags', {}).get('config', None)
259 if user_config:
260 GenerateOutputForConfig(target_list, target_dicts, data, params,
261 user_config)
262 else:
263 config_names = target_dicts[target_list[0]]['configurations'].keys()
264 for config_name in config_names:
265 GenerateOutputForConfig(target_list, target_dicts, data, params,
266 config_name)
267
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698