OLD | NEW |
---|---|
1 # Copyright (c) 2012 Google Inc. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """GYP backend that generates Eclipse CDT settings files. | 5 """GYP backend that generates Eclipse CDT settings files. |
6 | 6 |
7 This backend DOES NOT generate Eclipse CDT projects. Instead, it generates XML | 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 | 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). | 9 list of include paths and symbols (i.e. defines). |
10 | 10 |
11 Because a full .cproject definition is not created by this generator, it's not | 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 | 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 | 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 | 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. | 15 still result in a few indexer issues here and there. |
16 | 16 |
17 This generator has no automated tests, so expect it to be broken. | 17 This generator has no automated tests, so expect it to be broken. |
18 """ | 18 """ |
19 | 19 |
20 from xml.sax.saxutils import escape | 20 from xml.sax.saxutils import escape |
21 import os.path | 21 import os.path |
22 import subprocess | 22 import subprocess |
23 import gyp | 23 import gyp |
24 import gyp.common | 24 import gyp.common |
25 import gyp.msvs_emulation | |
25 import shlex | 26 import shlex |
26 | 27 |
27 generator_wants_static_library_dependencies_adjusted = False | 28 generator_wants_static_library_dependencies_adjusted = False |
28 | 29 |
29 generator_default_variables = { | 30 generator_default_variables = { |
30 } | 31 } |
31 | 32 |
32 for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']: | 33 for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']: |
33 # Some gyp steps fail if these are empty(!). | 34 # Some gyp steps fail if these are empty(!). |
34 generator_default_variables[dirname] = 'dir' | 35 generator_default_variables[dirname] = 'dir' |
(...skipping 11 matching lines...) Expand all Loading... | |
46 # replaced dynamically for each configuration. | 47 # replaced dynamically for each configuration. |
47 generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \ | 48 generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \ |
48 '$SHARED_INTERMEDIATE_DIR' | 49 '$SHARED_INTERMEDIATE_DIR' |
49 | 50 |
50 | 51 |
51 def CalculateVariables(default_variables, params): | 52 def CalculateVariables(default_variables, params): |
52 generator_flags = params.get('generator_flags', {}) | 53 generator_flags = params.get('generator_flags', {}) |
53 for key, val in generator_flags.items(): | 54 for key, val in generator_flags.items(): |
54 default_variables.setdefault(key, val) | 55 default_variables.setdefault(key, val) |
55 default_variables.setdefault('OS', gyp.common.GetFlavor(params)) | 56 default_variables.setdefault('OS', gyp.common.GetFlavor(params)) |
57 flavor = gyp.common.GetFlavor(params) | |
58 if flavor == 'win': | |
59 # Copy additional generator configuration data from VS, which is shared | |
60 # by the Windows Ninja generator. | |
Nico
2013/08/31 20:18:36
"by the Eclipse generator", right?
Slava Chigrin
2013/09/01 15:28:28
Done.
| |
61 import gyp.generator.msvs as msvs_generator | |
62 generator_additional_non_configuration_keys = getattr(msvs_generator, | |
63 'generator_additional_non_configuration_keys', []) | |
64 generator_additional_path_sections = getattr(msvs_generator, | |
65 'generator_additional_path_sections', []) | |
66 | |
67 # Set a variable so conditions can be based on msvs_version. | |
68 msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags) | |
69 default_variables['MSVS_VERSION'] = msvs_version.ShortName() | |
70 | |
71 # To determine processor word size on Windows, in addition to checking | |
Slava Chigrin
2013/08/31 13:49:16
Seems, at present these lines are duplicated in ni
| |
72 # PROCESSOR_ARCHITECTURE (which reflects the word size of the current | |
73 # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which | |
74 # contains the actual word size of the system when running thru WOW64). | |
75 if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or | |
76 '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')): | |
77 default_variables['MSVS_OS_BITS'] = 64 | |
78 else: | |
79 default_variables['MSVS_OS_BITS'] = 32 | |
56 | 80 |
57 | 81 |
58 def CalculateGeneratorInputInfo(params): | 82 def CalculateGeneratorInputInfo(params): |
59 """Calculate the generator specific info that gets fed to input (called by | 83 """Calculate the generator specific info that gets fed to input (called by |
60 gyp).""" | 84 gyp).""" |
61 generator_flags = params.get('generator_flags', {}) | 85 generator_flags = params.get('generator_flags', {}) |
62 if generator_flags.get('adjust_static_libraries', False): | 86 if generator_flags.get('adjust_static_libraries', False): |
63 global generator_wants_static_library_dependencies_adjusted | 87 global generator_wants_static_library_dependencies_adjusted |
64 generator_wants_static_library_dependencies_adjusted = True | 88 generator_wants_static_library_dependencies_adjusted = True |
65 | 89 |
66 | 90 |
67 def GetAllIncludeDirectories(target_list, target_dicts, | 91 def GetAllIncludeDirectories(target_list, target_dicts, |
68 shared_intermediate_dirs, config_name): | 92 shared_intermediate_dirs, config_name, params): |
69 """Calculate the set of include directories to be used. | 93 """Calculate the set of include directories to be used. |
70 | 94 |
71 Returns: | 95 Returns: |
72 A list including all the include_dir's specified for every target followed | 96 A list including all the include_dir's specified for every target followed |
73 by any include directories that were added as cflag compiler options. | 97 by any include directories that were added as cflag compiler options. |
74 """ | 98 """ |
75 | 99 |
76 gyp_includes_set = set() | 100 gyp_includes_set = set() |
77 compiler_includes_list = [] | 101 compiler_includes_list = [] |
78 | 102 |
103 flavor = gyp.common.GetFlavor(params) | |
104 if flavor == 'win': | |
105 generator_flags = params.get('generator_flags', {}) | |
79 for target_name in target_list: | 106 for target_name in target_list: |
80 target = target_dicts[target_name] | 107 target = target_dicts[target_name] |
81 if config_name in target['configurations']: | 108 if config_name in target['configurations']: |
82 config = target['configurations'][config_name] | 109 config = target['configurations'][config_name] |
83 | 110 |
84 # Look for any include dirs that were explicitly added via cflags. This | 111 # Look for any include dirs that were explicitly added via cflags. This |
85 # may be done in gyp files to force certain includes to come at the end. | 112 # may be done in gyp files to force certain includes to come at the end. |
86 # TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and | 113 # TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and |
87 # remove this. | 114 # remove this. |
88 cflags = config['cflags'] | 115 if flavor == 'win': |
116 msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags) | |
117 cflags = msvs_settings.GetCflags(config_name) | |
118 else: | |
119 cflags = config['cflags'] | |
89 for cflag in cflags: | 120 for cflag in cflags: |
90 include_dir = '' | 121 include_dir = '' |
91 if cflag.startswith('-I'): | 122 if cflag.startswith('-I'): |
92 include_dir = cflag[2:] | 123 include_dir = cflag[2:] |
93 if include_dir and not include_dir in compiler_includes_list: | 124 if include_dir and not include_dir in compiler_includes_list: |
94 compiler_includes_list.append(include_dir) | 125 compiler_includes_list.append(include_dir) |
95 | 126 |
96 # Find standard gyp include dirs. | 127 # Find standard gyp include dirs. |
97 if config.has_key('include_dirs'): | 128 if config.has_key('include_dirs'): |
98 include_dirs = config['include_dirs'] | 129 include_dirs = config['include_dirs'] |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
139 | 170 |
140 # Check to see if the compiler was specified as an environment variable. | 171 # Check to see if the compiler was specified as an environment variable. |
141 for key in ['CC_target', 'CC', 'CXX']: | 172 for key in ['CC_target', 'CC', 'CXX']: |
142 compiler = os.environ.get(key) | 173 compiler = os.environ.get(key) |
143 if compiler: | 174 if compiler: |
144 return compiler | 175 return compiler |
145 | 176 |
146 return 'gcc' | 177 return 'gcc' |
147 | 178 |
148 | 179 |
149 def GetAllDefines(target_list, target_dicts, data, config_name): | 180 def GetAllDefines(target_list, target_dicts, data, config_name, params): |
150 """Calculate the defines for a project. | 181 """Calculate the defines for a project. |
151 | 182 |
152 Returns: | 183 Returns: |
153 A dict that includes explict defines declared in gyp files along with all of | 184 A dict that includes explict defines declared in gyp files along with all of |
154 the default defines that the compiler uses. | 185 the default defines that the compiler uses. |
155 """ | 186 """ |
156 | 187 |
157 # Get defines declared in the gyp files. | 188 # Get defines declared in the gyp files. |
158 all_defines = {} | 189 all_defines = {} |
190 flavor = gyp.common.GetFlavor(params) | |
191 if flavor == 'win': | |
192 generator_flags = params.get('generator_flags', {}) | |
159 for target_name in target_list: | 193 for target_name in target_list: |
160 target = target_dicts[target_name] | 194 target = target_dicts[target_name] |
161 | 195 |
196 if flavor == 'win': | |
197 msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags) | |
198 extra_defines = msvs_settings.GetComputedDefines(config_name) | |
199 else: | |
200 extra_defines = [] | |
162 if config_name in target['configurations']: | 201 if config_name in target['configurations']: |
163 config = target['configurations'][config_name] | 202 config = target['configurations'][config_name] |
164 for define in config['defines']: | 203 target_defines = config['defines'] |
165 split_define = define.split('=', 1) | 204 else: |
166 if len(split_define) == 1: | 205 target_defines = [] |
167 split_define.append('1') | 206 for define in target_defines + extra_defines: |
168 if split_define[0].strip() in all_defines: | 207 split_define = define.split('=', 1) |
169 # Already defined | 208 if len(split_define) == 1: |
170 continue | 209 split_define.append('1') |
171 | 210 if split_define[0].strip() in all_defines: |
172 all_defines[split_define[0].strip()] = split_define[1].strip() | 211 # Already defined |
173 | 212 continue |
213 all_defines[split_define[0].strip()] = split_define[1].strip() | |
174 # Get default compiler defines (if possible). | 214 # Get default compiler defines (if possible). |
215 if flavor == 'win': | |
216 return all_defines # Default defines already processed in the loop above. | |
175 cc_target = GetCompilerPath(target_list, target_dicts, data) | 217 cc_target = GetCompilerPath(target_list, target_dicts, data) |
176 if cc_target: | 218 if cc_target: |
177 command = shlex.split(cc_target) | 219 command = shlex.split(cc_target) |
178 command.extend(['-E', '-dM', '-']) | 220 command.extend(['-E', '-dM', '-']) |
179 cpp_proc = subprocess.Popen(args=command, cwd='.', | 221 cpp_proc = subprocess.Popen(args=command, cwd='.', |
180 stdin=subprocess.PIPE, stdout=subprocess.PIPE) | 222 stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
181 cpp_output = cpp_proc.communicate()[0] | 223 cpp_output = cpp_proc.communicate()[0] |
182 cpp_lines = cpp_output.split('\n') | 224 cpp_lines = cpp_output.split('\n') |
183 for cpp_line in cpp_lines: | 225 for cpp_line in cpp_lines: |
184 if not cpp_line.strip(): | 226 if not cpp_line.strip(): |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 if not os.path.exists(toplevel_build): | 285 if not os.path.exists(toplevel_build): |
244 os.makedirs(toplevel_build) | 286 os.makedirs(toplevel_build) |
245 out = open(os.path.join(toplevel_build, 'eclipse-cdt-settings.xml'), 'w') | 287 out = open(os.path.join(toplevel_build, 'eclipse-cdt-settings.xml'), 'w') |
246 | 288 |
247 out.write('<?xml version="1.0" encoding="UTF-8"?>\n') | 289 out.write('<?xml version="1.0" encoding="UTF-8"?>\n') |
248 out.write('<cdtprojectproperties>\n') | 290 out.write('<cdtprojectproperties>\n') |
249 | 291 |
250 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File', | 292 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File', |
251 'GNU C++', 'GNU C', 'Assembly'] | 293 'GNU C++', 'GNU C', 'Assembly'] |
252 include_dirs = GetAllIncludeDirectories(target_list, target_dicts, | 294 include_dirs = GetAllIncludeDirectories(target_list, target_dicts, |
253 shared_intermediate_dirs, config_name) | 295 shared_intermediate_dirs, config_name, |
296 params) | |
254 WriteIncludePaths(out, eclipse_langs, include_dirs) | 297 WriteIncludePaths(out, eclipse_langs, include_dirs) |
255 defines = GetAllDefines(target_list, target_dicts, data, config_name) | 298 defines = GetAllDefines(target_list, target_dicts, data, config_name, params) |
256 WriteMacros(out, eclipse_langs, defines) | 299 WriteMacros(out, eclipse_langs, defines) |
257 | 300 |
258 out.write('</cdtprojectproperties>\n') | 301 out.write('</cdtprojectproperties>\n') |
259 out.close() | 302 out.close() |
260 | 303 |
261 | 304 |
262 def GenerateOutput(target_list, target_dicts, data, params): | 305 def GenerateOutput(target_list, target_dicts, data, params): |
263 """Generate an XML settings file that can be imported into a CDT project.""" | 306 """Generate an XML settings file that can be imported into a CDT project.""" |
264 | 307 |
265 if params['options'].generator_output: | 308 if params['options'].generator_output: |
266 raise NotImplementedError, "--generator_output not implemented for eclipse" | 309 raise NotImplementedError, "--generator_output not implemented for eclipse" |
267 | 310 |
268 user_config = params.get('generator_flags', {}).get('config', None) | 311 user_config = params.get('generator_flags', {}).get('config', None) |
269 if user_config: | 312 if user_config: |
270 GenerateOutputForConfig(target_list, target_dicts, data, params, | 313 GenerateOutputForConfig(target_list, target_dicts, data, params, |
271 user_config) | 314 user_config) |
272 else: | 315 else: |
273 config_names = target_dicts[target_list[0]]['configurations'].keys() | 316 config_names = target_dicts[target_list[0]]['configurations'].keys() |
274 for config_name in config_names: | 317 for config_name in config_names: |
275 GenerateOutputForConfig(target_list, target_dicts, data, params, | 318 GenerateOutputForConfig(target_list, target_dicts, data, params, |
276 config_name) | 319 config_name) |
277 | 320 |
OLD | NEW |