OLD | NEW |
---|---|
(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 """ | |
Nico
2012/04/16 17:21:52
Since you don't intend this to be generally useful
Jesse Greenwald
2012/04/27 17:12:29
Done.
| |
11 | |
12 import os.path | |
13 import subprocess | |
14 import gyp | |
15 import gyp.common | |
16 import shlex | |
17 | |
18 generator_wants_static_library_dependencies_adjusted = False | |
19 | |
20 generator_default_variables = { | |
21 } | |
22 | |
23 for dirname in ['INTERMEDIATE_DIR', 'PRODUCT_DIR', 'LIB_DIR', 'SHARED_LIB_DIR']: | |
24 # Some gyp steps fail if these are empty(!). | |
25 generator_default_variables[dirname] = 'dir' | |
26 | |
27 for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME', | |
28 'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT', | |
29 'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX', | |
30 'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX', | |
31 'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX']: | |
32 generator_default_variables[unused] = '' | |
33 | |
34 # Include dirs will occasionaly use the SHARED_INTERMEDIATE_DIR variable as | |
35 # part of the path when dealing with generated headers. | |
36 # TODO: Make this work for all gyp generators (possible?). This currently | |
37 # matches what make gyp generator does. | |
38 generator_default_variables['SHARED_INTERMEDIATE_DIR'] = \ | |
39 os.getcwd() + '/out/Release/obj/gen' | |
Nico
2012/04/16 17:21:52
If this supports just one configuration, maybe you
Jesse Greenwald
2012/04/27 17:12:29
I've updated it to match the ninja generator behav
| |
40 | |
41 | |
42 def CalculateVariables(default_variables, params): | |
43 generator_flags = params.get('generator_flags', {}) | |
44 for key, val in generator_flags.items(): | |
45 default_variables.setdefault(key, val) | |
46 default_variables.setdefault('OS', gyp.common.GetFlavor(params)) | |
47 | |
48 | |
49 def CalculateGeneratorInputInfo(params): | |
50 """Calculate the generator specific info that gets fed to input (called by | |
51 gyp).""" | |
52 generator_flags = params.get('generator_flags', {}) | |
53 if generator_flags.get('adjust_static_libraries', False): | |
54 global generator_wants_static_library_dependencies_adjusted | |
55 generator_wants_static_library_dependencies_adjusted = True | |
56 | |
57 | |
58 def GetAllIncludeDirs(target_list, target_dicts): | |
59 """Calculate the set of include dirs to be used. | |
60 | |
61 Returns: | |
62 A list including all the include_dir's specified for every target followed | |
63 by any incude dirs that were added as cflag compiler options. | |
Nico
2012/04/16 16:12:12
typo incude
Jesse Greenwald
2012/04/16 17:00:55
Done.
| |
64 """ | |
65 | |
66 gyp_includes = [] | |
67 compiler_includes = [] | |
68 | |
69 for target_name in target_list: | |
70 target = target_dicts[target_name] | |
71 | |
72 for _, config in target['configurations'].iteritems(): | |
73 | |
74 # Look for any include dirs that were explicitly added via cflags. This | |
75 # may be done in gyp files to force certain includes to come at the end. | |
76 cflags = config['cflags'] | |
Nico
2012/04/16 16:12:12
'cflags' is linux-specific. It shouldn't be used t
Jesse Greenwald
2012/04/16 17:00:55
That makes sense.. but unfortunately this is being
Nico
2012/04/16 17:21:52
build/common.gypi could be changed though, right?
Jesse Greenwald
2012/04/27 17:12:29
It could probably be fixed at some point, although
| |
77 for cflag in cflags: | |
78 include_dir = '' | |
79 if cflag.startswith('-I'): | |
80 include_dir = cflag[2:] | |
81 if include_dir and not include_dir in compiler_includes: | |
82 compiler_includes.append(include_dir) | |
83 | |
84 # Find standard gyp include dirs | |
Nico
2012/04/16 16:12:12
add trailing .
Jesse Greenwald
2012/04/16 17:00:55
Done.
| |
85 if config.has_key('include_dirs'): | |
86 include_dirs = config['include_dirs'] | |
87 for include_dir in include_dirs: | |
88 if not os.path.isabs(include_dir): | |
89 base_dir = os.path.dirname(target_name) | |
90 | |
91 include_dir = base_dir + '/' + include_dir | |
92 include_dir = os.path.abspath(include_dir) | |
93 | |
94 if not include_dir in gyp_includes: | |
95 gyp_includes.append(include_dir) | |
96 | |
97 gyp_includes.sort() | |
98 | |
99 # Generate a list that has all the include dirs | |
100 all_includes = list(gyp_includes) | |
101 for compiler_include in compiler_includes: | |
102 if not compiler_include in all_includes: | |
103 all_includes.append(compiler_include) | |
104 | |
105 # All done | |
106 return all_includes | |
107 | |
108 | |
109 def GetCompilerPath(target_list, target_dicts, data): | |
110 """Determine a command that can be used to invoke the compiler. | |
111 | |
112 Returns: | |
113 If this is a gyp project that has explicit make settings, try to determine | |
114 the compiler from that. Otherwise, see if a compiler was specified via the | |
115 CC_target environment variable. | |
116 """ | |
117 | |
118 # First, see if the compiler is configured in make's settings | |
119 build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0]) | |
120 make_global_settings_dict = data[build_file].get('make_global_settings', {}) | |
121 for key, value in make_global_settings_dict: | |
122 if key in ['CC', 'CXX']: | |
123 return value | |
124 | |
125 # Check to see if the compiler was specified as an environment variable | |
126 cc_target = os.environ.get('CC_target') | |
127 if cc_target: | |
128 return cc_target | |
129 | |
130 # Default | |
131 return 'gcc' | |
132 | |
133 | |
134 def GetAllDefines(target_list, target_dicts, data): | |
135 """Calculate the defines for a project. | |
136 | |
137 Returns: | |
138 A dict that includes explict defines declared in gyp files along with all of | |
139 the default defines that the compiler uses. | |
140 """ | |
141 | |
142 # Get defines declared in the gyp files | |
143 all_defines = {} | |
144 for target_name in target_list: | |
145 target = target_dicts[target_name] | |
146 | |
147 for _, config in target['configurations'].iteritems(): | |
148 for define in config['defines']: | |
149 split_define = define.split('=', 1) | |
150 if len(split_define) == 1: | |
151 split_define.append('1') | |
152 if split_define[0].strip() in all_defines: | |
153 # Already defined | |
154 continue | |
155 | |
156 all_defines[split_define[0].strip()] = split_define[1].strip() | |
157 | |
158 # Get default compiler defines (if possible) | |
159 cc_target = GetCompilerPath(target_list, target_dicts, data) | |
160 if cc_target: | |
161 command = shlex.split(cc_target) | |
162 command.extend(['-E', '-dM', '-']) | |
163 cpp_proc = subprocess.Popen(args=command, cwd='.', | |
164 stdin=subprocess.PIPE, stdout=subprocess.PIPE) | |
165 cpp_output = cpp_proc.communicate()[0] | |
166 cpp_lines = cpp_output.split('\n') | |
167 for cpp_line in cpp_lines: | |
168 if not cpp_line.strip(): | |
169 continue | |
170 cpp_line_parts = cpp_line.split(' ', 2) | |
171 key = cpp_line_parts[1] | |
172 if len(cpp_line_parts) >= 3: | |
173 val = cpp_line_parts[2] | |
174 else: | |
175 val = '1' | |
176 all_defines[key] = val | |
177 | |
178 return all_defines | |
179 | |
180 | |
181 def WriteIncludePaths(out, eclipse_langs, include_dirs): | |
182 """Write the includes section of a CDT settings export file.""" | |
183 | |
184 out.write(' <section name="org.eclipse.cdt.internal.ui.wizards.' \ | |
185 'settingswizards.IncludePaths">\n') | |
186 out.write(' <language name="holder for library settings"></language>\n') | |
187 for lang in eclipse_langs: | |
188 out.write(' <language name="%s">\n' % lang) | |
189 for include_dir in include_dirs: | |
190 out.write(' <includepath workspace_path="false">%s</includepath>\n' % | |
191 include_dir) | |
192 out.write(' </language>\n') | |
193 out.write(' </section>\n') | |
194 | |
195 | |
196 def WriteMacros(out, eclipse_langs, defines): | |
197 """Write the macros section of a CDT settings export file.""" | |
198 | |
199 out.write(' <section name="org.eclipse.cdt.internal.ui.wizards.' \ | |
200 'settingswizards.Macros">\n') | |
201 out.write(' <language name="holder for library settings"></language>\n') | |
202 for lang in eclipse_langs: | |
203 out.write(' <language name="%s">\n' % lang) | |
204 for key in sorted(defines.iterkeys()): | |
205 out.write(' <macro><name>%s</name><value>%s</value></macro>\n' % | |
206 (key, defines[key])) | |
207 out.write(' </language>\n') | |
208 out.write(' </section>\n') | |
209 | |
210 | |
211 def GenerateOutput(target_list, target_dicts, data, params): | |
212 """Generate an XML settings file that can be imported into a CDT project.""" | |
213 | |
Nico
2012/04/16 17:21:52
You might want to print a warning or error if any
Jesse Greenwald
2012/04/27 17:12:29
Done.
| |
214 out = open('eclipse-cdt-settings.xml', 'w') | |
215 | |
216 out.write('<?xml version="1.0" encoding="UTF-8"?>\n') | |
217 out.write('<cdtprojectproperties>\n') | |
218 | |
219 eclipse_langs = ['C++ Source File', 'C Source File', 'Assembly Source File', | |
220 'GNU C++', 'GNU C', 'Assembly'] | |
221 WriteIncludePaths(out, eclipse_langs, | |
222 GetAllIncludeDirs(target_list, target_dicts)) | |
223 WriteMacros(out, eclipse_langs, GetAllDefines(target_list, target_dicts, | |
Nico
2012/04/16 16:12:12
This looks like it sets all defines from all targe
Jesse Greenwald
2012/04/16 17:00:55
The settings.xml file that gets generated isn't pe
| |
224 data)) | |
225 | |
226 out.write('</cdtprojectproperties>\n') | |
227 out.close() | |
OLD | NEW |