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 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 def CalculateGeneratorInputInfo(params): | 70 def CalculateGeneratorInputInfo(params): |
71 """Calculate the generator specific info that gets fed to input (called by | 71 """Calculate the generator specific info that gets fed to input (called by |
72 gyp).""" | 72 gyp).""" |
73 generator_flags = params.get('generator_flags', {}) | 73 generator_flags = params.get('generator_flags', {}) |
74 if generator_flags.get('adjust_static_libraries', False): | 74 if generator_flags.get('adjust_static_libraries', False): |
75 global generator_wants_static_library_dependencies_adjusted | 75 global generator_wants_static_library_dependencies_adjusted |
76 generator_wants_static_library_dependencies_adjusted = True | 76 generator_wants_static_library_dependencies_adjusted = True |
77 | 77 |
78 | 78 |
79 def GetAllIncludeDirectories(target_list, target_dicts, | 79 def GetAllIncludeDirectories(target_list, target_dicts, |
80 shared_intermediate_dirs, config_name, params): | 80 shared_intermediate_dirs, config_name, params, |
| 81 compiler_path): |
81 """Calculate the set of include directories to be used. | 82 """Calculate the set of include directories to be used. |
82 | 83 |
83 Returns: | 84 Returns: |
84 A list including all the include_dir's specified for every target followed | 85 A list including all the include_dir's specified for every target followed |
85 by any include directories that were added as cflag compiler options. | 86 by any include directories that were added as cflag compiler options. |
86 """ | 87 """ |
87 | 88 |
88 gyp_includes_set = set() | 89 gyp_includes_set = set() |
89 compiler_includes_list = [] | 90 compiler_includes_list = [] |
90 | 91 |
| 92 # Find compiler's default include dirs. |
| 93 if compiler_path: |
| 94 command = shlex.split(compiler_path) |
| 95 command.extend(['-E', '-xc++', '-v', '-']) |
| 96 proc = subprocess.Popen(args=command, stdin=subprocess.PIPE, |
| 97 stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 98 output = proc.communicate()[1] |
| 99 # Extract the list of include dirs from the output, which has this format: |
| 100 # ... |
| 101 # #include "..." search starts here: |
| 102 # #include <...> search starts here: |
| 103 # /usr/include/c++/4.6 |
| 104 # /usr/local/include |
| 105 # End of search list. |
| 106 # ... |
| 107 in_include_list = False |
| 108 for line in output.splitlines(): |
| 109 if line.startswith('#include'): |
| 110 in_include_list = True |
| 111 continue |
| 112 if line.startswith('End of search list.'): |
| 113 break |
| 114 if in_include_list: |
| 115 include_dir = line.strip() |
| 116 if include_dir not in compiler_includes_list: |
| 117 compiler_includes_list.append(include_dir) |
| 118 |
91 flavor = gyp.common.GetFlavor(params) | 119 flavor = gyp.common.GetFlavor(params) |
92 if flavor == 'win': | 120 if flavor == 'win': |
93 generator_flags = params.get('generator_flags', {}) | 121 generator_flags = params.get('generator_flags', {}) |
94 for target_name in target_list: | 122 for target_name in target_list: |
95 target = target_dicts[target_name] | 123 target = target_dicts[target_name] |
96 if config_name in target['configurations']: | 124 if config_name in target['configurations']: |
97 config = target['configurations'][config_name] | 125 config = target['configurations'][config_name] |
98 | 126 |
99 # Look for any include dirs that were explicitly added via cflags. This | 127 # Look for any include dirs that were explicitly added via cflags. This |
100 # may be done in gyp files to force certain includes to come at the end. | 128 # may be done in gyp files to force certain includes to come at the end. |
101 # TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and | 129 # TODO(jgreenwald): Change the gyp files to not abuse cflags for this, and |
102 # remove this. | 130 # remove this. |
103 if flavor == 'win': | 131 if flavor == 'win': |
104 msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags) | 132 msvs_settings = gyp.msvs_emulation.MsvsSettings(target, generator_flags) |
105 cflags = msvs_settings.GetCflags(config_name) | 133 cflags = msvs_settings.GetCflags(config_name) |
106 else: | 134 else: |
107 cflags = config['cflags'] | 135 cflags = config['cflags'] |
108 for cflag in cflags: | 136 for cflag in cflags: |
109 include_dir = '' | |
110 if cflag.startswith('-I'): | 137 if cflag.startswith('-I'): |
111 include_dir = cflag[2:] | 138 include_dir = cflag[2:] |
112 if include_dir and not include_dir in compiler_includes_list: | 139 if include_dir not in compiler_includes_list: |
113 compiler_includes_list.append(include_dir) | 140 compiler_includes_list.append(include_dir) |
114 | 141 |
115 # Find standard gyp include dirs. | 142 # Find standard gyp include dirs. |
116 if config.has_key('include_dirs'): | 143 if config.has_key('include_dirs'): |
117 include_dirs = config['include_dirs'] | 144 include_dirs = config['include_dirs'] |
118 for shared_intermediate_dir in shared_intermediate_dirs: | 145 for shared_intermediate_dir in shared_intermediate_dirs: |
119 for include_dir in include_dirs: | 146 for include_dir in include_dirs: |
120 include_dir = include_dir.replace('$SHARED_INTERMEDIATE_DIR', | 147 include_dir = include_dir.replace('$SHARED_INTERMEDIATE_DIR', |
121 shared_intermediate_dir) | 148 shared_intermediate_dir) |
122 if not os.path.isabs(include_dir): | 149 if not os.path.isabs(include_dir): |
123 base_dir = os.path.dirname(target_name) | 150 base_dir = os.path.dirname(target_name) |
124 | 151 |
125 include_dir = base_dir + '/' + include_dir | 152 include_dir = base_dir + '/' + include_dir |
126 include_dir = os.path.abspath(include_dir) | 153 include_dir = os.path.abspath(include_dir) |
127 | 154 |
128 if not include_dir in gyp_includes_set: | 155 gyp_includes_set.add(include_dir) |
129 gyp_includes_set.add(include_dir) | |
130 | |
131 | 156 |
132 # Generate a list that has all the include dirs. | 157 # Generate a list that has all the include dirs. |
133 all_includes_list = list(gyp_includes_set) | 158 all_includes_list = list(gyp_includes_set) |
134 all_includes_list.sort() | 159 all_includes_list.sort() |
135 for compiler_include in compiler_includes_list: | 160 for compiler_include in compiler_includes_list: |
136 if not compiler_include in gyp_includes_set: | 161 if not compiler_include in gyp_includes_set: |
137 all_includes_list.append(compiler_include) | 162 all_includes_list.append(compiler_include) |
138 | 163 |
139 # All done. | 164 # All done. |
140 return all_includes_list | 165 return all_includes_list |
141 | 166 |
142 | 167 |
143 def GetCompilerPath(target_list, target_dicts, data): | 168 def GetCompilerPath(target_list, data): |
144 """Determine a command that can be used to invoke the compiler. | 169 """Determine a command that can be used to invoke the compiler. |
145 | 170 |
146 Returns: | 171 Returns: |
147 If this is a gyp project that has explicit make settings, try to determine | 172 If this is a gyp project that has explicit make settings, try to determine |
148 the compiler from that. Otherwise, see if a compiler was specified via the | 173 the compiler from that. Otherwise, see if a compiler was specified via the |
149 CC_target environment variable. | 174 CC_target environment variable. |
150 """ | 175 """ |
151 | 176 |
152 # First, see if the compiler is configured in make's settings. | 177 # First, see if the compiler is configured in make's settings. |
153 build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) | 178 build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) |
154 make_global_settings_dict = data[build_file].get('make_global_settings', {}) | 179 make_global_settings_dict = data[build_file].get('make_global_settings', {}) |
155 for key, value in make_global_settings_dict: | 180 for key, value in make_global_settings_dict: |
156 if key in ['CC', 'CXX']: | 181 if key in ['CC', 'CXX']: |
157 return value | 182 return value |
158 | 183 |
159 # Check to see if the compiler was specified as an environment variable. | 184 # Check to see if the compiler was specified as an environment variable. |
160 for key in ['CC_target', 'CC', 'CXX']: | 185 for key in ['CC_target', 'CC', 'CXX']: |
161 compiler = os.environ.get(key) | 186 compiler = os.environ.get(key) |
162 if compiler: | 187 if compiler: |
163 return compiler | 188 return compiler |
164 | 189 |
165 return 'gcc' | 190 return 'gcc' |
166 | 191 |
167 | 192 |
168 def GetAllDefines(target_list, target_dicts, data, config_name, params): | 193 def GetAllDefines(target_list, target_dicts, data, config_name, params, |
| 194 compiler_path): |
169 """Calculate the defines for a project. | 195 """Calculate the defines for a project. |
170 | 196 |
171 Returns: | 197 Returns: |
172 A dict that includes explict defines declared in gyp files along with all of | 198 A dict that includes explict defines declared in gyp files along with all of |
173 the default defines that the compiler uses. | 199 the default defines that the compiler uses. |
174 """ | 200 """ |
175 | 201 |
176 # Get defines declared in the gyp files. | 202 # Get defines declared in the gyp files. |
177 all_defines = {} | 203 all_defines = {} |
178 flavor = gyp.common.GetFlavor(params) | 204 flavor = gyp.common.GetFlavor(params) |
(...skipping 16 matching lines...) Expand all Loading... |
195 split_define = define.split('=', 1) | 221 split_define = define.split('=', 1) |
196 if len(split_define) == 1: | 222 if len(split_define) == 1: |
197 split_define.append('1') | 223 split_define.append('1') |
198 if split_define[0].strip() in all_defines: | 224 if split_define[0].strip() in all_defines: |
199 # Already defined | 225 # Already defined |
200 continue | 226 continue |
201 all_defines[split_define[0].strip()] = split_define[1].strip() | 227 all_defines[split_define[0].strip()] = split_define[1].strip() |
202 # Get default compiler defines (if possible). | 228 # Get default compiler defines (if possible). |
203 if flavor == 'win': | 229 if flavor == 'win': |
204 return all_defines # Default defines already processed in the loop above. | 230 return all_defines # Default defines already processed in the loop above. |
205 cc_target = GetCompilerPath(target_list, target_dicts, data) | 231 if compiler_path: |
206 if cc_target: | 232 command = shlex.split(compiler_path) |
207 command = shlex.split(cc_target) | |
208 command.extend(['-E', '-dM', '-']) | 233 command.extend(['-E', '-dM', '-']) |
209 cpp_proc = subprocess.Popen(args=command, cwd='.', | 234 cpp_proc = subprocess.Popen(args=command, cwd='.', |
210 stdin=subprocess.PIPE, stdout=subprocess.PIPE) | 235 stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
211 cpp_output = cpp_proc.communicate()[0] | 236 cpp_output = cpp_proc.communicate()[0] |
212 cpp_lines = cpp_output.split('\n') | 237 cpp_lines = cpp_output.split('\n') |
213 for cpp_line in cpp_lines: | 238 for cpp_line in cpp_lines: |
214 if not cpp_line.strip(): | 239 if not cpp_line.strip(): |
215 continue | 240 continue |
216 cpp_line_parts = cpp_line.split(' ', 2) | 241 cpp_line_parts = cpp_line.split(' ', 2) |
217 key = cpp_line_parts[1] | 242 key = cpp_line_parts[1] |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 | 297 |
273 out_name = os.path.join(toplevel_build, 'eclipse-cdt-settings.xml') | 298 out_name = os.path.join(toplevel_build, 'eclipse-cdt-settings.xml') |
274 gyp.common.EnsureDirExists(out_name) | 299 gyp.common.EnsureDirExists(out_name) |
275 out = open(out_name, 'w') | 300 out = open(out_name, 'w') |
276 | 301 |
277 out.write('<?xml version="1.0" encoding="UTF-8"?>\n') | 302 out.write('<?xml version="1.0" encoding="UTF-8"?>\n') |
278 out.write('<cdtprojectproperties>\n') | 303 out.write('<cdtprojectproperties>\n') |
279 | 304 |
280 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File', | 305 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File', |
281 'GNU C++', 'GNU C', 'Assembly'] | 306 'GNU C++', 'GNU C', 'Assembly'] |
| 307 compiler_path = GetCompilerPath(target_list, data) |
282 include_dirs = GetAllIncludeDirectories(target_list, target_dicts, | 308 include_dirs = GetAllIncludeDirectories(target_list, target_dicts, |
283 shared_intermediate_dirs, config_name, | 309 shared_intermediate_dirs, config_name, |
284 params) | 310 params, compiler_path) |
285 WriteIncludePaths(out, eclipse_langs, include_dirs) | 311 WriteIncludePaths(out, eclipse_langs, include_dirs) |
286 defines = GetAllDefines(target_list, target_dicts, data, config_name, params) | 312 defines = GetAllDefines(target_list, target_dicts, data, config_name, params, |
| 313 compiler_path) |
287 WriteMacros(out, eclipse_langs, defines) | 314 WriteMacros(out, eclipse_langs, defines) |
288 | 315 |
289 out.write('</cdtprojectproperties>\n') | 316 out.write('</cdtprojectproperties>\n') |
290 out.close() | 317 out.close() |
291 | 318 |
292 | 319 |
293 def GenerateOutput(target_list, target_dicts, data, params): | 320 def GenerateOutput(target_list, target_dicts, data, params): |
294 """Generate an XML settings file that can be imported into a CDT project.""" | 321 """Generate an XML settings file that can be imported into a CDT project.""" |
295 | 322 |
296 if params['options'].generator_output: | 323 if params['options'].generator_output: |
297 raise NotImplementedError, "--generator_output not implemented for eclipse" | 324 raise NotImplementedError, "--generator_output not implemented for eclipse" |
298 | 325 |
299 user_config = params.get('generator_flags', {}).get('config', None) | 326 user_config = params.get('generator_flags', {}).get('config', None) |
300 if user_config: | 327 if user_config: |
301 GenerateOutputForConfig(target_list, target_dicts, data, params, | 328 GenerateOutputForConfig(target_list, target_dicts, data, params, |
302 user_config) | 329 user_config) |
303 else: | 330 else: |
304 config_names = target_dicts[target_list[0]]['configurations'].keys() | 331 config_names = target_dicts[target_list[0]]['configurations'].keys() |
305 for config_name in config_names: | 332 for config_name in config_names: |
306 GenerateOutputForConfig(target_list, target_dicts, data, params, | 333 GenerateOutputForConfig(target_list, target_dicts, data, params, |
307 config_name) | 334 config_name) |
308 | 335 |
OLD | NEW |