Imported Upstream version 0.1~svn917
Giuseppe Iuculano
13 years ago
3 | 3 | |
4 | 4 | deps = { |
5 | 5 | "scons": |
6 | "svn://chrome-svn.corp.google.com/chrome/trunk/src/third_party/scons", | |
6 | "http://src.chromium.org/svn/trunk/src/third_party/scons@44099", | |
7 | 7 | } |
0 | # Copyright 2010, Google Inc. | |
1 | # All rights reserved. | |
2 | # | |
3 | # Redistribution and use in source and binary forms, with or without | |
4 | # modification, are permitted provided that the following conditions are | |
5 | # met: | |
6 | # | |
7 | # * Redistributions of source code must retain the above copyright | |
8 | # notice, this list of conditions and the following disclaimer. | |
9 | # * Redistributions in binary form must reproduce the above | |
10 | # copyright notice, this list of conditions and the following disclaimer | |
11 | # in the documentation and/or other materials provided with the | |
12 | # distribution. | |
13 | # * Neither the name of Google Inc. nor the names of its | |
14 | # contributors may be used to endorse or promote products derived from | |
15 | # this software without specific prior written permission. | |
16 | # | |
17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
18 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
19 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
20 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
21 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
23 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
27 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
0 | # Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
28 | 3 | |
29 | 4 | |
30 | EXCLUDED_PATHS = () | |
5 | """Top-level presubmit script for GYP. | |
6 | ||
7 | See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts | |
8 | for more details about the presubmit API built into gcl. | |
9 | """ | |
31 | 10 | |
32 | 11 | |
33 | 12 | def CheckChangeOnUpload(input_api, output_api): |
34 | 13 | report = [] |
35 | black_list = input_api.DEFAULT_BLACK_LIST + EXCLUDED_PATHS | |
36 | sources = lambda x: input_api.FilterSourceFile(x, black_list=black_list) | |
37 | report.extend(input_api.canned_checks.CheckChangeSvnEolStyle( | |
38 | input_api, output_api, sources)) | |
14 | report.extend(input_api.canned_checks.PanProjectChecks( | |
15 | input_api, output_api)) | |
39 | 16 | return report |
40 | 17 | |
41 | 18 | |
42 | 19 | def CheckChangeOnCommit(input_api, output_api): |
43 | 20 | report = [] |
44 | black_list = input_api.DEFAULT_BLACK_LIST + EXCLUDED_PATHS | |
45 | sources = lambda x: input_api.FilterSourceFile(x, black_list=black_list) | |
46 | report.extend(input_api.canned_checks.CheckChangeSvnEolStyle( | |
47 | input_api, output_api, sources)) | |
21 | report.extend(input_api.canned_checks.PanProjectChecks( | |
22 | input_api, output_api)) | |
48 | 23 | report.extend(input_api.canned_checks.CheckTreeIsOpen( |
49 | 24 | input_api, output_api, |
50 | 25 | 'http://gyp-status.appspot.com/status', |
51 | 26 | 'http://gyp-status.appspot.com/current')) |
52 | 27 | return report |
28 | ||
29 | ||
30 | def GetPreferredTrySlaves(): | |
31 | return ['gyp-win32', 'gyp-win64', 'gyp-linux', 'gyp-mac'] |
0 | #!/usr/bin/python | |
1 | # Copyright (c) 2011 The Chromium Authors. 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 | ||
6 | """Argument-less script to select what to run on the buildbots.""" | |
7 | ||
8 | ||
9 | import os | |
10 | import subprocess | |
11 | import sys | |
12 | ||
13 | ||
14 | def GypTestFormat(title, format, msvs_version=None): | |
15 | """Run the gyp tests for a given format, emitting annotator tags. | |
16 | ||
17 | See annotator docs at: | |
18 | https://sites.google.com/a/chromium.org/dev/developers/testing/chromium-build-infrastructure/buildbot-annotations | |
19 | Args: | |
20 | format: gyp format to test. | |
21 | Returns: | |
22 | 0 for sucesss, 1 for failure. | |
23 | """ | |
24 | print '@@@BUILD_STEP ' + title + '@@@' | |
25 | sys.stdout.flush() | |
26 | buildbot_dir = os.path.dirname(os.path.abspath(__file__)) | |
27 | trunk_dir = os.path.dirname(buildbot_dir) | |
28 | root_dir = os.path.dirname(trunk_dir) | |
29 | env = os.environ.copy() | |
30 | if msvs_version: | |
31 | env['GYP_MSVS_VERSION'] = msvs_version | |
32 | retcode = subprocess.call(' '.join( | |
33 | [sys.executable, 'trunk/gyptest.py', | |
34 | '--all', | |
35 | '--passed', | |
36 | '--format', format, | |
37 | '--chdir', 'trunk', | |
38 | '--path', '../scons']), | |
39 | cwd=root_dir, env=env, shell=True) | |
40 | if retcode: | |
41 | # Emit failure tag, and keep going. | |
42 | print '@@@STEP_FAILURE@@@' | |
43 | return 1 | |
44 | return 0 | |
45 | ||
46 | ||
47 | def GypBuild(): | |
48 | retcode = 0 | |
49 | if sys.platform in ['linux', 'linux2']: | |
50 | retcode += GypTestFormat('scons', format='scons') | |
51 | retcode += GypTestFormat('make', format='make') | |
52 | elif sys.platform == 'darwin': | |
53 | retcode += GypTestFormat('xcode', format='xcode') | |
54 | elif sys.platform == 'win32': | |
55 | retcode += GypTestFormat('msvs-2008', format='msvs', msvs_version='2008') | |
56 | if os.environ['BUILDBOT_BUILDERNAME'] == 'gyp-win64': | |
57 | retcode += GypTestFormat('msvs-2010', format='msvs', msvs_version='2010') | |
58 | else: | |
59 | raise Exception('Unknown platform') | |
60 | if retcode: | |
61 | # TODO(bradnelson): once the annotator supports a postscript (section for | |
62 | # after the build proper that could be used for cumulative failures), | |
63 | # use that instead of this. This isolates the final return value so | |
64 | # that it isn't misattributed to the last stage. | |
65 | print '@@@BUILD_STEP failures@@@' | |
66 | sys.exit(retcode) | |
67 | ||
68 | ||
69 | if __name__ == '__main__': | |
70 | GypBuild() |
8 | 8 | import common |
9 | 9 | import os |
10 | 10 | import random |
11 | ||
12 | import gyp.common | |
11 | 13 | |
12 | 14 | # hashlib is supplied as of Python 2.5 as the replacement interface for md5 |
13 | 15 | # and other secure hashes. In 2.6, md5 is deprecated. Import hashlib if |
104 | 106 | """Visual Studio project.""" |
105 | 107 | |
106 | 108 | def __init__(self, path, name = None, dependencies = None, guid = None, |
107 | config_platform_overrides = None): | |
109 | spec = None, build_file = None, config_platform_overrides = None, | |
110 | fixpath_prefix = None): | |
108 | 111 | """Initializes the project. |
109 | 112 | |
110 | 113 | Args: |
111 | path: Relative path to project file. | |
114 | path: Absolute path to the project file. | |
112 | 115 | name: Name of project. If None, the name will be the same as the base |
113 | 116 | name of the project file. |
114 | 117 | dependencies: List of other Project objects this project is dependent |
115 | 118 | upon, if not None. |
116 | 119 | guid: GUID to use for project, if not None. |
120 | spec: Dictionary specifying how to build this project. | |
121 | build_file: Filename of the .gyp file that the vcproj file comes from. | |
117 | 122 | config_platform_overrides: optional dict of configuration platforms to |
118 | 123 | used in place of the default for this target. |
124 | fixpath_prefix: the path used to adjust the behavior of _fixpath | |
119 | 125 | """ |
120 | 126 | self.path = path |
121 | 127 | self.guid = guid |
122 | ||
123 | if name: | |
124 | self.name = name | |
125 | else: | |
126 | # Use project filename | |
127 | self.name = os.path.splitext(os.path.basename(path))[0] | |
128 | self.spec = spec | |
129 | self.build_file = build_file | |
130 | # Use project filename if name not specified | |
131 | self.name = name or os.path.splitext(os.path.basename(path))[0] | |
128 | 132 | |
129 | 133 | # Copy passed lists (or set to empty lists) |
130 | 134 | self.dependencies = list(dependencies or []) |
135 | 139 | self.config_platform_overrides = config_platform_overrides |
136 | 140 | else: |
137 | 141 | self.config_platform_overrides = {} |
138 | ||
142 | self.fixpath_prefix = fixpath_prefix | |
143 | ||
144 | def set_dependencies(self, dependencies): | |
145 | self.dependencies = list(dependencies or []) | |
146 | ||
139 | 147 | def get_guid(self): |
140 | 148 | if self.guid is None: |
141 | 149 | # Set GUID from path |
240 | 248 | f.write('# %s\r\n' % self.version.Description()) |
241 | 249 | |
242 | 250 | # Project entries |
251 | sln_root = os.path.split(self.path)[0] | |
243 | 252 | for e in all_entries: |
253 | relative_path = gyp.common.RelativePath(e.path, sln_root) | |
244 | 254 | f.write('Project("%s") = "%s", "%s", "%s"\r\n' % ( |
245 | 255 | e.entry_type_guid, # Entry type GUID |
246 | 256 | e.name, # Folder name |
247 | e.path.replace('/', '\\'), # Folder name (again) | |
257 | relative_path.replace('/', '\\'), # Folder name (again) | |
248 | 258 | e.get_guid(), # Entry GUID |
249 | 259 | )) |
250 | 260 |
7 | 7 | |
8 | 8 | import common |
9 | 9 | import xml.dom |
10 | import xml.dom.minidom | |
11 | import MSVSNew | |
10 | import xml_fix | |
12 | 11 | |
13 | 12 | #------------------------------------------------------------------------------ |
14 | 13 | |
81 | 80 | guid: GUID to use for project, if not None. |
82 | 81 | """ |
83 | 82 | self.name = name |
84 | self.guid = guid or MSVSNew.MakeGuid(self.project_path) | |
83 | self.guid = guid | |
85 | 84 | |
86 | 85 | # Default to Win32 for platforms. |
87 | 86 | if not platforms: |
237 | 236 | def Write(self, writer=common.WriteOnDiff): |
238 | 237 | """Writes the project file.""" |
239 | 238 | f = writer(self.project_path) |
239 | fix = xml_fix.XmlFix() | |
240 | 240 | self.doc.writexml(f, encoding='Windows-1252', addindent=' ', newl='\r\n') |
241 | fix.Cleanup() | |
241 | 242 | f.close() |
242 | 243 | |
243 | 244 | #------------------------------------------------------------------------------ |
0 | #!/usr/bin/python | |
1 | # Copyright (c) 2011 The Chromium Authors. 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 | """Code to validate and convert settings of the Microsoft build tools. | |
6 | ||
7 | This file contains code to validate and convert settings of the Microsoft | |
8 | build tools. The function ConvertToMSBuildSettings(), ValidateMSVSSettings(), | |
9 | and ValidateMSBuildSettings() are the entry points. | |
10 | ||
11 | This file was created by comparing the projects created by Visual Studio 2008 | |
12 | and Visual Studio 2010 for all available settings through the user interface. | |
13 | The MSBuild schemas were also considered. They are typically found in the | |
14 | MSBuild install directory, e.g. c:\Program Files (x86)\MSBuild | |
15 | """ | |
16 | ||
17 | import sys | |
18 | ||
19 | ||
20 | # Dictionaries of settings validators. The key is the tool name, the value is | |
21 | # a dictionary mapping setting names to validation functions. | |
22 | _msvs_validators = {} | |
23 | _msbuild_validators = {} | |
24 | ||
25 | ||
26 | # A dictionary of settings converters. The key is the tool name, the value is | |
27 | # a dictionary mapping setting names to conversion functions. | |
28 | _msvs_to_msbuild_converters = {} | |
29 | ||
30 | ||
31 | # Tool name mapping from MSVS to MSBuild. | |
32 | _msbuild_name_of_tool = {} | |
33 | ||
34 | ||
35 | class _Tool(object): | |
36 | """Represents a tool used by MSVS or MSBuild. | |
37 | ||
38 | Attributes: | |
39 | msvs_name: The name of the tool in MSVS. | |
40 | msbuild_name: The name of the tool in MSBuild. | |
41 | """ | |
42 | ||
43 | def __init__(self, msvs_name, msbuild_name): | |
44 | self.msvs_name = msvs_name | |
45 | self.msbuild_name = msbuild_name | |
46 | ||
47 | ||
48 | def _AddTool(tool): | |
49 | """Adds a tool to the four dictionaries used to process settings. | |
50 | ||
51 | This only defines the tool. Each setting also needs to be added. | |
52 | ||
53 | Args: | |
54 | tool: The _Tool object to be added. | |
55 | """ | |
56 | _msvs_validators[tool.msvs_name] = {} | |
57 | _msbuild_validators[tool.msbuild_name] = {} | |
58 | _msvs_to_msbuild_converters[tool.msvs_name] = {} | |
59 | _msbuild_name_of_tool[tool.msvs_name] = tool.msbuild_name | |
60 | ||
61 | ||
62 | def _GetMSBuildToolSettings(msbuild_settings, tool): | |
63 | """Returns an MSBuild tool dictionary. Creates it if needed.""" | |
64 | return msbuild_settings.setdefault(tool.msbuild_name, {}) | |
65 | ||
66 | ||
67 | class _Type(object): | |
68 | """Type of settings (Base class).""" | |
69 | ||
70 | def ValidateMSVS(self, value): | |
71 | """Verifies that the value is legal for MSVS. | |
72 | ||
73 | Args: | |
74 | value: the value to check for this type. | |
75 | ||
76 | Raises: | |
77 | ValueError if value is not valid for MSVS. | |
78 | """ | |
79 | ||
80 | def ValidateMSBuild(self, value): | |
81 | """Verifies that the value is legal for MSBuild. | |
82 | ||
83 | Args: | |
84 | value: the value to check for this type. | |
85 | ||
86 | Raises: | |
87 | ValueError if value is not valid for MSBuild. | |
88 | """ | |
89 | ||
90 | def ConvertToMSBuild(self, value): | |
91 | """Returns the MSBuild equivalent of the MSVS value given. | |
92 | ||
93 | Args: | |
94 | value: the MSVS value to convert. | |
95 | ||
96 | Returns: | |
97 | the MSBuild equivalent. | |
98 | ||
99 | Raises: | |
100 | ValueError if value is not valid. | |
101 | """ | |
102 | return value | |
103 | ||
104 | ||
105 | class _String(_Type): | |
106 | """A setting that's just a string.""" | |
107 | ||
108 | def ValidateMSVS(self, value): | |
109 | if not isinstance(value, basestring): | |
110 | raise ValueError('expected string; got %r' % value) | |
111 | ||
112 | def ValidateMSBuild(self, value): | |
113 | if not isinstance(value, basestring): | |
114 | raise ValueError('expected string; got %r' % value) | |
115 | ||
116 | def ConvertToMSBuild(self, value): | |
117 | # Convert the macros | |
118 | return ConvertVCMacrosToMSBuild(value) | |
119 | ||
120 | ||
121 | class _StringList(_Type): | |
122 | """A settings that's a list of strings.""" | |
123 | ||
124 | def ValidateMSVS(self, value): | |
125 | if not isinstance(value, basestring) and not isinstance(value, list): | |
126 | raise ValueError('expected string list; got %r' % value) | |
127 | ||
128 | def ValidateMSBuild(self, value): | |
129 | if not isinstance(value, basestring) and not isinstance(value, list): | |
130 | raise ValueError('expected string list; got %r' % value) | |
131 | ||
132 | def ConvertToMSBuild(self, value): | |
133 | # Convert the macros | |
134 | if isinstance(value, list): | |
135 | return [ConvertVCMacrosToMSBuild(i) for i in value] | |
136 | else: | |
137 | return ConvertVCMacrosToMSBuild(value) | |
138 | ||
139 | ||
140 | class _Boolean(_Type): | |
141 | """Boolean settings, can have the values 'false' or 'true'.""" | |
142 | ||
143 | def _Validate(self, value): | |
144 | if value != 'true' and value != 'false': | |
145 | raise ValueError('expected bool; got %r' % value) | |
146 | ||
147 | def ValidateMSVS(self, value): | |
148 | self._Validate(value) | |
149 | ||
150 | def ValidateMSBuild(self, value): | |
151 | self._Validate(value) | |
152 | ||
153 | def ConvertToMSBuild(self, value): | |
154 | self._Validate(value) | |
155 | return value | |
156 | ||
157 | ||
158 | class _Integer(_Type): | |
159 | """Integer settings.""" | |
160 | ||
161 | def __init__(self, msbuild_base=10): | |
162 | _Type.__init__(self) | |
163 | self._msbuild_base = msbuild_base | |
164 | ||
165 | def ValidateMSVS(self, value): | |
166 | # Try to convert, this will raise ValueError if invalid. | |
167 | self.ConvertToMSBuild(value) | |
168 | ||
169 | def ValidateMSBuild(self, value): | |
170 | # Try to convert, this will raise ValueError if invalid. | |
171 | int(value, self._msbuild_base) | |
172 | ||
173 | def ConvertToMSBuild(self, value): | |
174 | msbuild_format = (self._msbuild_base == 10) and '%d' or '0x%04x' | |
175 | return msbuild_format % int(value) | |
176 | ||
177 | ||
178 | class _Enumeration(_Type): | |
179 | """Type of settings that is an enumeration. | |
180 | ||
181 | In MSVS, the values are indexes like '0', '1', and '2'. | |
182 | MSBuild uses text labels that are more representative, like 'Win32'. | |
183 | ||
184 | Constructor args: | |
185 | label_list: an array of MSBuild labels that correspond to the MSVS index. | |
186 | In the rare cases where MSVS has skipped an index value, None is | |
187 | used in the array to indicate the unused spot. | |
188 | new: an array of labels that are new to MSBuild. | |
189 | """ | |
190 | ||
191 | def __init__(self, label_list, new=None): | |
192 | _Type.__init__(self) | |
193 | self._label_list = label_list | |
194 | self._msbuild_values = set(value for value in label_list | |
195 | if value is not None) | |
196 | if new is not None: | |
197 | self._msbuild_values.update(new) | |
198 | ||
199 | def ValidateMSVS(self, value): | |
200 | # Try to convert. It will raise an exception if not valid. | |
201 | self.ConvertToMSBuild(value) | |
202 | ||
203 | def ValidateMSBuild(self, value): | |
204 | if value not in self._msbuild_values: | |
205 | raise ValueError('unrecognized enumerated value %s' % value) | |
206 | ||
207 | def ConvertToMSBuild(self, value): | |
208 | index = int(value) | |
209 | if index < 0 or index >= len(self._label_list): | |
210 | raise ValueError('index value (%d) not in expected range [0, %d)' % | |
211 | (index, len(self._label_list))) | |
212 | label = self._label_list[index] | |
213 | if label is None: | |
214 | raise ValueError('converted value for %s not specified.' % value) | |
215 | return label | |
216 | ||
217 | ||
218 | # Instantiate the various generic types. | |
219 | _boolean = _Boolean() | |
220 | _integer = _Integer() | |
221 | # For now, we don't do any special validation on these types: | |
222 | _string = _String() | |
223 | _file_name = _String() | |
224 | _folder_name = _String() | |
225 | _file_list = _StringList() | |
226 | _folder_list = _StringList() | |
227 | _string_list = _StringList() | |
228 | # Some boolean settings went from numerical values to boolean. The | |
229 | # mapping is 0: default, 1: false, 2: true. | |
230 | _newly_boolean = _Enumeration(['', 'false', 'true']) | |
231 | ||
232 | ||
233 | def _Same(tool, name, setting_type): | |
234 | """Defines a setting that has the same name in MSVS and MSBuild. | |
235 | ||
236 | Args: | |
237 | tool: a dictionary that gives the names of the tool for MSVS and MSBuild. | |
238 | name: the name of the setting. | |
239 | setting_type: the type of this setting. | |
240 | """ | |
241 | _Renamed(tool, name, name, setting_type) | |
242 | ||
243 | ||
244 | def _Renamed(tool, msvs_name, msbuild_name, setting_type): | |
245 | """Defines a setting for which the name has changed. | |
246 | ||
247 | Args: | |
248 | tool: a dictionary that gives the names of the tool for MSVS and MSBuild. | |
249 | msvs_name: the name of the MSVS setting. | |
250 | msbuild_name: the name of the MSBuild setting. | |
251 | setting_type: the type of this setting. | |
252 | """ | |
253 | ||
254 | def _Translate(value, msbuild_settings): | |
255 | msbuild_tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool) | |
256 | msbuild_tool_settings[msbuild_name] = setting_type.ConvertToMSBuild(value) | |
257 | ||
258 | _msvs_validators[tool.msvs_name][msvs_name] = setting_type.ValidateMSVS | |
259 | _msbuild_validators[tool.msbuild_name][msbuild_name] = ( | |
260 | setting_type.ValidateMSBuild) | |
261 | _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate | |
262 | ||
263 | ||
264 | def _Moved(tool, settings_name, msbuild_tool_name, setting_type): | |
265 | _MovedAndRenamed(tool, settings_name, msbuild_tool_name, settings_name, | |
266 | setting_type) | |
267 | ||
268 | ||
269 | def _MovedAndRenamed(tool, msvs_settings_name, msbuild_tool_name, | |
270 | msbuild_settings_name, setting_type): | |
271 | """Defines a setting that may have moved to a new section. | |
272 | ||
273 | Args: | |
274 | tool: a dictionary that gives the names of the tool for MSVS and MSBuild. | |
275 | msvs_settings_name: the MSVS name of the setting. | |
276 | msbuild_tool_name: the name of the MSBuild tool to place the setting under. | |
277 | msbuild_settings_name: the MSBuild name of the setting. | |
278 | setting_type: the type of this setting. | |
279 | """ | |
280 | ||
281 | def _Translate(value, msbuild_settings): | |
282 | tool_settings = msbuild_settings.setdefault(msbuild_tool_name, {}) | |
283 | tool_settings[msbuild_settings_name] = setting_type.ConvertToMSBuild(value) | |
284 | ||
285 | _msvs_validators[tool.msvs_name][msvs_settings_name] = ( | |
286 | setting_type.ValidateMSVS) | |
287 | validator = setting_type.ValidateMSBuild | |
288 | _msbuild_validators[msbuild_tool_name][msbuild_settings_name] = validator | |
289 | _msvs_to_msbuild_converters[tool.msvs_name][msvs_settings_name] = _Translate | |
290 | ||
291 | ||
292 | def _MSVSOnly(tool, name, setting_type): | |
293 | """Defines a setting that is only found in MSVS. | |
294 | ||
295 | Args: | |
296 | tool: a dictionary that gives the names of the tool for MSVS and MSBuild. | |
297 | name: the name of the setting. | |
298 | setting_type: the type of this setting. | |
299 | """ | |
300 | ||
301 | def _Translate(unused_value, unused_msbuild_settings): | |
302 | # Since this is for MSVS only settings, no translation will happen. | |
303 | pass | |
304 | ||
305 | _msvs_validators[tool.msvs_name][name] = setting_type.ValidateMSVS | |
306 | _msvs_to_msbuild_converters[tool.msvs_name][name] = _Translate | |
307 | ||
308 | ||
309 | def _MSBuildOnly(tool, name, setting_type): | |
310 | """Defines a setting that is only found in MSBuild. | |
311 | ||
312 | Args: | |
313 | tool: a dictionary that gives the names of the tool for MSVS and MSBuild. | |
314 | name: the name of the setting. | |
315 | setting_type: the type of this setting. | |
316 | """ | |
317 | _msbuild_validators[tool.msbuild_name][name] = setting_type.ValidateMSBuild | |
318 | ||
319 | ||
320 | def _ConvertedToAdditionalOption(tool, msvs_name, flag): | |
321 | """Defines a setting that's handled via a command line option in MSBuild. | |
322 | ||
323 | Args: | |
324 | tool: a dictionary that gives the names of the tool for MSVS and MSBuild. | |
325 | msvs_name: the name of the MSVS setting that if 'true' becomes a flag | |
326 | flag: the flag to insert at the end of the AdditionalOptions | |
327 | """ | |
328 | ||
329 | def _Translate(value, msbuild_settings): | |
330 | if value == 'true': | |
331 | tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool) | |
332 | if 'AdditionalOptions' in tool_settings: | |
333 | new_flags = '%s %s' % (tool_settings['AdditionalOptions'], flag) | |
334 | else: | |
335 | new_flags = flag | |
336 | tool_settings['AdditionalOptions'] = new_flags | |
337 | _msvs_validators[tool.msvs_name][msvs_name] = _boolean.ValidateMSVS | |
338 | _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate | |
339 | ||
340 | ||
341 | def _CustomGeneratePreprocessedFile(tool, msvs_name): | |
342 | def _Translate(value, msbuild_settings): | |
343 | tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool) | |
344 | if value == '0': | |
345 | tool_settings['PreprocessToFile'] = 'false' | |
346 | tool_settings['PreprocessSuppressLineNumbers'] = 'false' | |
347 | elif value == '1': # /P | |
348 | tool_settings['PreprocessToFile'] = 'true' | |
349 | tool_settings['PreprocessSuppressLineNumbers'] = 'false' | |
350 | elif value == '2': # /EP /P | |
351 | tool_settings['PreprocessToFile'] = 'true' | |
352 | tool_settings['PreprocessSuppressLineNumbers'] = 'true' | |
353 | else: | |
354 | raise ValueError('value must be one of [0, 1, 2]; got %s' % value) | |
355 | # Create a bogus validator that looks for '0', '1', or '2' | |
356 | msvs_validator = _Enumeration(['a', 'b', 'c']).ValidateMSVS | |
357 | _msvs_validators[tool.msvs_name][msvs_name] = msvs_validator | |
358 | msbuild_validator = _boolean.ValidateMSBuild | |
359 | msbuild_tool_validators = _msbuild_validators[tool.msbuild_name] | |
360 | msbuild_tool_validators['PreprocessToFile'] = msbuild_validator | |
361 | msbuild_tool_validators['PreprocessSuppressLineNumbers'] = msbuild_validator | |
362 | _msvs_to_msbuild_converters[tool.msvs_name][msvs_name] = _Translate | |
363 | ||
364 | ||
365 | def ConvertVCMacrosToMSBuild(s): | |
366 | """Convert the the MSVS macros found in the string to the MSBuild equivalent. | |
367 | ||
368 | This list is probably not exhaustive. Add as needed. | |
369 | """ | |
370 | if '$' in s: | |
371 | replace_map = { | |
372 | '$(ConfigurationName)': '$(Configuration)', | |
373 | '$(InputDir)': '%(RootDir)%(Directory)', | |
374 | '$(InputExt)': '%(Extension)', | |
375 | '$(InputFileName)': '%(Filename)%(Extension)', | |
376 | '$(InputName)': '%(Filename)', | |
377 | '$(InputPath)': '%(FullPath)', | |
378 | '$(ParentName)': '$(ProjectFileName)', | |
379 | '$(PlatformName)': '$(Platform)', | |
380 | '$(SafeInputName)': '%(Filename)', | |
381 | ||
382 | '$(IntDir)\\': '$(IntDir)', | |
383 | '$(OutDir)\\': '$(OutDir)', | |
384 | '$(IntDir)/': '$(IntDir)', | |
385 | '$(OutDir)/': '$(OutDir)', | |
386 | } | |
387 | for old, new in replace_map.iteritems(): | |
388 | s = s.replace(old, new) | |
389 | return s | |
390 | ||
391 | ||
392 | def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr): | |
393 | """Converts MSVS settings (VS2008 and earlier) to MSBuild settings (VS2010+). | |
394 | ||
395 | Args: | |
396 | msvs_settings: A dictionary. The key is the tool name. The values are | |
397 | themselves dictionaries of settings and their values. | |
398 | stderr: The stream receiving the error messages. | |
399 | ||
400 | Returns: | |
401 | A dictionary of MSBuild settings. The key is either the MSBuild tool name | |
402 | or the empty string (for the global settings). The values are themselves | |
403 | dictionaries of settings and their values. | |
404 | """ | |
405 | msbuild_settings = {} | |
406 | for msvs_tool_name, msvs_tool_settings in msvs_settings.iteritems(): | |
407 | if msvs_tool_name in _msvs_to_msbuild_converters: | |
408 | msvs_tool = _msvs_to_msbuild_converters[msvs_tool_name] | |
409 | for msvs_setting, msvs_value in msvs_tool_settings.iteritems(): | |
410 | if msvs_setting in msvs_tool: | |
411 | # Invoke the translation function. | |
412 | try: | |
413 | msvs_tool[msvs_setting](msvs_value, msbuild_settings) | |
414 | except ValueError, e: | |
415 | print >> stderr, ('Warning: while converting %s/%s to MSBuild, ' | |
416 | '%s' % (msvs_tool_name, msvs_setting, e)) | |
417 | else: | |
418 | # We don't know this setting. Give a warning. | |
419 | print >> stderr, ('Warning: unrecognized setting %s/%s ' | |
420 | 'while converting to MSBuild.' % | |
421 | (msvs_tool_name, msvs_setting)) | |
422 | else: | |
423 | print >> stderr, ('Warning: unrecognized tool %s while converting to ' | |
424 | 'MSBuild.' % msvs_tool_name) | |
425 | return msbuild_settings | |
426 | ||
427 | ||
428 | def ValidateMSVSSettings(settings, stderr=sys.stderr): | |
429 | """Validates that the names of the settings are valid for MSVS. | |
430 | ||
431 | Args: | |
432 | settings: A dictionary. The key is the tool name. The values are | |
433 | themselves dictionaries of settings and their values. | |
434 | stderr: The stream receiving the error messages. | |
435 | """ | |
436 | _ValidateSettings(_msvs_validators, settings, stderr) | |
437 | ||
438 | ||
439 | def ValidateMSBuildSettings(settings, stderr=sys.stderr): | |
440 | """Validates that the names of the settings are valid for MSBuild. | |
441 | ||
442 | Args: | |
443 | settings: A dictionary. The key is the tool name. The values are | |
444 | themselves dictionaries of settings and their values. | |
445 | stderr: The stream receiving the error messages. | |
446 | """ | |
447 | _ValidateSettings(_msbuild_validators, settings, stderr) | |
448 | ||
449 | ||
450 | def _ValidateSettings(validators, settings, stderr): | |
451 | """Validates that the settings are valid for MSBuild or MSVS. | |
452 | ||
453 | We currently only validate the names of the settings, not their values. | |
454 | ||
455 | Args: | |
456 | validators: A dictionary of tools and their validators. | |
457 | settings: A dictionary. The key is the tool name. The values are | |
458 | themselves dictionaries of settings and their values. | |
459 | stderr: The stream receiving the error messages. | |
460 | """ | |
461 | for tool_name in settings: | |
462 | if tool_name in validators: | |
463 | tool_validators = validators[tool_name] | |
464 | for setting, value in settings[tool_name].iteritems(): | |
465 | if setting in tool_validators: | |
466 | try: | |
467 | tool_validators[setting](value) | |
468 | except ValueError, e: | |
469 | print >> stderr, ('Warning: for %s/%s, %s' % | |
470 | (tool_name, setting, e)) | |
471 | else: | |
472 | print >> stderr, ('Warning: unrecognized setting %s/%s' % | |
473 | (tool_name, setting)) | |
474 | else: | |
475 | print >> stderr, ('Warning: unrecognized tool %s' % tool_name) | |
476 | ||
477 | ||
478 | # MSVS and MBuild names of the tools. | |
479 | _compile = _Tool('VCCLCompilerTool', 'ClCompile') | |
480 | _link = _Tool('VCLinkerTool', 'Link') | |
481 | _midl = _Tool('VCMIDLTool', 'Midl') | |
482 | _rc = _Tool('VCResourceCompilerTool', 'ResourceCompile') | |
483 | _lib = _Tool('VCLibrarianTool', 'Lib') | |
484 | _manifest = _Tool('VCManifestTool', 'Mt') | |
485 | ||
486 | ||
487 | _AddTool(_compile) | |
488 | _AddTool(_link) | |
489 | _AddTool(_midl) | |
490 | _AddTool(_rc) | |
491 | _AddTool(_lib) | |
492 | _AddTool(_manifest) | |
493 | # Add sections only found in the MSBuild settings. | |
494 | _msbuild_validators[''] = {} | |
495 | _msbuild_validators['ProjectReference'] = {} | |
496 | _msbuild_validators['ManifestResourceCompile'] = {} | |
497 | ||
498 | # Descriptions of the compiler options, i.e. VCCLCompilerTool in MSVS and | |
499 | # ClCompile in MSBuild. | |
500 | # See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\cl.xml" for | |
501 | # the schema of the MSBuild ClCompile settings. | |
502 | ||
503 | # Options that have the same name in MSVS and MSBuild | |
504 | _Same(_compile, 'AdditionalIncludeDirectories', _folder_list) # /I | |
505 | _Same(_compile, 'AdditionalOptions', _string_list) | |
506 | _Same(_compile, 'AdditionalUsingDirectories', _folder_list) # /AI | |
507 | _Same(_compile, 'AssemblerListingLocation', _file_name) # /Fa | |
508 | _Same(_compile, 'BrowseInformationFile', _file_name) | |
509 | _Same(_compile, 'BufferSecurityCheck', _boolean) # /GS | |
510 | _Same(_compile, 'DisableLanguageExtensions', _boolean) # /Za | |
511 | _Same(_compile, 'DisableSpecificWarnings', _string_list) # /wd | |
512 | _Same(_compile, 'EnableFiberSafeOptimizations', _boolean) # /GT | |
513 | _Same(_compile, 'EnablePREfast', _boolean) # /analyze Visible='false' | |
514 | _Same(_compile, 'ExpandAttributedSource', _boolean) # /Fx | |
515 | _Same(_compile, 'FloatingPointExceptions', _boolean) # /fp:except | |
516 | _Same(_compile, 'ForceConformanceInForLoopScope', _boolean) # /Zc:forScope | |
517 | _Same(_compile, 'ForcedIncludeFiles', _file_list) # /FI | |
518 | _Same(_compile, 'ForcedUsingFiles', _file_list) # /FU | |
519 | _Same(_compile, 'GenerateXMLDocumentationFiles', _boolean) # /doc | |
520 | _Same(_compile, 'IgnoreStandardIncludePath', _boolean) # /X | |
521 | _Same(_compile, 'MinimalRebuild', _boolean) # /Gm | |
522 | _Same(_compile, 'OmitDefaultLibName', _boolean) # /Zl | |
523 | _Same(_compile, 'OmitFramePointers', _boolean) # /Oy | |
524 | _Same(_compile, 'PreprocessorDefinitions', _string_list) # /D | |
525 | _Same(_compile, 'ProgramDataBaseFileName', _file_name) # /Fd | |
526 | _Same(_compile, 'RuntimeTypeInfo', _boolean) # /GR | |
527 | _Same(_compile, 'ShowIncludes', _boolean) # /showIncludes | |
528 | _Same(_compile, 'SmallerTypeCheck', _boolean) # /RTCc | |
529 | _Same(_compile, 'StringPooling', _boolean) # /GF | |
530 | _Same(_compile, 'SuppressStartupBanner', _boolean) # /nologo | |
531 | _Same(_compile, 'TreatWChar_tAsBuiltInType', _boolean) # /Zc:wchar_t | |
532 | _Same(_compile, 'UndefineAllPreprocessorDefinitions', _boolean) # /u | |
533 | _Same(_compile, 'UndefinePreprocessorDefinitions', _string_list) # /U | |
534 | _Same(_compile, 'UseFullPaths', _boolean) # /FC | |
535 | _Same(_compile, 'WholeProgramOptimization', _boolean) # /GL | |
536 | _Same(_compile, 'XMLDocumentationFileName', _file_name) | |
537 | ||
538 | _Same(_compile, 'AssemblerOutput', | |
539 | _Enumeration(['NoListing', | |
540 | 'AssemblyCode', # /FA | |
541 | 'All', # /FAcs | |
542 | 'AssemblyAndMachineCode', # /FAc | |
543 | 'AssemblyAndSourceCode'])) # /FAs | |
544 | _Same(_compile, 'BasicRuntimeChecks', | |
545 | _Enumeration(['Default', | |
546 | 'StackFrameRuntimeCheck', # /RTCs | |
547 | 'UninitializedLocalUsageCheck', # /RTCu | |
548 | 'EnableFastChecks'])) # /RTC1 | |
549 | _Same(_compile, 'BrowseInformation', | |
550 | _Enumeration(['false', | |
551 | 'true', # /FR | |
552 | 'true'])) # /Fr | |
553 | _Same(_compile, 'CallingConvention', | |
554 | _Enumeration(['Cdecl', # /Gd | |
555 | 'FastCall', # /Gr | |
556 | 'StdCall'])) # /Gz | |
557 | _Same(_compile, 'CompileAs', | |
558 | _Enumeration(['Default', | |
559 | 'CompileAsC', # /TC | |
560 | 'CompileAsCpp'])) # /TP | |
561 | _Same(_compile, 'DebugInformationFormat', | |
562 | _Enumeration(['', # Disabled | |
563 | 'OldStyle', # /Z7 | |
564 | None, | |
565 | 'ProgramDatabase', # /Zi | |
566 | 'EditAndContinue'])) # /ZI | |
567 | _Same(_compile, 'EnableEnhancedInstructionSet', | |
568 | _Enumeration(['NotSet', | |
569 | 'StreamingSIMDExtensions', # /arch:SSE | |
570 | 'StreamingSIMDExtensions2'])) # /arch:SSE2 | |
571 | _Same(_compile, 'ErrorReporting', | |
572 | _Enumeration(['None', # /errorReport:none | |
573 | 'Prompt', # /errorReport:prompt | |
574 | 'Queue'], # /errorReport:queue | |
575 | new=['Send'])) # /errorReport:send" | |
576 | _Same(_compile, 'ExceptionHandling', | |
577 | _Enumeration(['false', | |
578 | 'Sync', # /EHsc | |
579 | 'Async'], # /EHa | |
580 | new=['SyncCThrow'])) # /EHs | |
581 | _Same(_compile, 'FavorSizeOrSpeed', | |
582 | _Enumeration(['Neither', | |
583 | 'Speed', # /Ot | |
584 | 'Size'])) # /Os | |
585 | _Same(_compile, 'FloatingPointModel', | |
586 | _Enumeration(['Precise', # /fp:precise | |
587 | 'Strict', # /fp:strict | |
588 | 'Fast'])) # /fp:fast | |
589 | _Same(_compile, 'InlineFunctionExpansion', | |
590 | _Enumeration(['Default', | |
591 | 'OnlyExplicitInline', # /Ob1 | |
592 | 'AnySuitable'], # /Ob2 | |
593 | new=['Disabled'])) # /Ob0 | |
594 | _Same(_compile, 'Optimization', | |
595 | _Enumeration(['Disabled', # /Od | |
596 | 'MinSpace', # /O1 | |
597 | 'MaxSpeed', # /O2 | |
598 | 'Full'])) # /Ox | |
599 | _Same(_compile, 'RuntimeLibrary', | |
600 | _Enumeration(['MultiThreaded', # /MT | |
601 | 'MultiThreadedDebug', # /MTd | |
602 | 'MultiThreadedDLL', # /MD | |
603 | 'MultiThreadedDebugDLL'])) # /MDd | |
604 | _Same(_compile, 'StructMemberAlignment', | |
605 | _Enumeration(['Default', | |
606 | '1Byte', # /Zp1 | |
607 | '2Bytes', # /Zp2 | |
608 | '4Bytes', # /Zp4 | |
609 | '8Bytes', # /Zp8 | |
610 | '16Bytes'])) # /Zp16 | |
611 | _Same(_compile, 'WarningLevel', | |
612 | _Enumeration(['TurnOffAllWarnings', # /W0 | |
613 | 'Level1', # /W1 | |
614 | 'Level2', # /W2 | |
615 | 'Level3', # /W3 | |
616 | 'Level4'], # /W4 | |
617 | new=['EnableAllWarnings'])) # /Wall | |
618 | ||
619 | # Options found in MSVS that have been renamed in MSBuild. | |
620 | _Renamed(_compile, 'EnableFunctionLevelLinking', 'FunctionLevelLinking', | |
621 | _boolean) # /Gy | |
622 | _Renamed(_compile, 'EnableIntrinsicFunctions', 'IntrinsicFunctions', | |
623 | _boolean) # /Oi | |
624 | _Renamed(_compile, 'KeepComments', 'PreprocessKeepComments', _boolean) # /C | |
625 | _Renamed(_compile, 'ObjectFile', 'ObjectFileName', _file_name) # /Fo | |
626 | _Renamed(_compile, 'OpenMP', 'OpenMPSupport', _boolean) # /openmp | |
627 | _Renamed(_compile, 'PrecompiledHeaderThrough', 'PrecompiledHeaderFile', | |
628 | _file_name) # Used with /Yc and /Yu | |
629 | _Renamed(_compile, 'PrecompiledHeaderFile', 'PrecompiledHeaderOutputFile', | |
630 | _file_name) # /Fp | |
631 | _Renamed(_compile, 'UsePrecompiledHeader', 'PrecompiledHeader', | |
632 | _Enumeration(['NotUsing', # VS recognized '' for this value too. | |
633 | 'Create', # /Yc | |
634 | 'Use'])) # /Yu | |
635 | _Renamed(_compile, 'WarnAsError', 'TreatWarningAsError', _boolean) # /WX | |
636 | ||
637 | _ConvertedToAdditionalOption(_compile, 'DefaultCharIsUnsigned', '/J') | |
638 | ||
639 | # MSVS options not found in MSBuild. | |
640 | _MSVSOnly(_compile, 'Detect64BitPortabilityProblems', _boolean) | |
641 | _MSVSOnly(_compile, 'UseUnicodeResponseFiles', _boolean) | |
642 | ||
643 | # MSBuild options not found in MSVS. | |
644 | _MSBuildOnly(_compile, 'BuildingInIDE', _boolean) | |
645 | _MSBuildOnly(_compile, 'CompileAsManaged', | |
646 | _Enumeration([], new=['false', | |
647 | 'true', # /clr | |
648 | 'Pure', # /clr:pure | |
649 | 'Safe', # /clr:safe | |
650 | 'OldSyntax'])) # /clr:oldSyntax | |
651 | _MSBuildOnly(_compile, 'CreateHotpatchableImage', _boolean) # /hotpatch | |
652 | _MSBuildOnly(_compile, 'MultiProcessorCompilation', _boolean) # /MP | |
653 | _MSBuildOnly(_compile, 'PreprocessOutputPath', _string) # /Fi | |
654 | _MSBuildOnly(_compile, 'ProcessorNumber', _integer) # the number of processors | |
655 | _MSBuildOnly(_compile, 'TrackerLogDirectory', _folder_name) | |
656 | _MSBuildOnly(_compile, 'TreatSpecificWarningsAsErrors', _string_list) # /we | |
657 | _MSBuildOnly(_compile, 'UseUnicodeForAssemblerListing', _boolean) # /FAu | |
658 | ||
659 | # Defines a setting that needs very customized processing | |
660 | _CustomGeneratePreprocessedFile(_compile, 'GeneratePreprocessedFile') | |
661 | ||
662 | ||
663 | # Directives for converting MSVS VCLinkerTool to MSBuild Link. | |
664 | # See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\link.xml" for | |
665 | # the schema of the MSBuild Link settings. | |
666 | ||
667 | # Options that have the same name in MSVS and MSBuild | |
668 | _Same(_link, 'AdditionalDependencies', _file_list) | |
669 | _Same(_link, 'AdditionalLibraryDirectories', _folder_list) # /LIBPATH | |
670 | # /MANIFESTDEPENDENCY: | |
671 | _Same(_link, 'AdditionalManifestDependencies', _file_list) | |
672 | _Same(_link, 'AdditionalOptions', _string_list) | |
673 | _Same(_link, 'AddModuleNamesToAssembly', _file_list) # /ASSEMBLYMODULE | |
674 | _Same(_link, 'AllowIsolation', _boolean) # /ALLOWISOLATION | |
675 | _Same(_link, 'AssemblyLinkResource', _file_list) # /ASSEMBLYLINKRESOURCE | |
676 | _Same(_link, 'BaseAddress', _string) # /BASE | |
677 | _Same(_link, 'CLRUnmanagedCodeCheck', _boolean) # /CLRUNMANAGEDCODECHECK | |
678 | _Same(_link, 'DelayLoadDLLs', _file_list) # /DELAYLOAD | |
679 | _Same(_link, 'DelaySign', _boolean) # /DELAYSIGN | |
680 | _Same(_link, 'EmbedManagedResourceFile', _file_list) # /ASSEMBLYRESOURCE | |
681 | _Same(_link, 'EnableUAC', _boolean) # /MANIFESTUAC | |
682 | _Same(_link, 'EntryPointSymbol', _string) # /ENTRY | |
683 | _Same(_link, 'ForceSymbolReferences', _file_list) # /INCLUDE | |
684 | _Same(_link, 'FunctionOrder', _file_name) # /ORDER | |
685 | _Same(_link, 'GenerateDebugInformation', _boolean) # /DEBUG | |
686 | _Same(_link, 'GenerateMapFile', _boolean) # /MAP | |
687 | _Same(_link, 'HeapCommitSize', _string) | |
688 | _Same(_link, 'HeapReserveSize', _string) # /HEAP | |
689 | _Same(_link, 'IgnoreAllDefaultLibraries', _boolean) # /NODEFAULTLIB | |
690 | _Same(_link, 'IgnoreEmbeddedIDL', _boolean) # /IGNOREIDL | |
691 | _Same(_link, 'ImportLibrary', _file_name) # /IMPLIB | |
692 | _Same(_link, 'KeyContainer', _file_name) # /KEYCONTAINER | |
693 | _Same(_link, 'KeyFile', _file_name) # /KEYFILE | |
694 | _Same(_link, 'ManifestFile', _file_name) # /ManifestFile | |
695 | _Same(_link, 'MapExports', _boolean) # /MAPINFO:EXPORTS | |
696 | _Same(_link, 'MapFileName', _file_name) | |
697 | _Same(_link, 'MergedIDLBaseFileName', _file_name) # /IDLOUT | |
698 | _Same(_link, 'MergeSections', _string) # /MERGE | |
699 | _Same(_link, 'MidlCommandFile', _file_name) # /MIDL | |
700 | _Same(_link, 'ModuleDefinitionFile', _file_name) # /DEF | |
701 | _Same(_link, 'OutputFile', _file_name) # /OUT | |
702 | _Same(_link, 'PerUserRedirection', _boolean) | |
703 | _Same(_link, 'Profile', _boolean) # /PROFILE | |
704 | _Same(_link, 'ProfileGuidedDatabase', _file_name) # /PGD | |
705 | _Same(_link, 'ProgramDatabaseFile', _file_name) # /PDB | |
706 | _Same(_link, 'RegisterOutput', _boolean) | |
707 | _Same(_link, 'SetChecksum', _boolean) # /RELEASE | |
708 | _Same(_link, 'StackCommitSize', _string) | |
709 | _Same(_link, 'StackReserveSize', _string) # /STACK | |
710 | _Same(_link, 'StripPrivateSymbols', _file_name) # /PDBSTRIPPED | |
711 | _Same(_link, 'SupportUnloadOfDelayLoadedDLL', _boolean) # /DELAY:UNLOAD | |
712 | _Same(_link, 'SuppressStartupBanner', _boolean) # /NOLOGO | |
713 | _Same(_link, 'SwapRunFromCD', _boolean) # /SWAPRUN:CD | |
714 | _Same(_link, 'TurnOffAssemblyGeneration', _boolean) # /NOASSEMBLY | |
715 | _Same(_link, 'TypeLibraryFile', _file_name) # /TLBOUT | |
716 | _Same(_link, 'TypeLibraryResourceID', _integer) # /TLBID | |
717 | _Same(_link, 'UACUIAccess', _boolean) # /uiAccess='true' | |
718 | _Same(_link, 'Version', _string) # /VERSION | |
719 | ||
720 | _Same(_link, 'EnableCOMDATFolding', _newly_boolean) # /OPT:ICF | |
721 | _Same(_link, 'FixedBaseAddress', _newly_boolean) # /FIXED | |
722 | _Same(_link, 'LargeAddressAware', _newly_boolean) # /LARGEADDRESSAWARE | |
723 | _Same(_link, 'OptimizeReferences', _newly_boolean) # /OPT:REF | |
724 | _Same(_link, 'RandomizedBaseAddress', _newly_boolean) # /DYNAMICBASE | |
725 | _Same(_link, 'TerminalServerAware', _newly_boolean) # /TSAWARE | |
726 | ||
727 | _subsystem_enumeration = _Enumeration( | |
728 | ['NotSet', | |
729 | 'Console', # /SUBSYSTEM:CONSOLE | |
730 | 'Windows', # /SUBSYSTEM:WINDOWS | |
731 | 'Native', # /SUBSYSTEM:NATIVE | |
732 | 'EFI Application', # /SUBSYSTEM:EFI_APPLICATION | |
733 | 'EFI Boot Service Driver', # /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER | |
734 | 'EFI ROM', # /SUBSYSTEM:EFI_ROM | |
735 | 'EFI Runtime', # /SUBSYSTEM:EFI_RUNTIME_DRIVER | |
736 | 'WindowsCE'], # /SUBSYSTEM:WINDOWSCE | |
737 | new=['POSIX']) # /SUBSYSTEM:POSIX | |
738 | ||
739 | _target_machine_enumeration = _Enumeration( | |
740 | ['NotSet', | |
741 | 'MachineX86', # /MACHINE:X86 | |
742 | None, | |
743 | 'MachineARM', # /MACHINE:ARM | |
744 | 'MachineEBC', # /MACHINE:EBC | |
745 | 'MachineIA64', # /MACHINE:IA64 | |
746 | None, | |
747 | 'MachineMIPS', # /MACHINE:MIPS | |
748 | 'MachineMIPS16', # /MACHINE:MIPS16 | |
749 | 'MachineMIPSFPU', # /MACHINE:MIPSFPU | |
750 | 'MachineMIPSFPU16', # /MACHINE:MIPSFPU16 | |
751 | None, | |
752 | None, | |
753 | None, | |
754 | 'MachineSH4', # /MACHINE:SH4 | |
755 | None, | |
756 | 'MachineTHUMB', # /MACHINE:THUMB | |
757 | 'MachineX64']) # /MACHINE:X64 | |
758 | ||
759 | _Same(_link, 'AssemblyDebug', | |
760 | _Enumeration(['', | |
761 | 'true', # /ASSEMBLYDEBUG | |
762 | 'false'])) # /ASSEMBLYDEBUG:DISABLE | |
763 | _Same(_link, 'CLRImageType', | |
764 | _Enumeration(['Default', | |
765 | 'ForceIJWImage', # /CLRIMAGETYPE:IJW | |
766 | 'ForcePureILImage', # /Switch="CLRIMAGETYPE:PURE | |
767 | 'ForceSafeILImage'])) # /Switch="CLRIMAGETYPE:SAFE | |
768 | _Same(_link, 'CLRThreadAttribute', | |
769 | _Enumeration(['DefaultThreadingAttribute', # /CLRTHREADATTRIBUTE:NONE | |
770 | 'MTAThreadingAttribute', # /CLRTHREADATTRIBUTE:MTA | |
771 | 'STAThreadingAttribute'])) # /CLRTHREADATTRIBUTE:STA | |
772 | _Same(_link, 'DataExecutionPrevention', | |
773 | _Enumeration(['', | |
774 | 'false', # /NXCOMPAT:NO | |
775 | 'true'])) # /NXCOMPAT | |
776 | _Same(_link, 'Driver', | |
777 | _Enumeration(['NotSet', | |
778 | 'Driver', # /Driver | |
779 | 'UpOnly', # /DRIVER:UPONLY | |
780 | 'WDM'])) # /DRIVER:WDM | |
781 | _Same(_link, 'LinkTimeCodeGeneration', | |
782 | _Enumeration(['Default', | |
783 | 'UseLinkTimeCodeGeneration', # /LTCG | |
784 | 'PGInstrument', # /LTCG:PGInstrument | |
785 | 'PGOptimization', # /LTCG:PGOptimize | |
786 | 'PGUpdate'])) # /LTCG:PGUpdate | |
787 | _Same(_link, 'ShowProgress', | |
788 | _Enumeration(['NotSet', | |
789 | 'LinkVerbose', # /VERBOSE | |
790 | 'LinkVerboseLib'], # /VERBOSE:Lib | |
791 | new=['LinkVerboseICF', # /VERBOSE:ICF | |
792 | 'LinkVerboseREF', # /VERBOSE:REF | |
793 | 'LinkVerboseSAFESEH', # /VERBOSE:SAFESEH | |
794 | 'LinkVerboseCLR'])) # /VERBOSE:CLR | |
795 | _Same(_link, 'SubSystem', _subsystem_enumeration) | |
796 | _Same(_link, 'TargetMachine', _target_machine_enumeration) | |
797 | _Same(_link, 'UACExecutionLevel', | |
798 | _Enumeration(['AsInvoker', # /level='asInvoker' | |
799 | 'HighestAvailable', # /level='highestAvailable' | |
800 | 'RequireAdministrator'])) # /level='requireAdministrator' | |
801 | ||
802 | ||
803 | # Options found in MSVS that have been renamed in MSBuild. | |
804 | _Renamed(_link, 'ErrorReporting', 'LinkErrorReporting', | |
805 | _Enumeration(['NoErrorReport', # /ERRORREPORT:NONE | |
806 | 'PromptImmediately', # /ERRORREPORT:PROMPT | |
807 | 'QueueForNextLogin'], # /ERRORREPORT:QUEUE | |
808 | new=['SendErrorReport'])) # /ERRORREPORT:SEND | |
809 | _Renamed(_link, 'IgnoreDefaultLibraryNames', 'IgnoreSpecificDefaultLibraries', | |
810 | _file_list) # /NODEFAULTLIB | |
811 | _Renamed(_link, 'ResourceOnlyDLL', 'NoEntryPoint', _boolean) # /NOENTRY | |
812 | _Renamed(_link, 'SwapRunFromNet', 'SwapRunFromNET', _boolean) # /SWAPRUN:NET | |
813 | ||
814 | _Moved(_link, 'GenerateManifest', '', _boolean) | |
815 | _Moved(_link, 'IgnoreImportLibrary', '', _boolean) | |
816 | _Moved(_link, 'LinkIncremental', '', _newly_boolean) | |
817 | _Moved(_link, 'LinkLibraryDependencies', 'ProjectReference', _boolean) | |
818 | _Moved(_link, 'UseLibraryDependencyInputs', 'ProjectReference', _boolean) | |
819 | ||
820 | # MSVS options not found in MSBuild. | |
821 | _MSVSOnly(_link, 'OptimizeForWindows98', _newly_boolean) | |
822 | _MSVSOnly(_link, 'UseUnicodeResponseFiles', _boolean) | |
823 | # TODO(jeanluc) I don't think these are genuine settings but byproducts of Gyp. | |
824 | _MSVSOnly(_link, 'AdditionalLibraryDirectories_excluded', _folder_list) | |
825 | ||
826 | # MSBuild options not found in MSVS. | |
827 | _MSBuildOnly(_link, 'BuildingInIDE', _boolean) | |
828 | _MSBuildOnly(_link, 'ImageHasSafeExceptionHandlers', _boolean) # /SAFESEH | |
829 | _MSBuildOnly(_link, 'LinkDLL', _boolean) # /DLL Visible='false' | |
830 | _MSBuildOnly(_link, 'LinkStatus', _boolean) # /LTCG:STATUS | |
831 | _MSBuildOnly(_link, 'PreventDllBinding', _boolean) # /ALLOWBIND | |
832 | _MSBuildOnly(_link, 'SupportNobindOfDelayLoadedDLL', _boolean) # /DELAY:NOBIND | |
833 | _MSBuildOnly(_link, 'TrackerLogDirectory', _folder_name) | |
834 | _MSBuildOnly(_link, 'TreatLinkerWarningAsErrors', _boolean) # /WX | |
835 | _MSBuildOnly(_link, 'MinimumRequiredVersion', _string) | |
836 | _MSBuildOnly(_link, 'MSDOSStubFileName', _file_name) # /STUB Visible='false' | |
837 | _MSBuildOnly(_link, 'SectionAlignment', _integer) # /ALIGN | |
838 | _MSBuildOnly(_link, 'SpecifySectionAttributes', _string) # /SECTION | |
839 | _MSBuildOnly(_link, 'ForceFileOutput', | |
840 | _Enumeration([], new=['Enabled', # /FORCE | |
841 | # /FORCE:MULTIPLE | |
842 | 'MultiplyDefinedSymbolOnly', | |
843 | 'UndefinedSymbolOnly'])) # /FORCE:UNRESOLVED | |
844 | _MSBuildOnly(_link, 'CreateHotPatchableImage', | |
845 | _Enumeration([], new=['Enabled', # /FUNCTIONPADMIN | |
846 | 'X86Image', # /FUNCTIONPADMIN:5 | |
847 | 'X64Image', # /FUNCTIONPADMIN:6 | |
848 | 'ItaniumImage'])) # /FUNCTIONPADMIN:16 | |
849 | _MSBuildOnly(_link, 'CLRSupportLastError', | |
850 | _Enumeration([], new=['Enabled', # /CLRSupportLastError | |
851 | 'Disabled', # /CLRSupportLastError:NO | |
852 | # /CLRSupportLastError:SYSTEMDLL | |
853 | 'SystemDlls'])) | |
854 | ||
855 | ||
856 | # Directives for converting VCResourceCompilerTool to ResourceCompile. | |
857 | # See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\rc.xml" for | |
858 | # the schema of the MSBuild ResourceCompile settings. | |
859 | ||
860 | _Same(_rc, 'AdditionalOptions', _string_list) | |
861 | _Same(_rc, 'AdditionalIncludeDirectories', _folder_list) # /I | |
862 | _Same(_rc, 'Culture', _Integer(msbuild_base=16)) | |
863 | _Same(_rc, 'IgnoreStandardIncludePath', _boolean) # /X | |
864 | _Same(_rc, 'PreprocessorDefinitions', _string_list) # /D | |
865 | _Same(_rc, 'ResourceOutputFileName', _string) # /fo | |
866 | _Same(_rc, 'ShowProgress', _boolean) # /v | |
867 | # There is no UI in VisualStudio 2008 to set the following properties. | |
868 | # However they are found in CL and other tools. Include them here for | |
869 | # completeness, as they are very likely to have the same usage pattern. | |
870 | _Same(_rc, 'SuppressStartupBanner', _boolean) # /nologo | |
871 | _Same(_rc, 'UndefinePreprocessorDefinitions', _string_list) # /u | |
872 | ||
873 | # MSBuild options not found in MSVS. | |
874 | _MSBuildOnly(_rc, 'NullTerminateStrings', _boolean) # /n | |
875 | _MSBuildOnly(_rc, 'TrackerLogDirectory', _folder_name) | |
876 | ||
877 | ||
878 | # Directives for converting VCMIDLTool to Midl. | |
879 | # See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\midl.xml" for | |
880 | # the schema of the MSBuild Midl settings. | |
881 | ||
882 | _Same(_midl, 'AdditionalIncludeDirectories', _folder_list) # /I | |
883 | _Same(_midl, 'AdditionalOptions', _string_list) | |
884 | _Same(_midl, 'CPreprocessOptions', _string) # /cpp_opt | |
885 | _Same(_midl, 'ErrorCheckAllocations', _boolean) # /error allocation | |
886 | _Same(_midl, 'ErrorCheckBounds', _boolean) # /error bounds_check | |
887 | _Same(_midl, 'ErrorCheckEnumRange', _boolean) # /error enum | |
888 | _Same(_midl, 'ErrorCheckRefPointers', _boolean) # /error ref | |
889 | _Same(_midl, 'ErrorCheckStubData', _boolean) # /error stub_data | |
890 | _Same(_midl, 'GenerateStublessProxies', _boolean) # /Oicf | |
891 | _Same(_midl, 'GenerateTypeLibrary', _boolean) | |
892 | _Same(_midl, 'HeaderFileName', _file_name) # /h | |
893 | _Same(_midl, 'IgnoreStandardIncludePath', _boolean) # /no_def_idir | |
894 | _Same(_midl, 'InterfaceIdentifierFileName', _file_name) # /iid | |
895 | _Same(_midl, 'MkTypLibCompatible', _boolean) # /mktyplib203 | |
896 | _Same(_midl, 'OutputDirectory', _string) # /out | |
897 | _Same(_midl, 'PreprocessorDefinitions', _string_list) # /D | |
898 | _Same(_midl, 'ProxyFileName', _file_name) # /proxy | |
899 | _Same(_midl, 'RedirectOutputAndErrors', _file_name) # /o | |
900 | _Same(_midl, 'SuppressStartupBanner', _boolean) # /nologo | |
901 | _Same(_midl, 'TypeLibraryName', _file_name) # /tlb | |
902 | _Same(_midl, 'UndefinePreprocessorDefinitions', _string_list) # /U | |
903 | _Same(_midl, 'WarnAsError', _boolean) # /WX | |
904 | ||
905 | _Same(_midl, 'DefaultCharType', | |
906 | _Enumeration(['Unsigned', # /char unsigned | |
907 | 'Signed', # /char signed | |
908 | 'Ascii'])) # /char ascii7 | |
909 | _Same(_midl, 'TargetEnvironment', | |
910 | _Enumeration(['NotSet', | |
911 | 'Win32', # /env win32 | |
912 | 'Itanium', # /env ia64 | |
913 | 'X64'])) # /env x64 | |
914 | _Same(_midl, 'EnableErrorChecks', | |
915 | _Enumeration(['EnableCustom', | |
916 | 'None', # /error none | |
917 | 'All'])) # /error all | |
918 | _Same(_midl, 'StructMemberAlignment', | |
919 | _Enumeration(['NotSet', | |
920 | '1', # Zp1 | |
921 | '2', # Zp2 | |
922 | '4', # Zp4 | |
923 | '8'])) # Zp8 | |
924 | _Same(_midl, 'WarningLevel', | |
925 | _Enumeration(['0', # /W0 | |
926 | '1', # /W1 | |
927 | '2', # /W2 | |
928 | '3', # /W3 | |
929 | '4'])) # /W4 | |
930 | ||
931 | _Renamed(_midl, 'DLLDataFileName', 'DllDataFileName', _file_name) # /dlldata | |
932 | _Renamed(_midl, 'ValidateParameters', 'ValidateAllParameters', | |
933 | _boolean) # /robust | |
934 | ||
935 | # MSBuild options not found in MSVS. | |
936 | _MSBuildOnly(_midl, 'ApplicationConfigurationMode', _boolean) # /app_config | |
937 | _MSBuildOnly(_midl, 'ClientStubFile', _file_name) # /cstub | |
938 | _MSBuildOnly(_midl, 'GenerateClientFiles', | |
939 | _Enumeration([], new=['Stub', # /client stub | |
940 | 'None'])) # /client none | |
941 | _MSBuildOnly(_midl, 'GenerateServerFiles', | |
942 | _Enumeration([], new=['Stub', # /client stub | |
943 | 'None'])) # /client none | |
944 | _MSBuildOnly(_midl, 'LocaleID', _integer) # /lcid DECIMAL | |
945 | _MSBuildOnly(_midl, 'ServerStubFile', _file_name) # /sstub | |
946 | _MSBuildOnly(_midl, 'SuppressCompilerWarnings', _boolean) # /no_warn | |
947 | _MSBuildOnly(_midl, 'TrackerLogDirectory', _folder_name) | |
948 | _MSBuildOnly(_midl, 'TypeLibFormat', | |
949 | _Enumeration([], new=['NewFormat', # /newtlb | |
950 | 'OldFormat'])) # /oldtlb | |
951 | ||
952 | ||
953 | # Directives for converting VCLibrarianTool to Lib. | |
954 | # See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\lib.xml" for | |
955 | # the schema of the MSBuild Lib settings. | |
956 | ||
957 | _Same(_lib, 'AdditionalDependencies', _file_list) | |
958 | _Same(_lib, 'AdditionalLibraryDirectories', _folder_list) # /LIBPATH | |
959 | _Same(_lib, 'AdditionalOptions', _string_list) | |
960 | _Same(_lib, 'ExportNamedFunctions', _string_list) # /EXPORT | |
961 | _Same(_lib, 'ForceSymbolReferences', _string) # /INCLUDE | |
962 | _Same(_lib, 'IgnoreAllDefaultLibraries', _boolean) # /NODEFAULTLIB | |
963 | _Same(_lib, 'IgnoreSpecificDefaultLibraries', _file_list) # /NODEFAULTLIB | |
964 | _Same(_lib, 'ModuleDefinitionFile', _file_name) # /DEF | |
965 | _Same(_lib, 'OutputFile', _file_name) # /OUT | |
966 | _Same(_lib, 'SuppressStartupBanner', _boolean) # /NOLOGO | |
967 | _Same(_lib, 'UseUnicodeResponseFiles', _boolean) | |
968 | ||
969 | # TODO(jeanluc) _link defines the same value that gets moved to | |
970 | # ProjectReference. We may want to validate that they are consistent. | |
971 | _Moved(_lib, 'LinkLibraryDependencies', 'ProjectReference', _boolean) | |
972 | ||
973 | # TODO(jeanluc) I don't think these are genuine settings but byproducts of Gyp. | |
974 | _MSVSOnly(_lib, 'AdditionalLibraryDirectories_excluded', _folder_list) | |
975 | ||
976 | _MSBuildOnly(_lib, 'DisplayLibrary', _string) # /LIST Visible='false' | |
977 | _MSBuildOnly(_lib, 'ErrorReporting', | |
978 | _Enumeration([], new=['PromptImmediately', # /ERRORREPORT:PROMPT | |
979 | 'QueueForNextLogin', # /ERRORREPORT:QUEUE | |
980 | 'SendErrorReport', # /ERRORREPORT:SEND | |
981 | 'NoErrorReport'])) # /ERRORREPORT:NONE | |
982 | _MSBuildOnly(_lib, 'LinkTimeCodeGeneration', _boolean) # /LTCG | |
983 | _MSBuildOnly(_lib, 'MinimumRequiredVersion', _string) | |
984 | _MSBuildOnly(_lib, 'Name', _file_name) # /NAME | |
985 | _MSBuildOnly(_lib, 'RemoveObjects', _file_list) # /REMOVE | |
986 | _MSBuildOnly(_lib, 'SubSystem', _subsystem_enumeration) | |
987 | _MSBuildOnly(_lib, 'TargetMachine', _target_machine_enumeration) | |
988 | _MSBuildOnly(_lib, 'TrackerLogDirectory', _folder_name) | |
989 | _MSBuildOnly(_lib, 'TreatLibWarningAsErrors', _boolean) # /WX | |
990 | _MSBuildOnly(_lib, 'Verbose', _boolean) | |
991 | ||
992 | ||
993 | # Directives for converting VCManifestTool to Mt. | |
994 | # See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\mt.xml" for | |
995 | # the schema of the MSBuild Lib settings. | |
996 | ||
997 | # Options that have the same name in MSVS and MSBuild | |
998 | _Same(_manifest, 'AdditionalManifestFiles', _file_list) # /manifest | |
999 | _Same(_manifest, 'AdditionalOptions', _string_list) | |
1000 | _Same(_manifest, 'AssemblyIdentity', _string) # /identity: | |
1001 | _Same(_manifest, 'ComponentFileName', _file_name) # /dll | |
1002 | _Same(_manifest, 'GenerateCatalogFiles', _boolean) # /makecdfs | |
1003 | _Same(_manifest, 'InputResourceManifests', _string) # /inputresource | |
1004 | _Same(_manifest, 'OutputManifestFile', _file_name) # /out | |
1005 | _Same(_manifest, 'RegistrarScriptFile', _file_name) # /rgs | |
1006 | _Same(_manifest, 'ReplacementsFile', _file_name) # /replacements | |
1007 | _Same(_manifest, 'SuppressStartupBanner', _boolean) # /nologo | |
1008 | _Same(_manifest, 'TypeLibraryFile', _file_name) # /tlb: | |
1009 | _Same(_manifest, 'UpdateFileHashes', _boolean) # /hashupdate | |
1010 | _Same(_manifest, 'UpdateFileHashesSearchPath', _file_name) | |
1011 | _Same(_manifest, 'VerboseOutput', _boolean) # /verbose | |
1012 | ||
1013 | # Options that have moved location. | |
1014 | _MovedAndRenamed(_manifest, 'ManifestResourceFile', | |
1015 | 'ManifestResourceCompile', | |
1016 | 'ResourceOutputFileName', | |
1017 | _file_name) | |
1018 | _Moved(_manifest, 'EmbedManifest', '', _boolean) | |
1019 | ||
1020 | # MSVS options not found in MSBuild. | |
1021 | _MSVSOnly(_manifest, 'DependencyInformationFile', _file_name) | |
1022 | _MSVSOnly(_manifest, 'UseFAT32Workaround', _boolean) | |
1023 | _MSVSOnly(_manifest, 'UseUnicodeResponseFiles', _boolean) | |
1024 | ||
1025 | # MSBuild options not found in MSVS. | |
1026 | _MSBuildOnly(_manifest, 'EnableDPIAwareness', _boolean) | |
1027 | _MSBuildOnly(_manifest, 'GenerateCategoryTags', _boolean) # /category | |
1028 | _MSBuildOnly(_manifest, 'ManifestFromManagedAssembly', | |
1029 | _file_name) # /managedassemblyname | |
1030 | _MSBuildOnly(_manifest, 'OutputResourceManifests', _string) # /outputresource | |
1031 | _MSBuildOnly(_manifest, 'SuppressDependencyElement', _boolean) # /nodependency | |
1032 | _MSBuildOnly(_manifest, 'TrackerLogDirectory', _folder_name) |
0 | #!/usr/bin/python | |
1 | ||
2 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """Unit tests for the MSVSSettings.py file.""" | |
7 | ||
8 | import StringIO | |
9 | import unittest | |
10 | import MSVSSettings | |
11 | ||
12 | ||
13 | class TestSequenceFunctions(unittest.TestCase): | |
14 | ||
15 | def setUp(self): | |
16 | self.stderr = StringIO.StringIO() | |
17 | ||
18 | def _ExpectedWarnings(self, expected): | |
19 | """Compares recorded lines to expected warnings.""" | |
20 | self.stderr.seek(0) | |
21 | actual = self.stderr.read().split('\n') | |
22 | actual = [line for line in actual if line] | |
23 | self.assertEqual(sorted(expected), sorted(actual)) | |
24 | ||
25 | def testValidateMSVSSettings_tool_names(self): | |
26 | """Tests that only MSVS tool names are allowed.""" | |
27 | MSVSSettings.ValidateMSVSSettings( | |
28 | {'VCCLCompilerTool': {}, | |
29 | 'VCLinkerTool': {}, | |
30 | 'VCMIDLTool': {}, | |
31 | 'foo': {}, | |
32 | 'VCResourceCompilerTool': {}, | |
33 | 'VCLibrarianTool': {}, | |
34 | 'VCManifestTool': {}, | |
35 | 'ClCompile': {}}, | |
36 | self.stderr) | |
37 | self._ExpectedWarnings([ | |
38 | 'Warning: unrecognized tool foo', | |
39 | 'Warning: unrecognized tool ClCompile']) | |
40 | ||
41 | def testValidateMSVSSettings_settings(self): | |
42 | """Tests that for invalid MSVS settings.""" | |
43 | MSVSSettings.ValidateMSVSSettings( | |
44 | {'VCCLCompilerTool': { | |
45 | 'AdditionalIncludeDirectories': 'folder1;folder2', | |
46 | 'AdditionalOptions': ['string1', 'string2'], | |
47 | 'AdditionalUsingDirectories': 'folder1;folder2', | |
48 | 'AssemblerListingLocation': 'a_file_name', | |
49 | 'AssemblerOutput': '0', | |
50 | 'BasicRuntimeChecks': '5', | |
51 | 'BrowseInformation': 'fdkslj', | |
52 | 'BrowseInformationFile': 'a_file_name', | |
53 | 'BufferSecurityCheck': 'true', | |
54 | 'CallingConvention': '-1', | |
55 | 'CompileAs': '1', | |
56 | 'DebugInformationFormat': '2', | |
57 | 'DefaultCharIsUnsigned': 'true', | |
58 | 'Detect64BitPortabilityProblems': 'true', | |
59 | 'DisableLanguageExtensions': 'true', | |
60 | 'DisableSpecificWarnings': 'string1;string2', | |
61 | 'EnableEnhancedInstructionSet': '1', | |
62 | 'EnableFiberSafeOptimizations': 'true', | |
63 | 'EnableFunctionLevelLinking': 'true', | |
64 | 'EnableIntrinsicFunctions': 'true', | |
65 | 'EnablePREfast': 'true', | |
66 | 'Enableprefast': 'bogus', | |
67 | 'ErrorReporting': '1', | |
68 | 'ExceptionHandling': '1', | |
69 | 'ExpandAttributedSource': 'true', | |
70 | 'FavorSizeOrSpeed': '1', | |
71 | 'FloatingPointExceptions': 'true', | |
72 | 'FloatingPointModel': '1', | |
73 | 'ForceConformanceInForLoopScope': 'true', | |
74 | 'ForcedIncludeFiles': 'file1;file2', | |
75 | 'ForcedUsingFiles': 'file1;file2', | |
76 | 'GeneratePreprocessedFile': '1', | |
77 | 'GenerateXMLDocumentationFiles': 'true', | |
78 | 'IgnoreStandardIncludePath': 'true', | |
79 | 'InlineFunctionExpansion': '1', | |
80 | 'KeepComments': 'true', | |
81 | 'MinimalRebuild': 'true', | |
82 | 'ObjectFile': 'a_file_name', | |
83 | 'OmitDefaultLibName': 'true', | |
84 | 'OmitFramePointers': 'true', | |
85 | 'OpenMP': 'true', | |
86 | 'Optimization': '1', | |
87 | 'PrecompiledHeaderFile': 'a_file_name', | |
88 | 'PrecompiledHeaderThrough': 'a_file_name', | |
89 | 'PreprocessorDefinitions': 'string1;string2', | |
90 | 'ProgramDataBaseFileName': 'a_file_name', | |
91 | 'RuntimeLibrary': '1', | |
92 | 'RuntimeTypeInfo': 'true', | |
93 | 'ShowIncludes': 'true', | |
94 | 'SmallerTypeCheck': 'true', | |
95 | 'StringPooling': 'true', | |
96 | 'StructMemberAlignment': '1', | |
97 | 'SuppressStartupBanner': 'true', | |
98 | 'TreatWChar_tAsBuiltInType': 'true', | |
99 | 'UndefineAllPreprocessorDefinitions': 'true', | |
100 | 'UndefinePreprocessorDefinitions': 'string1;string2', | |
101 | 'UseFullPaths': 'true', | |
102 | 'UsePrecompiledHeader': '1', | |
103 | 'UseUnicodeResponseFiles': 'true', | |
104 | 'WarnAsError': 'true', | |
105 | 'WarningLevel': '1', | |
106 | 'WholeProgramOptimization': 'true', | |
107 | 'XMLDocumentationFileName': 'a_file_name', | |
108 | 'ZZXYZ': 'bogus'}, | |
109 | 'VCLinkerTool': { | |
110 | 'AdditionalDependencies': 'file1;file2', | |
111 | 'AdditionalLibraryDirectories': 'folder1;folder2', | |
112 | 'AdditionalManifestDependencies': 'file1;file2', | |
113 | 'AdditionalOptions': 'a string1', | |
114 | 'AddModuleNamesToAssembly': 'file1;file2', | |
115 | 'AllowIsolation': 'true', | |
116 | 'AssemblyDebug': '2', | |
117 | 'AssemblyLinkResource': 'file1;file2', | |
118 | 'BaseAddress': 'a string1', | |
119 | 'CLRImageType': '2', | |
120 | 'CLRThreadAttribute': '2', | |
121 | 'CLRUnmanagedCodeCheck': 'true', | |
122 | 'DataExecutionPrevention': '2', | |
123 | 'DelayLoadDLLs': 'file1;file2', | |
124 | 'DelaySign': 'true', | |
125 | 'Driver': '2', | |
126 | 'EmbedManagedResourceFile': 'file1;file2', | |
127 | 'EnableCOMDATFolding': '2', | |
128 | 'EnableUAC': 'true', | |
129 | 'EntryPointSymbol': 'a string1', | |
130 | 'ErrorReporting': '2', | |
131 | 'FixedBaseAddress': '2', | |
132 | 'ForceSymbolReferences': 'file1;file2', | |
133 | 'FunctionOrder': 'a_file_name', | |
134 | 'GenerateDebugInformation': 'true', | |
135 | 'GenerateManifest': 'true', | |
136 | 'GenerateMapFile': 'true', | |
137 | 'HeapCommitSize': 'a string1', | |
138 | 'HeapReserveSize': 'a string1', | |
139 | 'IgnoreAllDefaultLibraries': 'true', | |
140 | 'IgnoreDefaultLibraryNames': 'file1;file2', | |
141 | 'IgnoreEmbeddedIDL': 'true', | |
142 | 'IgnoreImportLibrary': 'true', | |
143 | 'ImportLibrary': 'a_file_name', | |
144 | 'KeyContainer': 'a_file_name', | |
145 | 'KeyFile': 'a_file_name', | |
146 | 'LargeAddressAware': '2', | |
147 | 'LinkIncremental': '2', | |
148 | 'LinkLibraryDependencies': 'true', | |
149 | 'LinkTimeCodeGeneration': '2', | |
150 | 'ManifestFile': 'a_file_name', | |
151 | 'MapExports': 'true', | |
152 | 'MapFileName': 'a_file_name', | |
153 | 'MergedIDLBaseFileName': 'a_file_name', | |
154 | 'MergeSections': 'a string1', | |
155 | 'MidlCommandFile': 'a_file_name', | |
156 | 'ModuleDefinitionFile': 'a_file_name', | |
157 | 'OptimizeForWindows98': '1', | |
158 | 'OptimizeReferences': '2', | |
159 | 'OutputFile': 'a_file_name', | |
160 | 'PerUserRedirection': 'true', | |
161 | 'Profile': 'true', | |
162 | 'ProfileGuidedDatabase': 'a_file_name', | |
163 | 'ProgramDatabaseFile': 'a_file_name', | |
164 | 'RandomizedBaseAddress': '2', | |
165 | 'RegisterOutput': 'true', | |
166 | 'ResourceOnlyDLL': 'true', | |
167 | 'SetChecksum': 'true', | |
168 | 'ShowProgress': '2', | |
169 | 'StackCommitSize': 'a string1', | |
170 | 'StackReserveSize': 'a string1', | |
171 | 'StripPrivateSymbols': 'a_file_name', | |
172 | 'SubSystem': '2', | |
173 | 'SupportUnloadOfDelayLoadedDLL': 'true', | |
174 | 'SuppressStartupBanner': 'true', | |
175 | 'SwapRunFromCD': 'true', | |
176 | 'SwapRunFromNet': 'true', | |
177 | 'TargetMachine': '2', | |
178 | 'TerminalServerAware': '2', | |
179 | 'TurnOffAssemblyGeneration': 'true', | |
180 | 'TypeLibraryFile': 'a_file_name', | |
181 | 'TypeLibraryResourceID': '33', | |
182 | 'UACExecutionLevel': '2', | |
183 | 'UACUIAccess': 'true', | |
184 | 'UseLibraryDependencyInputs': 'true', | |
185 | 'UseUnicodeResponseFiles': 'true', | |
186 | 'Version': 'a string1'}, | |
187 | 'VCMIDLTool': { | |
188 | 'AdditionalIncludeDirectories': 'folder1;folder2', | |
189 | 'AdditionalOptions': 'a string1', | |
190 | 'CPreprocessOptions': 'a string1', | |
191 | 'DefaultCharType': '1', | |
192 | 'DLLDataFileName': 'a_file_name', | |
193 | 'EnableErrorChecks': '1', | |
194 | 'ErrorCheckAllocations': 'true', | |
195 | 'ErrorCheckBounds': 'true', | |
196 | 'ErrorCheckEnumRange': 'true', | |
197 | 'ErrorCheckRefPointers': 'true', | |
198 | 'ErrorCheckStubData': 'true', | |
199 | 'GenerateStublessProxies': 'true', | |
200 | 'GenerateTypeLibrary': 'true', | |
201 | 'HeaderFileName': 'a_file_name', | |
202 | 'IgnoreStandardIncludePath': 'true', | |
203 | 'InterfaceIdentifierFileName': 'a_file_name', | |
204 | 'MkTypLibCompatible': 'true', | |
205 | 'notgood': 'bogus', | |
206 | 'OutputDirectory': 'a string1', | |
207 | 'PreprocessorDefinitions': 'string1;string2', | |
208 | 'ProxyFileName': 'a_file_name', | |
209 | 'RedirectOutputAndErrors': 'a_file_name', | |
210 | 'StructMemberAlignment': '1', | |
211 | 'SuppressStartupBanner': 'true', | |
212 | 'TargetEnvironment': '1', | |
213 | 'TypeLibraryName': 'a_file_name', | |
214 | 'UndefinePreprocessorDefinitions': 'string1;string2', | |
215 | 'ValidateParameters': 'true', | |
216 | 'WarnAsError': 'true', | |
217 | 'WarningLevel': '1'}, | |
218 | 'VCResourceCompilerTool': { | |
219 | 'AdditionalOptions': 'a string1', | |
220 | 'AdditionalIncludeDirectories': 'folder1;folder2', | |
221 | 'Culture': '1003', | |
222 | 'IgnoreStandardIncludePath': 'true', | |
223 | 'notgood2': 'bogus', | |
224 | 'PreprocessorDefinitions': 'string1;string2', | |
225 | 'ResourceOutputFileName': 'a string1', | |
226 | 'ShowProgress': 'true', | |
227 | 'SuppressStartupBanner': 'true', | |
228 | 'UndefinePreprocessorDefinitions': 'string1;string2'}, | |
229 | 'VCLibrarianTool': { | |
230 | 'AdditionalDependencies': 'file1;file2', | |
231 | 'AdditionalLibraryDirectories': 'folder1;folder2', | |
232 | 'AdditionalOptions': 'a string1', | |
233 | 'ExportNamedFunctions': 'string1;string2', | |
234 | 'ForceSymbolReferences': 'a string1', | |
235 | 'IgnoreAllDefaultLibraries': 'true', | |
236 | 'IgnoreSpecificDefaultLibraries': 'file1;file2', | |
237 | 'LinkLibraryDependencies': 'true', | |
238 | 'ModuleDefinitionFile': 'a_file_name', | |
239 | 'OutputFile': 'a_file_name', | |
240 | 'SuppressStartupBanner': 'true', | |
241 | 'UseUnicodeResponseFiles': 'true'}, | |
242 | 'VCManifestTool': { | |
243 | 'AdditionalManifestFiles': 'file1;file2', | |
244 | 'AdditionalOptions': 'a string1', | |
245 | 'AssemblyIdentity': 'a string1', | |
246 | 'ComponentFileName': 'a_file_name', | |
247 | 'DependencyInformationFile': 'a_file_name', | |
248 | 'GenerateCatalogFiles': 'true', | |
249 | 'InputResourceManifests': 'a string1', | |
250 | 'ManifestResourceFile': 'a_file_name', | |
251 | 'OutputManifestFile': 'a_file_name', | |
252 | 'RegistrarScriptFile': 'a_file_name', | |
253 | 'ReplacementsFile': 'a_file_name', | |
254 | 'SuppressStartupBanner': 'true', | |
255 | 'TypeLibraryFile': 'a_file_name', | |
256 | 'UpdateFileHashes': 'truel', | |
257 | 'UpdateFileHashesSearchPath': 'a_file_name', | |
258 | 'UseFAT32Workaround': 'true', | |
259 | 'UseUnicodeResponseFiles': 'true', | |
260 | 'VerboseOutput': 'true'}}, | |
261 | self.stderr) | |
262 | self._ExpectedWarnings([ | |
263 | 'Warning: for VCCLCompilerTool/BasicRuntimeChecks, ' | |
264 | 'index value (5) not in expected range [0, 4)', | |
265 | 'Warning: for VCCLCompilerTool/BrowseInformation, ' | |
266 | "invalid literal for int() with base 10: 'fdkslj'", | |
267 | 'Warning: for VCCLCompilerTool/CallingConvention, ' | |
268 | 'index value (-1) not in expected range [0, 3)', | |
269 | 'Warning: for VCCLCompilerTool/DebugInformationFormat, ' | |
270 | 'converted value for 2 not specified.', | |
271 | 'Warning: unrecognized setting VCCLCompilerTool/Enableprefast', | |
272 | 'Warning: unrecognized setting VCCLCompilerTool/ZZXYZ', | |
273 | 'Warning: for VCLinkerTool/TargetMachine, ' | |
274 | 'converted value for 2 not specified.', | |
275 | 'Warning: unrecognized setting VCMIDLTool/notgood', | |
276 | 'Warning: unrecognized setting VCResourceCompilerTool/notgood2', | |
277 | 'Warning: for VCManifestTool/UpdateFileHashes, ' | |
278 | "expected bool; got 'truel'" | |
279 | '']) | |
280 | ||
281 | def testValidateMSBuildSettings_settings(self): | |
282 | """Tests that for invalid MSBuild settings.""" | |
283 | MSVSSettings.ValidateMSBuildSettings( | |
284 | {'ClCompile': { | |
285 | 'AdditionalIncludeDirectories': 'folder1;folder2', | |
286 | 'AdditionalOptions': ['string1', 'string2'], | |
287 | 'AdditionalUsingDirectories': 'folder1;folder2', | |
288 | 'AssemblerListingLocation': 'a_file_name', | |
289 | 'AssemblerOutput': 'NoListing', | |
290 | 'BasicRuntimeChecks': 'StackFrameRuntimeCheck', | |
291 | 'BrowseInformation': 'false', | |
292 | 'BrowseInformationFile': 'a_file_name', | |
293 | 'BufferSecurityCheck': 'true', | |
294 | 'BuildingInIDE': 'true', | |
295 | 'CallingConvention': 'Cdecl', | |
296 | 'CompileAs': 'CompileAsC', | |
297 | 'CompileAsManaged': 'Pure', | |
298 | 'CreateHotpatchableImage': 'true', | |
299 | 'DebugInformationFormat': 'ProgramDatabase', | |
300 | 'DisableLanguageExtensions': 'true', | |
301 | 'DisableSpecificWarnings': 'string1;string2', | |
302 | 'EnableEnhancedInstructionSet': 'StreamingSIMDExtensions', | |
303 | 'EnableFiberSafeOptimizations': 'true', | |
304 | 'EnablePREfast': 'true', | |
305 | 'Enableprefast': 'bogus', | |
306 | 'ErrorReporting': 'Prompt', | |
307 | 'ExceptionHandling': 'SyncCThrow', | |
308 | 'ExpandAttributedSource': 'true', | |
309 | 'FavorSizeOrSpeed': 'Neither', | |
310 | 'FloatingPointExceptions': 'true', | |
311 | 'FloatingPointModel': 'Precise', | |
312 | 'ForceConformanceInForLoopScope': 'true', | |
313 | 'ForcedIncludeFiles': 'file1;file2', | |
314 | 'ForcedUsingFiles': 'file1;file2', | |
315 | 'FunctionLevelLinking': 'false', | |
316 | 'GenerateXMLDocumentationFiles': 'true', | |
317 | 'IgnoreStandardIncludePath': 'true', | |
318 | 'InlineFunctionExpansion': 'OnlyExplicitInline', | |
319 | 'IntrinsicFunctions': 'false', | |
320 | 'MinimalRebuild': 'true', | |
321 | 'MultiProcessorCompilation': 'true', | |
322 | 'ObjectFileName': 'a_file_name', | |
323 | 'OmitDefaultLibName': 'true', | |
324 | 'OmitFramePointers': 'true', | |
325 | 'OpenMPSupport': 'true', | |
326 | 'Optimization': 'Disabled', | |
327 | 'PrecompiledHeader': 'NotUsing', | |
328 | 'PrecompiledHeaderFile': 'a_file_name', | |
329 | 'PrecompiledHeaderOutputFile': 'a_file_name', | |
330 | 'PreprocessKeepComments': 'true', | |
331 | 'PreprocessorDefinitions': 'string1;string2', | |
332 | 'PreprocessOutputPath': 'a string1', | |
333 | 'PreprocessSuppressLineNumbers': 'false', | |
334 | 'PreprocessToFile': 'false', | |
335 | 'ProcessorNumber': '33', | |
336 | 'ProgramDataBaseFileName': 'a_file_name', | |
337 | 'RuntimeLibrary': 'MultiThreaded', | |
338 | 'RuntimeTypeInfo': 'true', | |
339 | 'ShowIncludes': 'true', | |
340 | 'SmallerTypeCheck': 'true', | |
341 | 'StringPooling': 'true', | |
342 | 'StructMemberAlignment': '1Byte', | |
343 | 'SuppressStartupBanner': 'true', | |
344 | 'TrackerLogDirectory': 'a_folder', | |
345 | 'TreatSpecificWarningsAsErrors': 'string1;string2', | |
346 | 'TreatWarningAsError': 'true', | |
347 | 'TreatWChar_tAsBuiltInType': 'true', | |
348 | 'UndefineAllPreprocessorDefinitions': 'true', | |
349 | 'UndefinePreprocessorDefinitions': 'string1;string2', | |
350 | 'UseFullPaths': 'true', | |
351 | 'UseUnicodeForAssemblerListing': 'true', | |
352 | 'WarningLevel': 'TurnOffAllWarnings', | |
353 | 'WholeProgramOptimization': 'true', | |
354 | 'XMLDocumentationFileName': 'a_file_name', | |
355 | 'ZZXYZ': 'bogus'}, | |
356 | 'Link': { | |
357 | 'AdditionalDependencies': 'file1;file2', | |
358 | 'AdditionalLibraryDirectories': 'folder1;folder2', | |
359 | 'AdditionalManifestDependencies': 'file1;file2', | |
360 | 'AdditionalOptions': 'a string1', | |
361 | 'AddModuleNamesToAssembly': 'file1;file2', | |
362 | 'AllowIsolation': 'true', | |
363 | 'AssemblyDebug': '', | |
364 | 'AssemblyLinkResource': 'file1;file2', | |
365 | 'BaseAddress': 'a string1', | |
366 | 'BuildingInIDE': 'true', | |
367 | 'CLRImageType': 'ForceIJWImage', | |
368 | 'CLRSupportLastError': 'Enabled', | |
369 | 'CLRThreadAttribute': 'MTAThreadingAttribute', | |
370 | 'CLRUnmanagedCodeCheck': 'true', | |
371 | 'CreateHotPatchableImage': 'X86Image', | |
372 | 'DataExecutionPrevention': 'false', | |
373 | 'DelayLoadDLLs': 'file1;file2', | |
374 | 'DelaySign': 'true', | |
375 | 'Driver': 'NotSet', | |
376 | 'EmbedManagedResourceFile': 'file1;file2', | |
377 | 'EnableCOMDATFolding': 'false', | |
378 | 'EnableUAC': 'true', | |
379 | 'EntryPointSymbol': 'a string1', | |
380 | 'FixedBaseAddress': 'false', | |
381 | 'ForceFileOutput': 'Enabled', | |
382 | 'ForceSymbolReferences': 'file1;file2', | |
383 | 'FunctionOrder': 'a_file_name', | |
384 | 'GenerateDebugInformation': 'true', | |
385 | 'GenerateMapFile': 'true', | |
386 | 'HeapCommitSize': 'a string1', | |
387 | 'HeapReserveSize': 'a string1', | |
388 | 'IgnoreAllDefaultLibraries': 'true', | |
389 | 'IgnoreEmbeddedIDL': 'true', | |
390 | 'IgnoreSpecificDefaultLibraries': 'a_file_list', | |
391 | 'ImageHasSafeExceptionHandlers': 'true', | |
392 | 'ImportLibrary': 'a_file_name', | |
393 | 'KeyContainer': 'a_file_name', | |
394 | 'KeyFile': 'a_file_name', | |
395 | 'LargeAddressAware': 'false', | |
396 | 'LinkDLL': 'true', | |
397 | 'LinkErrorReporting': 'SendErrorReport', | |
398 | 'LinkStatus': 'true', | |
399 | 'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration', | |
400 | 'ManifestFile': 'a_file_name', | |
401 | 'MapExports': 'true', | |
402 | 'MapFileName': 'a_file_name', | |
403 | 'MergedIDLBaseFileName': 'a_file_name', | |
404 | 'MergeSections': 'a string1', | |
405 | 'MidlCommandFile': 'a_file_name', | |
406 | 'MinimumRequiredVersion': 'a string1', | |
407 | 'ModuleDefinitionFile': 'a_file_name', | |
408 | 'MSDOSStubFileName': 'a_file_name', | |
409 | 'NoEntryPoint': 'true', | |
410 | 'OptimizeReferences': 'false', | |
411 | 'OutputFile': 'a_file_name', | |
412 | 'PerUserRedirection': 'true', | |
413 | 'PreventDllBinding': 'true', | |
414 | 'Profile': 'true', | |
415 | 'ProfileGuidedDatabase': 'a_file_name', | |
416 | 'ProgramDatabaseFile': 'a_file_name', | |
417 | 'RandomizedBaseAddress': 'false', | |
418 | 'RegisterOutput': 'true', | |
419 | 'SectionAlignment': '33', | |
420 | 'SetChecksum': 'true', | |
421 | 'ShowProgress': 'LinkVerboseREF', | |
422 | 'SpecifySectionAttributes': 'a string1', | |
423 | 'StackCommitSize': 'a string1', | |
424 | 'StackReserveSize': 'a string1', | |
425 | 'StripPrivateSymbols': 'a_file_name', | |
426 | 'SubSystem': 'Console', | |
427 | 'SupportNobindOfDelayLoadedDLL': 'true', | |
428 | 'SupportUnloadOfDelayLoadedDLL': 'true', | |
429 | 'SuppressStartupBanner': 'true', | |
430 | 'SwapRunFromCD': 'true', | |
431 | 'SwapRunFromNET': 'true', | |
432 | 'TargetMachine': 'MachineX86', | |
433 | 'TerminalServerAware': 'false', | |
434 | 'TrackerLogDirectory': 'a_folder', | |
435 | 'TreatLinkerWarningAsErrors': 'true', | |
436 | 'TurnOffAssemblyGeneration': 'true', | |
437 | 'TypeLibraryFile': 'a_file_name', | |
438 | 'TypeLibraryResourceID': '33', | |
439 | 'UACExecutionLevel': 'AsInvoker', | |
440 | 'UACUIAccess': 'true', | |
441 | 'Version': 'a string1'}, | |
442 | 'ResourceCompile': { | |
443 | 'AdditionalIncludeDirectories': 'folder1;folder2', | |
444 | 'AdditionalOptions': 'a string1', | |
445 | 'Culture': '0x236', | |
446 | 'IgnoreStandardIncludePath': 'true', | |
447 | 'NullTerminateStrings': 'true', | |
448 | 'PreprocessorDefinitions': 'string1;string2', | |
449 | 'ResourceOutputFileName': 'a string1', | |
450 | 'ShowProgress': 'true', | |
451 | 'SuppressStartupBanner': 'true', | |
452 | 'TrackerLogDirectory': 'a_folder', | |
453 | 'UndefinePreprocessorDefinitions': 'string1;string2'}, | |
454 | 'Midl': { | |
455 | 'AdditionalIncludeDirectories': 'folder1;folder2', | |
456 | 'AdditionalOptions': 'a string1', | |
457 | 'ApplicationConfigurationMode': 'true', | |
458 | 'ClientStubFile': 'a_file_name', | |
459 | 'CPreprocessOptions': 'a string1', | |
460 | 'DefaultCharType': 'Signed', | |
461 | 'DllDataFileName': 'a_file_name', | |
462 | 'EnableErrorChecks': 'EnableCustom', | |
463 | 'ErrorCheckAllocations': 'true', | |
464 | 'ErrorCheckBounds': 'true', | |
465 | 'ErrorCheckEnumRange': 'true', | |
466 | 'ErrorCheckRefPointers': 'true', | |
467 | 'ErrorCheckStubData': 'true', | |
468 | 'GenerateClientFiles': 'Stub', | |
469 | 'GenerateServerFiles': 'None', | |
470 | 'GenerateStublessProxies': 'true', | |
471 | 'GenerateTypeLibrary': 'true', | |
472 | 'HeaderFileName': 'a_file_name', | |
473 | 'IgnoreStandardIncludePath': 'true', | |
474 | 'InterfaceIdentifierFileName': 'a_file_name', | |
475 | 'LocaleID': '33', | |
476 | 'MkTypLibCompatible': 'true', | |
477 | 'OutputDirectory': 'a string1', | |
478 | 'PreprocessorDefinitions': 'string1;string2', | |
479 | 'ProxyFileName': 'a_file_name', | |
480 | 'RedirectOutputAndErrors': 'a_file_name', | |
481 | 'ServerStubFile': 'a_file_name', | |
482 | 'StructMemberAlignment': 'NotSet', | |
483 | 'SuppressCompilerWarnings': 'true', | |
484 | 'SuppressStartupBanner': 'true', | |
485 | 'TargetEnvironment': 'Itanium', | |
486 | 'TrackerLogDirectory': 'a_folder', | |
487 | 'TypeLibFormat': 'NewFormat', | |
488 | 'TypeLibraryName': 'a_file_name', | |
489 | 'UndefinePreprocessorDefinitions': 'string1;string2', | |
490 | 'ValidateAllParameters': 'true', | |
491 | 'WarnAsError': 'true', | |
492 | 'WarningLevel': '1'}, | |
493 | 'Lib': { | |
494 | 'AdditionalDependencies': 'file1;file2', | |
495 | 'AdditionalLibraryDirectories': 'folder1;folder2', | |
496 | 'AdditionalOptions': 'a string1', | |
497 | 'DisplayLibrary': 'a string1', | |
498 | 'ErrorReporting': 'PromptImmediately', | |
499 | 'ExportNamedFunctions': 'string1;string2', | |
500 | 'ForceSymbolReferences': 'a string1', | |
501 | 'IgnoreAllDefaultLibraries': 'true', | |
502 | 'IgnoreSpecificDefaultLibraries': 'file1;file2', | |
503 | 'LinkTimeCodeGeneration': 'true', | |
504 | 'MinimumRequiredVersion': 'a string1', | |
505 | 'ModuleDefinitionFile': 'a_file_name', | |
506 | 'Name': 'a_file_name', | |
507 | 'OutputFile': 'a_file_name', | |
508 | 'RemoveObjects': 'file1;file2', | |
509 | 'SubSystem': 'Console', | |
510 | 'SuppressStartupBanner': 'true', | |
511 | 'TargetMachine': 'MachineX86i', | |
512 | 'TrackerLogDirectory': 'a_folder', | |
513 | 'TreatLibWarningAsErrors': 'true', | |
514 | 'UseUnicodeResponseFiles': 'true', | |
515 | 'Verbose': 'true'}, | |
516 | 'Mt': { | |
517 | 'AdditionalManifestFiles': 'file1;file2', | |
518 | 'AdditionalOptions': 'a string1', | |
519 | 'AssemblyIdentity': 'a string1', | |
520 | 'ComponentFileName': 'a_file_name', | |
521 | 'EnableDPIAwareness': 'fal', | |
522 | 'GenerateCatalogFiles': 'truel', | |
523 | 'GenerateCategoryTags': 'true', | |
524 | 'InputResourceManifests': 'a string1', | |
525 | 'ManifestFromManagedAssembly': 'a_file_name', | |
526 | 'notgood3': 'bogus', | |
527 | 'OutputManifestFile': 'a_file_name', | |
528 | 'OutputResourceManifests': 'a string1', | |
529 | 'RegistrarScriptFile': 'a_file_name', | |
530 | 'ReplacementsFile': 'a_file_name', | |
531 | 'SuppressDependencyElement': 'true', | |
532 | 'SuppressStartupBanner': 'true', | |
533 | 'TrackerLogDirectory': 'a_folder', | |
534 | 'TypeLibraryFile': 'a_file_name', | |
535 | 'UpdateFileHashes': 'true', | |
536 | 'UpdateFileHashesSearchPath': 'a_file_name', | |
537 | 'VerboseOutput': 'true'}, | |
538 | 'ProjectReference': { | |
539 | 'LinkLibraryDependencies': 'true', | |
540 | 'UseLibraryDependencyInputs': 'true'}, | |
541 | 'ManifestResourceCompile': { | |
542 | 'ResourceOutputFileName': 'a_file_name'}, | |
543 | '': { | |
544 | 'EmbedManifest': 'true', | |
545 | 'GenerateManifest': 'true', | |
546 | 'IgnoreImportLibrary': 'true', | |
547 | 'LinkIncremental': 'false'}}, | |
548 | self.stderr) | |
549 | self._ExpectedWarnings([ | |
550 | 'Warning: unrecognized setting ClCompile/Enableprefast', | |
551 | 'Warning: unrecognized setting ClCompile/ZZXYZ', | |
552 | 'Warning: unrecognized setting Mt/notgood3', | |
553 | "Warning: for Mt/GenerateCatalogFiles, expected bool; got 'truel'", | |
554 | 'Warning: for Lib/TargetMachine, unrecognized enumerated value ' | |
555 | 'MachineX86i', | |
556 | "Warning: for Mt/EnableDPIAwareness, expected bool; got 'fal'"]) | |
557 | ||
558 | def testConvertToMSBuildSettings_empty(self): | |
559 | """Tests an empty conversion.""" | |
560 | msvs_settings = {} | |
561 | expected_msbuild_settings = {} | |
562 | actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( | |
563 | msvs_settings, | |
564 | self.stderr) | |
565 | self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) | |
566 | self._ExpectedWarnings([]) | |
567 | ||
568 | def testConvertToMSBuildSettings_minimal(self): | |
569 | """Tests a minimal conversion.""" | |
570 | msvs_settings = { | |
571 | 'VCCLCompilerTool': { | |
572 | 'AdditionalIncludeDirectories': 'dir1', | |
573 | 'AdditionalOptions': '/foo', | |
574 | 'BasicRuntimeChecks': '0', | |
575 | }, | |
576 | 'VCLinkerTool': { | |
577 | 'LinkTimeCodeGeneration': '1', | |
578 | 'ErrorReporting': '1', | |
579 | 'DataExecutionPrevention': '2', | |
580 | }, | |
581 | } | |
582 | expected_msbuild_settings = { | |
583 | 'ClCompile': { | |
584 | 'AdditionalIncludeDirectories': 'dir1', | |
585 | 'AdditionalOptions': '/foo', | |
586 | 'BasicRuntimeChecks': 'Default', | |
587 | }, | |
588 | 'Link': { | |
589 | 'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration', | |
590 | 'LinkErrorReporting': 'PromptImmediately', | |
591 | 'DataExecutionPrevention': 'true', | |
592 | }, | |
593 | } | |
594 | actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( | |
595 | msvs_settings, | |
596 | self.stderr) | |
597 | self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) | |
598 | self._ExpectedWarnings([]) | |
599 | ||
600 | def testConvertToMSBuildSettings_warnings(self): | |
601 | """Tests conversion that generates warnings.""" | |
602 | msvs_settings = { | |
603 | 'VCCLCompilerTool': { | |
604 | 'AdditionalIncludeDirectories': '1', | |
605 | 'AdditionalOptions': '2', | |
606 | # These are incorrect values: | |
607 | 'BasicRuntimeChecks': '12', | |
608 | 'BrowseInformation': '21', | |
609 | 'UsePrecompiledHeader': '13', | |
610 | 'GeneratePreprocessedFile': '14'}, | |
611 | 'VCLinkerTool': { | |
612 | # These are incorrect values: | |
613 | 'Driver': '10', | |
614 | 'LinkTimeCodeGeneration': '31', | |
615 | 'ErrorReporting': '21', | |
616 | 'FixedBaseAddress': '6'}, | |
617 | 'VCResourceCompilerTool': { | |
618 | # Custom | |
619 | 'Culture': '1003'}} | |
620 | expected_msbuild_settings = { | |
621 | 'ClCompile': { | |
622 | 'AdditionalIncludeDirectories': '1', | |
623 | 'AdditionalOptions': '2'}, | |
624 | 'Link': {}, | |
625 | 'ResourceCompile': { | |
626 | # Custom | |
627 | 'Culture': '0x03eb'}} | |
628 | actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( | |
629 | msvs_settings, | |
630 | self.stderr) | |
631 | self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) | |
632 | self._ExpectedWarnings([ | |
633 | 'Warning: while converting VCCLCompilerTool/BasicRuntimeChecks to ' | |
634 | 'MSBuild, index value (12) not in expected range [0, 4)', | |
635 | 'Warning: while converting VCCLCompilerTool/BrowseInformation to ' | |
636 | 'MSBuild, index value (21) not in expected range [0, 3)', | |
637 | 'Warning: while converting VCCLCompilerTool/UsePrecompiledHeader to ' | |
638 | 'MSBuild, index value (13) not in expected range [0, 3)', | |
639 | 'Warning: while converting VCCLCompilerTool/GeneratePreprocessedFile to ' | |
640 | 'MSBuild, value must be one of [0, 1, 2]; got 14', | |
641 | ||
642 | 'Warning: while converting VCLinkerTool/Driver to ' | |
643 | 'MSBuild, index value (10) not in expected range [0, 4)', | |
644 | 'Warning: while converting VCLinkerTool/LinkTimeCodeGeneration to ' | |
645 | 'MSBuild, index value (31) not in expected range [0, 5)', | |
646 | 'Warning: while converting VCLinkerTool/ErrorReporting to ' | |
647 | 'MSBuild, index value (21) not in expected range [0, 3)', | |
648 | 'Warning: while converting VCLinkerTool/FixedBaseAddress to ' | |
649 | 'MSBuild, index value (6) not in expected range [0, 3)', | |
650 | ]) | |
651 | ||
652 | def testConvertToMSBuildSettings_full_synthetic(self): | |
653 | """Tests conversion of all the MSBuild settings.""" | |
654 | msvs_settings = { | |
655 | 'VCCLCompilerTool': { | |
656 | 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', | |
657 | 'AdditionalOptions': 'a_string', | |
658 | 'AdditionalUsingDirectories': 'folder1;folder2;folder3', | |
659 | 'AssemblerListingLocation': 'a_file_name', | |
660 | 'AssemblerOutput': '0', | |
661 | 'BasicRuntimeChecks': '1', | |
662 | 'BrowseInformation': '2', | |
663 | 'BrowseInformationFile': 'a_file_name', | |
664 | 'BufferSecurityCheck': 'true', | |
665 | 'CallingConvention': '0', | |
666 | 'CompileAs': '1', | |
667 | 'DebugInformationFormat': '4', | |
668 | 'DefaultCharIsUnsigned': 'true', | |
669 | 'Detect64BitPortabilityProblems': 'true', | |
670 | 'DisableLanguageExtensions': 'true', | |
671 | 'DisableSpecificWarnings': 'd1;d2;d3', | |
672 | 'EnableEnhancedInstructionSet': '0', | |
673 | 'EnableFiberSafeOptimizations': 'true', | |
674 | 'EnableFunctionLevelLinking': 'true', | |
675 | 'EnableIntrinsicFunctions': 'true', | |
676 | 'EnablePREfast': 'true', | |
677 | 'ErrorReporting': '1', | |
678 | 'ExceptionHandling': '2', | |
679 | 'ExpandAttributedSource': 'true', | |
680 | 'FavorSizeOrSpeed': '0', | |
681 | 'FloatingPointExceptions': 'true', | |
682 | 'FloatingPointModel': '1', | |
683 | 'ForceConformanceInForLoopScope': 'true', | |
684 | 'ForcedIncludeFiles': 'file1;file2;file3', | |
685 | 'ForcedUsingFiles': 'file1;file2;file3', | |
686 | 'GeneratePreprocessedFile': '1', | |
687 | 'GenerateXMLDocumentationFiles': 'true', | |
688 | 'IgnoreStandardIncludePath': 'true', | |
689 | 'InlineFunctionExpansion': '2', | |
690 | 'KeepComments': 'true', | |
691 | 'MinimalRebuild': 'true', | |
692 | 'ObjectFile': 'a_file_name', | |
693 | 'OmitDefaultLibName': 'true', | |
694 | 'OmitFramePointers': 'true', | |
695 | 'OpenMP': 'true', | |
696 | 'Optimization': '3', | |
697 | 'PrecompiledHeaderFile': 'a_file_name', | |
698 | 'PrecompiledHeaderThrough': 'a_file_name', | |
699 | 'PreprocessorDefinitions': 'd1;d2;d3', | |
700 | 'ProgramDataBaseFileName': 'a_file_name', | |
701 | 'RuntimeLibrary': '0', | |
702 | 'RuntimeTypeInfo': 'true', | |
703 | 'ShowIncludes': 'true', | |
704 | 'SmallerTypeCheck': 'true', | |
705 | 'StringPooling': 'true', | |
706 | 'StructMemberAlignment': '1', | |
707 | 'SuppressStartupBanner': 'true', | |
708 | 'TreatWChar_tAsBuiltInType': 'true', | |
709 | 'UndefineAllPreprocessorDefinitions': 'true', | |
710 | 'UndefinePreprocessorDefinitions': 'd1;d2;d3', | |
711 | 'UseFullPaths': 'true', | |
712 | 'UsePrecompiledHeader': '1', | |
713 | 'UseUnicodeResponseFiles': 'true', | |
714 | 'WarnAsError': 'true', | |
715 | 'WarningLevel': '2', | |
716 | 'WholeProgramOptimization': 'true', | |
717 | 'XMLDocumentationFileName': 'a_file_name'}, | |
718 | 'VCLinkerTool': { | |
719 | 'AdditionalDependencies': 'file1;file2;file3', | |
720 | 'AdditionalLibraryDirectories': 'folder1;folder2;folder3', | |
721 | 'AdditionalLibraryDirectories_excluded': 'folder1;folder2;folder3', | |
722 | 'AdditionalManifestDependencies': 'file1;file2;file3', | |
723 | 'AdditionalOptions': 'a_string', | |
724 | 'AddModuleNamesToAssembly': 'file1;file2;file3', | |
725 | 'AllowIsolation': 'true', | |
726 | 'AssemblyDebug': '0', | |
727 | 'AssemblyLinkResource': 'file1;file2;file3', | |
728 | 'BaseAddress': 'a_string', | |
729 | 'CLRImageType': '1', | |
730 | 'CLRThreadAttribute': '2', | |
731 | 'CLRUnmanagedCodeCheck': 'true', | |
732 | 'DataExecutionPrevention': '0', | |
733 | 'DelayLoadDLLs': 'file1;file2;file3', | |
734 | 'DelaySign': 'true', | |
735 | 'Driver': '1', | |
736 | 'EmbedManagedResourceFile': 'file1;file2;file3', | |
737 | 'EnableCOMDATFolding': '0', | |
738 | 'EnableUAC': 'true', | |
739 | 'EntryPointSymbol': 'a_string', | |
740 | 'ErrorReporting': '0', | |
741 | 'FixedBaseAddress': '1', | |
742 | 'ForceSymbolReferences': 'file1;file2;file3', | |
743 | 'FunctionOrder': 'a_file_name', | |
744 | 'GenerateDebugInformation': 'true', | |
745 | 'GenerateManifest': 'true', | |
746 | 'GenerateMapFile': 'true', | |
747 | 'HeapCommitSize': 'a_string', | |
748 | 'HeapReserveSize': 'a_string', | |
749 | 'IgnoreAllDefaultLibraries': 'true', | |
750 | 'IgnoreDefaultLibraryNames': 'file1;file2;file3', | |
751 | 'IgnoreEmbeddedIDL': 'true', | |
752 | 'IgnoreImportLibrary': 'true', | |
753 | 'ImportLibrary': 'a_file_name', | |
754 | 'KeyContainer': 'a_file_name', | |
755 | 'KeyFile': 'a_file_name', | |
756 | 'LargeAddressAware': '2', | |
757 | 'LinkIncremental': '1', | |
758 | 'LinkLibraryDependencies': 'true', | |
759 | 'LinkTimeCodeGeneration': '2', | |
760 | 'ManifestFile': 'a_file_name', | |
761 | 'MapExports': 'true', | |
762 | 'MapFileName': 'a_file_name', | |
763 | 'MergedIDLBaseFileName': 'a_file_name', | |
764 | 'MergeSections': 'a_string', | |
765 | 'MidlCommandFile': 'a_file_name', | |
766 | 'ModuleDefinitionFile': 'a_file_name', | |
767 | 'OptimizeForWindows98': '1', | |
768 | 'OptimizeReferences': '0', | |
769 | 'OutputFile': 'a_file_name', | |
770 | 'PerUserRedirection': 'true', | |
771 | 'Profile': 'true', | |
772 | 'ProfileGuidedDatabase': 'a_file_name', | |
773 | 'ProgramDatabaseFile': 'a_file_name', | |
774 | 'RandomizedBaseAddress': '1', | |
775 | 'RegisterOutput': 'true', | |
776 | 'ResourceOnlyDLL': 'true', | |
777 | 'SetChecksum': 'true', | |
778 | 'ShowProgress': '0', | |
779 | 'StackCommitSize': 'a_string', | |
780 | 'StackReserveSize': 'a_string', | |
781 | 'StripPrivateSymbols': 'a_file_name', | |
782 | 'SubSystem': '2', | |
783 | 'SupportUnloadOfDelayLoadedDLL': 'true', | |
784 | 'SuppressStartupBanner': 'true', | |
785 | 'SwapRunFromCD': 'true', | |
786 | 'SwapRunFromNet': 'true', | |
787 | 'TargetMachine': '3', | |
788 | 'TerminalServerAware': '2', | |
789 | 'TurnOffAssemblyGeneration': 'true', | |
790 | 'TypeLibraryFile': 'a_file_name', | |
791 | 'TypeLibraryResourceID': '33', | |
792 | 'UACExecutionLevel': '1', | |
793 | 'UACUIAccess': 'true', | |
794 | 'UseLibraryDependencyInputs': 'false', | |
795 | 'UseUnicodeResponseFiles': 'true', | |
796 | 'Version': 'a_string'}, | |
797 | 'VCResourceCompilerTool': { | |
798 | 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', | |
799 | 'AdditionalOptions': 'a_string', | |
800 | 'Culture': '1003', | |
801 | 'IgnoreStandardIncludePath': 'true', | |
802 | 'PreprocessorDefinitions': 'd1;d2;d3', | |
803 | 'ResourceOutputFileName': 'a_string', | |
804 | 'ShowProgress': 'true', | |
805 | 'SuppressStartupBanner': 'true', | |
806 | 'UndefinePreprocessorDefinitions': 'd1;d2;d3'}, | |
807 | 'VCMIDLTool': { | |
808 | 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', | |
809 | 'AdditionalOptions': 'a_string', | |
810 | 'CPreprocessOptions': 'a_string', | |
811 | 'DefaultCharType': '0', | |
812 | 'DLLDataFileName': 'a_file_name', | |
813 | 'EnableErrorChecks': '2', | |
814 | 'ErrorCheckAllocations': 'true', | |
815 | 'ErrorCheckBounds': 'true', | |
816 | 'ErrorCheckEnumRange': 'true', | |
817 | 'ErrorCheckRefPointers': 'true', | |
818 | 'ErrorCheckStubData': 'true', | |
819 | 'GenerateStublessProxies': 'true', | |
820 | 'GenerateTypeLibrary': 'true', | |
821 | 'HeaderFileName': 'a_file_name', | |
822 | 'IgnoreStandardIncludePath': 'true', | |
823 | 'InterfaceIdentifierFileName': 'a_file_name', | |
824 | 'MkTypLibCompatible': 'true', | |
825 | 'OutputDirectory': 'a_string', | |
826 | 'PreprocessorDefinitions': 'd1;d2;d3', | |
827 | 'ProxyFileName': 'a_file_name', | |
828 | 'RedirectOutputAndErrors': 'a_file_name', | |
829 | 'StructMemberAlignment': '3', | |
830 | 'SuppressStartupBanner': 'true', | |
831 | 'TargetEnvironment': '1', | |
832 | 'TypeLibraryName': 'a_file_name', | |
833 | 'UndefinePreprocessorDefinitions': 'd1;d2;d3', | |
834 | 'ValidateParameters': 'true', | |
835 | 'WarnAsError': 'true', | |
836 | 'WarningLevel': '4'}, | |
837 | 'VCLibrarianTool': { | |
838 | 'AdditionalDependencies': 'file1;file2;file3', | |
839 | 'AdditionalLibraryDirectories': 'folder1;folder2;folder3', | |
840 | 'AdditionalLibraryDirectories_excluded': 'folder1;folder2;folder3', | |
841 | 'AdditionalOptions': 'a_string', | |
842 | 'ExportNamedFunctions': 'd1;d2;d3', | |
843 | 'ForceSymbolReferences': 'a_string', | |
844 | 'IgnoreAllDefaultLibraries': 'true', | |
845 | 'IgnoreSpecificDefaultLibraries': 'file1;file2;file3', | |
846 | 'LinkLibraryDependencies': 'true', | |
847 | 'ModuleDefinitionFile': 'a_file_name', | |
848 | 'OutputFile': 'a_file_name', | |
849 | 'SuppressStartupBanner': 'true', | |
850 | 'UseUnicodeResponseFiles': 'true'}, | |
851 | 'VCManifestTool': { | |
852 | 'AdditionalManifestFiles': 'file1;file2;file3', | |
853 | 'AdditionalOptions': 'a_string', | |
854 | 'AssemblyIdentity': 'a_string', | |
855 | 'ComponentFileName': 'a_file_name', | |
856 | 'DependencyInformationFile': 'a_file_name', | |
857 | 'EmbedManifest': 'true', | |
858 | 'GenerateCatalogFiles': 'true', | |
859 | 'InputResourceManifests': 'a_string', | |
860 | 'ManifestResourceFile': 'my_name', | |
861 | 'OutputManifestFile': 'a_file_name', | |
862 | 'RegistrarScriptFile': 'a_file_name', | |
863 | 'ReplacementsFile': 'a_file_name', | |
864 | 'SuppressStartupBanner': 'true', | |
865 | 'TypeLibraryFile': 'a_file_name', | |
866 | 'UpdateFileHashes': 'true', | |
867 | 'UpdateFileHashesSearchPath': 'a_file_name', | |
868 | 'UseFAT32Workaround': 'true', | |
869 | 'UseUnicodeResponseFiles': 'true', | |
870 | 'VerboseOutput': 'true'}} | |
871 | expected_msbuild_settings = { | |
872 | 'ClCompile': { | |
873 | 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', | |
874 | 'AdditionalOptions': 'a_string /J', | |
875 | 'AdditionalUsingDirectories': 'folder1;folder2;folder3', | |
876 | 'AssemblerListingLocation': 'a_file_name', | |
877 | 'AssemblerOutput': 'NoListing', | |
878 | 'BasicRuntimeChecks': 'StackFrameRuntimeCheck', | |
879 | 'BrowseInformation': 'true', | |
880 | 'BrowseInformationFile': 'a_file_name', | |
881 | 'BufferSecurityCheck': 'true', | |
882 | 'CallingConvention': 'Cdecl', | |
883 | 'CompileAs': 'CompileAsC', | |
884 | 'DebugInformationFormat': 'EditAndContinue', | |
885 | 'DisableLanguageExtensions': 'true', | |
886 | 'DisableSpecificWarnings': 'd1;d2;d3', | |
887 | 'EnableEnhancedInstructionSet': 'NotSet', | |
888 | 'EnableFiberSafeOptimizations': 'true', | |
889 | 'EnablePREfast': 'true', | |
890 | 'ErrorReporting': 'Prompt', | |
891 | 'ExceptionHandling': 'Async', | |
892 | 'ExpandAttributedSource': 'true', | |
893 | 'FavorSizeOrSpeed': 'Neither', | |
894 | 'FloatingPointExceptions': 'true', | |
895 | 'FloatingPointModel': 'Strict', | |
896 | 'ForceConformanceInForLoopScope': 'true', | |
897 | 'ForcedIncludeFiles': 'file1;file2;file3', | |
898 | 'ForcedUsingFiles': 'file1;file2;file3', | |
899 | 'FunctionLevelLinking': 'true', | |
900 | 'GenerateXMLDocumentationFiles': 'true', | |
901 | 'IgnoreStandardIncludePath': 'true', | |
902 | 'InlineFunctionExpansion': 'AnySuitable', | |
903 | 'IntrinsicFunctions': 'true', | |
904 | 'MinimalRebuild': 'true', | |
905 | 'ObjectFileName': 'a_file_name', | |
906 | 'OmitDefaultLibName': 'true', | |
907 | 'OmitFramePointers': 'true', | |
908 | 'OpenMPSupport': 'true', | |
909 | 'Optimization': 'Full', | |
910 | 'PrecompiledHeader': 'Create', | |
911 | 'PrecompiledHeaderFile': 'a_file_name', | |
912 | 'PrecompiledHeaderOutputFile': 'a_file_name', | |
913 | 'PreprocessKeepComments': 'true', | |
914 | 'PreprocessorDefinitions': 'd1;d2;d3', | |
915 | 'PreprocessSuppressLineNumbers': 'false', | |
916 | 'PreprocessToFile': 'true', | |
917 | 'ProgramDataBaseFileName': 'a_file_name', | |
918 | 'RuntimeLibrary': 'MultiThreaded', | |
919 | 'RuntimeTypeInfo': 'true', | |
920 | 'ShowIncludes': 'true', | |
921 | 'SmallerTypeCheck': 'true', | |
922 | 'StringPooling': 'true', | |
923 | 'StructMemberAlignment': '1Byte', | |
924 | 'SuppressStartupBanner': 'true', | |
925 | 'TreatWarningAsError': 'true', | |
926 | 'TreatWChar_tAsBuiltInType': 'true', | |
927 | 'UndefineAllPreprocessorDefinitions': 'true', | |
928 | 'UndefinePreprocessorDefinitions': 'd1;d2;d3', | |
929 | 'UseFullPaths': 'true', | |
930 | 'WarningLevel': 'Level2', | |
931 | 'WholeProgramOptimization': 'true', | |
932 | 'XMLDocumentationFileName': 'a_file_name'}, | |
933 | 'Link': { | |
934 | 'AdditionalDependencies': 'file1;file2;file3', | |
935 | 'AdditionalLibraryDirectories': 'folder1;folder2;folder3', | |
936 | 'AdditionalManifestDependencies': 'file1;file2;file3', | |
937 | 'AdditionalOptions': 'a_string', | |
938 | 'AddModuleNamesToAssembly': 'file1;file2;file3', | |
939 | 'AllowIsolation': 'true', | |
940 | 'AssemblyDebug': '', | |
941 | 'AssemblyLinkResource': 'file1;file2;file3', | |
942 | 'BaseAddress': 'a_string', | |
943 | 'CLRImageType': 'ForceIJWImage', | |
944 | 'CLRThreadAttribute': 'STAThreadingAttribute', | |
945 | 'CLRUnmanagedCodeCheck': 'true', | |
946 | 'DataExecutionPrevention': '', | |
947 | 'DelayLoadDLLs': 'file1;file2;file3', | |
948 | 'DelaySign': 'true', | |
949 | 'Driver': 'Driver', | |
950 | 'EmbedManagedResourceFile': 'file1;file2;file3', | |
951 | 'EnableCOMDATFolding': '', | |
952 | 'EnableUAC': 'true', | |
953 | 'EntryPointSymbol': 'a_string', | |
954 | 'FixedBaseAddress': 'false', | |
955 | 'ForceSymbolReferences': 'file1;file2;file3', | |
956 | 'FunctionOrder': 'a_file_name', | |
957 | 'GenerateDebugInformation': 'true', | |
958 | 'GenerateMapFile': 'true', | |
959 | 'HeapCommitSize': 'a_string', | |
960 | 'HeapReserveSize': 'a_string', | |
961 | 'IgnoreAllDefaultLibraries': 'true', | |
962 | 'IgnoreEmbeddedIDL': 'true', | |
963 | 'IgnoreSpecificDefaultLibraries': 'file1;file2;file3', | |
964 | 'ImportLibrary': 'a_file_name', | |
965 | 'KeyContainer': 'a_file_name', | |
966 | 'KeyFile': 'a_file_name', | |
967 | 'LargeAddressAware': 'true', | |
968 | 'LinkErrorReporting': 'NoErrorReport', | |
969 | 'LinkTimeCodeGeneration': 'PGInstrument', | |
970 | 'ManifestFile': 'a_file_name', | |
971 | 'MapExports': 'true', | |
972 | 'MapFileName': 'a_file_name', | |
973 | 'MergedIDLBaseFileName': 'a_file_name', | |
974 | 'MergeSections': 'a_string', | |
975 | 'MidlCommandFile': 'a_file_name', | |
976 | 'ModuleDefinitionFile': 'a_file_name', | |
977 | 'NoEntryPoint': 'true', | |
978 | 'OptimizeReferences': '', | |
979 | 'OutputFile': 'a_file_name', | |
980 | 'PerUserRedirection': 'true', | |
981 | 'Profile': 'true', | |
982 | 'ProfileGuidedDatabase': 'a_file_name', | |
983 | 'ProgramDatabaseFile': 'a_file_name', | |
984 | 'RandomizedBaseAddress': 'false', | |
985 | 'RegisterOutput': 'true', | |
986 | 'SetChecksum': 'true', | |
987 | 'ShowProgress': 'NotSet', | |
988 | 'StackCommitSize': 'a_string', | |
989 | 'StackReserveSize': 'a_string', | |
990 | 'StripPrivateSymbols': 'a_file_name', | |
991 | 'SubSystem': 'Windows', | |
992 | 'SupportUnloadOfDelayLoadedDLL': 'true', | |
993 | 'SuppressStartupBanner': 'true', | |
994 | 'SwapRunFromCD': 'true', | |
995 | 'SwapRunFromNET': 'true', | |
996 | 'TargetMachine': 'MachineARM', | |
997 | 'TerminalServerAware': 'true', | |
998 | 'TurnOffAssemblyGeneration': 'true', | |
999 | 'TypeLibraryFile': 'a_file_name', | |
1000 | 'TypeLibraryResourceID': '33', | |
1001 | 'UACExecutionLevel': 'HighestAvailable', | |
1002 | 'UACUIAccess': 'true', | |
1003 | 'Version': 'a_string'}, | |
1004 | 'ResourceCompile': { | |
1005 | 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', | |
1006 | 'AdditionalOptions': 'a_string', | |
1007 | 'Culture': '0x03eb', | |
1008 | 'IgnoreStandardIncludePath': 'true', | |
1009 | 'PreprocessorDefinitions': 'd1;d2;d3', | |
1010 | 'ResourceOutputFileName': 'a_string', | |
1011 | 'ShowProgress': 'true', | |
1012 | 'SuppressStartupBanner': 'true', | |
1013 | 'UndefinePreprocessorDefinitions': 'd1;d2;d3'}, | |
1014 | 'Midl': { | |
1015 | 'AdditionalIncludeDirectories': 'folder1;folder2;folder3', | |
1016 | 'AdditionalOptions': 'a_string', | |
1017 | 'CPreprocessOptions': 'a_string', | |
1018 | 'DefaultCharType': 'Unsigned', | |
1019 | 'DllDataFileName': 'a_file_name', | |
1020 | 'EnableErrorChecks': 'All', | |
1021 | 'ErrorCheckAllocations': 'true', | |
1022 | 'ErrorCheckBounds': 'true', | |
1023 | 'ErrorCheckEnumRange': 'true', | |
1024 | 'ErrorCheckRefPointers': 'true', | |
1025 | 'ErrorCheckStubData': 'true', | |
1026 | 'GenerateStublessProxies': 'true', | |
1027 | 'GenerateTypeLibrary': 'true', | |
1028 | 'HeaderFileName': 'a_file_name', | |
1029 | 'IgnoreStandardIncludePath': 'true', | |
1030 | 'InterfaceIdentifierFileName': 'a_file_name', | |
1031 | 'MkTypLibCompatible': 'true', | |
1032 | 'OutputDirectory': 'a_string', | |
1033 | 'PreprocessorDefinitions': 'd1;d2;d3', | |
1034 | 'ProxyFileName': 'a_file_name', | |
1035 | 'RedirectOutputAndErrors': 'a_file_name', | |
1036 | 'StructMemberAlignment': '4', | |
1037 | 'SuppressStartupBanner': 'true', | |
1038 | 'TargetEnvironment': 'Win32', | |
1039 | 'TypeLibraryName': 'a_file_name', | |
1040 | 'UndefinePreprocessorDefinitions': 'd1;d2;d3', | |
1041 | 'ValidateAllParameters': 'true', | |
1042 | 'WarnAsError': 'true', | |
1043 | 'WarningLevel': '4'}, | |
1044 | 'Lib': { | |
1045 | 'AdditionalDependencies': 'file1;file2;file3', | |
1046 | 'AdditionalLibraryDirectories': 'folder1;folder2;folder3', | |
1047 | 'AdditionalOptions': 'a_string', | |
1048 | 'ExportNamedFunctions': 'd1;d2;d3', | |
1049 | 'ForceSymbolReferences': 'a_string', | |
1050 | 'IgnoreAllDefaultLibraries': 'true', | |
1051 | 'IgnoreSpecificDefaultLibraries': 'file1;file2;file3', | |
1052 | 'ModuleDefinitionFile': 'a_file_name', | |
1053 | 'OutputFile': 'a_file_name', | |
1054 | 'SuppressStartupBanner': 'true', | |
1055 | 'UseUnicodeResponseFiles': 'true'}, | |
1056 | 'Mt': { | |
1057 | 'AdditionalManifestFiles': 'file1;file2;file3', | |
1058 | 'AdditionalOptions': 'a_string', | |
1059 | 'AssemblyIdentity': 'a_string', | |
1060 | 'ComponentFileName': 'a_file_name', | |
1061 | 'GenerateCatalogFiles': 'true', | |
1062 | 'InputResourceManifests': 'a_string', | |
1063 | 'OutputManifestFile': 'a_file_name', | |
1064 | 'RegistrarScriptFile': 'a_file_name', | |
1065 | 'ReplacementsFile': 'a_file_name', | |
1066 | 'SuppressStartupBanner': 'true', | |
1067 | 'TypeLibraryFile': 'a_file_name', | |
1068 | 'UpdateFileHashes': 'true', | |
1069 | 'UpdateFileHashesSearchPath': 'a_file_name', | |
1070 | 'VerboseOutput': 'true'}, | |
1071 | 'ManifestResourceCompile': { | |
1072 | 'ResourceOutputFileName': 'my_name'}, | |
1073 | 'ProjectReference': { | |
1074 | 'LinkLibraryDependencies': 'true', | |
1075 | 'UseLibraryDependencyInputs': 'false'}, | |
1076 | '': { | |
1077 | 'EmbedManifest': 'true', | |
1078 | 'GenerateManifest': 'true', | |
1079 | 'IgnoreImportLibrary': 'true', | |
1080 | 'LinkIncremental': 'false'}} | |
1081 | actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( | |
1082 | msvs_settings, | |
1083 | self.stderr) | |
1084 | self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) | |
1085 | self._ExpectedWarnings([]) | |
1086 | ||
1087 | def testConvertToMSBuildSettings_actual(self): | |
1088 | """Tests the conversion of an actual project. | |
1089 | ||
1090 | A VS2008 project with most of the options defined was created through the | |
1091 | VS2008 IDE. It was then converted to VS2010. The tool settings found in | |
1092 | the .vcproj and .vcxproj files were converted to the two dictionaries | |
1093 | msvs_settings and expected_msbuild_settings. | |
1094 | ||
1095 | Note that for many settings, the VS2010 converter adds macros like | |
1096 | %(AdditionalIncludeDirectories) to make sure than inherited values are | |
1097 | included. Since the Gyp projects we generate do not use inheritance, | |
1098 | we removed these macros. They were: | |
1099 | ClCompile: | |
1100 | AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)' | |
1101 | AdditionalOptions: ' %(AdditionalOptions)' | |
1102 | AdditionalUsingDirectories: ';%(AdditionalUsingDirectories)' | |
1103 | DisableSpecificWarnings: ';%(DisableSpecificWarnings)', | |
1104 | ForcedIncludeFiles: ';%(ForcedIncludeFiles)', | |
1105 | ForcedUsingFiles: ';%(ForcedUsingFiles)', | |
1106 | PreprocessorDefinitions: ';%(PreprocessorDefinitions)', | |
1107 | UndefinePreprocessorDefinitions: | |
1108 | ';%(UndefinePreprocessorDefinitions)', | |
1109 | Link: | |
1110 | AdditionalDependencies: ';%(AdditionalDependencies)', | |
1111 | AdditionalLibraryDirectories: ';%(AdditionalLibraryDirectories)', | |
1112 | AdditionalManifestDependencies: | |
1113 | ';%(AdditionalManifestDependencies)', | |
1114 | AdditionalOptions: ' %(AdditionalOptions)', | |
1115 | AddModuleNamesToAssembly: ';%(AddModuleNamesToAssembly)', | |
1116 | AssemblyLinkResource: ';%(AssemblyLinkResource)', | |
1117 | DelayLoadDLLs: ';%(DelayLoadDLLs)', | |
1118 | EmbedManagedResourceFile: ';%(EmbedManagedResourceFile)', | |
1119 | ForceSymbolReferences: ';%(ForceSymbolReferences)', | |
1120 | IgnoreSpecificDefaultLibraries: | |
1121 | ';%(IgnoreSpecificDefaultLibraries)', | |
1122 | ResourceCompile: | |
1123 | AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)', | |
1124 | AdditionalOptions: ' %(AdditionalOptions)', | |
1125 | PreprocessorDefinitions: ';%(PreprocessorDefinitions)', | |
1126 | Mt: | |
1127 | AdditionalManifestFiles: ';%(AdditionalManifestFiles)', | |
1128 | AdditionalOptions: ' %(AdditionalOptions)', | |
1129 | InputResourceManifests: ';%(InputResourceManifests)', | |
1130 | """ | |
1131 | msvs_settings = { | |
1132 | 'VCCLCompilerTool': { | |
1133 | 'AdditionalIncludeDirectories': 'dir1', | |
1134 | 'AdditionalOptions': '/more', | |
1135 | 'AdditionalUsingDirectories': 'test', | |
1136 | 'AssemblerListingLocation': '$(IntDir)\\a', | |
1137 | 'AssemblerOutput': '1', | |
1138 | 'BasicRuntimeChecks': '3', | |
1139 | 'BrowseInformation': '1', | |
1140 | 'BrowseInformationFile': '$(IntDir)\\e', | |
1141 | 'BufferSecurityCheck': 'false', | |
1142 | 'CallingConvention': '1', | |
1143 | 'CompileAs': '1', | |
1144 | 'DebugInformationFormat': '4', | |
1145 | 'DefaultCharIsUnsigned': 'true', | |
1146 | 'Detect64BitPortabilityProblems': 'true', | |
1147 | 'DisableLanguageExtensions': 'true', | |
1148 | 'DisableSpecificWarnings': 'abc', | |
1149 | 'EnableEnhancedInstructionSet': '1', | |
1150 | 'EnableFiberSafeOptimizations': 'true', | |
1151 | 'EnableFunctionLevelLinking': 'true', | |
1152 | 'EnableIntrinsicFunctions': 'true', | |
1153 | 'EnablePREfast': 'true', | |
1154 | 'ErrorReporting': '2', | |
1155 | 'ExceptionHandling': '2', | |
1156 | 'ExpandAttributedSource': 'true', | |
1157 | 'FavorSizeOrSpeed': '2', | |
1158 | 'FloatingPointExceptions': 'true', | |
1159 | 'FloatingPointModel': '1', | |
1160 | 'ForceConformanceInForLoopScope': 'false', | |
1161 | 'ForcedIncludeFiles': 'def', | |
1162 | 'ForcedUsingFiles': 'ge', | |
1163 | 'GeneratePreprocessedFile': '2', | |
1164 | 'GenerateXMLDocumentationFiles': 'true', | |
1165 | 'IgnoreStandardIncludePath': 'true', | |
1166 | 'InlineFunctionExpansion': '1', | |
1167 | 'KeepComments': 'true', | |
1168 | 'MinimalRebuild': 'true', | |
1169 | 'ObjectFile': '$(IntDir)\\b', | |
1170 | 'OmitDefaultLibName': 'true', | |
1171 | 'OmitFramePointers': 'true', | |
1172 | 'OpenMP': 'true', | |
1173 | 'Optimization': '3', | |
1174 | 'PrecompiledHeaderFile': '$(IntDir)\\$(TargetName).pche', | |
1175 | 'PrecompiledHeaderThrough': 'StdAfx.hd', | |
1176 | 'PreprocessorDefinitions': 'WIN32;_DEBUG;_CONSOLE', | |
1177 | 'ProgramDataBaseFileName': '$(IntDir)\\vc90b.pdb', | |
1178 | 'RuntimeLibrary': '3', | |
1179 | 'RuntimeTypeInfo': 'false', | |
1180 | 'ShowIncludes': 'true', | |
1181 | 'SmallerTypeCheck': 'true', | |
1182 | 'StringPooling': 'true', | |
1183 | 'StructMemberAlignment': '3', | |
1184 | 'SuppressStartupBanner': 'false', | |
1185 | 'TreatWChar_tAsBuiltInType': 'false', | |
1186 | 'UndefineAllPreprocessorDefinitions': 'true', | |
1187 | 'UndefinePreprocessorDefinitions': 'wer', | |
1188 | 'UseFullPaths': 'true', | |
1189 | 'UsePrecompiledHeader': '0', | |
1190 | 'UseUnicodeResponseFiles': 'false', | |
1191 | 'WarnAsError': 'true', | |
1192 | 'WarningLevel': '3', | |
1193 | 'WholeProgramOptimization': 'true', | |
1194 | 'XMLDocumentationFileName': '$(IntDir)\\c'}, | |
1195 | 'VCLinkerTool': { | |
1196 | 'AdditionalDependencies': 'zx', | |
1197 | 'AdditionalLibraryDirectories': 'asd', | |
1198 | 'AdditionalManifestDependencies': 's2', | |
1199 | 'AdditionalOptions': '/mor2', | |
1200 | 'AddModuleNamesToAssembly': 'd1', | |
1201 | 'AllowIsolation': 'false', | |
1202 | 'AssemblyDebug': '1', | |
1203 | 'AssemblyLinkResource': 'd5', | |
1204 | 'BaseAddress': '23423', | |
1205 | 'CLRImageType': '3', | |
1206 | 'CLRThreadAttribute': '1', | |
1207 | 'CLRUnmanagedCodeCheck': 'true', | |
1208 | 'DataExecutionPrevention': '0', | |
1209 | 'DelayLoadDLLs': 'd4', | |
1210 | 'DelaySign': 'true', | |
1211 | 'Driver': '2', | |
1212 | 'EmbedManagedResourceFile': 'd2', | |
1213 | 'EnableCOMDATFolding': '1', | |
1214 | 'EnableUAC': 'false', | |
1215 | 'EntryPointSymbol': 'f5', | |
1216 | 'ErrorReporting': '2', | |
1217 | 'FixedBaseAddress': '1', | |
1218 | 'ForceSymbolReferences': 'd3', | |
1219 | 'FunctionOrder': 'fssdfsd', | |
1220 | 'GenerateDebugInformation': 'true', | |
1221 | 'GenerateManifest': 'false', | |
1222 | 'GenerateMapFile': 'true', | |
1223 | 'HeapCommitSize': '13', | |
1224 | 'HeapReserveSize': '12', | |
1225 | 'IgnoreAllDefaultLibraries': 'true', | |
1226 | 'IgnoreDefaultLibraryNames': 'flob;flok', | |
1227 | 'IgnoreEmbeddedIDL': 'true', | |
1228 | 'IgnoreImportLibrary': 'true', | |
1229 | 'ImportLibrary': 'f4', | |
1230 | 'KeyContainer': 'f7', | |
1231 | 'KeyFile': 'f6', | |
1232 | 'LargeAddressAware': '2', | |
1233 | 'LinkIncremental': '0', | |
1234 | 'LinkLibraryDependencies': 'false', | |
1235 | 'LinkTimeCodeGeneration': '1', | |
1236 | 'ManifestFile': | |
1237 | '$(IntDir)\\$(TargetFileName).2intermediate.manifest', | |
1238 | 'MapExports': 'true', | |
1239 | 'MapFileName': 'd5', | |
1240 | 'MergedIDLBaseFileName': 'f2', | |
1241 | 'MergeSections': 'f5', | |
1242 | 'MidlCommandFile': 'f1', | |
1243 | 'ModuleDefinitionFile': 'sdsd', | |
1244 | 'OptimizeForWindows98': '2', | |
1245 | 'OptimizeReferences': '2', | |
1246 | 'OutputFile': '$(OutDir)\\$(ProjectName)2.exe', | |
1247 | 'PerUserRedirection': 'true', | |
1248 | 'Profile': 'true', | |
1249 | 'ProfileGuidedDatabase': '$(TargetDir)$(TargetName).pgdd', | |
1250 | 'ProgramDatabaseFile': 'Flob.pdb', | |
1251 | 'RandomizedBaseAddress': '1', | |
1252 | 'RegisterOutput': 'true', | |
1253 | 'ResourceOnlyDLL': 'true', | |
1254 | 'SetChecksum': 'false', | |
1255 | 'ShowProgress': '1', | |
1256 | 'StackCommitSize': '15', | |
1257 | 'StackReserveSize': '14', | |
1258 | 'StripPrivateSymbols': 'd3', | |
1259 | 'SubSystem': '1', | |
1260 | 'SupportUnloadOfDelayLoadedDLL': 'true', | |
1261 | 'SuppressStartupBanner': 'false', | |
1262 | 'SwapRunFromCD': 'true', | |
1263 | 'SwapRunFromNet': 'true', | |
1264 | 'TargetMachine': '1', | |
1265 | 'TerminalServerAware': '1', | |
1266 | 'TurnOffAssemblyGeneration': 'true', | |
1267 | 'TypeLibraryFile': 'f3', | |
1268 | 'TypeLibraryResourceID': '12', | |
1269 | 'UACExecutionLevel': '2', | |
1270 | 'UACUIAccess': 'true', | |
1271 | 'UseLibraryDependencyInputs': 'true', | |
1272 | 'UseUnicodeResponseFiles': 'false', | |
1273 | 'Version': '333'}, | |
1274 | 'VCResourceCompilerTool': { | |
1275 | 'AdditionalIncludeDirectories': 'f3', | |
1276 | 'AdditionalOptions': '/more3', | |
1277 | 'Culture': '3084', | |
1278 | 'IgnoreStandardIncludePath': 'true', | |
1279 | 'PreprocessorDefinitions': '_UNICODE;UNICODE2', | |
1280 | 'ResourceOutputFileName': '$(IntDir)/$(InputName)3.res', | |
1281 | 'ShowProgress': 'true'}, | |
1282 | 'VCManifestTool': { | |
1283 | 'AdditionalManifestFiles': 'sfsdfsd', | |
1284 | 'AdditionalOptions': 'afdsdafsd', | |
1285 | 'AssemblyIdentity': 'sddfdsadfsa', | |
1286 | 'ComponentFileName': 'fsdfds', | |
1287 | 'DependencyInformationFile': '$(IntDir)\\mt.depdfd', | |
1288 | 'EmbedManifest': 'false', | |
1289 | 'GenerateCatalogFiles': 'true', | |
1290 | 'InputResourceManifests': 'asfsfdafs', | |
1291 | 'ManifestResourceFile': | |
1292 | '$(IntDir)\\$(TargetFileName).embed.manifest.resfdsf', | |
1293 | 'OutputManifestFile': '$(TargetPath).manifestdfs', | |
1294 | 'RegistrarScriptFile': 'sdfsfd', | |
1295 | 'ReplacementsFile': 'sdffsd', | |
1296 | 'SuppressStartupBanner': 'false', | |
1297 | 'TypeLibraryFile': 'sfsd', | |
1298 | 'UpdateFileHashes': 'true', | |
1299 | 'UpdateFileHashesSearchPath': 'sfsd', | |
1300 | 'UseFAT32Workaround': 'true', | |
1301 | 'UseUnicodeResponseFiles': 'false', | |
1302 | 'VerboseOutput': 'true'}} | |
1303 | expected_msbuild_settings = { | |
1304 | 'ClCompile': { | |
1305 | 'AdditionalIncludeDirectories': 'dir1', | |
1306 | 'AdditionalOptions': '/more /J', | |
1307 | 'AdditionalUsingDirectories': 'test', | |
1308 | 'AssemblerListingLocation': '$(IntDir)a', | |
1309 | 'AssemblerOutput': 'AssemblyCode', | |
1310 | 'BasicRuntimeChecks': 'EnableFastChecks', | |
1311 | 'BrowseInformation': 'true', | |
1312 | 'BrowseInformationFile': '$(IntDir)e', | |
1313 | 'BufferSecurityCheck': 'false', | |
1314 | 'CallingConvention': 'FastCall', | |
1315 | 'CompileAs': 'CompileAsC', | |
1316 | 'DebugInformationFormat': 'EditAndContinue', | |
1317 | 'DisableLanguageExtensions': 'true', | |
1318 | 'DisableSpecificWarnings': 'abc', | |
1319 | 'EnableEnhancedInstructionSet': 'StreamingSIMDExtensions', | |
1320 | 'EnableFiberSafeOptimizations': 'true', | |
1321 | 'EnablePREfast': 'true', | |
1322 | 'ErrorReporting': 'Queue', | |
1323 | 'ExceptionHandling': 'Async', | |
1324 | 'ExpandAttributedSource': 'true', | |
1325 | 'FavorSizeOrSpeed': 'Size', | |
1326 | 'FloatingPointExceptions': 'true', | |
1327 | 'FloatingPointModel': 'Strict', | |
1328 | 'ForceConformanceInForLoopScope': 'false', | |
1329 | 'ForcedIncludeFiles': 'def', | |
1330 | 'ForcedUsingFiles': 'ge', | |
1331 | 'FunctionLevelLinking': 'true', | |
1332 | 'GenerateXMLDocumentationFiles': 'true', | |
1333 | 'IgnoreStandardIncludePath': 'true', | |
1334 | 'InlineFunctionExpansion': 'OnlyExplicitInline', | |
1335 | 'IntrinsicFunctions': 'true', | |
1336 | 'MinimalRebuild': 'true', | |
1337 | 'ObjectFileName': '$(IntDir)b', | |
1338 | 'OmitDefaultLibName': 'true', | |
1339 | 'OmitFramePointers': 'true', | |
1340 | 'OpenMPSupport': 'true', | |
1341 | 'Optimization': 'Full', | |
1342 | 'PrecompiledHeader': 'NotUsing', # Actual conversion gives '' | |
1343 | 'PrecompiledHeaderFile': 'StdAfx.hd', | |
1344 | 'PrecompiledHeaderOutputFile': '$(IntDir)$(TargetName).pche', | |
1345 | 'PreprocessKeepComments': 'true', | |
1346 | 'PreprocessorDefinitions': 'WIN32;_DEBUG;_CONSOLE', | |
1347 | 'PreprocessSuppressLineNumbers': 'true', | |
1348 | 'PreprocessToFile': 'true', | |
1349 | 'ProgramDataBaseFileName': '$(IntDir)vc90b.pdb', | |
1350 | 'RuntimeLibrary': 'MultiThreadedDebugDLL', | |
1351 | 'RuntimeTypeInfo': 'false', | |
1352 | 'ShowIncludes': 'true', | |
1353 | 'SmallerTypeCheck': 'true', | |
1354 | 'StringPooling': 'true', | |
1355 | 'StructMemberAlignment': '4Bytes', | |
1356 | 'SuppressStartupBanner': 'false', | |
1357 | 'TreatWarningAsError': 'true', | |
1358 | 'TreatWChar_tAsBuiltInType': 'false', | |
1359 | 'UndefineAllPreprocessorDefinitions': 'true', | |
1360 | 'UndefinePreprocessorDefinitions': 'wer', | |
1361 | 'UseFullPaths': 'true', | |
1362 | 'WarningLevel': 'Level3', | |
1363 | 'WholeProgramOptimization': 'true', | |
1364 | 'XMLDocumentationFileName': '$(IntDir)c'}, | |
1365 | 'Link': { | |
1366 | 'AdditionalDependencies': 'zx', | |
1367 | 'AdditionalLibraryDirectories': 'asd', | |
1368 | 'AdditionalManifestDependencies': 's2', | |
1369 | 'AdditionalOptions': '/mor2', | |
1370 | 'AddModuleNamesToAssembly': 'd1', | |
1371 | 'AllowIsolation': 'false', | |
1372 | 'AssemblyDebug': 'true', | |
1373 | 'AssemblyLinkResource': 'd5', | |
1374 | 'BaseAddress': '23423', | |
1375 | 'CLRImageType': 'ForceSafeILImage', | |
1376 | 'CLRThreadAttribute': 'MTAThreadingAttribute', | |
1377 | 'CLRUnmanagedCodeCheck': 'true', | |
1378 | 'DataExecutionPrevention': '', | |
1379 | 'DelayLoadDLLs': 'd4', | |
1380 | 'DelaySign': 'true', | |
1381 | 'Driver': 'UpOnly', | |
1382 | 'EmbedManagedResourceFile': 'd2', | |
1383 | 'EnableCOMDATFolding': 'false', | |
1384 | 'EnableUAC': 'false', | |
1385 | 'EntryPointSymbol': 'f5', | |
1386 | 'FixedBaseAddress': 'false', | |
1387 | 'ForceSymbolReferences': 'd3', | |
1388 | 'FunctionOrder': 'fssdfsd', | |
1389 | 'GenerateDebugInformation': 'true', | |
1390 | 'GenerateMapFile': 'true', | |
1391 | 'HeapCommitSize': '13', | |
1392 | 'HeapReserveSize': '12', | |
1393 | 'IgnoreAllDefaultLibraries': 'true', | |
1394 | 'IgnoreEmbeddedIDL': 'true', | |
1395 | 'IgnoreSpecificDefaultLibraries': 'flob;flok', | |
1396 | 'ImportLibrary': 'f4', | |
1397 | 'KeyContainer': 'f7', | |
1398 | 'KeyFile': 'f6', | |
1399 | 'LargeAddressAware': 'true', | |
1400 | 'LinkErrorReporting': 'QueueForNextLogin', | |
1401 | 'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration', | |
1402 | 'ManifestFile': '$(IntDir)$(TargetFileName).2intermediate.manifest', | |
1403 | 'MapExports': 'true', | |
1404 | 'MapFileName': 'd5', | |
1405 | 'MergedIDLBaseFileName': 'f2', | |
1406 | 'MergeSections': 'f5', | |
1407 | 'MidlCommandFile': 'f1', | |
1408 | 'ModuleDefinitionFile': 'sdsd', | |
1409 | 'NoEntryPoint': 'true', | |
1410 | 'OptimizeReferences': 'true', | |
1411 | 'OutputFile': '$(OutDir)$(ProjectName)2.exe', | |
1412 | 'PerUserRedirection': 'true', | |
1413 | 'Profile': 'true', | |
1414 | 'ProfileGuidedDatabase': '$(TargetDir)$(TargetName).pgdd', | |
1415 | 'ProgramDatabaseFile': 'Flob.pdb', | |
1416 | 'RandomizedBaseAddress': 'false', | |
1417 | 'RegisterOutput': 'true', | |
1418 | 'SetChecksum': 'false', | |
1419 | 'ShowProgress': 'LinkVerbose', | |
1420 | 'StackCommitSize': '15', | |
1421 | 'StackReserveSize': '14', | |
1422 | 'StripPrivateSymbols': 'd3', | |
1423 | 'SubSystem': 'Console', | |
1424 | 'SupportUnloadOfDelayLoadedDLL': 'true', | |
1425 | 'SuppressStartupBanner': 'false', | |
1426 | 'SwapRunFromCD': 'true', | |
1427 | 'SwapRunFromNET': 'true', | |
1428 | 'TargetMachine': 'MachineX86', | |
1429 | 'TerminalServerAware': 'false', | |
1430 | 'TurnOffAssemblyGeneration': 'true', | |
1431 | 'TypeLibraryFile': 'f3', | |
1432 | 'TypeLibraryResourceID': '12', | |
1433 | 'UACExecutionLevel': 'RequireAdministrator', | |
1434 | 'UACUIAccess': 'true', | |
1435 | 'Version': '333'}, | |
1436 | 'ResourceCompile': { | |
1437 | 'AdditionalIncludeDirectories': 'f3', | |
1438 | 'AdditionalOptions': '/more3', | |
1439 | 'Culture': '0x0c0c', | |
1440 | 'IgnoreStandardIncludePath': 'true', | |
1441 | 'PreprocessorDefinitions': '_UNICODE;UNICODE2', | |
1442 | 'ResourceOutputFileName': '$(IntDir)%(Filename)3.res', | |
1443 | 'ShowProgress': 'true'}, | |
1444 | 'Mt': { | |
1445 | 'AdditionalManifestFiles': 'sfsdfsd', | |
1446 | 'AdditionalOptions': 'afdsdafsd', | |
1447 | 'AssemblyIdentity': 'sddfdsadfsa', | |
1448 | 'ComponentFileName': 'fsdfds', | |
1449 | 'GenerateCatalogFiles': 'true', | |
1450 | 'InputResourceManifests': 'asfsfdafs', | |
1451 | 'OutputManifestFile': '$(TargetPath).manifestdfs', | |
1452 | 'RegistrarScriptFile': 'sdfsfd', | |
1453 | 'ReplacementsFile': 'sdffsd', | |
1454 | 'SuppressStartupBanner': 'false', | |
1455 | 'TypeLibraryFile': 'sfsd', | |
1456 | 'UpdateFileHashes': 'true', | |
1457 | 'UpdateFileHashesSearchPath': 'sfsd', | |
1458 | 'VerboseOutput': 'true'}, | |
1459 | 'ProjectReference': { | |
1460 | 'LinkLibraryDependencies': 'false', | |
1461 | 'UseLibraryDependencyInputs': 'true'}, | |
1462 | '': { | |
1463 | 'EmbedManifest': 'false', | |
1464 | 'GenerateManifest': 'false', | |
1465 | 'IgnoreImportLibrary': 'true', | |
1466 | 'LinkIncremental': '' | |
1467 | }, | |
1468 | 'ManifestResourceCompile': { | |
1469 | 'ResourceOutputFileName': | |
1470 | '$(IntDir)$(TargetFileName).embed.manifest.resfdsf'} | |
1471 | } | |
1472 | actual_msbuild_settings = MSVSSettings.ConvertToMSBuildSettings( | |
1473 | msvs_settings, | |
1474 | self.stderr) | |
1475 | self.assertEqual(expected_msbuild_settings, actual_msbuild_settings) | |
1476 | self._ExpectedWarnings([]) | |
1477 | ||
1478 | if __name__ == '__main__': | |
1479 | unittest.main() |
7 | 7 | |
8 | 8 | import common |
9 | 9 | import xml.dom |
10 | import xml.dom.minidom | |
10 | import xml_fix | |
11 | 11 | |
12 | 12 | |
13 | 13 | #------------------------------------------------------------------------------ |
72 | 72 | def Write(self, writer=common.WriteOnDiff): |
73 | 73 | """Writes the tool file.""" |
74 | 74 | f = writer(self.tool_file_path) |
75 | fix = xml_fix.XmlFix() | |
75 | 76 | self.doc.writexml(f, encoding='Windows-1252', addindent=' ', newl='\r\n') |
77 | fix.Cleanup() | |
76 | 78 | f.close() |
77 | 79 | |
78 | 80 | #------------------------------------------------------------------------------ |
10 | 10 | import re |
11 | 11 | import socket # for gethostname |
12 | 12 | import xml.dom |
13 | import xml.dom.minidom | |
13 | import xml_fix | |
14 | 14 | |
15 | 15 | |
16 | 16 | #------------------------------------------------------------------------------ |
0 | 0 | #!/usr/bin/python |
1 | ||
2 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | # Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
3 | 2 | # Use of this source code is governed by a BSD-style license that can be |
4 | 3 | # found in the LICENSE file. |
5 | 4 | |
6 | 5 | """Handle version information related to Visual Stuio.""" |
7 | 6 | |
7 | import errno | |
8 | 8 | import os |
9 | 9 | import re |
10 | 10 | import subprocess |
15 | 15 | """Information regarding a version of Visual Studio.""" |
16 | 16 | |
17 | 17 | def __init__(self, short_name, description, |
18 | solution_version, project_version, flat_sln): | |
18 | solution_version, project_version, flat_sln, uses_vcxproj): | |
19 | 19 | self.short_name = short_name |
20 | 20 | self.description = description |
21 | 21 | self.solution_version = solution_version |
22 | 22 | self.project_version = project_version |
23 | 23 | self.flat_sln = flat_sln |
24 | self.uses_vcxproj = uses_vcxproj | |
24 | 25 | |
25 | 26 | def ShortName(self): |
26 | 27 | return self.short_name |
34 | 35 | return self.solution_version |
35 | 36 | |
36 | 37 | def ProjectVersion(self): |
37 | """Get the version number of the vcproj files.""" | |
38 | """Get the version number of the vcproj or vcxproj files.""" | |
38 | 39 | return self.project_version |
39 | 40 | |
40 | 41 | def FlatSolution(self): |
41 | 42 | return self.flat_sln |
42 | 43 | |
43 | ||
44 | def _RegistryGetValue(key, value): | |
45 | """Use reg.exe to read a paricular key. | |
44 | def UsesVcxproj(self): | |
45 | """Returns true if this version uses a vcxproj file.""" | |
46 | return self.uses_vcxproj | |
47 | ||
48 | def ProjectExtension(self): | |
49 | """Returns the file extension for the project.""" | |
50 | return self.uses_vcxproj and '.vcxproj' or '.vcproj' | |
51 | ||
52 | def _RegistryQueryBase(sysdir, key, value): | |
53 | """Use reg.exe to read a particular key. | |
46 | 54 | |
47 | 55 | While ideally we might use the win32 module, we would like gyp to be |
48 | 56 | python neutral, so for instance cygwin python lacks this module. |
49 | 57 | |
50 | 58 | Arguments: |
59 | sysdir: The system subdirectory to attempt to launch reg.exe from. | |
51 | 60 | key: The registry key to read from. |
52 | 61 | value: The particular value to read. |
53 | 62 | Return: |
54 | The contents there, or None for failure. | |
55 | """ | |
56 | # Skip if not on Windows. | |
63 | stdout from reg.exe, or None for failure. | |
64 | """ | |
65 | # Skip if not on Windows or Python Win32 setup issue | |
57 | 66 | if sys.platform not in ('win32', 'cygwin'): |
58 | 67 | return None |
59 | # Run reg.exe. | |
60 | cmd = [os.path.join(os.environ.get('WINDIR', ''), 'System32', 'reg.exe'), | |
61 | 'query', key, '/v', value] | |
68 | # Setup params to pass to and attempt to launch reg.exe | |
69 | cmd = [os.path.join(os.environ.get('WINDIR', ''), sysdir, 'reg.exe'), | |
70 | 'query', key] | |
71 | if value: | |
72 | cmd.extend(['/v', value]) | |
62 | 73 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
74 | # Obtain the stdout from reg.exe, reading to the end so p.returncode is valid | |
75 | # Note that the error text may be in [1] in some cases | |
63 | 76 | text = p.communicate()[0] |
64 | # Require a successful return value. | |
77 | # Check return code from reg.exe; officially 0==success and 1==error | |
65 | 78 | if p.returncode: |
66 | 79 | return None |
80 | return text | |
81 | ||
82 | def _RegistryQuery(key, value=None): | |
83 | """Use reg.exe to read a particular key through _RegistryQueryBase. | |
84 | ||
85 | First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If | |
86 | that fails, it falls back to System32. Sysnative is available on Vista and | |
87 | up and available on Windows Server 2003 and XP through KB patch 942589. Note | |
88 | that Sysnative will always fail if using 64-bit python due to it being a | |
89 | virtual directory and System32 will work correctly in the first place. | |
90 | ||
91 | KB 942589 - http://support.microsoft.com/kb/942589/en-us. | |
92 | ||
93 | Arguments: | |
94 | key: The registry key. | |
95 | value: The particular registry value to read (optional). | |
96 | Return: | |
97 | stdout from reg.exe, or None for failure. | |
98 | """ | |
99 | text = None | |
100 | try: | |
101 | text = _RegistryQueryBase('Sysnative', key, value) | |
102 | except OSError, e: | |
103 | if e.errno == errno.ENOENT: | |
104 | text = _RegistryQueryBase('System32', key, value) | |
105 | else: | |
106 | raise | |
107 | return text | |
108 | ||
109 | def _RegistryGetValue(key, value): | |
110 | """Use reg.exe to obtain the value of a registry key. | |
111 | ||
112 | Args: | |
113 | key: The registry key. | |
114 | value: The particular registry value to read. | |
115 | Return: | |
116 | contents of the registry key's value, or None on failure. | |
117 | """ | |
118 | text = _RegistryQuery(key, value) | |
119 | if not text: | |
120 | return None | |
67 | 121 | # Extract value. |
68 | match = re.search(r'REG_\w+[ ]+([^\r]+)\r\n', text) | |
122 | match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text) | |
69 | 123 | if not match: |
70 | 124 | return None |
71 | 125 | return match.group(1) |
72 | 126 | |
127 | def _RegistryKeyExists(key): | |
128 | """Use reg.exe to see if a key exists. | |
129 | ||
130 | Args: | |
131 | key: The registry key to check. | |
132 | Return: | |
133 | True if the key exists | |
134 | """ | |
135 | if not _RegistryQuery(key): | |
136 | return False | |
137 | return True | |
138 | ||
73 | 139 | |
74 | 140 | def _CreateVersion(name): |
141 | """Sets up MSVS project generation. | |
142 | ||
143 | Setup is based off the GYP_MSVS_VERSION environment variable or whatever is | |
144 | autodetected if GYP_MSVS_VERSION is not explicitly specified. If a version is | |
145 | passed in that doesn't match a value in versions python will throw a error. | |
146 | """ | |
75 | 147 | versions = { |
148 | '2010': VisualStudioVersion('2010', | |
149 | 'Visual Studio 2010', | |
150 | solution_version='11.00', | |
151 | project_version='4.0', | |
152 | flat_sln=False, | |
153 | uses_vcxproj=True), | |
154 | '2010e': VisualStudioVersion('2010e', | |
155 | 'Visual Studio 2010', | |
156 | solution_version='11.00', | |
157 | project_version='4.0', | |
158 | flat_sln=True, | |
159 | uses_vcxproj=True), | |
76 | 160 | '2008': VisualStudioVersion('2008', |
77 | 161 | 'Visual Studio 2008', |
78 | 162 | solution_version='10.00', |
79 | 163 | project_version='9.00', |
80 | flat_sln=False), | |
164 | flat_sln=False, | |
165 | uses_vcxproj=False), | |
81 | 166 | '2008e': VisualStudioVersion('2008e', |
82 | 167 | 'Visual Studio 2008', |
83 | 168 | solution_version='10.00', |
84 | 169 | project_version='9.00', |
85 | flat_sln=True), | |
170 | flat_sln=True, | |
171 | uses_vcxproj=False), | |
86 | 172 | '2005': VisualStudioVersion('2005', |
87 | 173 | 'Visual Studio 2005', |
88 | 174 | solution_version='9.00', |
89 | 175 | project_version='8.00', |
90 | flat_sln=False), | |
176 | flat_sln=False, | |
177 | uses_vcxproj=False), | |
91 | 178 | '2005e': VisualStudioVersion('2005e', |
92 | 179 | 'Visual Studio 2005', |
93 | 180 | solution_version='9.00', |
94 | 181 | project_version='8.00', |
95 | flat_sln=True), | |
182 | flat_sln=True, | |
183 | uses_vcxproj=False), | |
96 | 184 | } |
97 | 185 | return versions[str(name)] |
98 | 186 | |
104 | 192 | A list of visual studio versions installed in descending order of |
105 | 193 | usage preference. |
106 | 194 | Base this on the registry and a quick check if devenv.exe exists. |
107 | Only versions 8-9 are considered. | |
195 | Only versions 8-10 are considered. | |
108 | 196 | Possibilities are: |
109 | 2005 - Visual Studio 2005 (8) | |
110 | 2008 - Visual Studio 2008 (9) | |
111 | """ | |
112 | version_to_year = {'8.0': '2005', '9.0': '2008'} | |
197 | 2005(e) - Visual Studio 2005 (8) | |
198 | 2008(e) - Visual Studio 2008 (9) | |
199 | 2010(e) - Visual Studio 2010 (10) | |
200 | Where (e) is e for express editions of MSVS and blank otherwise. | |
201 | """ | |
202 | version_to_year = {'8.0': '2005', '9.0': '2008', '10.0': '2010'} | |
113 | 203 | versions = [] |
114 | for version in ('9.0', '8.0'): | |
115 | # Get the install dir for this version. | |
116 | key = r'HKLM\Software\Microsoft\VisualStudio\%s' % version | |
117 | path = _RegistryGetValue(key, 'InstallDir') | |
118 | if not path: | |
119 | continue | |
120 | # Check for full. | |
121 | if os.path.exists(os.path.join(path, 'devenv.exe')): | |
122 | # Add this one. | |
123 | versions.append(_CreateVersion(version_to_year[version])) | |
124 | # Check for express. | |
125 | elif os.path.exists(os.path.join(path, 'vcexpress.exe')): | |
126 | # Add this one. | |
127 | versions.append(_CreateVersion(version_to_year[version] + 'e')) | |
204 | # For now, prefer versions before VS2010 | |
205 | for version in ('9.0', '8.0', '10.0'): | |
206 | # Check if VS2010 and later is installed as specified by | |
207 | # http://msdn.microsoft.com/en-us/library/bb164659.aspx | |
208 | keys = [r'HKLM\SOFTWARE\Microsoft\DevDiv\VS\Servicing\%s' % version, | |
209 | r'HKLM\SOFTWARE\Wow6432Node\Microsoft\DevDiv\VS\Servicing\%s' % ( | |
210 | version)] | |
211 | for index in range(len(keys)): | |
212 | if not _RegistryKeyExists(keys[index]): | |
213 | continue | |
214 | # Check for express | |
215 | if _RegistryKeyExists(keys[index] + '\\expbsln'): | |
216 | # Add this one | |
217 | versions.append(_CreateVersion(version_to_year[version] + 'e')) | |
218 | else: | |
219 | # Add this one | |
220 | versions.append(_CreateVersion(version_to_year[version])) | |
221 | ||
222 | # Old (pre-VS2010) method of searching for which VS version is installed | |
223 | keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version, | |
224 | r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version, | |
225 | r'HKLM\Software\Microsoft\VCExpress\%s' % version, | |
226 | r'HKLM\Software\Wow6432Node\Microsoft\VCExpress\%s' % version] | |
227 | for index in range(len(keys)): | |
228 | path = _RegistryGetValue(keys[index], 'InstallDir') | |
229 | if not path: | |
230 | continue | |
231 | # Check for full. | |
232 | if os.path.exists(os.path.join(path, 'devenv.exe')): | |
233 | # Add this one. | |
234 | versions.append(_CreateVersion(version_to_year[version])) | |
235 | # Check for express. | |
236 | elif os.path.exists(os.path.join(path, 'vcexpress.exe')): | |
237 | # Add this one. | |
238 | versions.append(_CreateVersion(version_to_year[version] + 'e')) | |
128 | 239 | return versions |
129 | 240 | |
130 | 241 |
264 | 264 | help='do not read options from environment variables') |
265 | 265 | parser.add_option('--check', dest='check', action='store_true', |
266 | 266 | help='check format of gyp files') |
267 | parser.add_option('--toplevel-dir', dest='toplevel_dir', action='store', | |
268 | default=None, metavar='DIR', type='path', | |
269 | help='directory to use as the root of the source tree') | |
267 | 270 | # --no-circular-check disables the check for circular relationships between |
268 | 271 | # .gyp files. These relationships should not exist, but they've only been |
269 | 272 | # observed to be harmful with the Xcode generator. Chromium's .gyp files |
292 | 295 | |
293 | 296 | # TODO(thomasvl): add support for ~/.gyp/defaults |
294 | 297 | |
295 | (options, build_files_arg) = parser.parse_args(args) | |
298 | options, build_files_arg = parser.parse_args(args) | |
296 | 299 | build_files = build_files_arg |
297 | 300 | |
298 | 301 | if not options.formats: |
326 | 329 | # Do an extra check to avoid work when we're not debugging. |
327 | 330 | if DEBUG_GENERAL in gyp.debug.keys(): |
328 | 331 | DebugOutput(DEBUG_GENERAL, 'running with these options:') |
329 | for (option, value) in options.__dict__.items(): | |
332 | for option, value in sorted(options.__dict__.items()): | |
330 | 333 | if option[0] == '_': |
331 | 334 | continue |
332 | 335 | if isinstance(value, basestring): |
369 | 372 | 'temporary Chromium feature that will be removed. Use ' + \ |
370 | 373 | '--depth as a workaround.' |
371 | 374 | |
375 | # If toplevel-dir is not set, we assume that depth is the root of our source | |
376 | # tree. | |
377 | if not options.toplevel_dir: | |
378 | options.toplevel_dir = options.depth | |
379 | ||
372 | 380 | # -D on the command line sets variable defaults - D isn't just for define, |
373 | 381 | # it's for default. Perhaps there should be a way to force (-F?) a |
374 | 382 | # variable's value so that it can't be overridden by anything else. |
220 | 220 | |
221 | 221 | |
222 | 222 | def DeepDependencyTargets(target_dicts, roots): |
223 | """Returns the recursive list of target dependencies. | |
224 | """ | |
223 | """Returns the recursive list of target dependencies.""" | |
225 | 224 | dependencies = set() |
226 | for r in roots: | |
225 | pending = set(roots) | |
226 | while pending: | |
227 | # Pluck out one. | |
228 | r = pending.pop() | |
229 | # Skip if visited already. | |
230 | if r in dependencies: | |
231 | continue | |
232 | # Add it. | |
233 | dependencies.add(r) | |
234 | # Add its children. | |
227 | 235 | spec = target_dicts[r] |
228 | r_deps = list(set((spec.get('dependencies', []) + | |
229 | spec.get('dependencies_original', [])))) | |
230 | for d in r_deps: | |
231 | if d not in roots: | |
232 | dependencies.add(d) | |
233 | for d in DeepDependencyTargets(target_dicts, r_deps): | |
234 | if d not in roots: | |
235 | dependencies.add(d) | |
236 | return list(dependencies) | |
236 | pending.update(set(spec.get('dependencies', []))) | |
237 | pending.update(set(spec.get('dependencies_original', []))) | |
238 | return list(dependencies - set(roots)) | |
237 | 239 | |
238 | 240 | |
239 | 241 | def BuildFileTargets(target_list, build_file): |
0 | #!/usr/bin/python | |
1 | ||
2 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | import xml.dom | |
7 | import xml_fix | |
8 | import common | |
9 | ||
10 | class EasyXml(object): | |
11 | """ Class to easily create XML files with substantial pre-defined structures. | |
12 | ||
13 | Visual Studio files have a lot of pre-defined structures. This class makes | |
14 | it easy to represent these structures as Python data structures, instead of | |
15 | having to create a lot of function calls. | |
16 | ||
17 | For this class, an XML element is represented as a list composed of: | |
18 | 1. The name of the element, a string, | |
19 | 2. The attributes of the element, an dictionary (optional), and | |
20 | 3+. The content of the element, if any. Strings are simple text nodes and | |
21 | lists are child elements. | |
22 | ||
23 | Example 1: | |
24 | <test/> | |
25 | becomes | |
26 | ['test'] | |
27 | ||
28 | Example 2: | |
29 | <myelement a='value1' b='value2'> | |
30 | <childtype>This is</childtype> | |
31 | <childtype>it!</childtype> | |
32 | </myelement> | |
33 | ||
34 | becomes | |
35 | ['myelement', {'a':'value1', 'b':'value2'}, | |
36 | ['childtype', 'This is'], | |
37 | ['childtype', 'it!'], | |
38 | ] | |
39 | """ | |
40 | ||
41 | def __init__(self, name, attributes=None): | |
42 | """ Constructs an object representing an XML document. | |
43 | ||
44 | Args: | |
45 | name: A string, the name of the root element. | |
46 | attributes: A dictionary, the attributes of the root. | |
47 | """ | |
48 | xml_impl = xml.dom.getDOMImplementation() | |
49 | self.doc = xml_impl.createDocument(None, name, None) | |
50 | if attributes: | |
51 | self.SetAttributes(self.doc.documentElement, attributes) | |
52 | ||
53 | def AppendChildren(self, parent, children_specifications): | |
54 | """ Appends multiple children. | |
55 | ||
56 | Args: | |
57 | parent: The node to which the children will be added. | |
58 | children_specifications: A list of node specifications. | |
59 | """ | |
60 | for specification in children_specifications: | |
61 | # If it's a string, append a text node. | |
62 | # Otherwise append an XML node. | |
63 | if isinstance(specification, str): | |
64 | parent.appendChild(self.doc.createTextNode(specification)) | |
65 | else: | |
66 | self.AppendNode(parent, specification) | |
67 | ||
68 | def AppendNode(self, parent, specification): | |
69 | """ Appends multiple children. | |
70 | ||
71 | Args: | |
72 | parent: The node to which the child will be added. | |
73 | children_specifications: A list, the node specification. The first | |
74 | entry is the name of the element. If the second entry is a | |
75 | dictionary, it is the attributes. The remaining entries of the | |
76 | list are the sub-elements. | |
77 | Returns: | |
78 | The XML element created. | |
79 | """ | |
80 | name = specification[0] | |
81 | if not isinstance(name, str): | |
82 | raise Exception('The first item of an EasyXml specification should be ' | |
83 | 'a string. Specification was ' + str(specification)) | |
84 | element = self.doc.createElement(name) | |
85 | parent.appendChild(element) | |
86 | rest = specification[1:] | |
87 | # The second element is optionally a dictionary of the attributes. | |
88 | if rest and isinstance(rest[0], dict): | |
89 | self.SetAttributes(element, rest[0]) | |
90 | rest = rest[1:] | |
91 | if rest: | |
92 | self.AppendChildren(element, rest) | |
93 | return element | |
94 | ||
95 | def SetAttributes(self, element, attribute_description): | |
96 | """ Sets the attributes of an element. | |
97 | ||
98 | Args: | |
99 | element: The node to which the child will be added. | |
100 | attribute_description: A dictionary that maps attribute names to | |
101 | attribute values. | |
102 | """ | |
103 | for attribute, value in attribute_description.iteritems(): | |
104 | element.setAttribute(attribute, value) | |
105 | ||
106 | def Root(self): | |
107 | """ Returns the root element. """ | |
108 | return self.doc.documentElement | |
109 | ||
110 | def WriteIfChanged(self, path): | |
111 | """ Writes the XML doc but don't touch the file if unchanged. """ | |
112 | f = common.WriteOnDiff(path) | |
113 | fix = xml_fix.XmlFix() | |
114 | self.doc.writexml(f, encoding='utf-8', addindent='', newl='') | |
115 | fix.Cleanup() | |
116 | f.close() | |
117 | ||
118 | def __str__(self): | |
119 | """ Converts the doc to a string. """ | |
120 | return self.doc.toxml() |
0 | #!/usr/bin/python | |
1 | ||
2 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ Unit tests for the easy_xml.py file. """ | |
7 | ||
8 | import easy_xml | |
9 | import unittest | |
10 | import StringIO | |
11 | ||
12 | ||
13 | class TestSequenceFunctions(unittest.TestCase): | |
14 | ||
15 | def setUp(self): | |
16 | self.stderr = StringIO.StringIO() | |
17 | ||
18 | def test_EasyXml_simple(self): | |
19 | xml = easy_xml.EasyXml('test') | |
20 | self.assertEqual(str(xml), '<?xml version="1.0" ?><test/>') | |
21 | ||
22 | def test_EasyXml_simple_with_attributes(self): | |
23 | xml = easy_xml.EasyXml('test2', {'a': 'value1', 'b': 'value2'}) | |
24 | self.assertEqual(str(xml), | |
25 | '<?xml version="1.0" ?><test2 a="value1" b="value2"/>') | |
26 | ||
27 | def test_EasyXml_add_node(self): | |
28 | # We want to create: | |
29 | target = ('<?xml version="1.0" ?>' | |
30 | '<test3>' | |
31 | '<GrandParent>' | |
32 | '<Parent1>' | |
33 | '<Child/>' | |
34 | '</Parent1>' | |
35 | '<Parent2/>' | |
36 | '</GrandParent>' | |
37 | '</test3>') | |
38 | ||
39 | # Do it the hard way first: | |
40 | xml = easy_xml.EasyXml('test3') | |
41 | grand_parent = xml.AppendNode(xml.Root(), ['GrandParent']) | |
42 | parent1 = xml.AppendNode(grand_parent, ['Parent1']) | |
43 | parent2 = xml.AppendNode(grand_parent, ['Parent2']) | |
44 | xml.AppendNode(parent1, ['Child']) | |
45 | self.assertEqual(str(xml), target) | |
46 | ||
47 | # Do it the easier way: | |
48 | xml = easy_xml.EasyXml('test3') | |
49 | xml.AppendNode(xml.Root(), | |
50 | ['GrandParent', | |
51 | ['Parent1', ['Child']], | |
52 | ['Parent2']]) | |
53 | self.assertEqual(str(xml), target) | |
54 | ||
55 | def test_EasyXml_complex(self): | |
56 | # We want to create: | |
57 | target = ('<?xml version="1.0" ?>' | |
58 | '<Project>' | |
59 | '<PropertyGroup Label="Globals">' | |
60 | '<ProjectGuid>{D2250C20-3A94-4FB9-AF73-11BC5B73884B}</ProjectGuid>' | |
61 | '<Keyword>Win32Proj</Keyword>' | |
62 | '<RootNamespace>automated_ui_tests</RootNamespace>' | |
63 | '</PropertyGroup>' | |
64 | '<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props"/>' | |
65 | '<PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\'' | |
66 | 'Debug|Win32\'" Label="Configuration">' | |
67 | '<ConfigurationType>Application</ConfigurationType>' | |
68 | '<CharacterSet>Unicode</CharacterSet>' | |
69 | '</PropertyGroup>' | |
70 | '</Project>') | |
71 | ||
72 | xml = easy_xml.EasyXml('Project') | |
73 | xml.AppendChildren(xml.Root(), [ | |
74 | ['PropertyGroup', {'Label': 'Globals'}, | |
75 | ['ProjectGuid', '{D2250C20-3A94-4FB9-AF73-11BC5B73884B}'], | |
76 | ['Keyword', 'Win32Proj'], | |
77 | ['RootNamespace', 'automated_ui_tests'] | |
78 | ], | |
79 | ['Import', {'Project': '$(VCTargetsPath)\\Microsoft.Cpp.props'}], | |
80 | ['PropertyGroup', | |
81 | {'Condition': "'$(Configuration)|$(Platform)'=='Debug|Win32'", | |
82 | 'Label': 'Configuration'}, | |
83 | ['ConfigurationType', 'Application'], | |
84 | ['CharacterSet', 'Unicode'] | |
85 | ] | |
86 | ]) | |
87 | self.assertEqual(str(xml), target) | |
88 | ||
89 | ||
90 | if __name__ == '__main__': | |
91 | unittest.main() |
0 | 0 | #!/usr/bin/python |
1 | 1 | |
2 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
2 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
3 | 3 | # Use of this source code is governed by a BSD-style license that can be |
4 | 4 | # found in the LICENSE file. |
5 | 5 | |
24 | 24 | |
25 | 25 | import gyp |
26 | 26 | import gyp.common |
27 | import gyp.system_test | |
27 | 28 | import os.path |
29 | import os | |
28 | 30 | |
29 | 31 | # Debugging-related imports -- remove me once we're solid. |
30 | 32 | import code |
71 | 73 | # It's even quicker (saves ~200ms) to pass -r on the command line. |
72 | 74 | MAKEFLAGS=-r |
73 | 75 | |
76 | # The source directory tree. | |
77 | srcdir := %(srcdir)s | |
78 | ||
79 | # The name of the builddir. | |
80 | builddir_name ?= %(builddir)s | |
81 | ||
74 | 82 | # The V=1 flag on command line makes us verbosely print command lines. |
75 | 83 | ifdef V |
76 | 84 | quiet= |
79 | 87 | endif |
80 | 88 | |
81 | 89 | # Specify BUILDTYPE=Release on the command line for a release build. |
82 | BUILDTYPE ?= __default_configuration__ | |
90 | BUILDTYPE ?= %(default_configuration)s | |
83 | 91 | |
84 | 92 | # Directory all our build output goes into. |
85 | 93 | # Note that this must be two directories beneath src/ for unit tests to pass, |
97 | 105 | all_deps := |
98 | 106 | |
99 | 107 | # C++ apps need to be linked with g++. Not sure what's appropriate. |
100 | LINK ?= $(CXX) | |
108 | # | |
109 | # Note, the flock is used to seralize linking. Linking is a memory-intensive | |
110 | # process so running parallel links can often lead to thrashing. To disable | |
111 | # the serialization, override LINK via an envrionment variable as follows: | |
112 | # | |
113 | # export LINK="$(CXX)" | |
114 | # | |
115 | # This will allow make to invoke N linker processes as specified in -jN. | |
116 | LINK ?= flock $(builddir)/linker.lock $(CXX) %(LINK_flags)s | |
101 | 117 | |
102 | 118 | CC.target ?= $(CC) |
103 | 119 | CFLAGS.target ?= $(CFLAGS) |
106 | 122 | LINK.target ?= $(LINK) |
107 | 123 | LDFLAGS.target ?= $(LDFLAGS) |
108 | 124 | AR.target ?= $(AR) |
109 | RANLIB.target ?= ranlib | |
110 | ||
125 | ARFLAGS.target ?= %(ARFLAGS.target)s | |
126 | ||
127 | # N.B.: the logic of which commands to run should match the computation done | |
128 | # in gyp's make.py where ARFLAGS.host etc. is computed. | |
129 | # TODO(evan): move all cross-compilation logic to gyp-time so we don't need | |
130 | # to replicate this environment fallback in make as well. | |
111 | 131 | CC.host ?= gcc |
112 | 132 | CFLAGS.host ?= |
113 | 133 | CXX.host ?= g++ |
115 | 135 | LINK.host ?= g++ |
116 | 136 | LDFLAGS.host ?= |
117 | 137 | AR.host ?= ar |
118 | RANLIB.host ?= ranlib | |
138 | ARFLAGS.host := %(ARFLAGS.host)s | |
119 | 139 | |
120 | 140 | # Flags to make gcc output dependency info. Note that you need to be |
121 | 141 | # careful here to use the flags that ccache and distcc can understand. |
144 | 164 | # and dollar signs past make, the shell, and sed at the same time.""" |
145 | 165 | r""" |
146 | 166 | define fixup_dep |
167 | # The depfile may not exist if the input file didn't have any #includes. | |
168 | touch $(depfile).raw | |
147 | 169 | # Fixup path as in (1). |
148 | 170 | sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile) |
149 | 171 | # Add extra rules as in (2). |
150 | 172 | # We remove slashes and replace spaces with new lines; |
151 | 173 | # remove blank lines; |
152 | 174 | # delete the first line and append a colon to the remaining lines. |
153 | sed -e 's|\\||' -e 's| |\n|g' $(depfile).raw |\ | |
154 | grep -v '^$$' |\ | |
155 | sed -e 1d -e 's|$$|:|' \ | |
175 | sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ | |
176 | grep -v '^$$' |\ | |
177 | sed -e 1d -e 's|$$|:|' \ | |
156 | 178 | >> $(depfile) |
157 | 179 | rm $(depfile).raw |
158 | 180 | endef |
163 | 185 | # - quiet_cmd_foo is the brief-output summary of the command. |
164 | 186 | |
165 | 187 | quiet_cmd_cc = CC($(TOOLSET)) $@ |
166 | cmd_cc = $(CC.$(TOOLSET)) $(CFLAGS.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) -c -o $@ $< | |
188 | cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< | |
167 | 189 | |
168 | 190 | quiet_cmd_cxx = CXX($(TOOLSET)) $@ |
169 | cmd_cxx = $(CXX.$(TOOLSET)) $(CXXFLAGS.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) -c -o $@ $< | |
170 | ||
171 | quiet_cmd_alink = AR+RANLIB($(TOOLSET)) $@ | |
172 | cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) rc $@ $(filter %.o,$^) && $(RANLIB.$(TOOLSET)) $@ | |
191 | cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< | |
192 | ||
193 | quiet_cmd_alink = AR($(TOOLSET)) $@ | |
194 | cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %%.o,$^) | |
173 | 195 | |
174 | 196 | quiet_cmd_touch = TOUCH $@ |
175 | 197 | cmd_touch = touch $@ |
182 | 204 | # special "figure out circular dependencies" flags around the entire |
183 | 205 | # input list during linking. |
184 | 206 | quiet_cmd_link = LINK($(TOOLSET)) $@ |
185 | cmd_link = $(LINK.$(TOOLSET)) $(LDFLAGS.$(TOOLSET)) $(GYP_LDFLAGS) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) | |
207 | cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) | |
186 | 208 | |
187 | 209 | # Shared-object link (for generating .so). |
188 | 210 | # Set SONAME to the library filename so our binaries don't reference the local, |
189 | 211 | # absolute paths used on the link command-line. |
190 | 212 | # TODO: perhaps this can share with the LINK command above? |
191 | 213 | quiet_cmd_solink = SOLINK($(TOOLSET)) $@ |
192 | cmd_solink = $(LINK.$(TOOLSET)) -shared $(LDFLAGS.$(TOOLSET)) $(GYP_LDFLAGS) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) | |
214 | cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) | |
193 | 215 | """ |
194 | 216 | r""" |
195 | 217 | # Define an escape_quotes function to escape single quotes. |
205 | 227 | # make. This uses printf instead of echo because printf's behaviour with respect |
206 | 228 | # to escape sequences is more portable than echo's across different shells |
207 | 229 | # (e.g., dash, bash). |
208 | exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' | |
230 | exact_echo = printf '%%s\n' '$(call escape_quotes,$(1))' | |
209 | 231 | """ |
210 | 232 | """ |
211 | 233 | # Helper to compare the command we're about to run against the command |
230 | 252 | |
231 | 253 | # do_cmd: run a command via the above cmd_foo names, if necessary. |
232 | 254 | # Should always run for a given target to handle command-line changes. |
233 | # Second argument, if non-zero, makes it do C/C++ dependency munging. | |
255 | # Second argument, if non-zero, makes it do asm/C/C++ dependency munging. | |
234 | 256 | define do_cmd |
235 | 257 | $(if $(or $(command_changed),$(prereq_changed)), |
236 | 258 | @$(call exact_echo, $($(quiet)cmd_$(1))) |
237 | 259 | @mkdir -p $(dir $@) $(dir $(depfile)) |
238 | @$(cmd_$(1)) | |
260 | $(if $(findstring flock,$(word 1,$(cmd_$1))), | |
261 | @$(cmd_$(1)) | |
262 | @echo " $(quiet_cmd_$(1)): Finished", | |
263 | @$(cmd_$(1)) | |
264 | ) | |
239 | 265 | @$(call exact_echo,$(call escape_vars,cmd_$@ := $(cmd_$(1)))) > $(depfile) |
240 | 266 | @$(if $(2),$(fixup_dep)) |
241 | 267 | ) |
245 | 271 | # deps yet. |
246 | 272 | .PHONY: all |
247 | 273 | all: |
248 | ||
249 | # make looks for ways to re-generate included makefiles, but in our case, we | |
250 | # don't have a direct way. Explicitly telling make that it has nothing to do | |
251 | # for them makes it go faster. | |
252 | %.d: ; | |
253 | 274 | |
254 | 275 | # Use FORCE_DO_CMD to force a target to run. Should be coupled with |
255 | 276 | # do_cmd. |
263 | 284 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD |
264 | 285 | @$(call do_cmd,cc,1) |
265 | 286 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD |
266 | @$(call do_cmd,cc) | |
287 | @$(call do_cmd,cc,1) | |
267 | 288 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD |
268 | @$(call do_cmd,cc) | |
289 | @$(call do_cmd,cc,1) | |
269 | 290 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD |
270 | 291 | @$(call do_cmd,cxx,1) |
271 | 292 | $(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD |
277 | 298 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD |
278 | 299 | @$(call do_cmd,cc,1) |
279 | 300 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD |
280 | @$(call do_cmd,cc) | |
301 | @$(call do_cmd,cc,1) | |
281 | 302 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD |
282 | @$(call do_cmd,cc) | |
303 | @$(call do_cmd,cc,1) | |
283 | 304 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD |
284 | 305 | @$(call do_cmd,cxx,1) |
285 | 306 | $(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD |
290 | 311 | $(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD |
291 | 312 | @$(call do_cmd,cc,1) |
292 | 313 | $(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD |
293 | @$(call do_cmd,cc) | |
314 | @$(call do_cmd,cc,1) | |
294 | 315 | $(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD |
295 | @$(call do_cmd,cc) | |
316 | @$(call do_cmd,cc,1) | |
296 | 317 | $(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD |
297 | 318 | @$(call do_cmd,cxx,1) |
298 | 319 | $(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD |
312 | 333 | """), |
313 | 334 | '.s': ("""\ |
314 | 335 | $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.s FORCE_DO_CMD |
315 | @$(call do_cmd,cc) | |
336 | @$(call do_cmd,cc,1) | |
316 | 337 | """), |
317 | 338 | '.S': ("""\ |
318 | 339 | $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.S FORCE_DO_CMD |
319 | @$(call do_cmd,cc) | |
340 | @$(call do_cmd,cc,1) | |
320 | 341 | """), |
321 | 342 | '.cpp': ("""\ |
322 | 343 | $(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD |
374 | 395 | ''.join(SHARED_HEADER_SUFFIX_RULES_OBJDIR2.values()) |
375 | 396 | ) |
376 | 397 | |
377 | # This gets added to the very beginning of the Makefile. | |
378 | SHARED_HEADER_SRCDIR = ("""\ | |
379 | # The source directory tree. | |
380 | srcdir := %s | |
381 | ||
382 | """) | |
383 | ||
384 | SHARED_HEADER_BUILDDIR_NAME = ("""\ | |
385 | # The name of the builddir. | |
386 | builddir_name ?= %s | |
387 | ||
388 | """) | |
389 | ||
390 | 398 | SHARED_FOOTER = """\ |
391 | 399 | # "all" is a concatenation of the "all" targets from all the included |
392 | 400 | # sub-makefiles. This is just here to clarify. |
399 | 407 | # Of those, only consider the ones with .d (dependency) info: |
400 | 408 | d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) |
401 | 409 | ifneq ($(d_files),) |
402 | include $(d_files) | |
410 | # Rather than include each individual .d file, concatenate them into a | |
411 | # single file which make is able to load faster. We split this into | |
412 | # commands that take 1000 files at a time to avoid overflowing the | |
413 | # command line. | |
414 | $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps) | |
415 | %(generate_all_deps)s | |
416 | # make looks for ways to re-generate included makefiles, but in our case, we | |
417 | # don't have a direct way. Explicitly telling make that it has nothing to do | |
418 | # for them makes it go faster. | |
419 | $(depsdir)/all.deps: ; | |
420 | ||
421 | include $(depsdir)/all.deps | |
403 | 422 | endif |
404 | 423 | """ |
405 | 424 | |
418 | 437 | return False |
419 | 438 | |
420 | 439 | |
440 | def Linkable(filename): | |
441 | """Return true if the file is linkable (should be on the link line).""" | |
442 | return filename.endswith('.o') | |
443 | ||
444 | ||
421 | 445 | def Target(filename): |
422 | 446 | """Translate a compilable filename to its .o target.""" |
423 | 447 | return os.path.splitext(filename)[0] + '.o' |
450 | 474 | if '"' in string: |
451 | 475 | string = '"' + string.replace('"', '\\"') + '"' |
452 | 476 | return string |
477 | ||
478 | ||
479 | def StringToMakefileVariable(string): | |
480 | """Convert a string to a value that is acceptable as a make variable name.""" | |
481 | # TODO: replace other metacharacters that we encounter. | |
482 | return string.replace(' ', '_') | |
453 | 483 | |
454 | 484 | |
455 | 485 | srcdir_prefix = '' |
476 | 506 | Its only real entry point is Write(), and is mostly used for namespacing. |
477 | 507 | """ |
478 | 508 | |
509 | def __init__(self): | |
510 | # Keep track of the total number of outputs for this makefile. | |
511 | self._num_outputs = 0 | |
512 | ||
513 | ||
514 | def NumOutputs(self): | |
515 | return self._num_outputs | |
516 | ||
517 | ||
479 | 518 | def Write(self, qualified_target, base_path, output_filename, spec, configs, |
480 | 519 | part_of_all): |
481 | 520 | """The main entry point: writes a .mk file for a single target. |
488 | 527 | spec, configs: gyp info |
489 | 528 | part_of_all: flag indicating this target is part of 'all' |
490 | 529 | """ |
491 | print 'Generating %s' % output_filename | |
492 | ||
493 | 530 | ensure_directory_exists(output_filename) |
494 | 531 | |
495 | 532 | self.fp = open(output_filename, 'w') |
515 | 552 | 'shared_library') |
516 | 553 | if self.type in self._INSTALLABLE_TARGETS: |
517 | 554 | self.alias = os.path.basename(self.output) |
555 | install_path = self._InstallableTargetInstallPath() | |
518 | 556 | else: |
519 | 557 | self.alias = self.output |
558 | install_path = self.output | |
520 | 559 | |
521 | 560 | self.WriteLn("TOOLSET := " + self.toolset) |
522 | 561 | self.WriteLn("TARGET := " + self.target) |
558 | 597 | extra_link_deps + link_deps, extra_outputs, part_of_all) |
559 | 598 | |
560 | 599 | # Update global list of target outputs, used in dependency tracking. |
561 | target_outputs[qualified_target] = self.alias | |
600 | target_outputs[qualified_target] = install_path | |
562 | 601 | |
563 | 602 | # Update global list of link dependencies. |
564 | 603 | if self.type == 'static_library': |
583 | 622 | targets: list of "all" targets for this sub-project |
584 | 623 | build_dir: build output directory, relative to the sub-project |
585 | 624 | """ |
586 | print 'Generating %s' % output_filename | |
587 | ||
588 | 625 | ensure_directory_exists(output_filename) |
589 | 626 | self.fp = open(output_filename, 'w') |
590 | 627 | self.fp.write(header) |
611 | 648 | part_of_all: flag indicating this target is part of 'all' |
612 | 649 | """ |
613 | 650 | for action in actions: |
614 | name = self.target + '_' + action['action_name'] | |
651 | name = self.target + '_' + StringToMakefileVariable(action['action_name']) | |
615 | 652 | self.WriteLn('### Rules for action "%s":' % action['action_name']) |
616 | 653 | inputs = action['inputs'] |
617 | 654 | outputs = action['outputs'] |
680 | 717 | part_of_all: flag indicating this target is part of 'all' |
681 | 718 | """ |
682 | 719 | for rule in rules: |
683 | name = self.target + '_' + rule['rule_name'] | |
720 | name = self.target + '_' + StringToMakefileVariable(rule['rule_name']) | |
684 | 721 | count = 0 |
685 | 722 | self.WriteLn('### Generated for rule %s:' % name) |
686 | 723 | |
687 | 724 | all_outputs = [] |
688 | 725 | |
689 | for rule_source in rule['rule_sources']: | |
726 | for rule_source in rule.get('rule_sources', []): | |
690 | 727 | dirs = set() |
691 | 728 | rule_source_basename = os.path.basename(rule_source) |
692 | 729 | (rule_source_root, rule_source_ext) = \ |
721 | 758 | self.WriteMakeRule(outputs[:1], ['builddir := $(abs_builddir)']) |
722 | 759 | self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions) |
723 | 760 | self.WriteLn('all_deps += %s' % ' '.join(outputs)) |
761 | self._num_outputs += len(outputs) | |
724 | 762 | |
725 | 763 | action = [self.ExpandInputRoot(ac, rule_source_root) |
726 | 764 | for ac in rule['action']] |
819 | 857 | includes = map(Sourceify, map(self.Absolutify, includes)) |
820 | 858 | self.WriteList(includes, 'INCS_%s' % configname, prefix='-I') |
821 | 859 | |
822 | sources = filter(Compilable, sources) | |
823 | objs = map(self.Objectify, map(self.Absolutify, map(Target, sources))) | |
860 | compilable = filter(Compilable, sources) | |
861 | objs = map(self.Objectify, map(self.Absolutify, map(Target, compilable))) | |
824 | 862 | self.WriteList(objs, 'OBJS') |
825 | 863 | |
826 | 864 | self.WriteLn('# Add to the list of files we specially track ' |
827 | 865 | 'dependencies for.') |
828 | 866 | self.WriteLn('all_deps += $(OBJS)') |
867 | self._num_outputs += len(objs) | |
829 | 868 | self.WriteLn() |
830 | 869 | |
831 | 870 | # Make sure our dependencies are built first. |
850 | 889 | # CFLAGS et al overrides must be target-local. |
851 | 890 | # See "Target-specific Variable Values" in the GNU Make manual.""") |
852 | 891 | self.WriteLn("$(OBJS): TOOLSET := $(TOOLSET)") |
853 | self.WriteLn("$(OBJS): GYP_CFLAGS := $(CFLAGS_$(BUILDTYPE)) " | |
854 | "$(CFLAGS_C_$(BUILDTYPE)) " | |
855 | "$(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE))") | |
856 | self.WriteLn("$(OBJS): GYP_CXXFLAGS := $(CFLAGS_$(BUILDTYPE)) " | |
857 | "$(CFLAGS_CC_$(BUILDTYPE)) " | |
858 | "$(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE))") | |
892 | self.WriteLn("$(OBJS): GYP_CFLAGS := " | |
893 | "$(DEFS_$(BUILDTYPE)) " | |
894 | "$(INCS_$(BUILDTYPE)) " | |
895 | "$(CFLAGS_$(BUILDTYPE)) " | |
896 | "$(CFLAGS_C_$(BUILDTYPE))") | |
897 | self.WriteLn("$(OBJS): GYP_CXXFLAGS := " | |
898 | "$(DEFS_$(BUILDTYPE)) " | |
899 | "$(INCS_$(BUILDTYPE)) " | |
900 | "$(CFLAGS_$(BUILDTYPE)) " | |
901 | "$(CFLAGS_CC_$(BUILDTYPE))") | |
902 | ||
903 | # If there are any object files in our input file list, link them into our | |
904 | # output. | |
905 | extra_link_deps += filter(Linkable, sources) | |
859 | 906 | |
860 | 907 | self.WriteLn() |
861 | 908 | |
988 | 1035 | # 2) They get shortcuts for building (e.g. "make chrome"). |
989 | 1036 | # 3) They are part of "make all". |
990 | 1037 | if self.type in self._INSTALLABLE_TARGETS: |
991 | if self.type in ('shared_library'): | |
1038 | if self.type == 'shared_library': | |
992 | 1039 | file_desc = 'shared library' |
993 | # Install all shared libs into a common directory (per toolset) for | |
994 | # convenient access with LD_LIBRARY_PATH. | |
995 | binpath = '$(builddir)/lib.%s/%s' % (self.toolset, self.alias) | |
996 | 1040 | else: |
997 | 1041 | file_desc = 'executable' |
998 | binpath = '$(builddir)/' + self.alias | |
1042 | install_path = self._InstallableTargetInstallPath() | |
999 | 1043 | installable_deps = [self.output] |
1000 | 1044 | # Point the target alias to the final binary output. |
1001 | self.WriteMakeRule([self.target], [binpath], | |
1045 | self.WriteMakeRule([self.target], [install_path], | |
1002 | 1046 | comment='Add target alias', phony = True) |
1003 | if binpath != self.output: | |
1004 | self.WriteDoCmd([binpath], [self.output], 'copy', | |
1047 | if install_path != self.output: | |
1048 | self.WriteDoCmd([install_path], [self.output], 'copy', | |
1005 | 1049 | comment = 'Copy this to the %s output path.' % |
1006 | 1050 | file_desc, part_of_all=part_of_all) |
1007 | installable_deps.append(binpath) | |
1051 | installable_deps.append(install_path) | |
1008 | 1052 | if self.output != self.alias and self.alias != self.target: |
1009 | 1053 | self.WriteMakeRule([self.alias], installable_deps, |
1010 | 1054 | comment = 'Short alias for building this %s.' % |
1011 | 1055 | file_desc, phony = True) |
1012 | 1056 | if part_of_all: |
1013 | self.WriteMakeRule(['all'], [binpath], | |
1057 | self.WriteMakeRule(['all'], [install_path], | |
1014 | 1058 | comment = 'Add %s to "all" target.' % file_desc, |
1015 | 1059 | phony = True) |
1016 | 1060 | |
1041 | 1085 | force = True) |
1042 | 1086 | # Add our outputs to the list of targets we read depfiles from. |
1043 | 1087 | self.WriteLn('all_deps += %s' % ' '.join(outputs)) |
1088 | self._num_outputs += len(outputs) | |
1044 | 1089 | |
1045 | 1090 | |
1046 | 1091 | def WriteMakeRule(self, outputs, inputs, actions=None, comment=None, |
1140 | 1185 | return path |
1141 | 1186 | |
1142 | 1187 | |
1188 | def _InstallableTargetInstallPath(self): | |
1189 | """Returns the location of the final output for an installable target.""" | |
1190 | if self.type == 'shared_library': | |
1191 | # Install all shared libs into a common directory (per toolset) for | |
1192 | # convenient access with LD_LIBRARY_PATH. | |
1193 | return '$(builddir)/lib.%s/%s' % (self.toolset, self.alias) | |
1194 | return '$(builddir)/' + self.alias | |
1195 | ||
1196 | ||
1197 | def WriteAutoRegenerationRule(params, root_makefile, makefile_name, | |
1198 | build_files): | |
1199 | """Write the target to regenerate the Makefile.""" | |
1200 | options = params['options'] | |
1201 | build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir) | |
1202 | for filename in params['build_files_arg']] | |
1203 | gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'], | |
1204 | options.toplevel_dir) | |
1205 | if not gyp_binary.startswith(os.sep): | |
1206 | gyp_binary = os.path.join('.', gyp_binary) | |
1207 | root_makefile.write( | |
1208 | "quiet_cmd_regen_makefile = ACTION Regenerating $@\n" | |
1209 | "cmd_regen_makefile = %(cmd)s\n" | |
1210 | "%(makefile_name)s: %(deps)s\n" | |
1211 | "\t$(call do_cmd,regen_makefile)\n\n" % { | |
1212 | 'makefile_name': makefile_name, | |
1213 | 'deps': ' '.join(map(Sourceify, build_files)), | |
1214 | 'cmd': gyp.common.EncodePOSIXShellList( | |
1215 | [gyp_binary, '-fmake'] + | |
1216 | gyp.RegenerateFlags(options) + | |
1217 | build_files_args)}) | |
1218 | ||
1219 | ||
1220 | def RunSystemTests(): | |
1221 | """Run tests against the system to compute default settings for commands. | |
1222 | ||
1223 | Returns: | |
1224 | dictionary of settings matching the block of command-lines used in | |
1225 | SHARED_HEADER. E.g. the dictionary will contain a ARFLAGS.target | |
1226 | key for the default ARFLAGS for the target ar command. | |
1227 | """ | |
1228 | # Compute flags used for building static archives. | |
1229 | # N.B.: this fallback logic should match the logic in SHARED_HEADER. | |
1230 | # See comment there for more details. | |
1231 | ar_target = os.environ.get('AR.target', os.environ.get('AR', 'ar')) | |
1232 | cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc')) | |
1233 | arflags_target = 'crs' | |
1234 | if gyp.system_test.TestArSupportsT(ar_command=ar_target, | |
1235 | cc_command=cc_target): | |
1236 | arflags_target = 'crsT' | |
1237 | ||
1238 | ar_host = os.environ.get('AR.host', 'ar') | |
1239 | cc_host = os.environ.get('CC.host', 'gcc') | |
1240 | arflags_host = 'crs' | |
1241 | # It feels redundant to compute this again given that most builds aren't | |
1242 | # cross-compiles, but due to quirks of history CC.host defaults to 'gcc' | |
1243 | # while CC.target defaults to 'cc', so the commands really are different | |
1244 | # even though they're nearly guaranteed to run the same code underneath. | |
1245 | if gyp.system_test.TestArSupportsT(ar_command=ar_host, cc_command=cc_host): | |
1246 | arflags_host = 'crsT' | |
1247 | ||
1248 | link_flags = '' | |
1249 | if gyp.system_test.TestLinkerSupportsThreads(cc_command=cc_target): | |
1250 | # N.B. we don't test for cross-compilation; as currently written, we | |
1251 | # don't even use flock when linking in the cross-compile setup! | |
1252 | # TODO(evan): refactor cross-compilation such that this code can | |
1253 | # be reused. | |
1254 | link_flags = '-Wl,--threads -Wl,--thread-count=4' | |
1255 | ||
1256 | # TODO(evan): cache this output. (But then we'll need to add extra | |
1257 | # flags to gyp to flush the cache, yuk! It's fast enough for now to | |
1258 | # just run it every time.) | |
1259 | ||
1260 | return { 'ARFLAGS.target': arflags_target, | |
1261 | 'ARFLAGS.host': arflags_host, | |
1262 | 'LINK_flags': link_flags } | |
1263 | ||
1264 | ||
1265 | def CalculateVariables(default_variables, params): | |
1266 | """Calculate additional variables for use in the build (called by gyp).""" | |
1267 | cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc')) | |
1268 | default_variables['LINKER_SUPPORTS_ICF'] = \ | |
1269 | gyp.system_test.TestLinkerSupportsICF(cc_command=cc_target) | |
1270 | ||
1271 | ||
1143 | 1272 | def GenerateOutput(target_list, target_dicts, data, params): |
1144 | 1273 | options = params['options'] |
1145 | 1274 | generator_flags = params.get('generator_flags', {}) |
1157 | 1286 | output_file = os.path.join(options.depth, base_path, base_name) |
1158 | 1287 | if options.generator_output: |
1159 | 1288 | output_file = os.path.join(options.generator_output, output_file) |
1160 | return (base_path, output_file) | |
1289 | base_path = gyp.common.RelativePath(os.path.dirname(build_file), | |
1290 | options.toplevel_dir) | |
1291 | return base_path, output_file | |
1161 | 1292 | |
1162 | 1293 | # TODO: search for the first non-'Default' target. This can go |
1163 | 1294 | # away when we add verification that all targets have the |
1174 | 1305 | |
1175 | 1306 | srcdir = '.' |
1176 | 1307 | makefile_name = 'Makefile' + options.suffix |
1177 | makefile_path = os.path.join(options.depth, makefile_name) | |
1308 | makefile_path = os.path.join(options.toplevel_dir, makefile_name) | |
1178 | 1309 | if options.generator_output: |
1179 | 1310 | global srcdir_prefix |
1180 | 1311 | makefile_path = os.path.join(options.generator_output, makefile_path) |
1181 | 1312 | srcdir = gyp.common.RelativePath(srcdir, options.generator_output) |
1182 | 1313 | srcdir_prefix = '$(srcdir)/' |
1314 | ||
1315 | header_params = { | |
1316 | 'srcdir': srcdir, | |
1317 | 'builddir': builddir_name, | |
1318 | 'default_configuration': default_configuration, | |
1319 | } | |
1320 | header_params.update(RunSystemTests()) | |
1321 | ||
1183 | 1322 | ensure_directory_exists(makefile_path) |
1184 | 1323 | root_makefile = open(makefile_path, 'w') |
1185 | root_makefile.write(SHARED_HEADER_SRCDIR % srcdir) | |
1186 | root_makefile.write(SHARED_HEADER_BUILDDIR_NAME % builddir_name) | |
1187 | root_makefile.write(SHARED_HEADER.replace('__default_configuration__', | |
1188 | default_configuration)) | |
1324 | root_makefile.write(SHARED_HEADER % header_params) | |
1189 | 1325 | for toolset in toolsets: |
1190 | 1326 | root_makefile.write('TOOLSET := %s\n' % toolset) |
1191 | 1327 | root_makefile.write(ROOT_HEADER_SUFFIX_RULES) |
1196 | 1332 | for target in gyp.common.AllTargets(target_list, target_dicts, build_file): |
1197 | 1333 | needed_targets.add(target) |
1198 | 1334 | |
1335 | num_outputs = 0 | |
1199 | 1336 | build_files = set() |
1200 | 1337 | include_list = set() |
1201 | 1338 | for qualified_target in target_list: |
1202 | 1339 | build_file, target, toolset = gyp.common.ParseQualifiedTarget( |
1203 | 1340 | qualified_target) |
1204 | build_files.add(gyp.common.RelativePath(build_file, options.depth)) | |
1341 | build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir)) | |
1205 | 1342 | included_files = data[build_file]['included_files'] |
1206 | 1343 | for included_file in included_files: |
1207 | 1344 | # The included_files entries are relative to the dir of the build file |
1208 | 1345 | # that included them, so we have to undo that and then make them relative |
1209 | 1346 | # to the root dir. |
1210 | 1347 | relative_include_file = gyp.common.RelativePath( |
1211 | gyp.common.UnrelativePath(included_file, build_file), options.depth) | |
1348 | gyp.common.UnrelativePath(included_file, build_file), | |
1349 | options.toplevel_dir) | |
1212 | 1350 | abs_include_file = os.path.abspath(relative_include_file) |
1213 | 1351 | # If the include file is from the ~/.gyp dir, we should use absolute path |
1214 | 1352 | # so that relocating the src dir doesn't break the path. |
1218 | 1356 | else: |
1219 | 1357 | build_files.add(relative_include_file) |
1220 | 1358 | |
1221 | (base_path, output_file) = CalculateMakefilePath(build_file, | |
1359 | base_path, output_file = CalculateMakefilePath(build_file, | |
1222 | 1360 | target + '.' + toolset + options.suffix + '.mk') |
1223 | 1361 | |
1224 | 1362 | spec = target_dicts[qualified_target] |
1227 | 1365 | writer = MakefileWriter() |
1228 | 1366 | writer.Write(qualified_target, base_path, output_file, spec, configs, |
1229 | 1367 | part_of_all=qualified_target in needed_targets) |
1368 | num_outputs += writer.NumOutputs() | |
1230 | 1369 | |
1231 | 1370 | # Our root_makefile lives at the source root. Compute the relative path |
1232 | 1371 | # from there to the output_file for including. |
1233 | 1372 | mkfile_rel_path = gyp.common.RelativePath(output_file, |
1234 | 1373 | os.path.dirname(makefile_path)) |
1235 | include_list.add('include ' + mkfile_rel_path + '\n') | |
1374 | include_list.add(mkfile_rel_path) | |
1236 | 1375 | |
1237 | 1376 | # Write out per-gyp (sub-project) Makefiles. |
1238 | 1377 | depth_rel_path = gyp.common.RelativePath(options.depth, os.getcwd()) |
1247 | 1386 | # Only generate Makefiles for gyp files with targets. |
1248 | 1387 | if not gyp_targets: |
1249 | 1388 | continue |
1250 | (base_path, output_file) = CalculateMakefilePath(build_file, | |
1389 | base_path, output_file = CalculateMakefilePath(build_file, | |
1251 | 1390 | os.path.splitext(os.path.basename(build_file))[0] + '.Makefile') |
1252 | 1391 | makefile_rel_path = gyp.common.RelativePath(os.path.dirname(makefile_path), |
1253 | 1392 | os.path.dirname(output_file)) |
1257 | 1396 | |
1258 | 1397 | # Write out the sorted list of includes. |
1259 | 1398 | root_makefile.write('\n') |
1260 | for include in sorted(include_list): | |
1261 | root_makefile.write(include) | |
1399 | for include_file in sorted(include_list): | |
1400 | # We wrap each .mk include in an if statement so users can tell make to | |
1401 | # not load a file by setting NO_LOAD. The below make code says, only | |
1402 | # load the .mk file if the .mk filename doesn't start with a token in | |
1403 | # NO_LOAD. | |
1404 | root_makefile.write( | |
1405 | "ifeq ($(strip $(foreach prefix,$(NO_LOAD),\\\n" | |
1406 | " $(findstring $(join ^,$(prefix)),\\\n" | |
1407 | " $(join ^," + include_file + ")))),)\n") | |
1408 | root_makefile.write(" include " + include_file + "\n") | |
1409 | root_makefile.write("endif\n") | |
1262 | 1410 | root_makefile.write('\n') |
1263 | 1411 | |
1264 | # Write the target to regenerate the Makefile. | |
1265 | 1412 | if generator_flags.get('auto_regeneration', True): |
1266 | build_files_args = [gyp.common.RelativePath(filename, options.depth) | |
1267 | for filename in params['build_files_arg']] | |
1268 | gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'], | |
1269 | options.depth) | |
1270 | if not gyp_binary.startswith(os.sep): | |
1271 | gyp_binary = os.path.join('.', gyp_binary) | |
1272 | root_makefile.write("%s: %s\n\t%s\n" % ( | |
1273 | makefile_name, | |
1274 | ' '.join(map(Sourceify, build_files)), | |
1275 | gyp.common.EncodePOSIXShellList( | |
1276 | [gyp_binary, '-fmake'] + | |
1277 | gyp.RegenerateFlags(options) + | |
1278 | build_files_args))) | |
1279 | ||
1280 | root_makefile.write(SHARED_FOOTER) | |
1413 | WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files) | |
1414 | ||
1415 | # Write the rule to load dependencies. We batch 1000 files at a time to | |
1416 | # avoid overflowing the command line. | |
1417 | all_deps = "" | |
1418 | for i in range(1001, num_outputs, 1000): | |
1419 | all_deps += (""" | |
1420 | ifneq ($(word %(start)d,$(d_files)),) | |
1421 | $(shell cat $(wordlist %(start)d,%(end)d,$(d_files)) >> $(depsdir)/all.deps) | |
1422 | endif""" % { 'start': i, 'end': i + 999 }) | |
1423 | ||
1424 | # Add a check to make sure we tried to process all the .d files. | |
1425 | all_deps += """ | |
1426 | ifneq ($(word %(last)d,$(d_files)),) | |
1427 | $(error Found unprocessed dependency files (gyp didn't generate enough rules!)) | |
1428 | endif | |
1429 | """ % { 'last': ((num_outputs / 1000) + 1) * 1000 + 1 } | |
1430 | ||
1431 | root_makefile.write(SHARED_FOOTER % { 'generate_all_deps': all_deps }) | |
1281 | 1432 | |
1282 | 1433 | root_makefile.close() |
0 | 0 | #!/usr/bin/python |
1 | 1 | |
2 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
2 | # Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
3 | 3 | # Use of this source code is governed by a BSD-style license that can be |
4 | 4 | # found in the LICENSE file. |
5 | 5 | |
6 | 6 | import ntpath |
7 | import os | |
7 | 8 | import posixpath |
8 | import os | |
9 | 9 | import re |
10 | 10 | import subprocess |
11 | 11 | import sys |
12 | 12 | |
13 | import gyp.common | |
14 | import gyp.easy_xml as easy_xml | |
13 | 15 | import gyp.MSVSNew as MSVSNew |
14 | 16 | import gyp.MSVSProject as MSVSProject |
17 | import gyp.MSVSSettings as MSVSSettings | |
15 | 18 | import gyp.MSVSToolFile as MSVSToolFile |
16 | 19 | import gyp.MSVSUserFile as MSVSUserFile |
17 | 20 | import gyp.MSVSVersion as MSVSVersion |
18 | import gyp.common | |
19 | 21 | |
20 | 22 | |
21 | 23 | # Regular expression for validating Visual Studio GUIDs. If the GUID |
40 | 42 | 'SHARED_INTERMEDIATE_DIR': '$(OutDir)/obj/global_intermediate', |
41 | 43 | 'OS': 'win', |
42 | 44 | 'PRODUCT_DIR': '$(OutDir)', |
45 | ||
46 | # TODO(jeanluc) The way we currently generate libraries makes Visual | |
47 | # Studio 2010 unhappy. We get a lot of warnings like: | |
48 | # warning MSB8012: TargetPath(...\Debug\gles2_c_lib.lib) does not match | |
49 | # the Library's OutputFile property value (...\Debug\lib\gles2_c_lib.lib). | |
50 | # This may cause your project to build incorrectly. To correct this, | |
51 | # please make sure that $(OutDir), $(TargetName) and $(TargetExt) property | |
52 | # values match the value specified in %(Lib.OutputFile). | |
53 | # Despite the warnings, this compile correctly. It would be nice to get rid | |
54 | # of the warnings. | |
55 | ||
56 | # TODO(jeanluc) I had: 'LIB_DIR': '$(OutDir)lib', | |
43 | 57 | 'LIB_DIR': '$(OutDir)/lib', |
44 | 58 | 'RULE_INPUT_ROOT': '$(InputName)', |
45 | 59 | 'RULE_INPUT_EXT': '$(InputExt)', |
55 | 69 | 'msvs_props', |
56 | 70 | ] |
57 | 71 | |
72 | ||
58 | 73 | generator_additional_non_configuration_keys = [ |
59 | 74 | 'msvs_cygwin_dirs', |
60 | 75 | 'msvs_cygwin_shell', |
61 | 76 | ] |
62 | 77 | |
78 | ||
79 | # List of precompiled header related keys. | |
80 | precomp_keys = [ | |
81 | 'msvs_precompiled_header', | |
82 | 'msvs_precompiled_source', | |
83 | ] | |
84 | ||
85 | ||
63 | 86 | cached_username = None |
87 | ||
88 | ||
64 | 89 | cached_domain = None |
90 | ||
65 | 91 | |
66 | 92 | # TODO(gspencer): Switch the os.environ calls to be |
67 | 93 | # win32api.GetDomainName() and win32api.GetUserName() once the |
77 | 103 | username = os.environ.get('USERNAME') |
78 | 104 | if not domain or not username: |
79 | 105 | call = subprocess.Popen(['net', 'config', 'Workstation'], |
80 | stdout=subprocess.PIPE) | |
106 | stdout=subprocess.PIPE) | |
81 | 107 | config = call.communicate()[0] |
82 | 108 | username_re = re.compile('^User name\s+(\S+)', re.MULTILINE) |
83 | 109 | username_match = username_re.search(config) |
93 | 119 | |
94 | 120 | fixpath_prefix = None |
95 | 121 | |
122 | ||
123 | def _NormalizedSource(source): | |
124 | """Normalize the path. | |
125 | ||
126 | But not if that gets rid of a variable, as this may expand to something | |
127 | larger than one directory. | |
128 | ||
129 | Arguments: | |
130 | source: The path to be normalize.d | |
131 | ||
132 | Returns: | |
133 | The normalized path. | |
134 | """ | |
135 | normalized = os.path.normpath(source) | |
136 | if source.count('$') == normalized.count('$'): | |
137 | source = normalized | |
138 | return source | |
139 | ||
140 | ||
96 | 141 | def _FixPath(path): |
97 | 142 | """Convert paths to a form that will make sense in a vcproj file. |
98 | 143 | |
104 | 149 | if fixpath_prefix and path and not os.path.isabs(path) and not path[0] == '$': |
105 | 150 | path = os.path.join(fixpath_prefix, path) |
106 | 151 | path = path.replace('/', '\\') |
107 | if len(path) > 0 and path[-1] == '\\': | |
152 | path = _NormalizedSource(path) | |
153 | if path and path[-1] == '\\': | |
108 | 154 | path = path[:-1] |
109 | 155 | return path |
110 | 156 | |
111 | 157 | |
112 | def _SourceInFolders(sources, prefix=None, excluded=None): | |
158 | def _FixPaths(paths): | |
159 | """Fix each of the paths of the list.""" | |
160 | return [_FixPath(i) for i in paths] | |
161 | ||
162 | ||
163 | def _ConvertSourcesToFilterHierarchy(sources, prefix=None, excluded=None): | |
113 | 164 | """Converts a list split source file paths into a vcproj folder hierarchy. |
114 | 165 | |
115 | 166 | Arguments: |
116 | 167 | sources: A list of source file paths split. |
117 | 168 | prefix: A list of source file path layers meant to apply to each of sources. |
169 | excluded: A set of excluded files. | |
170 | ||
118 | 171 | Returns: |
119 | 172 | A hierarchy of filenames and MSVSProject.Filter objects that matches the |
120 | 173 | layout of the source tree. |
121 | 174 | For example: |
122 | _SourceInFolders([['a', 'bob1.c'], ['b', 'bob2.c']], prefix=['joe']) | |
175 | _ConvertSourcesToFilterHierarchy([['a', 'bob1.c'], ['b', 'bob2.c']], | |
176 | prefix=['joe']) | |
123 | 177 | --> |
124 | 178 | [MSVSProject.Filter('a', contents=['joe\\a\\bob1.c']), |
125 | 179 | MSVSProject.Filter('b', contents=['joe\\b\\bob2.c'])] |
131 | 185 | # Gather files into the final result, excluded, or folders. |
132 | 186 | for s in sources: |
133 | 187 | if len(s) == 1: |
134 | filename = '\\'.join(prefix + s) | |
188 | filename = _NormalizedSource('\\'.join(prefix + s)) | |
135 | 189 | if filename in excluded: |
136 | 190 | excluded_result.append(filename) |
137 | 191 | else: |
147 | 201 | result.append(excluded_folder) |
148 | 202 | # Populate all the folders. |
149 | 203 | for f in folders: |
150 | contents = _SourceInFolders(folders[f], prefix=prefix + [f], | |
151 | excluded=excluded) | |
204 | contents = _ConvertSourcesToFilterHierarchy(folders[f], prefix=prefix + [f], | |
205 | excluded=excluded) | |
152 | 206 | contents = MSVSProject.Filter(f, contents=contents) |
153 | 207 | result.append(contents) |
154 | 208 | |
195 | 249 | return '%s|%s' % (_ConfigBaseName(config_name, platform_name), platform_name) |
196 | 250 | |
197 | 251 | |
198 | def _PrepareActionRaw(spec, cmd, cygwin_shell, has_input_path, quote_cmd): | |
252 | def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path, | |
253 | quote_cmd): | |
199 | 254 | if cygwin_shell: |
200 | 255 | # Find path to cygwin. |
201 | 256 | cygwin_dir = _FixPath(spec.get('msvs_cygwin_dirs', ['.'])[0]) |
215 | 270 | direct_cmd = ' '.join(direct_cmd) |
216 | 271 | # TODO(quote): regularize quoting path names throughout the module |
217 | 272 | cmd = ( |
218 | '"$(ProjectDir)%(cygwin_dir)s\\setup_env.bat" && ' | |
219 | 'set CYGWIN=nontsec&& ') | |
273 | 'call "$(ProjectDir)%(cygwin_dir)s\\setup_env.bat" && ' | |
274 | 'set CYGWIN=nontsec&& ') | |
220 | 275 | if direct_cmd.find('NUMBER_OF_PROCESSORS') >= 0: |
221 | 276 | cmd += 'set /a NUMBER_OF_PROCESSORS_PLUS_1=%%NUMBER_OF_PROCESSORS%%+1&& ' |
222 | 277 | if direct_cmd.find('INTDIR') >= 0: |
225 | 280 | cmd += 'set OUTDIR=$(OutDir)&& ' |
226 | 281 | if has_input_path and direct_cmd.find('INPUTPATH') >= 0: |
227 | 282 | cmd += 'set INPUTPATH=$(InputPath) && ' |
228 | cmd += ( | |
229 | 'bash -c "%(cmd)s"') | |
283 | cmd += 'bash -c "%(cmd)s"' | |
230 | 284 | cmd = cmd % {'cygwin_dir': cygwin_dir, |
231 | 285 | 'cmd': direct_cmd} |
232 | 286 | return cmd |
233 | 287 | else: |
234 | 288 | # Convert cat --> type to mimic unix. |
235 | 289 | if cmd[0] == 'cat': |
236 | cmd = ['type'] + cmd[1:] | |
290 | command = ['type'] | |
291 | else: | |
292 | command = [cmd[0].replace('/', '\\')] | |
293 | # Fix the paths | |
294 | # If the argument starts with a slash, it's probably a command line switch | |
295 | arguments = [i.startswith('/') and i or _FixPath(i) for i in cmd[1:]] | |
237 | 296 | if quote_cmd: |
238 | 297 | # Support a mode for using cmd directly. |
239 | 298 | # Convert any paths to native form (first element is used directly). |
240 | 299 | # TODO(quote): regularize quoting path names throughout the module |
241 | direct_cmd = ([cmd[0].replace('/', '\\')] + | |
242 | ['"%s"' % _FixPath(i) for i in cmd[1:]]) | |
243 | else: | |
244 | direct_cmd = ([cmd[0].replace('/', '\\')] + | |
245 | [_FixPath(i) for i in cmd[1:]]) | |
300 | arguments = ['"%s"' % i for i in arguments] | |
246 | 301 | # Collapse into a single command. |
247 | return ' '.join(direct_cmd) | |
248 | ||
249 | def _PrepareAction(spec, rule, has_input_path): | |
302 | return ' '.join(command + arguments) | |
303 | ||
304 | ||
305 | def _BuildCommandLineForRule(spec, rule, has_input_path): | |
250 | 306 | # Find path to cygwin. |
251 | 307 | cygwin_dir = _FixPath(spec.get('msvs_cygwin_dirs', ['.'])[0]) |
252 | 308 | |
260 | 316 | elif isinstance(mcs, str): |
261 | 317 | mcs = int(mcs) |
262 | 318 | quote_cmd = int(rule.get('msvs_quote_cmd', 1)) |
263 | return _PrepareActionRaw(spec, rule['action'], mcs, | |
264 | has_input_path, quote_cmd) | |
265 | ||
266 | ||
267 | def _PickPrimaryInput(inputs): | |
268 | # Pick second input as the primary one, unless there's only one. | |
269 | # TODO(bradnelson): this is a bit of a hack, | |
270 | # find something more general. | |
271 | if len(inputs) > 1: | |
272 | return inputs[1] | |
273 | else: | |
274 | return inputs[0] | |
275 | ||
276 | def _SetRunAs(user_file, config_name, c_data, command, | |
277 | environment={}, working_directory=""): | |
278 | """Add a run_as rule to the user file. | |
279 | ||
280 | Arguments: | |
281 | user_file: The MSVSUserFile to add the command to. | |
282 | config_name: The name of the configuration to add it to | |
283 | c_data: The dict of the configuration to add it to | |
284 | command: The path to the command to execute. | |
285 | args: An array of arguments to the command. (optional) | |
286 | working_directory: Directory to run the command in. (optional) | |
287 | """ | |
288 | user_file.AddDebugSettings(_ConfigFullName(config_name, c_data), | |
289 | command, environment, working_directory) | |
290 | ||
291 | def _AddCustomBuildTool(p, spec, inputs, outputs, description, cmd): | |
319 | return _BuildCommandLineForRuleRaw(spec, rule['action'], mcs, has_input_path, | |
320 | quote_cmd) | |
321 | ||
322 | ||
323 | def _AddActionStep(actions_dict, inputs, outputs, description, command): | |
324 | """Merge action into an existing list of actions. | |
325 | ||
326 | Care must be taken so that actions which have overlapping inputs either don't | |
327 | get assigned to the same input, or get collapsed into one. | |
328 | ||
329 | Arguments: | |
330 | actions_dict: dictionary keyed on input name, which maps to a list of | |
331 | dicts describing the actions attached to that input file. | |
332 | inputs: list of inputs | |
333 | outputs: list of outputs | |
334 | description: description of the action | |
335 | command: command line to execute | |
336 | """ | |
337 | # Require there to be at least one input (call sites will ensure this). | |
338 | assert inputs | |
339 | ||
340 | action = { | |
341 | 'inputs': inputs, | |
342 | 'outputs': outputs, | |
343 | 'description': description, | |
344 | 'command': command, | |
345 | } | |
346 | ||
347 | # Pick where to stick this action. | |
348 | # While less than optimal in terms of build time, attach them to the first | |
349 | # input for now. | |
350 | chosen_input = inputs[0] | |
351 | ||
352 | # Add it there. | |
353 | if chosen_input not in actions_dict: | |
354 | actions_dict[chosen_input] = [] | |
355 | actions_dict[chosen_input].append(action) | |
356 | ||
357 | ||
358 | def _AddCustomBuildToolForMSVS(p, spec, primary_input, | |
359 | inputs, outputs, description, cmd): | |
292 | 360 | """Add a custom build tool to execute something. |
293 | 361 | |
294 | 362 | Arguments: |
295 | 363 | p: the target project |
296 | 364 | spec: the target project dict |
365 | primary_input: input file to attach the build tool to | |
297 | 366 | inputs: list of inputs |
298 | 367 | outputs: list of outputs |
299 | 368 | description: description of the action |
300 | 369 | cmd: command line to execute |
301 | 370 | """ |
302 | inputs = [_FixPath(i) for i in inputs] | |
303 | outputs = [_FixPath(i) for i in outputs] | |
371 | inputs = _FixPaths(inputs) | |
372 | outputs = _FixPaths(outputs) | |
304 | 373 | tool = MSVSProject.Tool( |
305 | 'VCCustomBuildTool', { | |
306 | 'Description': description, | |
307 | 'AdditionalDependencies': ';'.join(inputs), | |
308 | 'Outputs': ';'.join(outputs), | |
309 | 'CommandLine': cmd, | |
374 | 'VCCustomBuildTool', | |
375 | {'Description': description, | |
376 | 'AdditionalDependencies': ';'.join(inputs), | |
377 | 'Outputs': ';'.join(outputs), | |
378 | 'CommandLine': cmd, | |
310 | 379 | }) |
311 | primary_input = _PickPrimaryInput(inputs) | |
312 | 380 | # Add to the properties of primary input for each config. |
313 | 381 | for config_name, c_data in spec['configurations'].iteritems(): |
314 | p.AddFileConfig(primary_input, | |
382 | p.AddFileConfig(_FixPath(primary_input), | |
315 | 383 | _ConfigFullName(config_name, c_data), tools=[tool]) |
384 | ||
385 | ||
386 | def _AddAccumulatedActionsToMSVS(p, spec, actions_dict): | |
387 | """Add actions accumulated into an actions_dict, merging as needed. | |
388 | ||
389 | Arguments: | |
390 | p: the target project | |
391 | spec: the target project dict | |
392 | actions_dict: dictionary keyed on input name, which maps to a list of | |
393 | dicts describing the actions attached to that input file. | |
394 | """ | |
395 | for primary_input in actions_dict: | |
396 | inputs = set() | |
397 | outputs = set() | |
398 | descriptions = [] | |
399 | commands = [] | |
400 | for action in actions_dict[primary_input]: | |
401 | inputs.update(set(action['inputs'])) | |
402 | outputs.update(set(action['outputs'])) | |
403 | descriptions.append(action['description']) | |
404 | commands.append(action['command']) | |
405 | # Add the custom build step for one input file. | |
406 | description = ', and also '.join(descriptions) | |
407 | command = '\r\n'.join(commands) | |
408 | _AddCustomBuildToolForMSVS(p, spec, | |
409 | primary_input=primary_input, | |
410 | inputs=inputs, | |
411 | outputs=outputs, | |
412 | description=description, | |
413 | cmd=command) | |
316 | 414 | |
317 | 415 | |
318 | 416 | def _RuleExpandPath(path, input_file): |
350 | 448 | """Find the inputs and outputs generated by a rule. |
351 | 449 | |
352 | 450 | Arguments: |
353 | rule: the rule in question | |
354 | sources: the set of all known source files for this project | |
451 | rule: the rule in question. | |
452 | trigger_file: the main trigger for this rule. | |
355 | 453 | Returns: |
356 | 454 | The pair of (inputs, outputs) involved in this rule. |
357 | 455 | """ |
358 | raw_inputs = rule.get('inputs', []) | |
359 | raw_outputs = rule.get('outputs', []) | |
456 | raw_inputs = _FixPaths(rule.get('inputs', [])) | |
457 | raw_outputs = _FixPaths(rule.get('outputs', [])) | |
360 | 458 | inputs = set() |
361 | 459 | outputs = set() |
362 | 460 | inputs.add(trigger_file) |
367 | 465 | return (inputs, outputs) |
368 | 466 | |
369 | 467 | |
370 | def _GenerateNativeRules(p, rules, output_dir, spec, options): | |
468 | def _GenerateNativeRulesForMSVS(p, rules, output_dir, spec, options): | |
371 | 469 | """Generate a native rules file. |
372 | 470 | |
373 | 471 | Arguments: |
385 | 483 | for r in rules: |
386 | 484 | rule_name = r['rule_name'] |
387 | 485 | rule_ext = r['extension'] |
388 | inputs = [_FixPath(i) for i in r.get('inputs', [])] | |
389 | outputs = [_FixPath(i) for i in r.get('outputs', [])] | |
390 | cmd = _PrepareAction(spec, r, has_input_path=True) | |
486 | inputs = _FixPaths(r.get('inputs', [])) | |
487 | outputs = _FixPaths(r.get('outputs', [])) | |
488 | cmd = _BuildCommandLineForRule(spec, r, has_input_path=True) | |
391 | 489 | rules_file.AddCustomBuildRule(name=rule_name, |
392 | 490 | description=r.get('message', rule_name), |
393 | 491 | extensions=[rule_ext], |
407 | 505 | return path |
408 | 506 | |
409 | 507 | |
410 | def _GenerateExternalRules(p, rules, output_dir, spec, | |
508 | def _GenerateExternalRules(rules, output_dir, spec, | |
411 | 509 | sources, options, actions_to_add): |
412 | 510 | """Generate an external makefile to do a set of rules. |
413 | 511 | |
414 | 512 | Arguments: |
415 | p: the target project | |
416 | 513 | rules: the list of rules to include |
417 | 514 | output_dir: path containing project and gyp files |
418 | 515 | spec: project specification data |
419 | 516 | sources: set of sources known |
420 | 517 | options: global generator options |
518 | actions_to_add: The list of actions we will add to. | |
421 | 519 | """ |
422 | 520 | filename = '%s_rules%s.mk' % (spec['target_name'], options.suffix) |
423 | file = gyp.common.WriteOnDiff(os.path.join(output_dir, filename)) | |
521 | mk_file = gyp.common.WriteOnDiff(os.path.join(output_dir, filename)) | |
424 | 522 | # Find cygwin style versions of some paths. |
425 | file.write('OutDirCygwin:=$(shell cygpath -u "$(OutDir)")\n') | |
426 | file.write('IntDirCygwin:=$(shell cygpath -u "$(IntDir)")\n') | |
523 | mk_file.write('OutDirCygwin:=$(shell cygpath -u "$(OutDir)")\n') | |
524 | mk_file.write('IntDirCygwin:=$(shell cygpath -u "$(IntDir)")\n') | |
427 | 525 | # Gather stuff needed to emit all: target. |
428 | 526 | all_inputs = set() |
429 | 527 | all_outputs = set() |
444 | 542 | all_output_dirs.add(od) |
445 | 543 | first_outputs_cyg = [_Cygwinify(i) for i in first_outputs] |
446 | 544 | # Write out all: target, including mkdir for each output directory. |
447 | file.write('all: %s\n' % ' '.join(first_outputs_cyg)) | |
545 | mk_file.write('all: %s\n' % ' '.join(first_outputs_cyg)) | |
448 | 546 | for od in all_output_dirs: |
449 | file.write('\tmkdir -p %s\n' % od) | |
450 | file.write('\n') | |
547 | mk_file.write('\tmkdir -p %s\n' % od) | |
548 | mk_file.write('\n') | |
451 | 549 | # Define how each output is generated. |
452 | 550 | for rule in rules: |
453 | 551 | trigger_files = _FindRuleTriggerFiles(rule, sources) |
461 | 559 | cmd = ['"%s"' % i for i in cmd] |
462 | 560 | cmd = ' '.join(cmd) |
463 | 561 | # Add it to the makefile. |
464 | file.write('%s: %s\n' % (' '.join(outputs), ' '.join(inputs))) | |
465 | file.write('\t%s\n\n' % cmd) | |
562 | mk_file.write('%s: %s\n' % (' '.join(outputs), ' '.join(inputs))) | |
563 | mk_file.write('\t%s\n\n' % cmd) | |
466 | 564 | # Close up the file. |
467 | file.close() | |
565 | mk_file.close() | |
468 | 566 | |
469 | 567 | # Add makefile to list of sources. |
470 | 568 | sources.add(filename) |
474 | 572 | 'IntDir=$(IntDir)', |
475 | 573 | '-j', '${NUMBER_OF_PROCESSORS_PLUS_1}', |
476 | 574 | '-f', filename] |
477 | cmd = _PrepareActionRaw(spec, cmd, True, False, True) | |
478 | # TODO(bradnelson): this won't be needed if we have a better way to pick | |
479 | # the primary input. | |
575 | cmd = _BuildCommandLineForRuleRaw(spec, cmd, True, False, True) | |
576 | # Insert makefile as 0'th input, so it gets the action attached there, | |
577 | # as this is easier to understand from in the IDE. | |
480 | 578 | all_inputs = list(all_inputs) |
481 | all_inputs.insert(1, filename) | |
482 | actions_to_add.append({ | |
483 | 'inputs': [_FixPath(i) for i in all_inputs], | |
484 | 'outputs': [_FixPath(i) for i in all_outputs], | |
485 | 'description': 'Running %s' % cmd, | |
486 | 'cmd': cmd, | |
487 | }) | |
579 | all_inputs.insert(0, filename) | |
580 | _AddActionStep(actions_to_add, | |
581 | inputs=_FixPaths(all_inputs), | |
582 | outputs=_FixPaths(all_outputs), | |
583 | description='Running %s' % cmd, | |
584 | command=cmd) | |
488 | 585 | |
489 | 586 | |
490 | 587 | def _EscapeEnvironmentVariableExpansion(s): |
491 | """Escapes any % characters so that Windows-style environment variable | |
492 | expansions will leave them alone. | |
493 | See http://connect.microsoft.com/VisualStudio/feedback/details/106127/cl-d-name-text-containing-percentage-characters-doesnt-compile | |
494 | to understand why we have to do this.""" | |
588 | """Escapes % characters. | |
589 | ||
590 | Escapes any % characters so that Windows-style environment variable | |
591 | expansions will leave them alone. | |
592 | See http://connect.microsoft.com/VisualStudio/feedback/details/106127/cl-d-name-text-containing-percentage-characters-doesnt-compile | |
593 | to understand why we have to do this. | |
594 | ||
595 | Args: | |
596 | s: The string to be escaped. | |
597 | ||
598 | Returns: | |
599 | The escaped string. | |
600 | """ | |
495 | 601 | s = s.replace('%', '%%') |
496 | 602 | return s |
497 | 603 | |
498 | 604 | |
499 | 605 | quote_replacer_regex = re.compile(r'(\\*)"') |
500 | def _EscapeCommandLineArgument(s): | |
501 | """Escapes a Windows command-line argument, so that the Win32 | |
502 | CommandLineToArgv function will turn the escaped result back into the | |
503 | original string. See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx | |
504 | ("Parsing C++ Command-Line Arguments") to understand why we have to do | |
505 | this.""" | |
506 | def replace(match): | |
606 | ||
607 | ||
608 | def _EscapeCommandLineArgumentForMSVS(s): | |
609 | """Escapes a Windows command-line argument. | |
610 | ||
611 | So that the Win32 CommandLineToArgv function will turn the escaped result back | |
612 | into the original string. | |
613 | See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx | |
614 | ("Parsing C++ Command-Line Arguments") to understand why we have to do | |
615 | this. | |
616 | ||
617 | Args: | |
618 | s: the string to be escaped. | |
619 | Returns: | |
620 | the escaped string. | |
621 | """ | |
622 | ||
623 | def _Replace(match): | |
507 | 624 | # For a literal quote, CommandLineToArgv requires an odd number of |
508 | 625 | # backslashes preceding it, and it produces half as many literal backslashes |
509 | 626 | # (rounded down). So we need to produce 2n+1 backslashes. |
510 | 627 | return 2 * match.group(1) + '\\"' |
628 | ||
511 | 629 | # Escape all quotes so that they are interpreted literally. |
512 | s = quote_replacer_regex.sub(replace, s) | |
630 | s = quote_replacer_regex.sub(_Replace, s) | |
513 | 631 | # Now add unescaped quotes so that any whitespace is interpreted literally. |
514 | 632 | s = '"' + s + '"' |
515 | 633 | return s |
516 | 634 | |
517 | 635 | |
518 | 636 | delimiters_replacer_regex = re.compile(r'(\\*)([,;]+)') |
637 | ||
638 | ||
519 | 639 | def _EscapeVCProjCommandLineArgListItem(s): |
520 | """The VCProj format stores string lists in a single string using commas and | |
521 | semi-colons as separators, which must be quoted if they are to be | |
522 | interpreted literally. However, command-line arguments may already have | |
523 | quotes, and the VCProj parser is ignorant of the backslash escaping | |
524 | convention used by CommandLineToArgv, so the command-line quotes and the | |
525 | VCProj quotes may not be the same quotes. So to store a general | |
526 | command-line argument in a VCProj list, we need to parse the existing | |
527 | quoting according to VCProj's convention and quote any delimiters that are | |
528 | not already quoted by that convention. The quotes that we add will also be | |
529 | seen by CommandLineToArgv, so if backslashes precede them then we also have | |
530 | to escape those backslashes according to the CommandLineToArgv | |
531 | convention.""" | |
532 | def replace(match): | |
640 | """Escapes command line arguments for MSVS. | |
641 | ||
642 | The VCProj format stores string lists in a single string using commas and | |
643 | semi-colons as separators, which must be quoted if they are to be | |
644 | interpreted literally. However, command-line arguments may already have | |
645 | quotes, and the VCProj parser is ignorant of the backslash escaping | |
646 | convention used by CommandLineToArgv, so the command-line quotes and the | |
647 | VCProj quotes may not be the same quotes. So to store a general | |
648 | command-line argument in a VCProj list, we need to parse the existing | |
649 | quoting according to VCProj's convention and quote any delimiters that are | |
650 | not already quoted by that convention. The quotes that we add will also be | |
651 | seen by CommandLineToArgv, so if backslashes precede them then we also have | |
652 | to escape those backslashes according to the CommandLineToArgv | |
653 | convention. | |
654 | ||
655 | Args: | |
656 | s: the string to be escaped. | |
657 | Returns: | |
658 | the escaped string. | |
659 | """ | |
660 | ||
661 | def _Replace(match): | |
533 | 662 | # For a non-literal quote, CommandLineToArgv requires an even number of |
534 | 663 | # backslashes preceding it, and it produces half as many literal |
535 | 664 | # backslashes. So we need to produce 2n backslashes. |
536 | 665 | return 2 * match.group(1) + '"' + match.group(2) + '"' |
537 | list = s.split('"') | |
666 | ||
667 | segments = s.split('"') | |
538 | 668 | # The unquoted segments are at the even-numbered indices. |
539 | for i in range(0, len(list), 2): | |
540 | list[i] = delimiters_replacer_regex.sub(replace, list[i]) | |
669 | for i in range(0, len(segments), 2): | |
670 | segments[i] = delimiters_replacer_regex.sub(_Replace, segments[i]) | |
541 | 671 | # Concatenate back into a single string |
542 | s = '"'.join(list) | |
543 | if len(list) % 2 == 0: | |
672 | s = '"'.join(segments) | |
673 | if len(segments) % 2 == 0: | |
544 | 674 | # String ends while still quoted according to VCProj's convention. This |
545 | 675 | # means the delimiter and the next list item that follow this one in the |
546 | 676 | # .vcproj file will be misinterpreted as part of this item. There is nothing |
549 | 679 | # the item to the end of the list does works, but that's only possible if |
550 | 680 | # there's only one such item. Let's just warn the user. |
551 | 681 | print >> sys.stderr, ('Warning: MSVS may misinterpret the odd number of ' + |
552 | 'quotes in ' + s) | |
682 | 'quotes in ' + s) | |
553 | 683 | return s |
554 | 684 | |
555 | 685 | |
556 | def _EscapeCppDefine(s): | |
686 | def _EscapeCppDefineForMSVS(s): | |
557 | 687 | """Escapes a CPP define so that it will reach the compiler unaltered.""" |
558 | 688 | s = _EscapeEnvironmentVariableExpansion(s) |
559 | s = _EscapeCommandLineArgument(s) | |
689 | s = _EscapeCommandLineArgumentForMSVS(s) | |
560 | 690 | s = _EscapeVCProjCommandLineArgListItem(s) |
561 | 691 | return s |
562 | 692 | |
563 | 693 | |
564 | def _GenerateRules(p, output_dir, options, spec, | |
565 | sources, excluded_sources, | |
566 | actions_to_add): | |
694 | quote_replacer_regex2 = re.compile(r'(\\+)"') | |
695 | ||
696 | ||
697 | def _EscapeCommandLineArgumentForMSBuild(s): | |
698 | """Escapes a Windows command-line argument for use by MSBuild.""" | |
699 | ||
700 | def _Replace(match): | |
701 | return (len(match.group(1))/2*4)*'\\' + '\\"' | |
702 | ||
703 | # Escape all quotes so that they are interpreted literally. | |
704 | s = quote_replacer_regex2.sub(_Replace, s) | |
705 | return s | |
706 | ||
707 | ||
708 | def _EscapeMSBuildSpecialCharacters(s): | |
709 | escape_dictionary = { | |
710 | '%': '%25', | |
711 | '$': '%24', | |
712 | '@': '%40', | |
713 | "'": '%27', | |
714 | ';': '%3B', | |
715 | '?': '%3F', | |
716 | '*': '%2A' | |
717 | } | |
718 | result = ''.join([escape_dictionary.get(c, c) for c in s]) | |
719 | return result | |
720 | ||
721 | ||
722 | def _EscapeCppDefineForMSBuild(s): | |
723 | """Escapes a CPP define so that it will reach the compiler unaltered.""" | |
724 | s = _EscapeEnvironmentVariableExpansion(s) | |
725 | s = _EscapeCommandLineArgumentForMSBuild(s) | |
726 | s = _EscapeMSBuildSpecialCharacters(s) | |
727 | return s | |
728 | ||
729 | ||
730 | def _GenerateRulesForMSVS(p, output_dir, options, spec, | |
731 | sources, excluded_sources, | |
732 | actions_to_add): | |
567 | 733 | """Generate all the rules for a particular project. |
568 | 734 | |
569 | 735 | Arguments: |
736 | p: the project | |
570 | 737 | output_dir: directory to emit rules to |
571 | 738 | options: global options passed to the generator |
572 | 739 | spec: the specification for this project |
580 | 747 | |
581 | 748 | # Handle rules that use a native rules file. |
582 | 749 | if rules_native: |
583 | _GenerateNativeRules(p, rules_native, output_dir, spec, options) | |
750 | _GenerateNativeRulesForMSVS(p, rules_native, output_dir, spec, options) | |
584 | 751 | |
585 | 752 | # Handle external rules (non-native rules). |
586 | 753 | if rules_external: |
587 | _GenerateExternalRules(p, rules_external, output_dir, spec, | |
754 | _GenerateExternalRules(rules_external, output_dir, spec, | |
588 | 755 | sources, options, actions_to_add) |
589 | ||
756 | _AdjustSourcesForRules(rules, sources, excluded_sources) | |
757 | ||
758 | ||
759 | def _AdjustSourcesForRules(rules, sources, excluded_sources): | |
590 | 760 | # Add outputs generated by each rule (if applicable). |
591 | 761 | for rule in rules: |
592 | 762 | # Done if not processing outputs as sources. |
593 | 763 | if int(rule.get('process_outputs_as_sources', False)): |
594 | 764 | # Add in the outputs from this rule. |
595 | 765 | trigger_files = _FindRuleTriggerFiles(rule, sources) |
596 | for tf in trigger_files: | |
597 | inputs, outputs = _RuleInputsAndOutputs(rule, tf) | |
598 | inputs.remove(tf) | |
766 | for trigger_file in trigger_files: | |
767 | inputs, outputs = _RuleInputsAndOutputs(rule, trigger_file) | |
768 | inputs = set(_FixPaths(inputs)) | |
769 | outputs = set(_FixPaths(outputs)) | |
770 | inputs.remove(_FixPath(trigger_file)) | |
599 | 771 | sources.update(inputs) |
600 | 772 | excluded_sources.update(inputs) |
601 | 773 | sources.update(outputs) |
602 | 774 | |
603 | 775 | |
604 | def _GenerateProject(vcproj_filename, build_file, spec, options, version): | |
605 | """Generates a vcproj file. | |
606 | ||
607 | Arguments: | |
608 | vcproj_filename: Filename of the vcproj file to generate. | |
609 | build_file: Filename of the .gyp file that the vcproj file comes from. | |
776 | def _FilterActionsFromExcluded(excluded_sources, actions_to_add): | |
777 | """Take inputs with actions attached out of the list of exclusions. | |
778 | ||
779 | Arguments: | |
780 | excluded_sources: list of source files not to be built. | |
781 | actions_to_add: dict of actions keyed on source file they're attached to. | |
782 | Returns: | |
783 | excluded_sources with files that have actions attached removed. | |
784 | """ | |
785 | must_keep = set(_FixPaths(actions_to_add.keys())) | |
786 | return [s for s in excluded_sources if s not in must_keep] | |
787 | ||
788 | ||
789 | def _GetDefaultConfiguration(spec): | |
790 | return spec['configurations'][spec['default_configuration']] | |
791 | ||
792 | ||
793 | def _GetGuidOfProject(proj_path, spec): | |
794 | """Get the guid for the project. | |
795 | ||
796 | Arguments: | |
797 | proj_path: Path of the vcproj or vcxproj file to generate. | |
610 | 798 | spec: The target dictionary containing the properties of the target. |
799 | Returns: | |
800 | the guid. | |
801 | Raises: | |
802 | ValueError: if the specified GUID is invalid. | |
611 | 803 | """ |
612 | 804 | # Pluck out the default configuration. |
613 | default_config = spec['configurations'][spec['default_configuration']] | |
805 | default_config = _GetDefaultConfiguration(spec) | |
614 | 806 | # Decide the guid of the project. |
615 | 807 | guid = default_config.get('msvs_guid') |
616 | 808 | if guid: |
617 | if VALID_MSVS_GUID_CHARS.match(guid) == None: | |
809 | if VALID_MSVS_GUID_CHARS.match(guid) is None: | |
618 | 810 | raise ValueError('Invalid MSVS guid: "%s". Must match regex: "%s".' % |
619 | 811 | (guid, VALID_MSVS_GUID_CHARS.pattern)) |
620 | 812 | guid = '{%s}' % guid |
813 | guid = guid or MSVSNew.MakeGuid(proj_path) | |
814 | return guid | |
815 | ||
816 | ||
817 | def _GenerateProject(project, options, version): | |
818 | """Generates a vcproj file. | |
819 | ||
820 | Arguments: | |
821 | project: the MSVSProject object. | |
822 | options: global generator options. | |
823 | version: the MSVSVersion object. | |
824 | """ | |
825 | default_config = _GetDefaultConfiguration(project.spec) | |
621 | 826 | |
622 | 827 | # Skip emitting anything if told to with msvs_existing_vcproj option. |
623 | 828 | if default_config.get('msvs_existing_vcproj'): |
624 | return guid | |
625 | ||
626 | #print 'Generating %s' % vcproj_filename | |
627 | ||
628 | vcproj_dir = os.path.dirname(vcproj_filename) | |
829 | return | |
830 | ||
831 | if version.UsesVcxproj(): | |
832 | _GenerateMSBuildProject(project, options, version) | |
833 | else: | |
834 | _GenerateMSVSProject(project, options, version) | |
835 | ||
836 | ||
837 | def _GenerateMSVSProject(project, options, version): | |
838 | """Generates a .vcproj file. It may create .rules and .user files too. | |
839 | ||
840 | Arguments: | |
841 | project: The project object we will generate the file for. | |
842 | options: Global options passed to the generator. | |
843 | version: The VisualStudioVersion object. | |
844 | """ | |
845 | spec = project.spec | |
846 | vcproj_dir = os.path.dirname(project.path) | |
629 | 847 | if vcproj_dir and not os.path.exists(vcproj_dir): |
630 | 848 | os.makedirs(vcproj_dir) |
631 | 849 | |
850 | platforms = _GetUniquePlatforms(spec) | |
851 | p = MSVSProject.Writer(project.path, version=version) | |
852 | p.Create(spec['target_name'], guid=project.guid, platforms=platforms) | |
853 | ||
854 | # Get directory project file is in. | |
855 | gyp_dir = os.path.split(project.path)[0] | |
856 | gyp_file = posixpath.split(project.build_file)[1] | |
857 | gyp_path = _NormalizedSource(gyp_file) | |
858 | relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, gyp_dir) | |
859 | ||
860 | config_type = _GetMSVSConfigurationType(spec, project.build_file) | |
861 | for config_name, config in spec['configurations'].iteritems(): | |
862 | _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config) | |
863 | ||
864 | # Prepare list of sources and excluded sources. | |
865 | sources, excluded_sources = _PrepareListOfSources(spec, | |
866 | relative_path_of_gyp_file) | |
867 | ||
868 | # Add rules. | |
869 | actions_to_add = {} | |
870 | _GenerateRulesForMSVS(p, gyp_dir, options, spec, | |
871 | sources, excluded_sources, | |
872 | actions_to_add) | |
873 | sources, excluded_sources, excluded_idl = ( | |
874 | _AdjustSourcesAndConvertToFilterHierarchy( | |
875 | spec, options, gyp_dir, sources, excluded_sources)) | |
876 | ||
877 | # Add in files. | |
878 | p.AddFiles(sources) | |
879 | ||
880 | _AddToolFilesToMSVS(p, spec) | |
881 | _HandlePreCompileHeaderStubs(p, spec) | |
882 | _AddActions(actions_to_add, spec, relative_path_of_gyp_file) | |
883 | _AddCopies(actions_to_add, spec) | |
884 | _WriteMSVSUserFile(project.path, version, spec) | |
885 | ||
886 | # NOTE: this stanza must appear after all actions have been decided. | |
887 | # Don't excluded sources with actions attached, or they won't run. | |
888 | excluded_sources = _FilterActionsFromExcluded( | |
889 | excluded_sources, actions_to_add) | |
890 | _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl) | |
891 | _AddAccumulatedActionsToMSVS(p, spec, actions_to_add) | |
892 | ||
893 | # Write it out. | |
894 | p.Write() | |
895 | ||
896 | ||
897 | def _GetUniquePlatforms(spec): | |
898 | """Returns the list of unique platforms for this spec, e.g ['win32', ...]. | |
899 | ||
900 | Arguments: | |
901 | spec: The target dictionary containing the properties of the target. | |
902 | Returns: | |
903 | The MSVSUserFile object created. | |
904 | """ | |
632 | 905 | # Gather list of unique platforms. |
633 | 906 | platforms = set() |
634 | 907 | for configuration in spec['configurations']: |
635 | 908 | platforms.add(_ConfigPlatform(spec['configurations'][configuration])) |
636 | 909 | platforms = list(platforms) |
637 | ||
638 | p = MSVSProject.Writer(vcproj_filename, version=version) | |
639 | p.Create(spec['target_name'], guid=guid, platforms=platforms) | |
640 | ||
641 | # Create the user file. | |
910 | return platforms | |
911 | ||
912 | ||
913 | def _CreateMSVSUserFile(proj_path, version, spec): | |
914 | """Generates a .user file for the user running this Gyp program. | |
915 | ||
916 | Arguments: | |
917 | proj_path: The path of the project file being created. The .user file | |
918 | shares the same path (with an appropriate suffix). | |
919 | version: The VisualStudioVersion object. | |
920 | spec: The target dictionary containing the properties of the target. | |
921 | Returns: | |
922 | The MSVSUserFile object created. | |
923 | """ | |
642 | 924 | (domain, username) = _GetDomainAndUserName() |
643 | vcuser_filename = '.'.join([vcproj_filename, domain, username, 'user']) | |
925 | vcuser_filename = '.'.join([proj_path, domain, username, 'user']) | |
644 | 926 | user_file = MSVSUserFile.Writer(vcuser_filename, version=version) |
645 | 927 | user_file.Create(spec['target_name']) |
646 | ||
647 | # Get directory project file is in. | |
648 | gyp_dir = os.path.split(vcproj_filename)[0] | |
649 | ||
650 | # Pick target configuration type. | |
928 | return user_file | |
929 | ||
930 | ||
931 | def _GetMSVSConfigurationType(spec, build_file): | |
932 | """Returns the configuration type for this project. | |
933 | ||
934 | It's a number defined by Microsoft. May raise an exception. | |
935 | ||
936 | Args: | |
937 | spec: The target dictionary containing the properties of the target. | |
938 | build_file: The path of the gyp file. | |
939 | Returns: | |
940 | An integer, the configuration type. | |
941 | """ | |
651 | 942 | try: |
652 | 943 | config_type = { |
653 | 944 | 'executable': '1', # .exe |
657 | 948 | 'none': '10', # Utility type |
658 | 949 | 'dummy_executable': '1', # .exe |
659 | 950 | }[spec['type']] |
660 | except KeyError, e: | |
951 | except KeyError: | |
661 | 952 | if spec.get('type'): |
662 | 953 | raise Exception('Target type %s is not a valid target type for ' |
663 | 954 | 'target %s in %s.' % |
665 | 956 | else: |
666 | 957 | raise Exception('Missing type field for target %s in %s.' % |
667 | 958 | (spec['target_name'], build_file)) |
668 | ||
669 | for config_name, c in spec['configurations'].iteritems(): | |
670 | # Process each configuration. | |
671 | vsprops_dirs = c.get('msvs_props', []) | |
672 | vsprops_dirs = [_FixPath(i) for i in vsprops_dirs] | |
673 | ||
674 | # Prepare the list of tools as a dictionary. | |
675 | tools = dict() | |
676 | ||
677 | # Add in msvs_settings. | |
678 | for tool in c.get('msvs_settings', {}): | |
679 | settings = c['msvs_settings'][tool] | |
680 | for setting in settings: | |
681 | _ToolAppend(tools, tool, setting, settings[setting]) | |
682 | ||
683 | # Add in includes. | |
684 | # TODO(bradnelson): include_dirs should really be flexible enough not to | |
685 | # require this sort of thing. | |
686 | include_dirs = ( | |
687 | c.get('include_dirs', []) + | |
688 | c.get('msvs_system_include_dirs', [])) | |
689 | resource_include_dirs = c.get('resource_include_dirs', include_dirs) | |
690 | include_dirs = [_FixPath(i) for i in include_dirs] | |
691 | resource_include_dirs = [_FixPath(i) for i in resource_include_dirs] | |
959 | return config_type | |
960 | ||
961 | ||
962 | def _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config): | |
963 | """Adds a configuration to the MSVS project. | |
964 | ||
965 | Many settings in a vcproj file are specific to a configuration. This | |
966 | function the main part of the vcproj file that's configuration specific. | |
967 | ||
968 | Arguments: | |
969 | p: The target project being generated. | |
970 | spec: The target dictionary containing the properties of the target. | |
971 | config_type: The configuration type, a number as defined by Microsoft. | |
972 | config_name: The name of the configuration. | |
973 | config: The dictionnary that defines the special processing to be done | |
974 | for this configuration. | |
975 | """ | |
976 | # Get the information for this configuration | |
977 | include_dirs, resource_include_dirs = _GetIncludeDirs(config) | |
978 | libraries = _GetLibraries(spec) | |
979 | out_file, vc_tool, _ = _GetOutputFilePathAndTool(spec) | |
980 | defines = _GetDefines(config) | |
981 | defines = [_EscapeCppDefineForMSVS(d) for d in defines] | |
982 | disabled_warnings = _GetDisabledWarnings(config) | |
983 | prebuild = config.get('msvs_prebuild') | |
984 | postbuild = config.get('msvs_postbuild') | |
985 | def_file = _GetModuleDefinition(spec) | |
986 | precompiled_header = config.get('msvs_precompiled_header') | |
987 | ||
988 | # Prepare the list of tools as a dictionary. | |
989 | tools = dict() | |
990 | # Add in user specified msvs_settings. | |
991 | msvs_settings = config.get('msvs_settings', {}) | |
992 | MSVSSettings.ValidateMSVSSettings(msvs_settings) | |
993 | for tool in msvs_settings: | |
994 | settings = config['msvs_settings'][tool] | |
995 | for setting in settings: | |
996 | _ToolAppend(tools, tool, setting, settings[setting]) | |
997 | # Add the information to the appropriate tool | |
998 | _ToolAppend(tools, 'VCCLCompilerTool', | |
999 | 'AdditionalIncludeDirectories', include_dirs) | |
1000 | _ToolAppend(tools, 'VCResourceCompilerTool', | |
1001 | 'AdditionalIncludeDirectories', resource_include_dirs) | |
1002 | # Add in libraries. | |
1003 | _ToolAppend(tools, 'VCLinkerTool', 'AdditionalDependencies', libraries) | |
1004 | if out_file: | |
1005 | _ToolAppend(tools, vc_tool, 'OutputFile', out_file, only_if_unset=True) | |
1006 | # Add defines. | |
1007 | _ToolAppend(tools, 'VCCLCompilerTool', 'PreprocessorDefinitions', defines) | |
1008 | _ToolAppend(tools, 'VCResourceCompilerTool', 'PreprocessorDefinitions', | |
1009 | defines) | |
1010 | # Change program database directory to prevent collisions. | |
1011 | _ToolAppend(tools, 'VCCLCompilerTool', 'ProgramDataBaseFileName', | |
1012 | '$(IntDir)\\$(ProjectName)\\vc80.pdb') | |
1013 | # Add disabled warnings. | |
1014 | _ToolAppend(tools, 'VCCLCompilerTool', | |
1015 | 'DisableSpecificWarnings', disabled_warnings) | |
1016 | # Add Pre-build. | |
1017 | _ToolAppend(tools, 'VCPreBuildEventTool', 'CommandLine', prebuild) | |
1018 | # Add Post-build. | |
1019 | _ToolAppend(tools, 'VCPostBuildEventTool', 'CommandLine', postbuild) | |
1020 | # Turn on precompiled headers if appropriate. | |
1021 | if precompiled_header: | |
1022 | precompiled_header = os.path.split(precompiled_header)[1] | |
1023 | _ToolAppend(tools, 'VCCLCompilerTool', 'UsePrecompiledHeader', '2') | |
692 | 1024 | _ToolAppend(tools, 'VCCLCompilerTool', |
693 | 'AdditionalIncludeDirectories', include_dirs) | |
694 | _ToolAppend(tools, 'VCResourceCompilerTool', | |
695 | 'AdditionalIncludeDirectories', resource_include_dirs) | |
696 | ||
697 | # Add in libraries. | |
698 | libraries = spec.get('libraries', []) | |
699 | # Strip out -l, as it is not used on windows (but is needed so we can pass | |
700 | # in libraries that are assumed to be in the default library path). | |
701 | libraries = [re.sub('^(\-l)', '', lib) for lib in libraries] | |
702 | # Add them. | |
703 | _ToolAppend(tools, 'VCLinkerTool', | |
704 | 'AdditionalDependencies', libraries) | |
705 | ||
706 | # Select a name for the output file. | |
707 | output_file_map = { | |
708 | 'executable': ('VCLinkerTool', '$(OutDir)\\', '.exe'), | |
709 | 'shared_library': ('VCLinkerTool', '$(OutDir)\\', '.dll'), | |
710 | 'loadable_module': ('VCLinkerTool', '$(OutDir)\\', '.dll'), | |
711 | 'static_library': ('VCLibrarianTool', '$(OutDir)\\lib\\', '.lib'), | |
712 | 'dummy_executable': ('VCLinkerTool', '$(IntDir)\\', '.junk'), | |
713 | } | |
714 | output_file_props = output_file_map.get(spec['type']) | |
715 | if output_file_props and int(spec.get('msvs_auto_output_file', 1)): | |
716 | vc_tool, out_dir, suffix = output_file_props | |
717 | out_dir = spec.get('product_dir', out_dir) | |
718 | product_extension = spec.get('product_extension') | |
719 | if product_extension: | |
720 | suffix = '.' + product_extension | |
721 | prefix = spec.get('product_prefix', '') | |
722 | product_name = spec.get('product_name', '$(ProjectName)') | |
723 | out_file = ntpath.join(out_dir, prefix + product_name + suffix) | |
724 | _ToolAppend(tools, vc_tool, 'OutputFile', out_file, | |
725 | only_if_unset=True) | |
726 | ||
727 | # Add defines. | |
728 | defines = [] | |
729 | for d in c.get('defines', []): | |
730 | if type(d) == list: | |
731 | fd = '='.join([str(dpart) for dpart in d]) | |
1025 | 'PrecompiledHeaderThrough', precompiled_header) | |
1026 | _ToolAppend(tools, 'VCCLCompilerTool', | |
1027 | 'ForcedIncludeFiles', precompiled_header) | |
1028 | # Loadable modules don't generate import libraries; | |
1029 | # tell dependent projects to not expect one. | |
1030 | if spec['type'] == 'loadable_module': | |
1031 | _ToolAppend(tools, 'VCLinkerTool', 'IgnoreImportLibrary', 'true') | |
1032 | # Set the module definition file if any. | |
1033 | if def_file: | |
1034 | _ToolAppend(tools, 'VCLinkerTool', 'ModuleDefinitionFile', def_file) | |
1035 | ||
1036 | _AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name) | |
1037 | ||
1038 | ||
1039 | def _GetIncludeDirs(config): | |
1040 | """Returns the list of directories to be used for #include directives. | |
1041 | ||
1042 | Arguments: | |
1043 | config: The dictionnary that defines the special processing to be done | |
1044 | for this configuration. | |
1045 | Returns: | |
1046 | The list of directory paths. | |
1047 | """ | |
1048 | # TODO(bradnelson): include_dirs should really be flexible enough not to | |
1049 | # require this sort of thing. | |
1050 | include_dirs = ( | |
1051 | config.get('include_dirs', []) + | |
1052 | config.get('msvs_system_include_dirs', [])) | |
1053 | resource_include_dirs = config.get('resource_include_dirs', include_dirs) | |
1054 | include_dirs = _FixPaths(include_dirs) | |
1055 | resource_include_dirs = _FixPaths(resource_include_dirs) | |
1056 | return include_dirs, resource_include_dirs | |
1057 | ||
1058 | ||
1059 | def _GetLibraries(spec): | |
1060 | """Returns the list of libraries for this configuration. | |
1061 | ||
1062 | Arguments: | |
1063 | spec: The target dictionary containing the properties of the target. | |
1064 | Returns: | |
1065 | The list of directory paths. | |
1066 | """ | |
1067 | libraries = spec.get('libraries', []) | |
1068 | # Strip out -l, as it is not used on windows (but is needed so we can pass | |
1069 | # in libraries that are assumed to be in the default library path). | |
1070 | return [re.sub('^(\-l)', '', lib) for lib in libraries] | |
1071 | ||
1072 | ||
1073 | def _GetOutputFilePathAndTool(spec): | |
1074 | """Returns the path and tool to use for this target. | |
1075 | ||
1076 | Figures out the path of the file this spec will create and the name of | |
1077 | the VC tool that will create it. | |
1078 | ||
1079 | Arguments: | |
1080 | spec: The target dictionary containing the properties of the target. | |
1081 | Returns: | |
1082 | A triple of (file path, name of the vc tool, name of the msbuild tool) | |
1083 | """ | |
1084 | # Select a name for the output file. | |
1085 | out_file = '' | |
1086 | vc_tool = '' | |
1087 | msbuild_tool = '' | |
1088 | output_file_map = { | |
1089 | 'executable': ('VCLinkerTool', 'Link', '$(OutDir)\\', '.exe'), | |
1090 | 'shared_library': ('VCLinkerTool', 'Link', '$(OutDir)\\', '.dll'), | |
1091 | 'loadable_module': ('VCLinkerTool', 'Link', '$(OutDir)\\', '.dll'), | |
1092 | # TODO(jeanluc) If we want to avoid the MSB8012 warnings in | |
1093 | # VisualStudio 2010, we will have to change the value of $(OutDir) | |
1094 | # to contain the \lib suffix, rather than doing it as below. | |
1095 | 'static_library': ('VCLibrarianTool', 'Lib', '$(OutDir)\\lib\\', '.lib'), | |
1096 | 'dummy_executable': ('VCLinkerTool', 'Link', '$(IntDir)\\', '.junk'), | |
1097 | } | |
1098 | output_file_props = output_file_map.get(spec['type']) | |
1099 | if output_file_props and int(spec.get('msvs_auto_output_file', 1)): | |
1100 | vc_tool, msbuild_tool, out_dir, suffix = output_file_props | |
1101 | out_dir = spec.get('product_dir', out_dir) | |
1102 | product_extension = spec.get('product_extension') | |
1103 | if product_extension: | |
1104 | suffix = '.' + product_extension | |
1105 | prefix = spec.get('product_prefix', '') | |
1106 | product_name = spec.get('product_name', '$(ProjectName)') | |
1107 | out_file = ntpath.join(out_dir, prefix + product_name + suffix) | |
1108 | return out_file, vc_tool, msbuild_tool | |
1109 | ||
1110 | ||
1111 | def _GetDefines(config): | |
1112 | """Returns the list of preprocessor definitions for this configuation. | |
1113 | ||
1114 | Arguments: | |
1115 | config: The dictionnary that defines the special processing to be done | |
1116 | for this configuration. | |
1117 | Returns: | |
1118 | The list of preprocessor definitions. | |
1119 | """ | |
1120 | defines = [] | |
1121 | for d in config.get('defines', []): | |
1122 | if type(d) == list: | |
1123 | fd = '='.join([str(dpart) for dpart in d]) | |
1124 | else: | |
1125 | fd = str(d) | |
1126 | defines.append(fd) | |
1127 | return defines | |
1128 | ||
1129 | ||
1130 | def _GetDisabledWarnings(config): | |
1131 | return [str(i) for i in config.get('msvs_disabled_warnings', [])] | |
1132 | ||
1133 | ||
1134 | def _GetModuleDefinition(spec): | |
1135 | def_file = '' | |
1136 | if spec['type'] in ['shared_library', 'loadable_module']: | |
1137 | def_files = [s for s in spec.get('sources', []) if s.endswith('.def')] | |
1138 | if len(def_files) == 1: | |
1139 | def_file = _FixPath(def_files[0]) | |
1140 | elif def_files: | |
1141 | raise ValueError( | |
1142 | 'Multiple module definition files in one target, target %s lists ' | |
1143 | 'multiple .def files: %s' % ( | |
1144 | spec['target_name'], ' '.join(def_files))) | |
1145 | return def_file | |
1146 | ||
1147 | ||
1148 | def _ConvertToolsToExpectedForm(tools): | |
1149 | """Convert tools to a form expected by Visual Studio. | |
1150 | ||
1151 | Arguments: | |
1152 | tools: A dictionnary of settings; the tool name is the key. | |
1153 | Returns: | |
1154 | A list of Tool objects. | |
1155 | """ | |
1156 | tool_list = [] | |
1157 | for tool, settings in tools.iteritems(): | |
1158 | # Collapse settings with lists. | |
1159 | settings_fixed = {} | |
1160 | for setting, value in settings.iteritems(): | |
1161 | if type(value) == list: | |
1162 | if ((tool == 'VCLinkerTool' and | |
1163 | setting == 'AdditionalDependencies') or | |
1164 | setting == 'AdditionalOptions'): | |
1165 | settings_fixed[setting] = ' '.join(value) | |
1166 | else: | |
1167 | settings_fixed[setting] = ';'.join(value) | |
732 | 1168 | else: |
733 | fd = str(d) | |
734 | fd = _EscapeCppDefine(fd) | |
735 | defines.append(fd) | |
736 | ||
737 | _ToolAppend(tools, 'VCCLCompilerTool', | |
738 | 'PreprocessorDefinitions', defines) | |
739 | _ToolAppend(tools, 'VCResourceCompilerTool', | |
740 | 'PreprocessorDefinitions', defines) | |
741 | ||
742 | # Change program database directory to prevent collisions. | |
743 | _ToolAppend(tools, 'VCCLCompilerTool', 'ProgramDataBaseFileName', | |
744 | '$(IntDir)\\$(ProjectName)\\vc80.pdb') | |
745 | ||
746 | # Add disabled warnings. | |
747 | disabled_warnings = [str(i) for i in c.get('msvs_disabled_warnings', [])] | |
748 | _ToolAppend(tools, 'VCCLCompilerTool', | |
749 | 'DisableSpecificWarnings', disabled_warnings) | |
750 | ||
751 | # Add Pre-build. | |
752 | prebuild = c.get('msvs_prebuild') | |
753 | _ToolAppend(tools, 'VCPreBuildEventTool', 'CommandLine', prebuild) | |
754 | ||
755 | # Add Post-build. | |
756 | postbuild = c.get('msvs_postbuild') | |
757 | _ToolAppend(tools, 'VCPostBuildEventTool', 'CommandLine', postbuild) | |
758 | ||
759 | # Turn on precompiled headers if appropriate. | |
760 | header = c.get('msvs_precompiled_header') | |
761 | if header: | |
762 | header = os.path.split(header)[1] | |
763 | _ToolAppend(tools, 'VCCLCompilerTool', 'UsePrecompiledHeader', '2') | |
764 | _ToolAppend(tools, 'VCCLCompilerTool', | |
765 | 'PrecompiledHeaderThrough', header) | |
766 | _ToolAppend(tools, 'VCCLCompilerTool', | |
767 | 'ForcedIncludeFiles', header) | |
768 | ||
769 | # Loadable modules don't generate import libraries; | |
770 | # tell dependent projects to not expect one. | |
771 | if spec['type'] == 'loadable_module': | |
772 | _ToolAppend(tools, 'VCLinkerTool', 'IgnoreImportLibrary', 'true') | |
773 | ||
774 | # Set the module definition file if any. | |
775 | if spec['type'] in ['shared_library', 'loadable_module']: | |
776 | def_files = [s for s in spec.get('sources', []) if s.endswith('.def')] | |
777 | if len(def_files) == 1: | |
778 | _ToolAppend(tools, 'VCLinkerTool', 'ModuleDefinitionFile', | |
779 | _FixPath(def_files[0])) | |
780 | elif def_files: | |
781 | raise ValueError('Multiple module definition files in one target, ' | |
782 | 'target %s lists multiple .def files: %s' % ( | |
783 | spec['target_name'], ' '.join(def_files))) | |
784 | ||
785 | # Convert tools to expected form. | |
786 | tool_list = [] | |
787 | for tool, settings in tools.iteritems(): | |
788 | # Collapse settings with lists. | |
789 | settings_fixed = {} | |
790 | for setting, value in settings.iteritems(): | |
791 | if type(value) == list: | |
792 | if ((tool == 'VCLinkerTool' and | |
793 | setting == 'AdditionalDependencies') or | |
794 | setting == 'AdditionalOptions'): | |
795 | settings_fixed[setting] = ' '.join(value) | |
796 | else: | |
797 | settings_fixed[setting] = ';'.join(value) | |
798 | else: | |
799 | settings_fixed[setting] = value | |
800 | # Add in this tool. | |
801 | tool_list.append(MSVSProject.Tool(tool, settings_fixed)) | |
802 | ||
803 | # Prepare configuration attributes. | |
804 | prepared_attrs = {} | |
805 | source_attrs = c.get('msvs_configuration_attributes', {}) | |
806 | for a in source_attrs: | |
807 | prepared_attrs[a] = source_attrs[a] | |
808 | # Add props files. | |
809 | if vsprops_dirs: | |
810 | prepared_attrs['InheritedPropertySheets'] = ';'.join(vsprops_dirs) | |
811 | # Set configuration type. | |
812 | prepared_attrs['ConfigurationType'] = config_type | |
813 | if not prepared_attrs.has_key('OutputDirectory'): | |
814 | prepared_attrs['OutputDirectory'] = '$(SolutionDir)$(ConfigurationName)' | |
815 | if not prepared_attrs.has_key('IntermediateDirectory'): | |
816 | intermediate = '$(ConfigurationName)\\obj\\$(ProjectName)' | |
817 | prepared_attrs['IntermediateDirectory'] = intermediate | |
818 | ||
819 | # Add in this configuration. | |
820 | p.AddConfig(_ConfigFullName(config_name, c), | |
821 | attrs=prepared_attrs, tools=tool_list) | |
822 | ||
823 | # Prepare list of sources and excluded sources. | |
824 | sources = set(spec.get('sources', [])) | |
1169 | settings_fixed[setting] = value | |
1170 | # Add in this tool. | |
1171 | tool_list.append(MSVSProject.Tool(tool, settings_fixed)) | |
1172 | return tool_list | |
1173 | ||
1174 | ||
1175 | def _AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name): | |
1176 | """Add to the project file the configuration specified by config. | |
1177 | ||
1178 | Arguments: | |
1179 | p: The target project being generated. | |
1180 | spec: the target project dict. | |
1181 | tools: A dictionnary of settings; the tool name is the key. | |
1182 | config: The dictionnary that defines the special processing to be done | |
1183 | for this configuration. | |
1184 | config_type: The configuration type, a number as defined by Microsoft. | |
1185 | config_name: The name of the configuration. | |
1186 | """ | |
1187 | attributes = _GetMSVSAttributes(spec, config, config_type) | |
1188 | # Add in this configuration. | |
1189 | tool_list = _ConvertToolsToExpectedForm(tools) | |
1190 | p.AddConfig(_ConfigFullName(config_name, config), | |
1191 | attrs=attributes, tools=tool_list) | |
1192 | ||
1193 | ||
1194 | def _GetMSVSAttributes(spec, config, config_type): | |
1195 | # Prepare configuration attributes. | |
1196 | prepared_attrs = {} | |
1197 | source_attrs = config.get('msvs_configuration_attributes', {}) | |
1198 | for a in source_attrs: | |
1199 | prepared_attrs[a] = source_attrs[a] | |
1200 | # Add props files. | |
1201 | vsprops_dirs = config.get('msvs_props', []) | |
1202 | vsprops_dirs = _FixPaths(vsprops_dirs) | |
1203 | if vsprops_dirs: | |
1204 | prepared_attrs['InheritedPropertySheets'] = ';'.join(vsprops_dirs) | |
1205 | # Set configuration type. | |
1206 | prepared_attrs['ConfigurationType'] = config_type | |
1207 | output_dir = prepared_attrs.get('OutputDirectory', | |
1208 | '$(SolutionDir)$(ConfigurationName)') | |
1209 | # TODO(jeanluc) If we want to avoid the MSB8012 warning, we should | |
1210 | # add code like the following to place libraries in their own directory. | |
1211 | # if config_type == '4': | |
1212 | # output_dir = spec.get('product_dir', output_dir + '\\lib') | |
1213 | prepared_attrs['OutputDirectory'] = output_dir | |
1214 | if 'IntermediateDirectory' not in prepared_attrs: | |
1215 | intermediate = '$(ConfigurationName)\\obj\\$(ProjectName)' | |
1216 | prepared_attrs['IntermediateDirectory'] = intermediate | |
1217 | return prepared_attrs | |
1218 | ||
1219 | ||
1220 | def _AddNormalizedSources(sources_set, sources_array): | |
1221 | sources = [_NormalizedSource(s) for s in sources_array] | |
1222 | sources_set.update(set(sources)) | |
1223 | ||
1224 | ||
1225 | def _PrepareListOfSources(spec, relative_path_of_gyp_file): | |
1226 | """Prepare list of sources and excluded sources. | |
1227 | ||
1228 | Besides the sources specified directly in the spec, adds the gyp file so | |
1229 | that a change to it will cause a re-compile. Also adds appropriate sources | |
1230 | for actions and copies. Assumes later stage will un-exclude files which | |
1231 | have custom build steps attached. | |
1232 | ||
1233 | Arguments: | |
1234 | spec: The target dictionary containing the properties of the target. | |
1235 | relative_path_of_gyp_file: The relative path of the gyp file. | |
1236 | Returns: | |
1237 | A pair of (list of sources, list of excluded sources) | |
1238 | """ | |
1239 | sources = set() | |
1240 | _AddNormalizedSources(sources, spec.get('sources', [])) | |
825 | 1241 | excluded_sources = set() |
826 | 1242 | # Add in the gyp file. |
827 | gyp_file = os.path.split(build_file)[1] | |
828 | sources.add(gyp_file) | |
1243 | sources.add(relative_path_of_gyp_file) | |
1244 | ||
829 | 1245 | # Add in 'action' inputs and outputs. |
830 | 1246 | for a in spec.get('actions', []): |
831 | inputs = a.get('inputs') | |
832 | if not inputs: | |
833 | # This is an action with no inputs. Make the primary input | |
834 | # by the .gyp file itself so Visual Studio has a place to | |
835 | # hang the custom build rule. | |
836 | inputs = [gyp_file] | |
837 | a['inputs'] = inputs | |
838 | primary_input = _PickPrimaryInput(inputs) | |
1247 | inputs = a.get('inputs', []) | |
1248 | inputs = [_NormalizedSource(i) for i in inputs] | |
1249 | # Add all inputs to sources and excluded sources. | |
839 | 1250 | inputs = set(inputs) |
840 | 1251 | sources.update(inputs) |
841 | inputs.remove(primary_input) | |
842 | 1252 | excluded_sources.update(inputs) |
843 | 1253 | if int(a.get('process_outputs_as_sources', False)): |
844 | outputs = set(a.get('outputs', [])) | |
845 | sources.update(outputs) | |
1254 | _AddNormalizedSources(sources, a.get('outputs', [])) | |
846 | 1255 | # Add in 'copies' inputs and outputs. |
847 | 1256 | for cpy in spec.get('copies', []): |
848 | files = set(cpy.get('files', [])) | |
849 | sources.update(files) | |
850 | ||
851 | # Add rules. | |
852 | actions_to_add = [] | |
853 | _GenerateRules(p, gyp_dir, options, spec, | |
854 | sources, excluded_sources, | |
855 | actions_to_add) | |
856 | ||
1257 | _AddNormalizedSources(sources, cpy.get('files', [])) | |
1258 | return (sources, excluded_sources) | |
1259 | ||
1260 | ||
1261 | def _AdjustSourcesAndConvertToFilterHierarchy( | |
1262 | spec, options, gyp_dir, sources, excluded_sources): | |
1263 | """Adjusts the list of sources and excluded sources. | |
1264 | ||
1265 | Also converts the sets to lists. | |
1266 | ||
1267 | Arguments: | |
1268 | spec: The target dictionary containing the properties of the target. | |
1269 | options: Global generator options. | |
1270 | gyp_dir: The path to the gyp file being processed. | |
1271 | sources: A set of sources to be included for this project. | |
1272 | excluded_sources: A set of sources to be excluded for this project. | |
1273 | Returns: | |
1274 | A trio of (list of sources, list of excluded sources, | |
1275 | path of excluded IDL file) | |
1276 | """ | |
857 | 1277 | # Exclude excluded sources coming into the generator. |
858 | 1278 | excluded_sources.update(set(spec.get('sources_excluded', []))) |
859 | 1279 | # Add excluded sources into sources for good measure. |
861 | 1281 | # Convert to proper windows form. |
862 | 1282 | # NOTE: sources goes from being a set to a list here. |
863 | 1283 | # NOTE: excluded_sources goes from being a set to a list here. |
864 | sources = [_FixPath(i) for i in sources] | |
1284 | sources = _FixPaths(sources) | |
865 | 1285 | # Convert to proper windows form. |
866 | excluded_sources = [_FixPath(i) for i in excluded_sources] | |
867 | ||
1286 | excluded_sources = _FixPaths(excluded_sources) | |
1287 | ||
1288 | excluded_idl = _IdlFilesHandledNonNatively(spec, sources) | |
1289 | ||
1290 | precompiled_related = _GetPrecompileRelatedFiles(spec) | |
1291 | # Find the excluded ones, minus the precompiled header related ones. | |
1292 | fully_excluded = [i for i in excluded_sources if i not in precompiled_related] | |
1293 | ||
1294 | # Convert to folders and the right slashes. | |
1295 | sources = [i.split('\\') for i in sources] | |
1296 | sources = _ConvertSourcesToFilterHierarchy(sources, excluded=fully_excluded) | |
1297 | # Add in dummy file for type none. | |
1298 | if spec['type'] == 'dummy_executable': | |
1299 | # Pull in a dummy main so it can link successfully. | |
1300 | dummy_relpath = gyp.common.RelativePath( | |
1301 | options.depth + '\\tools\\gyp\\gyp_dummy.c', gyp_dir) | |
1302 | sources.append(dummy_relpath) | |
1303 | ||
1304 | return sources, excluded_sources, excluded_idl | |
1305 | ||
1306 | ||
1307 | def _IdlFilesHandledNonNatively(spec, sources): | |
868 | 1308 | # If any non-native rules use 'idl' as an extension exclude idl files. |
869 | 1309 | # Gather a list here to use later. |
870 | 1310 | using_idl = False |
876 | 1316 | excluded_idl = [i for i in sources if i.endswith('.idl')] |
877 | 1317 | else: |
878 | 1318 | excluded_idl = [] |
879 | ||
880 | # List of precompiled header related keys. | |
881 | precomp_keys = [ | |
882 | 'msvs_precompiled_header', | |
883 | 'msvs_precompiled_source', | |
884 | ] | |
885 | ||
1319 | return excluded_idl | |
1320 | ||
1321 | ||
1322 | def _GetPrecompileRelatedFiles(spec): | |
886 | 1323 | # Gather a list of precompiled header related sources. |
887 | 1324 | precompiled_related = [] |
888 | for config_name, c in spec['configurations'].iteritems(): | |
1325 | for _, config in spec['configurations'].iteritems(): | |
889 | 1326 | for k in precomp_keys: |
890 | f = c.get(k) | |
1327 | f = config.get(k) | |
891 | 1328 | if f: |
892 | 1329 | precompiled_related.append(_FixPath(f)) |
893 | ||
894 | # Find the excluded ones, minus the precompiled header related ones. | |
895 | fully_excluded = [i for i in excluded_sources if i not in precompiled_related] | |
896 | ||
897 | # Convert to folders and the right slashes. | |
898 | sources = [i.split('\\') for i in sources] | |
899 | sources = _SourceInFolders(sources, excluded=fully_excluded) | |
900 | # Add in dummy file for type none. | |
901 | if spec['type'] == 'dummy_executable': | |
902 | # Pull in a dummy main so it can link successfully. | |
903 | dummy_relpath = gyp.common.RelativePath( | |
904 | options.depth + '\\tools\\gyp\\gyp_dummy.c', gyp_dir) | |
905 | sources.append(dummy_relpath) | |
906 | # Add in files. | |
907 | p.AddFiles(sources) | |
908 | ||
909 | # Add deferred actions to add. | |
910 | for a in actions_to_add: | |
911 | _AddCustomBuildTool(p, spec, | |
912 | inputs=a['inputs'], | |
913 | outputs=a['outputs'], | |
914 | description=a['description'], | |
915 | cmd=a['cmd']) | |
916 | ||
1330 | return precompiled_related | |
1331 | ||
1332 | ||
1333 | def _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl): | |
1334 | exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl) | |
1335 | for file_name, excluded_configs in exclusions.iteritems(): | |
1336 | for config_name, config in excluded_configs: | |
1337 | p.AddFileConfig(file_name, _ConfigFullName(config_name, config), | |
1338 | {'ExcludedFromBuild': 'true'}) | |
1339 | ||
1340 | ||
1341 | def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl): | |
1342 | exclusions = {} | |
917 | 1343 | # Exclude excluded sources from being built. |
918 | 1344 | for f in excluded_sources: |
919 | for config_name, c in spec['configurations'].iteritems(): | |
920 | precomped = [_FixPath(c.get(i, '')) for i in precomp_keys] | |
1345 | excluded_configs = [] | |
1346 | for config_name, config in spec['configurations'].iteritems(): | |
1347 | precomped = [_FixPath(config.get(i, '')) for i in precomp_keys] | |
921 | 1348 | # Don't do this for ones that are precompiled header related. |
922 | 1349 | if f not in precomped: |
923 | p.AddFileConfig(f, _ConfigFullName(config_name, c), | |
924 | {'ExcludedFromBuild': 'true'}) | |
925 | ||
1350 | excluded_configs.append((config_name, config)) | |
1351 | exclusions[f] = excluded_configs | |
926 | 1352 | # If any non-native rules use 'idl' as an extension exclude idl files. |
927 | 1353 | # Exclude them now. |
928 | for config_name, c in spec['configurations'].iteritems(): | |
929 | for f in excluded_idl: | |
930 | p.AddFileConfig(f, _ConfigFullName(config_name, c), | |
931 | {'ExcludedFromBuild': 'true'}) | |
932 | ||
1354 | for f in excluded_idl: | |
1355 | excluded_configs = [] | |
1356 | for config_name, config in spec['configurations'].iteritems(): | |
1357 | excluded_configs.append((config_name, config)) | |
1358 | exclusions[f] = excluded_configs | |
1359 | return exclusions | |
1360 | ||
1361 | ||
1362 | def _AddToolFilesToMSVS(p, spec): | |
933 | 1363 | # Add in tool files (rules). |
934 | 1364 | tool_files = set() |
935 | for config_name, c in spec['configurations'].iteritems(): | |
936 | for f in c.get('msvs_tool_files', []): | |
1365 | for _, config in spec['configurations'].iteritems(): | |
1366 | for f in config.get('msvs_tool_files', []): | |
937 | 1367 | tool_files.add(f) |
938 | 1368 | for f in tool_files: |
939 | 1369 | p.AddToolFile(f) |
940 | 1370 | |
1371 | ||
1372 | def _HandlePreCompileHeaderStubs(p, spec): | |
941 | 1373 | # Handle pre-compiled headers source stubs specially. |
942 | for config_name, c in spec['configurations'].iteritems(): | |
943 | source = c.get('msvs_precompiled_source') | |
1374 | for config_name, config in spec['configurations'].iteritems(): | |
1375 | source = config.get('msvs_precompiled_source') | |
944 | 1376 | if source: |
945 | 1377 | source = _FixPath(source) |
946 | 1378 | # UsePrecompiledHeader=1 for if using precompiled headers. |
947 | 1379 | tool = MSVSProject.Tool('VCCLCompilerTool', |
948 | 1380 | {'UsePrecompiledHeader': '1'}) |
949 | p.AddFileConfig(source, _ConfigFullName(config_name, c), | |
1381 | p.AddFileConfig(source, _ConfigFullName(config_name, config), | |
950 | 1382 | {}, tools=[tool]) |
951 | 1383 | |
1384 | ||
1385 | def _AddActions(actions_to_add, spec, relative_path_of_gyp_file): | |
952 | 1386 | # Add actions. |
953 | 1387 | actions = spec.get('actions', []) |
954 | 1388 | for a in actions: |
955 | cmd = _PrepareAction(spec, a, has_input_path=False) | |
956 | _AddCustomBuildTool(p, spec, | |
957 | inputs=a.get('inputs', []), | |
958 | outputs=a.get('outputs', []), | |
959 | description=a.get('message', a['action_name']), | |
960 | cmd=cmd) | |
961 | ||
1389 | cmd = _BuildCommandLineForRule(spec, a, has_input_path=False) | |
1390 | # Attach actions to the gyp file if nothing else is there. | |
1391 | inputs = a.get('inputs') or [relative_path_of_gyp_file] | |
1392 | # Add the action. | |
1393 | _AddActionStep(actions_to_add, | |
1394 | inputs=inputs, | |
1395 | outputs=a.get('outputs', []), | |
1396 | description=a.get('message', a['action_name']), | |
1397 | command=cmd) | |
1398 | ||
1399 | ||
1400 | def _WriteMSVSUserFile(project_path, version, spec): | |
962 | 1401 | # Add run_as and test targets. |
963 | has_run_as = False | |
964 | if spec.get('run_as') or int(spec.get('test', 0)): | |
965 | has_run_as = True | |
966 | run_as = spec.get('run_as', { | |
967 | 'action' : ['$(TargetPath)', '--gtest_print_time'], | |
968 | }) | |
969 | working_directory = run_as.get('working_directory', '.') | |
1402 | if 'run_as' in spec: | |
1403 | run_as = spec['run_as'] | |
970 | 1404 | action = run_as.get('action', []) |
971 | 1405 | environment = run_as.get('environment', []) |
972 | for config_name, c_data in spec['configurations'].iteritems(): | |
973 | _SetRunAs(user_file, config_name, c_data, | |
974 | action, environment, working_directory) | |
975 | ||
1406 | working_directory = run_as.get('working_directory', '.') | |
1407 | elif int(spec.get('test', 0)): | |
1408 | action = ['$(TargetPath)', '--gtest_print_time'] | |
1409 | environment = [] | |
1410 | working_directory = '.' | |
1411 | else: | |
1412 | return # Nothing to add | |
1413 | # Write out the user file. | |
1414 | user_file = _CreateMSVSUserFile(project_path, version, spec) | |
1415 | for config_name, c_data in spec['configurations'].iteritems(): | |
1416 | user_file.AddDebugSettings(_ConfigFullName(config_name, c_data), | |
1417 | action, environment, working_directory) | |
1418 | user_file.Write() | |
1419 | ||
1420 | ||
1421 | def _AddCopies(actions_to_add, spec): | |
1422 | copies = _GetCopies(spec) | |
1423 | for inputs, outputs, cmd, description in copies: | |
1424 | _AddActionStep(actions_to_add, inputs=inputs, outputs=outputs, | |
1425 | description=description, command=cmd) | |
1426 | ||
1427 | ||
1428 | def _GetCopies(spec): | |
1429 | copies = [] | |
976 | 1430 | # Add copies. |
977 | 1431 | for cpy in spec.get('copies', []): |
978 | 1432 | for src in cpy.get('files', []): |
979 | 1433 | dst = os.path.join(cpy['destination'], os.path.basename(src)) |
980 | # _AddCustomBuildTool() will call _FixPath() on the inputs and | |
1434 | # _AddCustomBuildToolForMSVS() will call _FixPath() on the inputs and | |
981 | 1435 | # outputs, so do the same for our generated command line. |
982 | 1436 | if src.endswith('/'): |
983 | 1437 | src_bare = src[:-1] |
985 | 1439 | outer_dir = posixpath.split(src_bare)[1] |
986 | 1440 | cmd = 'cd "%s" && xcopy /e /f /y "%s" "%s\\%s\\"' % ( |
987 | 1441 | _FixPath(base_dir), outer_dir, _FixPath(dst), outer_dir) |
988 | _AddCustomBuildTool(p, spec, | |
989 | inputs=[src], | |
990 | outputs=['dummy_copies', dst], | |
991 | description='Copying %s to %s' % (src, dst), | |
992 | cmd=cmd) | |
1442 | copies.append(([src], ['dummy_copies', dst], cmd, | |
1443 | 'Copying %s to %s' % (src, dst))) | |
993 | 1444 | else: |
994 | 1445 | cmd = 'mkdir "%s" 2>nul & set ERRORLEVEL=0 & copy /Y "%s" "%s"' % ( |
995 | 1446 | _FixPath(cpy['destination']), _FixPath(src), _FixPath(dst)) |
996 | _AddCustomBuildTool(p, spec, | |
997 | inputs=[src], outputs=[dst], | |
998 | description='Copying %s to %s' % (src, dst), | |
999 | cmd=cmd) | |
1000 | ||
1001 | # Write it out. | |
1002 | p.Write() | |
1003 | ||
1004 | # Write out the user file, but only if we need to. | |
1005 | if has_run_as: | |
1006 | user_file.Write() | |
1007 | ||
1008 | # Return the guid so we can refer to it elsewhere. | |
1009 | return p.guid | |
1447 | copies.append(([src], [dst], cmd, 'Copying %s to %s' % (src, dst))) | |
1448 | return copies | |
1010 | 1449 | |
1011 | 1450 | |
1012 | 1451 | def _GetPathDict(root, path): |
1013 | if path == '': | |
1452 | if not path: | |
1014 | 1453 | return root |
1015 | 1454 | parent, folder = os.path.split(path) |
1016 | 1455 | parent_dict = _GetPathDict(root, parent) |
1048 | 1487 | return node[node.keys()[0]] |
1049 | 1488 | if type(node) != dict: |
1050 | 1489 | return node |
1051 | for child in node.keys(): | |
1490 | for child in node: | |
1052 | 1491 | node[child] = _CollapseSingles(child, node[child]) |
1053 | 1492 | return node |
1054 | 1493 | |
1055 | 1494 | |
1056 | def _GatherSolutionFolders(project_objs, flat): | |
1495 | def _GatherSolutionFolders(sln_projects, project_objects, flat): | |
1057 | 1496 | root = {} |
1058 | 1497 | # Convert into a tree of dicts on path. |
1059 | for p in project_objs.keys(): | |
1498 | for p in sln_projects: | |
1060 | 1499 | gyp_file, target = gyp.common.ParseQualifiedTarget(p)[0:2] |
1061 | 1500 | gyp_dir = os.path.dirname(gyp_file) |
1062 | 1501 | path_dict = _GetPathDict(root, gyp_dir) |
1063 | path_dict[target + '.vcproj'] = project_objs[p] | |
1502 | path_dict[target + '.vcproj'] = project_objects[p] | |
1064 | 1503 | # Walk down from the top until we hit a folder that has more than one entry. |
1065 | 1504 | # In practice, this strips the top-level "src/" dir from the hierarchy in |
1066 | 1505 | # the solution. |
1072 | 1511 | return _DictsToFolders('', root, flat) |
1073 | 1512 | |
1074 | 1513 | |
1075 | def _ProjectObject(sln, qualified_target, project_objs, projects): | |
1076 | # Done if this project has an object. | |
1077 | if project_objs.get(qualified_target): | |
1078 | return project_objs[qualified_target] | |
1079 | # Get dependencies for this project. | |
1080 | spec = projects[qualified_target]['spec'] | |
1081 | deps = spec.get('dependencies', []) | |
1082 | # Get objects for each dependency. | |
1083 | deps = [_ProjectObject(sln, d, project_objs, projects) for d in deps] | |
1084 | # Find relative path to vcproj from sln. | |
1085 | vcproj_rel_path = gyp.common.RelativePath( | |
1086 | projects[qualified_target]['vcproj_path'], os.path.split(sln)[0]) | |
1087 | vcproj_rel_path = _FixPath(vcproj_rel_path) | |
1514 | def _GetPathOfProject(qualified_target, spec, options, msvs_version): | |
1515 | default_config = _GetDefaultConfiguration(spec) | |
1516 | proj_filename = default_config.get('msvs_existing_vcproj') | |
1517 | if not proj_filename: | |
1518 | proj_filename = (spec['target_name'] + options.suffix + | |
1519 | msvs_version.ProjectExtension()) | |
1520 | ||
1521 | build_file = gyp.common.BuildFile(qualified_target) | |
1522 | proj_path = os.path.join(os.path.split(build_file)[0], proj_filename) | |
1523 | fix_prefix = None | |
1524 | if options.generator_output: | |
1525 | project_dir_path = os.path.dirname(os.path.abspath(proj_path)) | |
1526 | proj_path = os.path.join(options.generator_output, proj_path) | |
1527 | fix_prefix = gyp.common.RelativePath(project_dir_path, | |
1528 | os.path.dirname(proj_path)) | |
1529 | return proj_path, fix_prefix | |
1530 | ||
1531 | ||
1532 | def _GetPlatformOverridesOfProject(spec): | |
1088 | 1533 | # Prepare a dict indicating which project configurations are used for which |
1089 | 1534 | # solution configurations for this target. |
1090 | 1535 | config_platform_overrides = {} |
1094 | 1539 | fixed_config_fullname = '%s|%s' % ( |
1095 | 1540 | _ConfigBaseName(config_name, _ConfigPlatform(c)), platform) |
1096 | 1541 | config_platform_overrides[config_fullname] = fixed_config_fullname |
1097 | # Create object for this project. | |
1098 | obj = MSVSNew.MSVSProject( | |
1099 | vcproj_rel_path, | |
1100 | name=spec['target_name'], | |
1101 | guid=projects[qualified_target]['guid'], | |
1102 | dependencies=deps, | |
1103 | config_platform_overrides=config_platform_overrides) | |
1104 | # Store it to the list of objects. | |
1105 | project_objs[qualified_target] = obj | |
1106 | # Return project object. | |
1107 | return obj | |
1542 | return config_platform_overrides | |
1543 | ||
1544 | ||
1545 | def _CreateProjectObjects(target_list, target_dicts, options, msvs_version): | |
1546 | """Create a MSVSProject object for the targets found in target list. | |
1547 | ||
1548 | Arguments: | |
1549 | target_list: the list of targets to generate project objects for. | |
1550 | target_dicts: the dictionary of specifications. | |
1551 | options: global generator options. | |
1552 | msvs_version: the MSVSVersion object. | |
1553 | Returns: | |
1554 | A set of created projects, keyed by target. | |
1555 | """ | |
1556 | global fixpath_prefix | |
1557 | # Generate each project. | |
1558 | projects = {} | |
1559 | for qualified_target in target_list: | |
1560 | spec = target_dicts[qualified_target] | |
1561 | if spec['toolset'] != 'target': | |
1562 | raise Exception( | |
1563 | 'Multiple toolsets not supported in msvs build (target %s)' % | |
1564 | qualified_target) | |
1565 | proj_path, fixpath_prefix = _GetPathOfProject(qualified_target, spec, | |
1566 | options, msvs_version) | |
1567 | guid = _GetGuidOfProject(proj_path, spec) | |
1568 | overrides = _GetPlatformOverridesOfProject(spec) | |
1569 | build_file = gyp.common.BuildFile(qualified_target) | |
1570 | # Create object for this project. | |
1571 | obj = MSVSNew.MSVSProject( | |
1572 | _FixPath(proj_path), | |
1573 | name=spec['target_name'], | |
1574 | guid=guid, | |
1575 | spec=spec, | |
1576 | build_file=build_file, | |
1577 | config_platform_overrides=overrides, | |
1578 | fixpath_prefix=fixpath_prefix) | |
1579 | projects[qualified_target] = obj | |
1580 | # Set all the dependencies | |
1581 | for project in projects.values(): | |
1582 | deps = project.spec.get('dependencies', []) | |
1583 | deps = [projects[d] for d in deps] | |
1584 | project.set_dependencies(deps) | |
1585 | return projects | |
1108 | 1586 | |
1109 | 1587 | |
1110 | 1588 | def CalculateVariables(default_variables, params): |
1113 | 1591 | generator_flags = params.get('generator_flags', {}) |
1114 | 1592 | |
1115 | 1593 | # Select project file format version (if unset, default to auto detecting). |
1116 | msvs_version = \ | |
1117 | MSVSVersion.SelectVisualStudioVersion(generator_flags.get('msvs_version', | |
1118 | 'auto')) | |
1594 | msvs_version = MSVSVersion.SelectVisualStudioVersion( | |
1595 | generator_flags.get('msvs_version', 'auto')) | |
1119 | 1596 | # Stash msvs_version for later (so we don't have to probe the system twice). |
1120 | 1597 | params['msvs_version'] = msvs_version |
1121 | 1598 | |
1145 | 1622 | global fixpath_prefix |
1146 | 1623 | |
1147 | 1624 | options = params['options'] |
1148 | generator_flags = params.get('generator_flags', {}) | |
1149 | 1625 | |
1150 | 1626 | # Get the project file format version back out of where we stashed it in |
1151 | 1627 | # GeneratorCalculatedVariables. |
1154 | 1630 | # Prepare the set of configurations. |
1155 | 1631 | configs = set() |
1156 | 1632 | for qualified_target in target_list: |
1157 | build_file = gyp.common.BuildFile(qualified_target) | |
1158 | 1633 | spec = target_dicts[qualified_target] |
1159 | for config_name, c in spec['configurations'].iteritems(): | |
1160 | configs.add(_ConfigFullName(config_name, c)) | |
1634 | for config_name, config in spec['configurations'].iteritems(): | |
1635 | configs.add(_ConfigFullName(config_name, config)) | |
1161 | 1636 | configs = list(configs) |
1162 | 1637 | |
1638 | # Figure out all the projects that will be generated and their guids | |
1639 | project_objects = _CreateProjectObjects(target_list, target_dicts, options, | |
1640 | msvs_version) | |
1641 | ||
1163 | 1642 | # Generate each project. |
1164 | projects = {} | |
1165 | for qualified_target in target_list: | |
1166 | build_file = gyp.common.BuildFile(qualified_target) | |
1167 | spec = target_dicts[qualified_target] | |
1168 | if spec['toolset'] != 'target': | |
1169 | raise Exception( | |
1170 | 'Multiple toolsets not supported in msvs build (target %s)' % | |
1171 | qualified_target) | |
1172 | default_config = spec['configurations'][spec['default_configuration']] | |
1173 | vcproj_filename = default_config.get('msvs_existing_vcproj') | |
1174 | if not vcproj_filename: | |
1175 | vcproj_filename = spec['target_name'] + options.suffix + '.vcproj' | |
1176 | vcproj_path = os.path.join(os.path.split(build_file)[0], vcproj_filename) | |
1177 | if options.generator_output: | |
1178 | projectDirPath = os.path.dirname(os.path.abspath(vcproj_path)) | |
1179 | vcproj_path = os.path.join(options.generator_output, vcproj_path) | |
1180 | fixpath_prefix = gyp.common.RelativePath(projectDirPath, | |
1181 | os.path.dirname(vcproj_path)) | |
1182 | projects[qualified_target] = { | |
1183 | 'vcproj_path': vcproj_path, | |
1184 | 'guid': _GenerateProject(vcproj_path, build_file, | |
1185 | spec, options, version=msvs_version), | |
1186 | 'spec': spec, | |
1187 | } | |
1188 | ||
1643 | for project in project_objects.values(): | |
1644 | fixpath_prefix = project.fixpath_prefix | |
1645 | _GenerateProject(project, options, msvs_version) | |
1189 | 1646 | fixpath_prefix = None |
1190 | 1647 | |
1191 | for build_file in data.keys(): | |
1648 | for build_file in data: | |
1192 | 1649 | # Validate build_file extension |
1193 | 1650 | if build_file[-4:] != '.gyp': |
1194 | 1651 | continue |
1195 | 1652 | sln_path = build_file[:-4] + options.suffix + '.sln' |
1196 | 1653 | if options.generator_output: |
1197 | 1654 | sln_path = os.path.join(options.generator_output, sln_path) |
1198 | #print 'Generating %s' % sln_path | |
1199 | 1655 | # Get projects in the solution, and their dependents. |
1200 | 1656 | sln_projects = gyp.common.BuildFileTargets(target_list, build_file) |
1201 | 1657 | sln_projects += gyp.common.DeepDependencyTargets(target_dicts, sln_projects) |
1202 | # Convert projects to Project Objects. | |
1203 | project_objs = {} | |
1204 | for p in sln_projects: | |
1205 | _ProjectObject(sln_path, p, project_objs, projects) | |
1206 | 1658 | # Create folder hierarchy. |
1207 | 1659 | root_entries = _GatherSolutionFolders( |
1208 | project_objs, flat=msvs_version.FlatSolution()) | |
1660 | sln_projects, project_objects, flat=msvs_version.FlatSolution()) | |
1209 | 1661 | # Create solution. |
1210 | 1662 | sln = MSVSNew.MSVSSolution(sln_path, |
1211 | 1663 | entries=root_entries, |
1213 | 1665 | websiteProperties=False, |
1214 | 1666 | version=msvs_version) |
1215 | 1667 | sln.Write() |
1668 | ||
1669 | ||
1670 | def _GenerateMSBuildFiltersFile(filters_path, source_files, | |
1671 | extension_to_rule_name): | |
1672 | """Generate the filters file. | |
1673 | ||
1674 | This file is used by Visual Studio to organize the presentation of source | |
1675 | files into folders. | |
1676 | ||
1677 | Arguments: | |
1678 | filters_path: The path of the file to be created. | |
1679 | source_files: The hierarchical structure of all the sources. | |
1680 | extension_to_rule_name: A dictionary mapping file extensions to rules. | |
1681 | """ | |
1682 | filter_group = [] | |
1683 | source_group = [] | |
1684 | _AppendFiltersForMSBuild('', source_files, extension_to_rule_name, | |
1685 | filter_group, source_group) | |
1686 | if filter_group: | |
1687 | doc = easy_xml.EasyXml( | |
1688 | 'Project', | |
1689 | {'ToolsVersion': '4.0', | |
1690 | 'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) | |
1691 | root = doc.Root() | |
1692 | doc.AppendChildren(root, [ | |
1693 | ['ItemGroup'] + filter_group, | |
1694 | ['ItemGroup'] + source_group]) | |
1695 | doc.WriteIfChanged(filters_path) | |
1696 | elif os.path.exists(filters_path): | |
1697 | # We don't need this filter anymore. Delete the old filter file. | |
1698 | os.unlink(filters_path) | |
1699 | ||
1700 | ||
1701 | def _AppendFiltersForMSBuild(parent_filter_name, sources, | |
1702 | extension_to_rule_name, | |
1703 | filter_group, source_group): | |
1704 | """Creates the list of filters and sources to be added in the filter file. | |
1705 | ||
1706 | Args: | |
1707 | parent_filter_name: The name of the filter under which the sources are | |
1708 | found. | |
1709 | sources: The hierarchy of filters and sources to process. | |
1710 | extension_to_rule_name: A dictionary mapping file extensions to rules. | |
1711 | filter_group: The list to which filter entries will be appended. | |
1712 | source_group: The list to which source entries will be appeneded. | |
1713 | """ | |
1714 | for source in sources: | |
1715 | if isinstance(source, MSVSProject.Filter): | |
1716 | # We have a sub-filter. Create the name of that sub-filter. | |
1717 | if not parent_filter_name: | |
1718 | filter_name = source.name | |
1719 | else: | |
1720 | filter_name = '%s\\%s' % (parent_filter_name, source.name) | |
1721 | # Add the filter to the group. | |
1722 | filter_group.append( | |
1723 | ['Filter', {'Include': filter_name}, | |
1724 | ['UniqueIdentifier', MSVSNew.MakeGuid(source.name)]]) | |
1725 | # Recurse and add its dependents. | |
1726 | _AppendFiltersForMSBuild(filter_name, source.contents, | |
1727 | extension_to_rule_name, | |
1728 | filter_group, source_group) | |
1729 | else: | |
1730 | # It's a source. Create a source entry. | |
1731 | _, element = _MapFileToMsBuildSourceType(source, extension_to_rule_name) | |
1732 | source_entry = [element, {'Include': source}] | |
1733 | # Specify the filter it is part of, if any. | |
1734 | if parent_filter_name: | |
1735 | source_entry.append(['Filter', parent_filter_name]) | |
1736 | source_group.append(source_entry) | |
1737 | ||
1738 | ||
1739 | def _MapFileToMsBuildSourceType(source, extension_to_rule_name): | |
1740 | """Returns the group and element type of the source file. | |
1741 | ||
1742 | Arguments: | |
1743 | source: The source file name. | |
1744 | extension_to_rule_name: A dictionary mapping file extensions to rules. | |
1745 | ||
1746 | Returns: | |
1747 | A pair of (group this file should be part of, the label of element) | |
1748 | """ | |
1749 | _, ext = os.path.splitext(source) | |
1750 | if ext in ['.cc', '.cpp', '.c', '.cxx']: | |
1751 | group = 'compile' | |
1752 | element = 'ClCompile' | |
1753 | elif ext in ['.h', '.hxx']: | |
1754 | group = 'include' | |
1755 | element = 'ClInclude' | |
1756 | elif ext == '.rc': | |
1757 | group = 'resource' | |
1758 | element = 'ResourceCompile' | |
1759 | elif ext == '.idl': | |
1760 | group = 'midl' | |
1761 | element = 'Midl' | |
1762 | elif ext in extension_to_rule_name: | |
1763 | group = 'rule' | |
1764 | element = extension_to_rule_name[ext] | |
1765 | else: | |
1766 | group = 'none' | |
1767 | element = 'None' | |
1768 | return (group, element) | |
1769 | ||
1770 | ||
1771 | def _GenerateRulesForMSBuild(output_dir, options, spec, | |
1772 | sources, excluded_sources, | |
1773 | props_files_of_rules, targets_files_of_rules, | |
1774 | actions_to_add, extension_to_rule_name): | |
1775 | # MSBuild rules are implemented using three files: an XML file, a .targets | |
1776 | # file and a .props file. | |
1777 | # See http://blogs.msdn.com/b/vcblog/archive/2010/04/21/quick-help-on-vs2010-custom-build-rule.aspx | |
1778 | # for more details. | |
1779 | rules = spec.get('rules', []) | |
1780 | rules_native = [r for r in rules if not int(r.get('msvs_external_rule', 0))] | |
1781 | rules_external = [r for r in rules if int(r.get('msvs_external_rule', 0))] | |
1782 | ||
1783 | msbuild_rules = [] | |
1784 | for rule in rules_native: | |
1785 | msbuild_rule = MSBuildRule(rule, spec) | |
1786 | msbuild_rules.append(msbuild_rule) | |
1787 | extension_to_rule_name[msbuild_rule.extension] = msbuild_rule.rule_name | |
1788 | if msbuild_rules: | |
1789 | base = spec['target_name'] + options.suffix | |
1790 | props_name = base + '.props' | |
1791 | targets_name = base + '.targets' | |
1792 | xml_name = base + '.xml' | |
1793 | ||
1794 | props_files_of_rules.add(props_name) | |
1795 | targets_files_of_rules.add(targets_name) | |
1796 | ||
1797 | props_path = os.path.join(output_dir, props_name) | |
1798 | targets_path = os.path.join(output_dir, targets_name) | |
1799 | xml_path = os.path.join(output_dir, xml_name) | |
1800 | ||
1801 | _GenerateMSBuildRulePropsFile(props_path, msbuild_rules) | |
1802 | _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules) | |
1803 | _GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules) | |
1804 | ||
1805 | if rules_external: | |
1806 | _GenerateExternalRules(rules_external, output_dir, spec, | |
1807 | sources, options, actions_to_add) | |
1808 | _AdjustSourcesForRules(rules, sources, excluded_sources) | |
1809 | ||
1810 | ||
1811 | class MSBuildRule(object): | |
1812 | """Used to store information used to generate an MSBuild rule. | |
1813 | ||
1814 | Attributes: | |
1815 | rule_name: The rule name, sanitized to use in XML. | |
1816 | target_name: The name of the target. | |
1817 | after_targets: The name of the AfterTargets element. | |
1818 | before_targets: The name of the BeforeTargets element. | |
1819 | depends_on: The name of the DependsOn element. | |
1820 | compute_output: The name of the ComputeOutput element. | |
1821 | dirs_to_make: The name of the DirsToMake element. | |
1822 | tlog: The name of the _tlog element. | |
1823 | extension: The extension this rule applies to. | |
1824 | description: The message displayed when this rule is invoked. | |
1825 | additional_dependencies: A string listing additional dependencies. | |
1826 | outputs: The outputs of this rule. | |
1827 | command: The command used to run the rule. | |
1828 | """ | |
1829 | ||
1830 | def __init__(self, rule, spec): | |
1831 | self.display_name = rule['rule_name'] | |
1832 | # Assure that the rule name is only characters and numbers | |
1833 | self.rule_name = re.sub(r'\W', '_', self.display_name) | |
1834 | # Create the various element names, following the example set by the | |
1835 | # Visual Studio 2008 to 2010 conversion. I don't know if VS2010 | |
1836 | # is sensitive to the exact names. | |
1837 | self.target_name = '_' + self.rule_name | |
1838 | self.after_targets = self.rule_name + 'AfterTargets' | |
1839 | self.before_targets = self.rule_name + 'BeforeTargets' | |
1840 | self.depends_on = self.rule_name + 'DependsOn' | |
1841 | self.compute_output = 'Compute%sOutput' % self.rule_name | |
1842 | self.dirs_to_make = self.rule_name + 'DirsToMake' | |
1843 | self.tlog = self.rule_name + '_tlog' | |
1844 | self.extension = rule['extension'] | |
1845 | if not self.extension.startswith('.'): | |
1846 | self.extension = '.' + self.extension | |
1847 | ||
1848 | self.description = MSVSSettings.ConvertVCMacrosToMSBuild( | |
1849 | rule.get('message', self.rule_name)) | |
1850 | old_additional_dependencies = _FixPaths(rule.get('inputs', [])) | |
1851 | self.additional_dependencies = ( | |
1852 | ';'.join([MSVSSettings.ConvertVCMacrosToMSBuild(i) | |
1853 | for i in old_additional_dependencies])) | |
1854 | old_outputs = _FixPaths(rule.get('outputs', [])) | |
1855 | self.outputs = ';'.join([MSVSSettings.ConvertVCMacrosToMSBuild(i) | |
1856 | for i in old_outputs]) | |
1857 | old_command = _BuildCommandLineForRule(spec, rule, has_input_path=True) | |
1858 | self.command = MSVSSettings.ConvertVCMacrosToMSBuild(old_command) | |
1859 | ||
1860 | ||
1861 | def _GenerateMSBuildRulePropsFile(props_path, msbuild_rules): | |
1862 | """Generate the .props file.""" | |
1863 | doc = easy_xml.EasyXml( | |
1864 | 'Project', | |
1865 | {'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) | |
1866 | root = doc.Root() | |
1867 | for rule in msbuild_rules: | |
1868 | doc.AppendChildren(root, [ | |
1869 | ['PropertyGroup', | |
1870 | {'Condition': "'$(%s)' == '' and '$(%s)' == '' and " | |
1871 | "'$(ConfigurationType)' != 'Makefile'" % (rule.before_targets, | |
1872 | rule.after_targets) | |
1873 | }, | |
1874 | [rule.before_targets, 'Midl'], | |
1875 | [rule.after_targets, 'CustomBuild'], | |
1876 | ], | |
1877 | ['PropertyGroup', | |
1878 | [rule.depends_on, | |
1879 | {'Condition': "'$(ConfigurationType)' != 'Makefile'"}, | |
1880 | '_SelectedFiles;$(%s)' % rule.depends_on | |
1881 | ], | |
1882 | ], | |
1883 | ['ItemDefinitionGroup', | |
1884 | [rule.rule_name, | |
1885 | ['CommandLineTemplate', rule.command], | |
1886 | ['Outputs', rule.outputs], | |
1887 | ['ExecutionDescription', rule.description], | |
1888 | ['AdditionalDependencies', rule.additional_dependencies], | |
1889 | ], | |
1890 | ] | |
1891 | ]) | |
1892 | doc.WriteIfChanged(props_path) | |
1893 | ||
1894 | ||
1895 | def _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules): | |
1896 | """Generate the .targets file.""" | |
1897 | doc = easy_xml.EasyXml( | |
1898 | 'Project', | |
1899 | {'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003'}) | |
1900 | root = doc.Root() | |
1901 | item_group = doc.AppendNode( | |
1902 | root, | |
1903 | ['ItemGroup', | |
1904 | ['PropertyPageSchema', | |
1905 | {'Include': '$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml'} | |
1906 | ], | |
1907 | ]) | |
1908 | for rule in msbuild_rules: | |
1909 | doc.AppendNode( | |
1910 | item_group, | |
1911 | ['AvailableItemName', | |
1912 | {'Include': rule.rule_name}, | |
1913 | ['Targets', rule.target_name], | |
1914 | ]) | |
1915 | for rule in msbuild_rules: | |
1916 | doc.AppendNode( | |
1917 | root, | |
1918 | ['UsingTask', | |
1919 | {'TaskName': rule.rule_name, | |
1920 | 'TaskFactory': 'XamlTaskFactory', | |
1921 | 'AssemblyName': 'Microsoft.Build.Tasks.v4.0' | |
1922 | }, | |
1923 | ['Task', '$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml'], | |
1924 | ]) | |
1925 | for rule in msbuild_rules: | |
1926 | rule_name = rule.rule_name | |
1927 | target_outputs = '%%(%s.Outputs)' % rule_name | |
1928 | target_inputs = ('%%(%s.Identity);%%(%s.AdditionalDependencies);' | |
1929 | '$(MSBuildProjectFile)') % (rule_name, rule_name) | |
1930 | rule_inputs = '%%(%s.Identity)' % rule_name | |
1931 | extension_condition = ("'%(Extension)'=='.obj' or " | |
1932 | "'%(Extension)'=='.res' or " | |
1933 | "'%(Extension)'=='.rsc' or " | |
1934 | "'%(Extension)'=='.lib'") | |
1935 | remove_section = [ | |
1936 | 'ItemGroup', | |
1937 | {'Condition': "'@(SelectedFiles)' != ''"}, | |
1938 | [rule_name, | |
1939 | {'Remove': '@(%s)' % rule_name, | |
1940 | 'Condition': "'%(Identity)' != '@(SelectedFiles)'" | |
1941 | } | |
1942 | ] | |
1943 | ] | |
1944 | logging_section = [ | |
1945 | 'ItemGroup', | |
1946 | [rule.tlog, | |
1947 | {'Include': '%%(%s.Outputs)' % rule_name, | |
1948 | 'Condition': ("'%%(%s.Outputs)' != '' and " | |
1949 | "'%%(%s.ExcludedFromBuild)' != 'true'" % | |
1950 | (rule_name, rule_name)) | |
1951 | }, | |
1952 | ['Source', "@(%s, '|')" % rule_name], | |
1953 | ], | |
1954 | ] | |
1955 | message_section = [ | |
1956 | 'Message', | |
1957 | {'Importance': 'High', | |
1958 | 'Text': '%%(%s.ExecutionDescription)' % rule_name | |
1959 | } | |
1960 | ] | |
1961 | write_lines_section = [ | |
1962 | 'WriteLinesToFile', | |
1963 | {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != " | |
1964 | "'true'" % (rule.tlog, rule.tlog), | |
1965 | 'File': '$(IntDir)$(ProjectName).write.1.tlog', | |
1966 | 'Lines': "^%%(%s.Source);@(%s->'%%(Fullpath)')" % (rule.tlog, | |
1967 | rule.tlog) | |
1968 | } | |
1969 | ] | |
1970 | command_and_input_section = [ | |
1971 | rule_name, | |
1972 | {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != " | |
1973 | "'true'" % (rule_name, rule_name), | |
1974 | 'CommandLineTemplate': '%%(%s.CommandLineTemplate)' % rule_name, | |
1975 | 'AdditionalOptions': '%%(%s.AdditionalOptions)' % rule_name, | |
1976 | 'Inputs': rule_inputs | |
1977 | } | |
1978 | ] | |
1979 | doc.AppendChildren(root, [ | |
1980 | ['Target', | |
1981 | {'Name': rule.target_name, | |
1982 | 'BeforeTargets': '$(%s)' % rule.before_targets, | |
1983 | 'AfterTargets': '$(%s)' % rule.after_targets, | |
1984 | 'Condition': "'@(%s)' != ''" % rule_name, | |
1985 | 'DependsOnTargets': '$(%s);%s' % (rule.depends_on, | |
1986 | rule.compute_output), | |
1987 | 'Outputs': target_outputs, | |
1988 | 'Inputs': target_inputs | |
1989 | }, | |
1990 | remove_section, | |
1991 | logging_section, | |
1992 | message_section, | |
1993 | write_lines_section, | |
1994 | command_and_input_section, | |
1995 | ], | |
1996 | ['PropertyGroup', | |
1997 | ['ComputeLinkInputsTargets', | |
1998 | '$(ComputeLinkInputsTargets);', | |
1999 | '%s;' % rule.compute_output | |
2000 | ], | |
2001 | ['ComputeLibInputsTargets', | |
2002 | '$(ComputeLibInputsTargets);', | |
2003 | '%s;' % rule.compute_output | |
2004 | ], | |
2005 | ], | |
2006 | ['Target', | |
2007 | {'Name': rule.compute_output, | |
2008 | 'Condition': "'@(%s)' != ''" % rule_name | |
2009 | }, | |
2010 | ['ItemGroup', | |
2011 | [rule.dirs_to_make, | |
2012 | {'Condition': "'@(%s)' != '' and " | |
2013 | "'%%(%s.ExcludedFromBuild)' != 'true'" % (rule_name, rule_name), | |
2014 | 'Include': '%%(%s.Outputs)' % rule_name | |
2015 | } | |
2016 | ], | |
2017 | ['Link', | |
2018 | {'Include': '%%(%s.Identity)' % rule.dirs_to_make, | |
2019 | 'Condition': extension_condition | |
2020 | } | |
2021 | ], | |
2022 | ['Lib', | |
2023 | {'Include': '%%(%s.Identity)' % rule.dirs_to_make, | |
2024 | 'Condition': extension_condition | |
2025 | } | |
2026 | ], | |
2027 | ['ImpLib', | |
2028 | {'Include': '%%(%s.Identity)' % rule.dirs_to_make, | |
2029 | 'Condition': extension_condition | |
2030 | } | |
2031 | ], | |
2032 | ], | |
2033 | ['MakeDir', | |
2034 | {'Directories': ("@(%s->'%%(RootDir)%%(Directory)')" % | |
2035 | rule.dirs_to_make) | |
2036 | } | |
2037 | ] | |
2038 | ], | |
2039 | ]) | |
2040 | doc.WriteIfChanged(targets_path) | |
2041 | ||
2042 | ||
2043 | def _GenerateMSBuildRuleXmlFile(xml_path, msbuild_rules): | |
2044 | # Generate the .xml file | |
2045 | doc = easy_xml.EasyXml( | |
2046 | 'ProjectSchemaDefinitions', | |
2047 | {'xmlns': ('clr-namespace:Microsoft.Build.Framework.XamlTypes;' | |
2048 | 'assembly=Microsoft.Build.Framework'), | |
2049 | 'xmlns:x': 'http://schemas.microsoft.com/winfx/2006/xaml', | |
2050 | 'xmlns:sys': 'clr-namespace:System;assembly=mscorlib', | |
2051 | 'xmlns:transformCallback': | |
2052 | 'Microsoft.Cpp.Dev10.ConvertPropertyCallback'}) | |
2053 | root = doc.Root() | |
2054 | for rule in msbuild_rules: | |
2055 | doc.AppendChildren(root, [ | |
2056 | ['Rule', | |
2057 | {'Name': rule.rule_name, | |
2058 | 'PageTemplate': 'tool', | |
2059 | 'DisplayName': rule.display_name, | |
2060 | 'Order': '200' | |
2061 | }, | |
2062 | ['Rule.DataSource', | |
2063 | ['DataSource', | |
2064 | {'Persistence': 'ProjectFile', | |
2065 | 'ItemType': rule.rule_name | |
2066 | } | |
2067 | ] | |
2068 | ], | |
2069 | ['Rule.Categories', | |
2070 | ['Category', | |
2071 | {'Name': 'General'}, | |
2072 | ['Category.DisplayName', | |
2073 | ['sys:String', 'General'], | |
2074 | ], | |
2075 | ], | |
2076 | ['Category', | |
2077 | {'Name': 'Command Line', | |
2078 | 'Subtype': 'CommandLine' | |
2079 | }, | |
2080 | ['Category.DisplayName', | |
2081 | ['sys:String', 'Command Line'], | |
2082 | ], | |
2083 | ], | |
2084 | ], | |
2085 | ['StringListProperty', | |
2086 | {'Name': 'Inputs', | |
2087 | 'Category': 'Command Line', | |
2088 | 'IsRequired': 'true', | |
2089 | 'Switch': ' ' | |
2090 | }, | |
2091 | ['StringListProperty.DataSource', | |
2092 | ['DataSource', | |
2093 | {'Persistence': 'ProjectFile', | |
2094 | 'ItemType': rule.rule_name, | |
2095 | 'SourceType': 'Item' | |
2096 | } | |
2097 | ] | |
2098 | ], | |
2099 | ], | |
2100 | ['StringProperty', | |
2101 | {'Name': 'CommandLineTemplate', | |
2102 | 'DisplayName': 'Command Line', | |
2103 | 'Visible': 'False', | |
2104 | 'IncludeInCommandLine': 'False' | |
2105 | } | |
2106 | ], | |
2107 | ['DynamicEnumProperty', | |
2108 | {'Name': rule.before_targets, | |
2109 | 'Category': 'General', | |
2110 | 'EnumProvider': 'Targets', | |
2111 | 'IncludeInCommandLine': 'False' | |
2112 | }, | |
2113 | ['DynamicEnumProperty.DisplayName', | |
2114 | ['sys:String', 'Execute Before'], | |
2115 | ], | |
2116 | ['DynamicEnumProperty.Description', | |
2117 | ['sys:String', 'Specifies the targets for the build customization' | |
2118 | ' to run before.' | |
2119 | ], | |
2120 | ], | |
2121 | ['DynamicEnumProperty.ProviderSettings', | |
2122 | ['NameValuePair', | |
2123 | {'Name': 'Exclude', | |
2124 | 'Value': '^%s|^Compute' % rule.before_targets | |
2125 | } | |
2126 | ] | |
2127 | ], | |
2128 | ['DynamicEnumProperty.DataSource', | |
2129 | ['DataSource', | |
2130 | {'Persistence': 'ProjectFile', | |
2131 | 'HasConfigurationCondition': 'true' | |
2132 | } | |
2133 | ] | |
2134 | ], | |
2135 | ], | |
2136 | ['DynamicEnumProperty', | |
2137 | {'Name': rule.after_targets, | |
2138 | 'Category': 'General', | |
2139 | 'EnumProvider': 'Targets', | |
2140 | 'IncludeInCommandLine': 'False' | |
2141 | }, | |
2142 | ['DynamicEnumProperty.DisplayName', | |
2143 | ['sys:String', 'Execute After'], | |
2144 | ], | |
2145 | ['DynamicEnumProperty.Description', | |
2146 | ['sys:String', ('Specifies the targets for the build customization' | |
2147 | ' to run after.') | |
2148 | ], | |
2149 | ], | |
2150 | ['DynamicEnumProperty.ProviderSettings', | |
2151 | ['NameValuePair', | |
2152 | {'Name': 'Exclude', | |
2153 | 'Value': '^%s|^Compute' % rule.after_targets | |
2154 | } | |
2155 | ] | |
2156 | ], | |
2157 | ['DynamicEnumProperty.DataSource', | |
2158 | ['DataSource', | |
2159 | {'Persistence': 'ProjectFile', | |
2160 | 'ItemType': '', | |
2161 | 'HasConfigurationCondition': 'true' | |
2162 | } | |
2163 | ] | |
2164 | ], | |
2165 | ], | |
2166 | ['StringListProperty', | |
2167 | {'Name': 'Outputs', | |
2168 | 'DisplayName': 'Outputs', | |
2169 | 'Visible': 'False', | |
2170 | 'IncludeInCommandLine': 'False' | |
2171 | } | |
2172 | ], | |
2173 | ['StringProperty', | |
2174 | {'Name': 'ExecutionDescription', | |
2175 | 'DisplayName': 'Execution Description', | |
2176 | 'Visible': 'False', | |
2177 | 'IncludeInCommandLine': 'False' | |
2178 | } | |
2179 | ], | |
2180 | ['StringListProperty', | |
2181 | {'Name': 'AdditionalDependencies', | |
2182 | 'DisplayName': 'Additional Dependencies', | |
2183 | 'IncludeInCommandLine': 'False', | |
2184 | 'Visible': 'false' | |
2185 | } | |
2186 | ], | |
2187 | ['StringProperty', | |
2188 | {'Subtype': 'AdditionalOptions', | |
2189 | 'Name': 'AdditionalOptions', | |
2190 | 'Category': 'Command Line' | |
2191 | }, | |
2192 | ['StringProperty.DisplayName', | |
2193 | ['sys:String', 'Additional Options'], | |
2194 | ], | |
2195 | ['StringProperty.Description', | |
2196 | ['sys:String', 'Additional Options'], | |
2197 | ], | |
2198 | ], | |
2199 | ], | |
2200 | ['ItemType', | |
2201 | {'Name': rule.rule_name, | |
2202 | 'DisplayName': rule.display_name | |
2203 | } | |
2204 | ], | |
2205 | ['FileExtension', | |
2206 | {'Name': '*' + rule.extension, | |
2207 | 'ContentType': rule.rule_name | |
2208 | } | |
2209 | ], | |
2210 | ['ContentType', | |
2211 | {'Name': rule.rule_name, | |
2212 | 'DisplayName': '', | |
2213 | 'ItemType': rule.rule_name | |
2214 | } | |
2215 | ] | |
2216 | ]) | |
2217 | doc.WriteIfChanged(xml_path) | |
2218 | ||
2219 | ||
2220 | def _GetConfigurationAndPlatform(name, settings): | |
2221 | configuration = name.rsplit('_', 1)[0] | |
2222 | platform = settings.get('msvs_configuration_platform', 'Win32') | |
2223 | return (configuration, platform) | |
2224 | ||
2225 | ||
2226 | def _GetConfigurationCondition(name, settings): | |
2227 | return (r"'$(Configuration)|$(Platform)'=='%s|%s'" % | |
2228 | _GetConfigurationAndPlatform(name, settings)) | |
2229 | ||
2230 | ||
2231 | def _GetMSBuildProjectConfigurations(configurations): | |
2232 | group = ['ItemGroup', {'Label': 'ProjectConfigurations'}] | |
2233 | for (name, settings) in sorted(configurations.iteritems()): | |
2234 | configuration, platform = _GetConfigurationAndPlatform(name, settings) | |
2235 | designation = '%s|%s' % (configuration, platform) | |
2236 | group.append( | |
2237 | ['ProjectConfiguration', {'Include': designation}, | |
2238 | ['Configuration', configuration], | |
2239 | ['Platform', platform]]) | |
2240 | return [group] | |
2241 | ||
2242 | ||
2243 | def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name): | |
2244 | prefix = spec.get('product_prefix', '') | |
2245 | product_name = spec.get('product_name', '$(ProjectName)') | |
2246 | target_name = prefix + product_name | |
2247 | namespace = os.path.splitext(gyp_file_name)[0] | |
2248 | return [ | |
2249 | ['PropertyGroup', {'Label': 'Globals'}, | |
2250 | ['ProjectGuid', guid], | |
2251 | ['Keyword', 'Win32Proj'], | |
2252 | ['RootNamespace', namespace], | |
2253 | ['TargetName', target_name], | |
2254 | ] | |
2255 | ] | |
2256 | ||
2257 | ||
2258 | def _GetMSBuildConfigurationDetails(spec, build_file): | |
2259 | groups = [] | |
2260 | for (name, settings) in sorted(spec['configurations'].iteritems()): | |
2261 | msbuild_attributes = _GetMSBuildAttributes(spec, settings, build_file) | |
2262 | group = ['PropertyGroup', | |
2263 | {'Condition': _GetConfigurationCondition(name, settings), | |
2264 | 'Label': 'Configuration'}, | |
2265 | ['ConfigurationType', msbuild_attributes['ConfigurationType']]] | |
2266 | if 'CharacterSet' in msbuild_attributes: | |
2267 | group.append(['CharacterSet', msbuild_attributes['CharacterSet']]) | |
2268 | groups.append(group) | |
2269 | return groups | |
2270 | ||
2271 | ||
2272 | def _GetMSBuildPropertySheets(configurations): | |
2273 | sheets = [] | |
2274 | for (name, settings) in sorted(configurations.iteritems()): | |
2275 | user_props = r'$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props' | |
2276 | sheets.append( | |
2277 | ['ImportGroup', | |
2278 | {'Label': 'PropertySheets', | |
2279 | 'Condition': _GetConfigurationCondition(name, settings) | |
2280 | }, | |
2281 | ['Import', | |
2282 | {'Project': user_props, | |
2283 | 'Condition': "exists('%s')" % user_props, | |
2284 | 'Label': 'LocalAppDataPlatform' | |
2285 | } | |
2286 | ] | |
2287 | ]) | |
2288 | return sheets | |
2289 | ||
2290 | ||
2291 | def _GetMSBuildAttributes(spec, config, build_file): | |
2292 | # Use the MSVS attributes and convert them. In the future, we may want to | |
2293 | # support Gyp files specifying 'msbuild_configuration_attributes' directly. | |
2294 | config_type = _GetMSVSConfigurationType(spec, build_file) | |
2295 | msvs_attributes = _GetMSVSAttributes(spec, config, config_type) | |
2296 | msbuild_attributes = {} | |
2297 | for a in msvs_attributes: | |
2298 | if a in ['IntermediateDirectory', 'OutputDirectory']: | |
2299 | directory = MSVSSettings.ConvertVCMacrosToMSBuild(msvs_attributes[a]) | |
2300 | if not directory.endswith('\\'): | |
2301 | directory += '\\' | |
2302 | msbuild_attributes[a] = directory | |
2303 | elif a == 'CharacterSet': | |
2304 | msbuild_attributes[a] = { | |
2305 | '0': 'MultiByte', | |
2306 | '1': 'Unicode' | |
2307 | }[msvs_attributes[a]] | |
2308 | elif a == 'ConfigurationType': | |
2309 | msbuild_attributes[a] = { | |
2310 | '1': 'Application', | |
2311 | '2': 'DynamicLibrary', | |
2312 | '4': 'StaticLibrary', | |
2313 | '10': 'Utility' | |
2314 | }[msvs_attributes[a]] | |
2315 | else: | |
2316 | print 'Warning: Do not know how to convert MSVS attribute ' + a | |
2317 | return msbuild_attributes | |
2318 | ||
2319 | ||
2320 | def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file): | |
2321 | group = ['PropertyGroup'] | |
2322 | for (name, configuration) in sorted(configurations.iteritems()): | |
2323 | condition = _GetConfigurationCondition(name, configuration) | |
2324 | attributes = _GetMSBuildAttributes(spec, configuration, build_file) | |
2325 | msbuild_settings = configuration['finalized_msbuild_settings'] | |
2326 | group.extend( | |
2327 | [['IntDir', | |
2328 | {'Condition': condition}, | |
2329 | attributes['IntermediateDirectory'] | |
2330 | ], | |
2331 | ['OutDir', | |
2332 | {'Condition': condition}, | |
2333 | attributes['OutputDirectory'] | |
2334 | ], | |
2335 | ]) | |
2336 | # TODO(jeanluc) We could optimize out the following and do it only if | |
2337 | # there are actions. | |
2338 | # TODO(jeanluc) Handle the equivalent of setting 'CYGWIN=nontsec'. | |
2339 | new_paths = [] | |
2340 | cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])[0] | |
2341 | if cygwin_dirs: | |
2342 | cyg_path = '$(MSBuildProjectDirectory)\\%s\\bin\\' % _FixPath(cygwin_dirs) | |
2343 | new_paths.append(cyg_path) | |
2344 | # TODO(jeanluc) Change the convention to have both a cygwin_dir and a | |
2345 | # python_dir. | |
2346 | python_path = cyg_path.replace('cygwin\\bin', 'python_26') | |
2347 | new_paths.append(python_path) | |
2348 | if new_paths: | |
2349 | group.append(['ExecutablePath', {'Condition': condition}, | |
2350 | '$(ExecutablePath);' + ';'.join(new_paths)]) | |
2351 | tool_settings = msbuild_settings.get('', {}) | |
2352 | for name, value in sorted(tool_settings.iteritems()): | |
2353 | formatted_value = _GetValueFormattedForMSBuild('', name, value) | |
2354 | group.append([name, {'Condition': condition}, formatted_value]) | |
2355 | return [group] | |
2356 | ||
2357 | ||
2358 | def _GetMSBuildToolSettingsSections(spec, configurations): | |
2359 | groups = [] | |
2360 | for (name, configuration) in sorted(configurations.iteritems()): | |
2361 | msbuild_settings = configuration['finalized_msbuild_settings'] | |
2362 | group = ['ItemDefinitionGroup', | |
2363 | {'Condition': _GetConfigurationCondition(name, configuration)} | |
2364 | ] | |
2365 | for tool_name, tool_settings in sorted(msbuild_settings.iteritems()): | |
2366 | # Skip the tool named '' which is a holder of global settings handled | |
2367 | # by _GetMSBuildConfigurationGlobalProperties. | |
2368 | if tool_name: | |
2369 | if tool_settings: | |
2370 | tool = [tool_name] | |
2371 | for name, value in sorted(tool_settings.iteritems()): | |
2372 | formatted_value = _GetValueFormattedForMSBuild(tool_name, name, | |
2373 | value) | |
2374 | tool.append([name, formatted_value]) | |
2375 | group.append(tool) | |
2376 | groups.append(group) | |
2377 | return groups | |
2378 | ||
2379 | ||
2380 | def _FinalizeMSBuildSettings(spec, configuration): | |
2381 | if 'msbuild_settings' in configuration: | |
2382 | converted = False | |
2383 | msbuild_settings = configuration['msbuild_settings'] | |
2384 | MSVSSettings.ValidateMSBuildSettings(msbuild_settings) | |
2385 | else: | |
2386 | converted = True | |
2387 | msvs_settings = configuration.get('msvs_settings', {}) | |
2388 | msbuild_settings = MSVSSettings.ConvertToMSBuildSettings(msvs_settings) | |
2389 | include_dirs, resource_include_dirs = _GetIncludeDirs(configuration) | |
2390 | libraries = _GetLibraries(spec) | |
2391 | out_file, _, msbuild_tool = _GetOutputFilePathAndTool(spec) | |
2392 | defines = _GetDefines(configuration) | |
2393 | if converted: | |
2394 | # Visual Studio 2010 has TR1 | |
2395 | defines = [d for d in defines if d != '_HAS_TR1=0'] | |
2396 | # Warn of ignored settings | |
2397 | ignored_settings = ['msvs_prebuild', 'msvs_postbuild', 'msvs_tool_files'] | |
2398 | for ignored_setting in ignored_settings: | |
2399 | value = configuration.get(ignored_setting) | |
2400 | if value: | |
2401 | print ('Warning: The automatic conversion to MSBuild does not handle ' | |
2402 | '%s. Ignoring setting of %s' % (ignored_setting, str(value))) | |
2403 | ||
2404 | defines = [_EscapeCppDefineForMSBuild(d) for d in defines] | |
2405 | disabled_warnings = _GetDisabledWarnings(configuration) | |
2406 | # TODO(jeanluc) Validate & warn that we don't translate | |
2407 | # prebuild = configuration.get('msvs_prebuild') | |
2408 | # postbuild = configuration.get('msvs_postbuild') | |
2409 | def_file = _GetModuleDefinition(spec) | |
2410 | precompiled_header = configuration.get('msvs_precompiled_header') | |
2411 | ||
2412 | # Add the information to the appropriate tool | |
2413 | # TODO(jeanluc) We could optimize and generate these settings only if | |
2414 | # the corresponding files are found, e.g. don't generate ResourceCompile | |
2415 | # if you don't have any resources. | |
2416 | _ToolAppend(msbuild_settings, 'ClCompile', | |
2417 | 'AdditionalIncludeDirectories', include_dirs) | |
2418 | _ToolAppend(msbuild_settings, 'ResourceCompile', | |
2419 | 'AdditionalIncludeDirectories', resource_include_dirs) | |
2420 | # Add in libraries. | |
2421 | _ToolAppend(msbuild_settings, 'Link', 'AdditionalDependencies', libraries) | |
2422 | if out_file: | |
2423 | _ToolAppend(msbuild_settings, msbuild_tool, 'OutputFile', out_file, | |
2424 | only_if_unset=True) | |
2425 | # Add defines. | |
2426 | _ToolAppend(msbuild_settings, 'ClCompile', | |
2427 | 'PreprocessorDefinitions', defines) | |
2428 | _ToolAppend(msbuild_settings, 'ResourceCompile', | |
2429 | 'PreprocessorDefinitions', defines) | |
2430 | # Add disabled warnings. | |
2431 | _ToolAppend(msbuild_settings, 'ClCompile', | |
2432 | 'DisableSpecificWarnings', disabled_warnings) | |
2433 | # Turn on precompiled headers if appropriate. | |
2434 | if precompiled_header: | |
2435 | precompiled_header = os.path.split(precompiled_header)[1] | |
2436 | _ToolAppend(msbuild_settings, 'ClCompile', 'PrecompiledHeader', 'Use') | |
2437 | _ToolAppend(msbuild_settings, 'ClCompile', | |
2438 | 'PrecompiledHeaderFile', precompiled_header) | |
2439 | _ToolAppend(msbuild_settings, 'ClCompile', | |
2440 | 'ForcedIncludeFiles', precompiled_header) | |
2441 | # Loadable modules don't generate import libraries; | |
2442 | # tell dependent projects to not expect one. | |
2443 | if spec['type'] == 'loadable_module': | |
2444 | _ToolAppend(msbuild_settings, '', 'IgnoreImportLibrary', 'true') | |
2445 | # Set the module definition file if any. | |
2446 | if def_file: | |
2447 | _ToolAppend(msbuild_settings, 'Link', 'ModuleDefinitionFile', def_file) | |
2448 | configuration['finalized_msbuild_settings'] = msbuild_settings | |
2449 | ||
2450 | ||
2451 | def _GetValueFormattedForMSBuild(tool_name, name, value): | |
2452 | if type(value) == list: | |
2453 | # For some settings, VS2010 does not automatically extends the settings | |
2454 | # TODO(jeanluc) Is this what we want? | |
2455 | if name in ['AdditionalDependencies', | |
2456 | 'AdditionalIncludeDirectories', | |
2457 | 'AdditionalLibraryDirectories', | |
2458 | 'AdditionalOptions', | |
2459 | 'DelayLoadDLLs', | |
2460 | 'DisableSpecificWarnings', | |
2461 | 'PreprocessorDefinitions']: | |
2462 | value.append('%%(%s)' % name) | |
2463 | # TODO(jeanluc) Not all of them need to be fixed, why? | |
2464 | if name in ['AdditionalIncludeDirectories', 'AdditionalLibraryDirectories']: | |
2465 | value = _FixPaths(value) | |
2466 | # For most tools, entries in a list should be separated with ';' but some | |
2467 | # settings use a space. Check for those first. | |
2468 | exceptions = { | |
2469 | 'ClCompile': ['AdditionalOptions'], | |
2470 | 'Link': ['AdditionalOptions'], | |
2471 | 'Lib': ['AdditionalOptions']} | |
2472 | if tool_name in exceptions and name in exceptions[tool_name]: | |
2473 | char = ' ' | |
2474 | else: | |
2475 | char = ';' | |
2476 | formatted_value = char.join( | |
2477 | [MSVSSettings.ConvertVCMacrosToMSBuild(i) for i in value]) | |
2478 | else: | |
2479 | formatted_value = MSVSSettings.ConvertVCMacrosToMSBuild(value) | |
2480 | return formatted_value | |
2481 | ||
2482 | ||
2483 | def _GetMSBuildSources(spec, root_dir, sources, exclusions, | |
2484 | extension_to_rule_name, actions_spec, | |
2485 | sources_handled_by_action): | |
2486 | groups = ['none', 'midl', 'include', 'compile', 'resource', 'rule'] | |
2487 | grouped_sources = {} | |
2488 | for g in groups: | |
2489 | grouped_sources[g] = [] | |
2490 | ||
2491 | _AddSources2(spec, root_dir, sources, exclusions, grouped_sources, | |
2492 | extension_to_rule_name, sources_handled_by_action) | |
2493 | sources = [] | |
2494 | for g in groups: | |
2495 | if grouped_sources[g]: | |
2496 | sources.append(['ItemGroup'] + grouped_sources[g]) | |
2497 | if actions_spec: | |
2498 | sources.append(['ItemGroup'] + actions_spec) | |
2499 | return sources | |
2500 | ||
2501 | ||
2502 | def _AddSources2(spec, root_dir, sources, exclusions, grouped_sources, | |
2503 | extension_to_rule_name, sources_handled_by_action): | |
2504 | for source in sources: | |
2505 | if isinstance(source, MSVSProject.Filter): | |
2506 | _AddSources2(spec, root_dir, source.contents, exclusions, grouped_sources, | |
2507 | extension_to_rule_name, sources_handled_by_action) | |
2508 | else: | |
2509 | # If it is a regular source file, i.e. not created at run time, | |
2510 | # warn if it does not exists. Missing header files will cause needless | |
2511 | # but no otherwise visible errors. | |
2512 | if '$' not in source: | |
2513 | full_path = os.path.join(root_dir, source) | |
2514 | if not os.path.exists(full_path): | |
2515 | print 'Warning: Missing input file ' + full_path | |
2516 | if not source in sources_handled_by_action: | |
2517 | detail = [] | |
2518 | for config_name, configuration in sorted(exclusions.get(source, [])): | |
2519 | condition = _GetConfigurationCondition(config_name, configuration) | |
2520 | detail.append(['ExcludedFromBuild', {'Condition': condition}, 'true']) | |
2521 | # Add precompile if needed | |
2522 | for config_name, configuration in spec['configurations'].iteritems(): | |
2523 | precompiled_source = configuration.get('msvs_precompiled_source', '') | |
2524 | precompiled_source = _FixPath(precompiled_source) | |
2525 | if precompiled_source == source: | |
2526 | condition = _GetConfigurationCondition(config_name, configuration) | |
2527 | detail.append(['PrecompiledHeader', | |
2528 | {'Condition': condition}, | |
2529 | 'Create' | |
2530 | ]) | |
2531 | group, element = _MapFileToMsBuildSourceType(source, | |
2532 | extension_to_rule_name) | |
2533 | grouped_sources[group].append([element, {'Include': source}] + detail) | |
2534 | ||
2535 | ||
2536 | def _GetMSBuildProjectReferences(project): | |
2537 | references = [] | |
2538 | if project.dependencies: | |
2539 | group = ['ItemGroup'] | |
2540 | for dependency in project.dependencies: | |
2541 | guid = dependency.guid | |
2542 | project_dir = os.path.split(project.path)[0] | |
2543 | relative_path = gyp.common.RelativePath(dependency.path, project_dir) | |
2544 | group.append( | |
2545 | ['ProjectReference', | |
2546 | {'Include': relative_path}, | |
2547 | ['Project', guid], | |
2548 | ['ReferenceOutputAssembly', 'false'] | |
2549 | ]) | |
2550 | references.append(group) | |
2551 | return references | |
2552 | ||
2553 | ||
2554 | def _GenerateMSBuildProject(project, options, version): | |
2555 | spec = project.spec | |
2556 | configurations = spec['configurations'] | |
2557 | gyp_dir, gyp_file_name = os.path.split(project.path) | |
2558 | msbuildproj_dir = os.path.dirname(project.path) | |
2559 | if msbuildproj_dir and not os.path.exists(msbuildproj_dir): | |
2560 | os.makedirs(msbuildproj_dir) | |
2561 | # Prepare list of sources and excluded sources. | |
2562 | gyp_dir = os.path.split(project.path)[0] | |
2563 | gyp_file = posixpath.split(project.build_file)[1] | |
2564 | gyp_path = _NormalizedSource(gyp_file) | |
2565 | relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, gyp_dir) | |
2566 | ||
2567 | sources, excluded_sources = _PrepareListOfSources(spec, | |
2568 | relative_path_of_gyp_file) | |
2569 | # Add rules. | |
2570 | actions_to_add = {} | |
2571 | props_files_of_rules = set() | |
2572 | targets_files_of_rules = set() | |
2573 | extension_to_rule_name = {} | |
2574 | _GenerateRulesForMSBuild(gyp_dir, options, spec, | |
2575 | sources, excluded_sources, | |
2576 | props_files_of_rules, targets_files_of_rules, | |
2577 | actions_to_add, extension_to_rule_name) | |
2578 | sources, excluded_sources, excluded_idl = ( | |
2579 | _AdjustSourcesAndConvertToFilterHierarchy(spec, options, | |
2580 | gyp_dir, sources, | |
2581 | excluded_sources)) | |
2582 | _AddActions(actions_to_add, spec, project.build_file) | |
2583 | _AddCopies(actions_to_add, spec) | |
2584 | ||
2585 | # NOTE: this stanza must appear after all actions have been decided. | |
2586 | # Don't excluded sources with actions attached, or they won't run. | |
2587 | excluded_sources = _FilterActionsFromExcluded( | |
2588 | excluded_sources, actions_to_add) | |
2589 | ||
2590 | exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl) | |
2591 | actions_spec, sources_handled_by_action = _GenerateActionsForMSBuild( | |
2592 | spec, actions_to_add) | |
2593 | ||
2594 | _GenerateMSBuildFiltersFile(project.path + '.filters', sources, | |
2595 | extension_to_rule_name) | |
2596 | ||
2597 | for (_, configuration) in configurations.iteritems(): | |
2598 | _FinalizeMSBuildSettings(spec, configuration) | |
2599 | ||
2600 | # Add attributes to root element | |
2601 | ||
2602 | doc = easy_xml.EasyXml( | |
2603 | 'Project', | |
2604 | {'xmlns': 'http://schemas.microsoft.com/developer/msbuild/2003', | |
2605 | 'ToolsVersion': version.ProjectVersion(), | |
2606 | 'DefaultTargets': 'Build' | |
2607 | }) | |
2608 | ||
2609 | import_default_section = [ | |
2610 | ['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.Default.props'}]] | |
2611 | import_cpp_props_section = [ | |
2612 | ['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.props'}]] | |
2613 | import_cpp_targets_section = [ | |
2614 | ['Import', {'Project': r'$(VCTargetsPath)\Microsoft.Cpp.targets'}]] | |
2615 | macro_section = [['PropertyGroup', {'Label': 'UserMacros'}]] | |
2616 | ||
2617 | content = _GetMSBuildProjectConfigurations(configurations) | |
2618 | content += _GetMSBuildGlobalProperties(spec, project.guid, gyp_file_name) | |
2619 | content += import_default_section | |
2620 | content += _GetMSBuildConfigurationDetails(spec, project.build_file) | |
2621 | content += import_cpp_props_section | |
2622 | content += _GetMSBuildExtensions(props_files_of_rules) | |
2623 | content += _GetMSBuildPropertySheets(configurations) | |
2624 | content += macro_section | |
2625 | content += _GetMSBuildConfigurationGlobalProperties(spec, configurations, | |
2626 | project.build_file) | |
2627 | content += _GetMSBuildToolSettingsSections(spec, configurations) | |
2628 | content += _GetMSBuildSources( | |
2629 | spec, gyp_dir, sources, exclusions, extension_to_rule_name, actions_spec, | |
2630 | sources_handled_by_action) | |
2631 | content += _GetMSBuildProjectReferences(project) | |
2632 | content += import_cpp_targets_section | |
2633 | content += _GetMSBuildExtensionTargets(targets_files_of_rules) | |
2634 | ||
2635 | # TODO(jeanluc) File a bug to get rid of runas. We had in MSVS: | |
2636 | # has_run_as = _WriteMSVSUserFile(project.path, version, spec) | |
2637 | ||
2638 | doc.AppendChildren(doc.Root(), content) | |
2639 | doc.WriteIfChanged(project.path) | |
2640 | ||
2641 | ||
2642 | def _GetMSBuildExtensions(props_files_of_rules): | |
2643 | extensions = ['ImportGroup', {'Label': 'ExtensionSettings'}] | |
2644 | for props_file in props_files_of_rules: | |
2645 | extensions.append(['Import', {'Project': props_file}]) | |
2646 | return [extensions] | |
2647 | ||
2648 | ||
2649 | def _GetMSBuildExtensionTargets(targets_files_of_rules): | |
2650 | targets_node = ['ImportGroup', {'Label': 'ExtensionTargets'}] | |
2651 | for targets_file in sorted(targets_files_of_rules): | |
2652 | targets_node.append(['Import', {'Project': targets_file}]) | |
2653 | return [targets_node] | |
2654 | ||
2655 | ||
2656 | def _GenerateActionsForMSBuild(spec, actions_to_add): | |
2657 | """Add actions accumulated into an actions_to_add, merging as needed. | |
2658 | ||
2659 | Arguments: | |
2660 | spec: the target project dict | |
2661 | actions_to_add: dictionary keyed on input name, which maps to a list of | |
2662 | dicts describing the actions attached to that input file. | |
2663 | ||
2664 | Returns: | |
2665 | A pair of (action specification, the sources handled by this action). | |
2666 | """ | |
2667 | sources_handled_by_action = set() | |
2668 | actions_spec = [] | |
2669 | for primary_input, actions in actions_to_add.iteritems(): | |
2670 | inputs = set() | |
2671 | outputs = set() | |
2672 | descriptions = [] | |
2673 | commands = [] | |
2674 | for action in actions: | |
2675 | inputs.update(set(action['inputs'])) | |
2676 | outputs.update(set(action['outputs'])) | |
2677 | descriptions.append(action['description']) | |
2678 | cmd = action['command'] | |
2679 | # For most actions, add 'call' so that actions that invoke batch files | |
2680 | # return and continue executing. msbuild_use_call provides a way to | |
2681 | # disable this but I have not seen any adverse effect from doing that | |
2682 | # for everything. | |
2683 | if action.get('msbuild_use_call', True): | |
2684 | cmd = 'call ' + cmd | |
2685 | commands.append(cmd) | |
2686 | # Add the custom build action for one input file. | |
2687 | description = ', and also '.join(descriptions) | |
2688 | command = ' && '.join(commands) | |
2689 | _AddMSBuildAction(spec, | |
2690 | primary_input, | |
2691 | inputs, | |
2692 | outputs, | |
2693 | command, | |
2694 | description, | |
2695 | sources_handled_by_action, | |
2696 | actions_spec) | |
2697 | return actions_spec, sources_handled_by_action | |
2698 | ||
2699 | ||
2700 | def _AddMSBuildAction(spec, primary_input, inputs, outputs, cmd, description, | |
2701 | sources_handled_by_action, actions_spec): | |
2702 | command = MSVSSettings.ConvertVCMacrosToMSBuild(cmd) | |
2703 | primary_input = _FixPath(primary_input) | |
2704 | inputs_array = _FixPaths(inputs) | |
2705 | outputs_array = _FixPaths(outputs) | |
2706 | additional_inputs = ';'.join([i for i in inputs_array | |
2707 | if i != primary_input]) | |
2708 | outputs = ';'.join(outputs_array) | |
2709 | sources_handled_by_action.add(primary_input) | |
2710 | action_spec = ['CustomBuild', {'Include': primary_input}] | |
2711 | for name, configuration in spec['configurations'].iteritems(): | |
2712 | condition_clause = { | |
2713 | 'Condition': | |
2714 | _GetConfigurationCondition(name, configuration) | |
2715 | } | |
2716 | action_spec.extend( | |
2717 | # TODO(jeanluc) 'Document' for all or just if as_sources? | |
2718 | [['FileType', 'Document'], | |
2719 | ['Command', condition_clause, command], | |
2720 | ['Message', condition_clause, description], | |
2721 | ['Outputs', condition_clause, outputs] | |
2722 | ]) | |
2723 | if additional_inputs: | |
2724 | action_spec.append(['AdditionalInputs', condition_clause, | |
2725 | additional_inputs]) | |
2726 | actions_spec.append(action_spec) |
529 | 529 | fp.write(fmt % (repr(dest), repr(f))) |
530 | 530 | fp.write('target_files.extend(_outputs)\n') |
531 | 531 | |
532 | if spec.get('run_as') or int(spec.get('test', 0)): | |
533 | run_as = spec.get('run_as', { | |
534 | 'action' : ['$TARGET_NAME', '--gtest_print_time'], | |
535 | }) | |
532 | run_as = spec.get('run_as') | |
533 | if run_as: | |
536 | 534 | action = run_as.get('action', []) |
537 | 535 | working_directory = run_as.get('working_directory') |
538 | 536 | if not working_directory: |
563 | 561 | fp.write(' env.Requires(prerequisite, dependencies)\n') |
564 | 562 | fp.write('env.Requires(gyp_target, prerequisites)\n') |
565 | 563 | |
566 | if spec.get('run_as', 0) or int(spec.get('test', 0)): | |
564 | if run_as: | |
567 | 565 | fp.write(_run_as_template_suffix % { |
568 | 566 | 'target_name': target_name, |
569 | 567 | }) |
29 | 29 | # SHARED_INTERMEDIATE_DIR is the same, except that it is shared among all |
30 | 30 | # targets that share the same BUILT_PRODUCTS_DIR. |
31 | 31 | _shared_intermediate_var = 'SHARED_INTERMEDIATE_DIR' |
32 | ||
33 | _library_search_paths_var = 'LIBRARY_SEARCH_PATHS' | |
32 | 34 | |
33 | 35 | generator_default_variables = { |
34 | 36 | 'EXECUTABLE_PREFIX': '', |
57 | 59 | # The Xcode-specific sections that hold paths. |
58 | 60 | generator_additional_path_sections = [ |
59 | 61 | 'mac_bundle_resources', |
62 | 'mac_framework_headers', | |
63 | 'mac_framework_private_headers', | |
60 | 64 | # 'mac_framework_dirs', input already handles _dirs endings. |
61 | 65 | ] |
62 | 66 | |
65 | 69 | generator_additional_non_configuration_keys = [ |
66 | 70 | 'mac_bundle', |
67 | 71 | 'mac_bundle_resources', |
72 | 'mac_framework_headers', | |
73 | 'mac_framework_private_headers', | |
68 | 74 | 'xcode_create_dependents_test_runner', |
69 | 75 | ] |
70 | 76 | |
71 | 77 | # We want to let any rules apply to files that are resources also. |
72 | 78 | generator_extra_sources_for_rules = [ |
73 | 79 | 'mac_bundle_resources', |
80 | 'mac_framework_headers', | |
81 | 'mac_framework_private_headers', | |
74 | 82 | ] |
75 | 83 | |
84 | # Xcode's standard set of library directories, which don't need to be duplicated | |
85 | # in LIBRARY_SEARCH_PATHS. This list is not exhaustive, but that's okay. | |
86 | xcode_standard_library_dirs = frozenset([ | |
87 | '$(SDKROOT)/usr/lib', | |
88 | '$(SDKROOT)/usr/local/lib', | |
89 | ]) | |
76 | 90 | |
77 | 91 | def CreateXCConfigurationList(configuration_names): |
78 | 92 | xccl = gyp.xcodeproj_file.XCConfigurationList({'buildConfigurations': []}) |
93 | if len(configuration_names) == 0: | |
94 | configuration_names = ['Default'] | |
79 | 95 | for configuration_name in configuration_names: |
80 | 96 | xcbc = gyp.xcodeproj_file.XCBuildConfiguration({ |
81 | 97 | 'name': configuration_name}) |
150 | 166 | xccl.SetBuildSetting(_shared_intermediate_var, |
151 | 167 | '$(SYMROOT)/DerivedSources/$(CONFIGURATION)') |
152 | 168 | |
153 | # Set user-specified project-wide build settings. This is intended to be | |
154 | # used very sparingly. Really, almost everything should go into | |
155 | # target-specific build settings sections. The project-wide settings are | |
156 | # only intended to be used in cases where Xcode attempts to resolve | |
157 | # variable references in a project context as opposed to a target context, | |
158 | # such as when resolving sourceTree references while building up the tree | |
159 | # tree view for UI display. | |
169 | # Set user-specified project-wide build settings and config files. This | |
170 | # is intended to be used very sparingly. Really, almost everything should | |
171 | # go into target-specific build settings sections. The project-wide | |
172 | # settings are only intended to be used in cases where Xcode attempts to | |
173 | # resolve variable references in a project context as opposed to a target | |
174 | # context, such as when resolving sourceTree references while building up | |
175 | # the tree tree view for UI display. | |
176 | # Any values set globally are applied to all configurations, then any | |
177 | # per-configuration values are applied. | |
160 | 178 | for xck, xcv in self.build_file_dict.get('xcode_settings', {}).iteritems(): |
161 | 179 | xccl.SetBuildSetting(xck, xcv) |
180 | if 'xcode_config_file' in self.build_file_dict: | |
181 | config_ref = self.project.AddOrGetFileInRootGroup( | |
182 | self.build_file_dict['xcode_config_file']) | |
183 | xccl.SetBaseConfiguration(config_ref) | |
184 | build_file_configurations = self.build_file_dict.get('configurations', {}) | |
185 | if build_file_configurations: | |
186 | for config_name in configurations: | |
187 | build_file_configuration_named = \ | |
188 | build_file_configurations.get(config_name, {}) | |
189 | if build_file_configuration_named: | |
190 | xcc = xccl.ConfigurationNamed(config_name) | |
191 | for xck, xcv in build_file_configuration_named.get('xcode_settings', | |
192 | {}).iteritems(): | |
193 | xcc.SetBuildSetting(xck, xcv) | |
194 | if 'xcode_config_file' in build_file_configuration_named: | |
195 | config_ref = self.project.AddOrGetFileInRootGroup( | |
196 | build_file_configurations[config_name]['xcode_config_file']) | |
197 | xcc.SetBaseConfiguration(config_ref) | |
162 | 198 | |
163 | 199 | # Sort the targets based on how they appeared in the input. |
164 | 200 | # TODO(mark): Like a lot of other things here, this assumes internal |
204 | 240 | if target_name.lower() == 'all': |
205 | 241 | has_custom_all = True; |
206 | 242 | |
207 | # If this target has a 'run_as' attribute, or is a test, add its | |
208 | # target to the targets, and (if it's a test) add it the to the | |
209 | # test targets. | |
210 | is_test = int(target.get('test', 0)) | |
211 | if target.get('run_as') or is_test: | |
243 | # If this target has a 'run_as' attribute, add its target to the | |
244 | # targets, and add it to the test targets. | |
245 | if target.get('run_as'): | |
212 | 246 | # Make a target to run something. It should have one |
213 | 247 | # dependency, the parent xcode target. |
214 | 248 | xccl = CreateXCConfigurationList(configurations) |
220 | 254 | parent=self.project) |
221 | 255 | run_target.AddDependency(xcode_target) |
222 | 256 | |
223 | # The test runner target has a build phase that executes the | |
224 | # test, if this has the 'test' attribute. If the 'run_as' tag | |
225 | # doesn't exist (meaning that this must be a test), then we | |
226 | # define a default test command line. | |
227 | command = target.get('run_as', { | |
228 | 'action': ['${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}'] | |
229 | }) | |
230 | ||
257 | command = target['run_as'] | |
231 | 258 | script = '' |
232 | 259 | if command.get('working_directory'): |
233 | 260 | script = script + 'cd "%s"\n' % \ |
247 | 274 | # little bit of python does the same as the linux flock utility to |
248 | 275 | # make sure only one runs at a time. |
249 | 276 | command_prefix = '' |
250 | if is_test and serialize_all_tests: | |
277 | if serialize_all_tests: | |
251 | 278 | command_prefix = \ |
252 | 279 | """python -c "import fcntl, subprocess, sys |
253 | 280 | file = open('$TMPDIR/GYP_serialize_test_runs', 'a') |
269 | 296 | |
270 | 297 | # Add the run target to the project file. |
271 | 298 | targets.append(run_target) |
272 | if is_test: | |
273 | run_test_targets.append(run_target) | |
274 | xcode_target.test_runner = run_target | |
299 | run_test_targets.append(run_target) | |
300 | xcode_target.test_runner = run_target | |
275 | 301 | |
276 | 302 | |
277 | 303 | # Make sure that the list of targets being replaced is the same length as |
351 | 377 | for pbxtd in pbxtds: |
352 | 378 | pbxcip = pbxtd.GetProperty('targetProxy') |
353 | 379 | dependency_xct = pbxcip.GetProperty('remoteGlobalIDString') |
354 | target_dict = xcode_target_to_target_dict[dependency_xct] | |
355 | if target_dict and int(target_dict.get('test', 0)): | |
356 | assert dependency_xct.test_runner | |
380 | if hasattr(dependency_xct, 'test_runner'): | |
357 | 381 | all_run_tests.append(dependency_xct.test_runner) |
358 | 382 | |
359 | 383 | # Directly depend on all the runners as they depend on the target |
490 | 514 | |
491 | 515 | |
492 | 516 | def AddSourceToTarget(source, pbxp, xct): |
493 | # TODO(mark): Perhaps this can be made a little bit fancier. | |
517 | # TODO(mark): Perhaps source_extensions and library_extensions can be made a | |
518 | # little bit fancier. | |
494 | 519 | source_extensions = ['c', 'cc', 'cpp', 'cxx', 'm', 'mm', 's'] |
520 | ||
521 | # .o is conceptually more of a "source" than a "library," but Xcode thinks | |
522 | # of "sources" as things to compile and "libraries" (or "frameworks") as | |
523 | # things to link with. Adding an object file to an Xcode target's frameworks | |
524 | # phase works properly. | |
525 | library_extensions = ['a', 'dylib', 'framework', 'o'] | |
526 | ||
495 | 527 | basename = posixpath.basename(source) |
496 | 528 | (root, ext) = posixpath.splitext(basename) |
497 | 529 | if ext != '': |
499 | 531 | |
500 | 532 | if ext in source_extensions: |
501 | 533 | xct.SourcesPhase().AddFile(source) |
534 | elif ext in library_extensions: | |
535 | xct.FrameworksPhase().AddFile(source) | |
502 | 536 | else: |
503 | # Files that aren't added to a sources build phase can still go into | |
504 | # the project file, just not as part of a build phase. | |
537 | # Files that aren't added to a sources or frameworks build phase can still | |
538 | # go into the project file, just not as part of a build phase. | |
505 | 539 | pbxp.AddOrGetFileInRootGroup(source) |
506 | 540 | |
507 | 541 | |
509 | 543 | # TODO(mark): Combine with AddSourceToTarget above? Or just inline this call |
510 | 544 | # where it's used. |
511 | 545 | xct.ResourcesPhase().AddFile(resource) |
546 | ||
547 | ||
548 | def AddHeaderToTarget(header, pbxp, xct, is_public): | |
549 | # TODO(mark): Combine with AddSourceToTarget above? Or just inline this call | |
550 | # where it's used. | |
551 | settings = '{ATTRIBUTES = (%s, ); }' % ('Private', 'Public')[is_public] | |
552 | xct.HeadersPhase().AddFile(header, settings) | |
512 | 553 | |
513 | 554 | |
514 | 555 | _xcode_variable_re = re.compile('(\$\((.*?)\))') |
552 | 593 | parallel_builds = generator_flags.get('xcode_parallel_builds', True) |
553 | 594 | serialize_all_tests = \ |
554 | 595 | generator_flags.get('xcode_serialize_all_test_runs', True) |
596 | project_version = generator_flags.get('xcode_project_version', None) | |
597 | skip_excluded_files = \ | |
598 | not generator_flags.get('xcode_list_excluded_files', True) | |
555 | 599 | xcode_projects = {} |
556 | 600 | for build_file, build_file_dict in data.iteritems(): |
557 | 601 | (build_file_root, build_file_ext) = os.path.splitext(build_file) |
567 | 611 | if parallel_builds: |
568 | 612 | pbxp.SetProperty('attributes', |
569 | 613 | {'BuildIndependentTargetsInParallel': 'YES'}) |
614 | if project_version: | |
615 | xcp.project_file.SetXcodeVersion(project_version) | |
570 | 616 | |
571 | 617 | main_group = pbxp.GetProperty('mainGroup') |
572 | 618 | build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'}) |
596 | 642 | # supplied. |
597 | 643 | xccl = CreateXCConfigurationList(configuration_names) |
598 | 644 | |
599 | # Create an XCTarget subclass object for the target. We use the type | |
600 | # with "+bundle" appended if the target has "mac_bundle" set. | |
645 | # Create an XCTarget subclass object for the target. The type with | |
646 | # "+bundle" appended will be used if the target has "mac_bundle" set. | |
647 | # loadable_modules not in a mac_bundle are mapped to | |
648 | # com.googlecode.gyp.xcode.bundle, a pseudo-type that xcode.py interprets | |
649 | # to create a single-file mh_bundle. | |
601 | 650 | _types = { |
602 | 651 | 'executable': 'com.apple.product-type.tool', |
603 | 'loadable_module': 'com.apple.product-type.library.dynamic', | |
652 | 'loadable_module': 'com.googlecode.gyp.xcode.bundle', | |
604 | 653 | 'shared_library': 'com.apple.product-type.library.dynamic', |
605 | 654 | 'static_library': 'com.apple.product-type.library.static', |
606 | 655 | 'executable+bundle': 'com.apple.product-type.application', |
640 | 689 | pbxp.AppendProperty('targets', xct) |
641 | 690 | xcode_targets[qualified_target] = xct |
642 | 691 | xcode_target_to_target_dict[xct] = spec |
643 | ||
644 | # Xcode does not have a distinct type for loadable_modules that are pure | |
645 | # BSD targets (ie-unbundled). It uses the same setup as a shared_library | |
646 | # but the mach-o type is explictly set in the settings. So before we do | |
647 | # anything else, for this one case, we stuff in that one setting. This | |
648 | # would allow the other data in the spec to change it if need be. | |
649 | if type == 'loadable_module' and not is_bundle: | |
650 | xccl.SetBuildSetting('MACH_O_TYPE', 'mh_bundle') | |
651 | 692 | |
652 | 693 | spec_actions = spec.get('actions', []) |
653 | 694 | spec_rules = spec.get('rules', []) |
868 | 909 | message = rule.get('message') |
869 | 910 | if message: |
870 | 911 | message = gyp.common.EncodePOSIXShellArgument(message) |
871 | message = '@echo note: ' + ExpandXcodeVariables(message, | |
872 | rule_input_dict) | |
912 | message = ExpandXcodeVariables(message, rule_input_dict) | |
873 | 913 | messages.append(message) |
874 | 914 | |
875 | 915 | # Turn the list into a string that can be passed to a shell. |
946 | 986 | |
947 | 987 | # Make sure that output directories exist before executing the rule |
948 | 988 | # action. |
949 | # TODO(mark): quote the list of concrete_output_dirs. | |
950 | 989 | if len(concrete_output_dirs) > 0: |
951 | makefile.write('\tmkdir -p %s\n' % ' '.join(concrete_output_dirs)) | |
990 | makefile.write('\t@mkdir -p "%s"\n' % | |
991 | '" "'.join(concrete_output_dirs)) | |
952 | 992 | |
953 | 993 | # The rule message and action have already had the necessary variable |
954 | 994 | # substitutions performed. |
955 | 995 | if message: |
956 | makefile.write('\t%s\n' % message) | |
996 | # Mark it with note: so Xcode picks it up in build output. | |
997 | makefile.write('\t@echo note: %s\n' % message) | |
957 | 998 | makefile.write('\t%s\n' % action) |
958 | 999 | |
959 | 1000 | makefile.close() |
1005 | 1046 | |
1006 | 1047 | # Extra rule inputs also go into the project file. Concrete outputs were |
1007 | 1048 | # already added when they were computed. |
1008 | for group in ['inputs', 'inputs_excluded']: | |
1049 | groups = ['inputs', 'inputs_excluded'] | |
1050 | if skip_excluded_files: | |
1051 | groups = [x for x in groups if not x.endswith('_excluded')] | |
1052 | for group in groups: | |
1009 | 1053 | for item in rule.get(group, []): |
1010 | 1054 | pbxp.AddOrGetFileInRootGroup(item) |
1011 | 1055 | |
1019 | 1063 | else: |
1020 | 1064 | pbxp.AddOrGetFileInRootGroup(source) |
1021 | 1065 | |
1022 | # Add "mac_bundle_resources" if it's a bundle of any type. | |
1066 | # Add "mac_bundle_resources", "mac_framework_headers", and | |
1067 | # "mac_framework_private_headers" if it's a bundle of any type. | |
1023 | 1068 | if is_bundle: |
1024 | 1069 | for resource in tgt_mac_bundle_resources: |
1025 | 1070 | (resource_root, resource_extension) = posixpath.splitext(resource) |
1027 | 1072 | AddResourceToTarget(resource, pbxp, xct) |
1028 | 1073 | else: |
1029 | 1074 | pbxp.AddOrGetFileInRootGroup(resource) |
1075 | ||
1076 | for header in spec.get('mac_framework_headers', []): | |
1077 | AddHeaderToTarget(header, pbxp, xct, True) | |
1078 | ||
1079 | for header in spec.get('mac_framework_private_headers', []): | |
1080 | AddHeaderToTarget(header, pbxp, xct, False) | |
1030 | 1081 | |
1031 | 1082 | # Add "copies". |
1032 | 1083 | for copy_group in spec.get('copies', []): |
1048 | 1099 | pbxcp.AddFile(file) |
1049 | 1100 | |
1050 | 1101 | # Excluded files can also go into the project file. |
1051 | for key in ['sources', 'mac_bundle_resources']: | |
1052 | excluded_key = key + '_excluded' | |
1053 | for item in spec.get(excluded_key, []): | |
1054 | pbxp.AddOrGetFileInRootGroup(item) | |
1102 | if not skip_excluded_files: | |
1103 | for key in ['sources', 'mac_bundle_resources', 'mac_framework_headers', | |
1104 | 'mac_framework_private_headers']: | |
1105 | excluded_key = key + '_excluded' | |
1106 | for item in spec.get(excluded_key, []): | |
1107 | pbxp.AddOrGetFileInRootGroup(item) | |
1055 | 1108 | |
1056 | 1109 | # So can "inputs" and "outputs" sections of "actions" groups. |
1110 | groups = ['inputs', 'inputs_excluded', 'outputs', 'outputs_excluded'] | |
1111 | if skip_excluded_files: | |
1112 | groups = [x for x in groups if not x.endswith('_excluded')] | |
1057 | 1113 | for action in spec.get('actions', []): |
1058 | groups = ['inputs', 'inputs_excluded', 'outputs', 'outputs_excluded'] | |
1059 | 1114 | for group in groups: |
1060 | 1115 | for item in action.get(group, []): |
1061 | 1116 | # Exclude anything in BUILT_PRODUCTS_DIR. They're products, not |
1066 | 1121 | for postbuild in spec.get('postbuilds', []): |
1067 | 1122 | action_string_sh = gyp.common.EncodePOSIXShellList(postbuild['action']) |
1068 | 1123 | script = 'exec ' + action_string_sh + '\nexit 1\n' |
1124 | ||
1125 | # Make the postbuild step depend on the output of ld or ar from this | |
1126 | # target. Apparently putting the script step after the link step isn't | |
1127 | # sufficient to ensure proper ordering in all cases. With an input | |
1128 | # declared but no outputs, the script step should run every time, as | |
1129 | # desired. | |
1069 | 1130 | ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({ |
1131 | 'inputPaths': ['$(BUILT_PRODUCTS_DIR)/$(EXECUTABLE_PATH)'], | |
1070 | 1132 | 'name': 'Postbuild "' + postbuild['postbuild_name'] + '"', |
1071 | 1133 | 'shellScript': script, |
1072 | 1134 | 'showEnvVarsInLog': 0, |
1097 | 1159 | xct.FrameworksPhase().AddFile(library) |
1098 | 1160 | # Add the library's directory to LIBRARY_SEARCH_PATHS if necessary. |
1099 | 1161 | # I wish Xcode handled this automatically. |
1100 | # TODO(mark): this logic isn't right. There are certain directories | |
1101 | # that are always searched, we should check to see if the library is | |
1102 | # in one of those directories, and if not, we should do the | |
1103 | # AppendBuildSetting thing. | |
1104 | if not posixpath.isabs(library) and not library.startswith('$'): | |
1105 | # TODO(mark): Need to check to see if library_dir is already in | |
1106 | # LIBRARY_SEARCH_PATHS. | |
1107 | library_dir = posixpath.dirname(library) | |
1108 | xct.AppendBuildSetting('LIBRARY_SEARCH_PATHS', library_dir) | |
1162 | library_dir = posixpath.dirname(library) | |
1163 | if library_dir not in xcode_standard_library_dirs and ( | |
1164 | not xct.HasBuildSetting(_library_search_paths_var) or | |
1165 | library_dir not in xct.GetBuildSetting(_library_search_paths_var)): | |
1166 | xct.AppendBuildSetting(_library_search_paths_var, library_dir) | |
1109 | 1167 | |
1110 | 1168 | for configuration_name in configuration_names: |
1111 | 1169 | configuration = spec['configurations'][configuration_name] |
1121 | 1179 | if 'xcode_settings' in configuration: |
1122 | 1180 | for xck, xcv in configuration['xcode_settings'].iteritems(): |
1123 | 1181 | xcbc.SetBuildSetting(xck, xcv) |
1182 | if 'xcode_config_file' in configuration: | |
1183 | config_ref = pbxp.AddOrGetFileInRootGroup( | |
1184 | configuration['xcode_config_file']) | |
1185 | xcbc.SetBaseConfiguration(config_ref) | |
1124 | 1186 | |
1125 | 1187 | build_files = [] |
1126 | 1188 | for build_file, build_file_dict in data.iteritems(): |
0 | 0 | #!/usr/bin/python |
1 | 1 | |
2 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
2 | # Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
3 | 3 | # Use of this source code is governed by a BSD-style license that can be |
4 | 4 | # found in the LICENSE file. |
5 | 5 | |
82 | 82 | 'sources', |
83 | 83 | 'suppress_wildcard', |
84 | 84 | 'target_name', |
85 | 'test', | |
86 | 85 | 'toolset', |
87 | 86 | 'toolsets', |
88 | 87 | 'type', |
93 | 92 | 'variables', |
94 | 93 | ] |
95 | 94 | non_configuration_keys = [] |
95 | ||
96 | # Keys that do not belong inside a configuration dictionary. | |
97 | invalid_configuration_keys = [ | |
98 | 'actions', | |
99 | 'all_dependent_settings', | |
100 | 'configurations', | |
101 | 'dependencies', | |
102 | 'direct_dependent_settings', | |
103 | 'libraries', | |
104 | 'link_settings', | |
105 | 'sources', | |
106 | 'target_name', | |
107 | 'type', | |
108 | ] | |
96 | 109 | |
97 | 110 | # Controls how the generator want the build file paths. |
98 | 111 | absolute_build_file_paths = False |
759 | 772 | # It's possible that condition[0] won't work in which case this |
760 | 773 | # attempt will raise its own IndexError. That's probably fine. |
761 | 774 | raise IndexError, conditions_key + ' ' + condition[0] + \ |
762 | ' must be length 2 or 3, not ' + len(condition) | |
775 | ' must be length 2 or 3, not ' + str(len(condition)) | |
763 | 776 | |
764 | 777 | [cond_expr, true_dict] = condition[0:2] |
765 | 778 | false_dict = None |
1783 | 1796 | for key in delete_keys: |
1784 | 1797 | del target_dict[key] |
1785 | 1798 | |
1799 | # Check the configurations to see if they contain invalid keys. | |
1800 | for configuration in target_dict['configurations'].keys(): | |
1801 | configuration_dict = target_dict['configurations'][configuration] | |
1802 | for key in configuration_dict.keys(): | |
1803 | if key in invalid_configuration_keys: | |
1804 | raise KeyError, ('%s not allowed in the %s configuration, found in ' | |
1805 | 'target %s' % (key, configuration, target)) | |
1806 | ||
1807 | ||
1786 | 1808 | |
1787 | 1809 | def ProcessListFiltersInDict(name, the_dict): |
1788 | 1810 | """Process regular expression and exclusion-based filters on lists. |
2078 | 2100 | TurnIntIntoStrInList(item) |
2079 | 2101 | |
2080 | 2102 | |
2103 | def VerifyNoCollidingTargets(targets): | |
2104 | """Verify that no two targets in the same directory share the same name. | |
2105 | ||
2106 | Arguments: | |
2107 | targets: A list of targets in the form 'path/to/file.gyp:target_name'. | |
2108 | """ | |
2109 | # Keep a dict going from 'subdirectory:target_name' to 'foo.gyp'. | |
2110 | used = {} | |
2111 | for target in targets: | |
2112 | # Separate out 'path/to/file.gyp, 'target_name' from | |
2113 | # 'path/to/file.gyp:target_name'. | |
2114 | path, name = target.rsplit(':', 1) | |
2115 | # Separate out 'path/to', 'file.gyp' from 'path/to/file.gyp'. | |
2116 | subdir, gyp = os.path.split(path) | |
2117 | # Use '.' for the current directory '', so that the error messages make | |
2118 | # more sense. | |
2119 | if not subdir: | |
2120 | subdir = '.' | |
2121 | # Prepare a key like 'path/to:target_name'. | |
2122 | key = subdir + ':' + name | |
2123 | if key in used: | |
2124 | # Complain if this target is already used. | |
2125 | raise Exception('Duplicate target name "%s" in directory "%s" used both ' | |
2126 | 'in "%s" and "%s".' % (name, subdir, gyp, used[key])) | |
2127 | used[key] = gyp | |
2128 | ||
2129 | ||
2081 | 2130 | def Load(build_files, variables, includes, depth, generator_input_info, check, |
2082 | 2131 | circular_check): |
2083 | 2132 | # Set up path_sections and non_configuration_keys with the default data plus |
2142 | 2191 | |
2143 | 2192 | [dependency_nodes, flat_list] = BuildDependencyList(targets) |
2144 | 2193 | |
2194 | # Check that no two targets in the same directory have the same name. | |
2195 | VerifyNoCollidingTargets(flat_list) | |
2196 | ||
2197 | ||
2145 | 2198 | # Handle dependent settings of various types. |
2146 | 2199 | for settings_type in ['all_dependent_settings', |
2147 | 2200 | 'direct_dependent_settings', |
0 | #!/usr/bin/python | |
1 | ||
2 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | import os | |
7 | import tempfile | |
8 | import shutil | |
9 | import subprocess | |
10 | ||
11 | def TestCommands(commands, files={}, env={}): | |
12 | """Run commands in a temporary directory, returning true if they all succeed. | |
13 | Return false on failures or if any commands produce output. | |
14 | ||
15 | Arguments: | |
16 | commands: an array of shell-interpretable commands, e.g. ['ls -l', 'pwd'] | |
17 | each will be expanded with Python %-expansion using env first. | |
18 | files: a dictionary mapping filename to contents; | |
19 | files will be created in the temporary directory before running | |
20 | the command. | |
21 | env: a dictionary of strings to expand commands with. | |
22 | """ | |
23 | tempdir = tempfile.mkdtemp() | |
24 | try: | |
25 | for name, contents in files.items(): | |
26 | f = open(os.path.join(tempdir, name), 'wb') | |
27 | f.write(contents) | |
28 | f.close() | |
29 | for command in commands: | |
30 | proc = subprocess.Popen(command % env, shell=True, | |
31 | stdout=subprocess.PIPE, | |
32 | stderr=subprocess.STDOUT, | |
33 | cwd=tempdir) | |
34 | output = proc.communicate()[0] | |
35 | if proc.returncode != 0 or output: | |
36 | return False | |
37 | return True | |
38 | finally: | |
39 | shutil.rmtree(tempdir) | |
40 | return False | |
41 | ||
42 | ||
43 | def TestArSupportsT(ar_command='ar', cc_command='cc'): | |
44 | """Test whether 'ar' supports the 'T' flag.""" | |
45 | return TestCommands(['%(cc)s -c test.c', | |
46 | '%(ar)s crsT test.a test.o', | |
47 | '%(cc)s test.a'], | |
48 | files={'test.c': 'int main(){}'}, | |
49 | env={'ar': ar_command, 'cc': cc_command}) | |
50 | ||
51 | ||
52 | def TestLinkerSupportsThreads(cc_command='cc'): | |
53 | """Test whether the linker supports the --threads flag.""" | |
54 | return TestCommands(['%(cc)s -Wl,--threads test.c'], | |
55 | files={'test.c': 'int main(){}'}, | |
56 | env={'cc': cc_command}) | |
57 | ||
58 | ||
59 | def TestLinkerSupportsICF(cc_command='cc'): | |
60 | """Test whether the linker supports identical code folding.""" | |
61 | return TestCommands(['%(cc)s -Wl,--icf=safe test.c'], | |
62 | files={'test.c': 'int main(){}'}, | |
63 | env={'cc': cc_command}) | |
64 | ||
65 | ||
66 | if __name__ == '__main__': | |
67 | # Run the various test functions and print the results. | |
68 | def RunTest(description, function, **kwargs): | |
69 | print "Testing " + description + ':', | |
70 | if function(**kwargs): | |
71 | print 'ok' | |
72 | else: | |
73 | print 'fail' | |
74 | RunTest("ar 'T' flag", TestArSupportsT) | |
75 | RunTest("ar 'T' flag with ccache", TestArSupportsT, cc_command='ccache cc') | |
76 | RunTest("ld --threads", TestLinkerSupportsThreads) |
656 | 656 | else: |
657 | 657 | value_to_print = value |
658 | 658 | |
659 | # PBXBuildFile's settings property is represented in the output as a dict, | |
660 | # but a hack here has it represented as a string. Arrange to strip off the | |
661 | # quotes so that it shows up in the output as expected. | |
662 | if key == 'settings' and isinstance(self, PBXBuildFile): | |
663 | strip_value_quotes = True | |
664 | else: | |
665 | strip_value_quotes = False | |
666 | ||
659 | 667 | # In another one-off, let's set flatten_list on buildSettings properties |
660 | 668 | # of XCBuildConfiguration objects, because that's how Xcode treats them. |
661 | 669 | if key == 'buildSettings' and isinstance(self, XCBuildConfiguration): |
664 | 672 | flatten_list = False |
665 | 673 | |
666 | 674 | try: |
667 | printable += self._XCPrintableValue(tabs, key, flatten_list) + ' = ' + \ | |
668 | self._XCPrintableValue(tabs, value_to_print, flatten_list) + \ | |
669 | ';' + after_kv | |
675 | printable_key = self._XCPrintableValue(tabs, key, flatten_list) | |
676 | printable_value = self._XCPrintableValue(tabs, value_to_print, | |
677 | flatten_list) | |
678 | if strip_value_quotes and len(printable_value) > 1 and \ | |
679 | printable_value[0] == '"' and printable_value[-1] == '"': | |
680 | printable_value = printable_value[1:-1] | |
681 | printable += printable_key + ' = ' + printable_value + ';' + after_kv | |
670 | 682 | except TypeError, e: |
671 | 683 | gyp.common.ExceptionAppend(e, |
672 | 684 | 'while printing key "%s"' % key) |
1450 | 1462 | 'm': 'sourcecode.c.objc', |
1451 | 1463 | 'mm': 'sourcecode.cpp.objcpp', |
1452 | 1464 | 'nib': 'wrapper.nib', |
1465 | 'o': 'compiled.mach-o.objfile', | |
1453 | 1466 | 'pdf': 'image.pdf', |
1454 | 1467 | 'pl': 'text.script.perl', |
1455 | 1468 | 'plist': 'text.plist.xml', |
1523 | 1536 | if key in self._properties['buildSettings']: |
1524 | 1537 | del self._properties['buildSettings'][key] |
1525 | 1538 | |
1539 | def SetBaseConfiguration(self, value): | |
1540 | self._properties['baseConfigurationReference'] = value | |
1526 | 1541 | |
1527 | 1542 | class XCConfigurationList(XCObject): |
1528 | 1543 | # _configs is the default list of configurations. |
1631 | 1646 | for configuration in self._properties['buildConfigurations']: |
1632 | 1647 | configuration.DelBuildSetting(key) |
1633 | 1648 | |
1649 | def SetBaseConfiguration(self, value): | |
1650 | """Sets the build configuration in all child XCBuildConfiguration objects. | |
1651 | """ | |
1652 | ||
1653 | for configuration in self._properties['buildConfigurations']: | |
1654 | configuration.SetBaseConfiguration(value) | |
1655 | ||
1634 | 1656 | |
1635 | 1657 | class PBXBuildFile(XCObject): |
1636 | 1658 | _schema = XCObject._schema.copy() |
1637 | 1659 | _schema.update({ |
1638 | 'fileRef': [0, XCFileLikeElement, 0, 1], | |
1660 | 'fileRef': [0, XCFileLikeElement, 0, 1], | |
1661 | 'settings': [0, str, 0, 0], # hack, it's a dict | |
1639 | 1662 | }) |
1640 | 1663 | |
1641 | 1664 | # Weird output rules for PBXBuildFile. |
1780 | 1803 | self.AppendProperty('files', pbxbuildfile) |
1781 | 1804 | self._AddBuildFileToDicts(pbxbuildfile, path) |
1782 | 1805 | |
1783 | def AddFile(self, path): | |
1806 | def AddFile(self, path, settings=None): | |
1784 | 1807 | (file_group, hierarchical) = self.FileGroup(path) |
1785 | 1808 | file_ref = file_group.AddOrGetFileByPath(path, hierarchical) |
1786 | 1809 | |
1793 | 1816 | self._AddBuildFileToDicts(pbxbuildfile, path) |
1794 | 1817 | else: |
1795 | 1818 | # Add a new PBXBuildFile to get file_ref into the phase. |
1796 | pbxbuildfile = PBXBuildFile({'fileRef': file_ref}) | |
1819 | if settings is None: | |
1820 | pbxbuildfile = PBXBuildFile({'fileRef': file_ref}) | |
1821 | else: | |
1822 | pbxbuildfile = PBXBuildFile({'fileRef': file_ref, 'settings': settings}) | |
1797 | 1823 | self.AppendBuildFile(pbxbuildfile, path) |
1798 | 1824 | |
1799 | 1825 | |
1834 | 1860 | return 'Frameworks' |
1835 | 1861 | |
1836 | 1862 | def FileGroup(self, path): |
1837 | return (self.PBXProjectAncestor().FrameworksGroup(), False) | |
1863 | (root, ext) = posixpath.splitext(path) | |
1864 | if ext != '': | |
1865 | ext = ext[1:].lower() | |
1866 | if ext == 'o': | |
1867 | # .o files are added to Xcode Frameworks phases, but conceptually aren't | |
1868 | # frameworks, they're more like sources or intermediates. Redirect them | |
1869 | # to show up in one of those other groups. | |
1870 | return self.PBXProjectAncestor().RootGroupForPath(path) | |
1871 | else: | |
1872 | return (self.PBXProjectAncestor().FrameworksGroup(), False) | |
1838 | 1873 | |
1839 | 1874 | |
1840 | 1875 | class PBXShellScriptBuildPhase(XCBuildPhase): |
2160 | 2195 | # filetype : used for explicitFileType in the project file |
2161 | 2196 | # prefix : the prefix for the file name |
2162 | 2197 | # suffix : the suffix for the filen ame |
2163 | # set_xc_exe_prefix : bool to say if EXECUTABLE_PREFIX should be set to the | |
2164 | # prefix value. | |
2165 | 2198 | _product_filetypes = { |
2166 | 2199 | 'com.apple.product-type.application': ['wrapper.application', |
2167 | '', '.app', False], | |
2200 | '', '.app'], | |
2168 | 2201 | 'com.apple.product-type.bundle': ['wrapper.cfbundle', |
2169 | '', '.bundle', False], | |
2202 | '', '.bundle'], | |
2170 | 2203 | 'com.apple.product-type.framework': ['wrapper.framework', |
2171 | '', '.framework', False], | |
2204 | '', '.framework'], | |
2172 | 2205 | 'com.apple.product-type.library.dynamic': ['compiled.mach-o.dylib', |
2173 | 'lib', '.dylib', True], | |
2206 | 'lib', '.dylib'], | |
2174 | 2207 | 'com.apple.product-type.library.static': ['archive.ar', |
2175 | 'lib', '.a', False], | |
2208 | 'lib', '.a'], | |
2176 | 2209 | 'com.apple.product-type.tool': ['compiled.mach-o.executable', |
2177 | '', '', False], | |
2210 | '', ''], | |
2211 | 'com.googlecode.gyp.xcode.bundle': ['compiled.mach-o.dylib', | |
2212 | '', '.so'], | |
2178 | 2213 | } |
2179 | 2214 | |
2180 | 2215 | def __init__(self, properties=None, id=None, parent=None, |
2192 | 2227 | products_group = pbxproject.ProductsGroup() |
2193 | 2228 | |
2194 | 2229 | if products_group != None: |
2195 | (filetype, prefix, suffix, set_xc_exe_prefix) = \ | |
2230 | (filetype, prefix, suffix) = \ | |
2196 | 2231 | self._product_filetypes[self._properties['productType']] |
2232 | # Xcode does not have a distinct type for loadable modules that are | |
2233 | # pure BSD targets (not in a bundle wrapper). GYP allows such modules | |
2234 | # to be specified by setting a target type to loadable_module without | |
2235 | # having mac_bundle set. These are mapped to the pseudo-product type | |
2236 | # com.googlecode.gyp.xcode.bundle. | |
2237 | # | |
2238 | # By picking up this special type and converting it to a dynamic | |
2239 | # library (com.apple.product-type.library.dynamic) with fix-ups, | |
2240 | # single-file loadable modules can be produced. | |
2241 | # | |
2242 | # MACH_O_TYPE is changed to mh_bundle to produce the proper file type | |
2243 | # (as opposed to mh_dylib). In order for linking to succeed, | |
2244 | # DYLIB_CURRENT_VERSION and DYLIB_COMPATIBILITY_VERSION must be | |
2245 | # cleared. They are meaningless for type mh_bundle. | |
2246 | # | |
2247 | # Finally, the .so extension is forcibly applied over the default | |
2248 | # (.dylib), unless another forced extension is already selected. | |
2249 | # .dylib is plainly wrong, and .bundle is used by loadable_modules in | |
2250 | # bundle wrappers (com.apple.product-type.bundle). .so seems an odd | |
2251 | # choice because it's used as the extension on many other systems that | |
2252 | # don't distinguish between linkable shared libraries and non-linkable | |
2253 | # loadable modules, but there's precedent: Python loadable modules on | |
2254 | # Mac OS X use an .so extension. | |
2255 | if self._properties['productType'] == 'com.googlecode.gyp.xcode.bundle': | |
2256 | self._properties['productType'] = \ | |
2257 | 'com.apple.product-type.library.dynamic' | |
2258 | self.SetBuildSetting('MACH_O_TYPE', 'mh_bundle') | |
2259 | self.SetBuildSetting('DYLIB_CURRENT_VERSION', '') | |
2260 | self.SetBuildSetting('DYLIB_COMPATIBILITY_VERSION', '') | |
2261 | if force_extension == None: | |
2262 | force_extension = suffix[1:] | |
2197 | 2263 | |
2198 | 2264 | if force_extension is not None: |
2199 | 2265 | # If it's a wrapper (bundle), set WRAPPER_EXTENSION. |
2266 | 2332 | the_phase = phase |
2267 | 2333 | |
2268 | 2334 | return the_phase |
2335 | ||
2336 | def HeadersPhase(self): | |
2337 | headers_phase = self.GetBuildPhaseByType(PBXHeadersBuildPhase) | |
2338 | if headers_phase == None: | |
2339 | headers_phase = PBXHeadersBuildPhase() | |
2340 | ||
2341 | # The headers phase should come before the resources, sources, and | |
2342 | # frameworks phases, if any. | |
2343 | insert_at = len(self._properties['buildPhases']) | |
2344 | for index in xrange(0, len(self._properties['buildPhases'])): | |
2345 | phase = self._properties['buildPhases'][index] | |
2346 | if isinstance(phase, PBXResourcesBuildPhase) or \ | |
2347 | isinstance(phase, PBXSourcesBuildPhase) or \ | |
2348 | isinstance(phase, PBXFrameworksBuildPhase): | |
2349 | insert_at = index | |
2350 | break | |
2351 | ||
2352 | self._properties['buildPhases'].insert(insert_at, headers_phase) | |
2353 | headers_phase.parent = self | |
2354 | ||
2355 | return headers_phase | |
2269 | 2356 | |
2270 | 2357 | def ResourcesPhase(self): |
2271 | 2358 | resources_phase = self.GetBuildPhaseByType(PBXResourcesBuildPhase) |
2678 | 2765 | 'rootObject': [0, PBXProject, 1, 1], |
2679 | 2766 | }) |
2680 | 2767 | |
2768 | def SetXcodeVersion(self, version): | |
2769 | version_to_object_version = { | |
2770 | '2.4': 45, | |
2771 | '3.0': 45, | |
2772 | '3.1': 45, | |
2773 | '3.2': 46, | |
2774 | } | |
2775 | if not version in version_to_object_version: | |
2776 | supported_str = ', '.join(sorted(version_to_object_version.keys())) | |
2777 | raise Exception( | |
2778 | 'Unsupported Xcode version %s (supported: %s)' % | |
2779 | ( version, supported_str ) ) | |
2780 | compatibility_version = 'Xcode %s' % version | |
2781 | self._properties['rootObject'].SetProperty('compatibilityVersion', | |
2782 | compatibility_version) | |
2783 | self.SetProperty('objectVersion', version_to_object_version[version]); | |
2784 | ||
2681 | 2785 | def ComputeIDs(self, recursive=True, overwrite=True, hash=None): |
2682 | 2786 | # Although XCProjectFile is implemented here as an XCObject, it's not a |
2683 | 2787 | # proper object in the Xcode sense, and it certainly doesn't have its own |
0 | #!/usr/bin/python | |
1 | # Copyright (c) 2011 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 | """Applies a fix to CR LF TAB handling in xml.dom. | |
6 | ||
7 | Fixes this: http://code.google.com/p/chromium/issues/detail?id=76293 | |
8 | Working around this: http://bugs.python.org/issue5752 | |
9 | TODO(bradnelson): Consider dropping this when we drop XP support. | |
10 | """ | |
11 | ||
12 | ||
13 | import xml.dom.minidom | |
14 | ||
15 | ||
16 | def _Replacement_write_data(writer, data, is_attrib=False): | |
17 | """Writes datachars to writer.""" | |
18 | data = data.replace("&", "&").replace("<", "<") | |
19 | data = data.replace("\"", """).replace(">", ">") | |
20 | if is_attrib: | |
21 | data = data.replace( | |
22 | "\r", "
").replace( | |
23 | "\n", "
").replace( | |
24 | "\t", "	") | |
25 | writer.write(data) | |
26 | ||
27 | ||
28 | def _Replacement_writexml(self, writer, indent="", addindent="", newl=""): | |
29 | # indent = current indentation | |
30 | # addindent = indentation to add to higher levels | |
31 | # newl = newline string | |
32 | writer.write(indent+"<" + self.tagName) | |
33 | ||
34 | attrs = self._get_attributes() | |
35 | a_names = attrs.keys() | |
36 | a_names.sort() | |
37 | ||
38 | for a_name in a_names: | |
39 | writer.write(" %s=\"" % a_name) | |
40 | _Replacement_write_data(writer, attrs[a_name].value, is_attrib=True) | |
41 | writer.write("\"") | |
42 | if self.childNodes: | |
43 | writer.write(">%s" % newl) | |
44 | for node in self.childNodes: | |
45 | node.writexml(writer, indent + addindent, addindent, newl) | |
46 | writer.write("%s</%s>%s" % (indent, self.tagName, newl)) | |
47 | else: | |
48 | writer.write("/>%s" % newl) | |
49 | ||
50 | ||
51 | class XmlFix(object): | |
52 | """Object to manage temporary patching of xml.dom.minidom.""" | |
53 | ||
54 | def __init__(self): | |
55 | # Preserve current xml.dom.minidom functions. | |
56 | self.write_data = xml.dom.minidom._write_data | |
57 | self.writexml = xml.dom.minidom.Element.writexml | |
58 | # Inject replacement versions of a function and a method. | |
59 | xml.dom.minidom._write_data = _Replacement_write_data | |
60 | xml.dom.minidom.Element.writexml = _Replacement_writexml | |
61 | ||
62 | def Cleanup(self): | |
63 | if self.write_data: | |
64 | xml.dom.minidom._write_data = self.write_data | |
65 | xml.dom.minidom.Element.writexml = self.writexml | |
66 | self.write_data = None | |
67 | ||
68 | def __del__(self): | |
69 | self.Cleanup() |
11 | 11 | import os |
12 | 12 | import TestGyp |
13 | 13 | |
14 | test = TestGyp.TestGyp() | |
14 | test = TestGyp.TestGyp(workdir='workarea_all') | |
15 | 15 | |
16 | 16 | test.run_gyp('actions.gyp', chdir='src') |
17 | 17 |
9 | 9 | |
10 | 10 | import TestGyp |
11 | 11 | |
12 | test = TestGyp.TestGyp() | |
12 | test = TestGyp.TestGyp(workdir='workarea_default') | |
13 | 13 | |
14 | 14 | test.run_gyp('actions.gyp', chdir='src') |
15 | 15 |
0 | #!/usr/bin/env python | |
0 | #!/usr/bin/env python | |
1 | 1 | |
2 | 2 | # Copyright (c) 2009 Google Inc. All rights reserved. |
3 | 3 | # Use of this source code is governed by a BSD-style license that can be |
4 | 4 | # found in the LICENSE file. |
5 | ||
6 | """ | |
7 | Verifies behavior for different action configuration errors: | |
8 | exit status of 1, and the expected error message must be in stderr. | |
9 | """ | |
10 | ||
11 | import TestGyp | |
12 | ||
13 | test = TestGyp.TestGyp() | |
14 | ||
15 | ||
16 | test.run_gyp('action_missing_name.gyp', chdir='src', status=1, stderr=None) | |
17 | expect = [ | |
18 | "Anonymous action in target broken_actions2. An action must have an 'action_name' field.", | |
19 | ] | |
20 | test.must_contain_all_lines(test.stderr(), expect) | |
21 | ||
22 | ||
23 | test.pass_test() | |
5 | ||
6 | """ | |
7 | Verifies behavior for different action configuration errors: | |
8 | exit status of 1, and the expected error message must be in stderr. | |
9 | """ | |
10 | ||
11 | import TestGyp | |
12 | ||
13 | test = TestGyp.TestGyp(workdir='workarea_errors') | |
14 | ||
15 | ||
16 | test.run_gyp('action_missing_name.gyp', chdir='src', status=1, stderr=None) | |
17 | expect = [ | |
18 | "Anonymous action in target broken_actions2. An action must have an 'action_name' field.", | |
19 | ] | |
20 | test.must_contain_all_lines(test.stderr(), expect) | |
21 | ||
22 | ||
23 | test.pass_test() |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Verifies two actions can be attached to the same input files. | |
8 | """ | |
9 | ||
10 | import TestGyp | |
11 | ||
12 | test = TestGyp.TestGyp() | |
13 | ||
14 | test.run_gyp('actions.gyp', chdir='src') | |
15 | ||
16 | test.relocate('src', 'relocate/src') | |
17 | ||
18 | # Test that two actions can be attached to the same inputs. | |
19 | test.build('actions.gyp', test.ALL, chdir='relocate/src') | |
20 | test.must_contain('relocate/src/output1.txt', 'hello there') | |
21 | test.must_contain('relocate/src/output2.txt', 'hello there') | |
22 | test.must_contain('relocate/src/output3.txt', 'hello there') | |
23 | test.must_contain('relocate/src/output4.txt', 'hello there') | |
24 | ||
25 | # Test that process_outputs_as_sources works in conjuction with merged | |
26 | # actions. | |
27 | test.run_built_executable( | |
28 | 'multiple_action_source_filter', | |
29 | chdir='relocate/src', | |
30 | stdout=( | |
31 | '{\n' | |
32 | 'bar\n' | |
33 | 'car\n' | |
34 | 'dar\n' | |
35 | 'ear\n' | |
36 | '}\n' | |
37 | ), | |
38 | ) | |
39 | ||
40 | ||
41 | test.pass_test() |
0 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'variables': { | |
6 | # Have a long string so that actions will exceed xp 512 character | |
7 | # command limit on xp. | |
8 | 'long_string': | |
9 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
10 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
11 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
12 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
13 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
14 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
15 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
16 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
17 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
18 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
19 | 'abcdefghijklmnopqrstuvwxyz0123456789' | |
20 | }, | |
21 | 'targets': [ | |
22 | { | |
23 | 'target_name': 'multiple_action_target', | |
24 | 'type': 'none', | |
25 | 'actions': [ | |
26 | { | |
27 | 'action_name': 'action1', | |
28 | 'inputs': [ | |
29 | 'copy.py', | |
30 | 'input.txt', | |
31 | ], | |
32 | 'outputs': [ | |
33 | 'output1.txt', | |
34 | ], | |
35 | 'action': [ | |
36 | 'python', '<@(_inputs)', '<(_outputs)', '<(long_string)', | |
37 | ], | |
38 | # Allows the test to run without hermetic cygwin on windows. | |
39 | 'msvs_cygwin_shell': 0, | |
40 | }, | |
41 | { | |
42 | 'action_name': 'action2', | |
43 | 'inputs': [ | |
44 | 'copy.py', | |
45 | 'input.txt', | |
46 | ], | |
47 | 'outputs': [ | |
48 | 'output2.txt', | |
49 | ], | |
50 | 'action': [ | |
51 | 'python', '<@(_inputs)', '<(_outputs)', '<(long_string)', | |
52 | ], | |
53 | # Allows the test to run without hermetic cygwin on windows. | |
54 | 'msvs_cygwin_shell': 0, | |
55 | }, | |
56 | { | |
57 | 'action_name': 'action3', | |
58 | 'inputs': [ | |
59 | 'copy.py', | |
60 | 'input.txt', | |
61 | ], | |
62 | 'outputs': [ | |
63 | 'output3.txt', | |
64 | ], | |
65 | 'action': [ | |
66 | 'python', '<@(_inputs)', '<(_outputs)', '<(long_string)', | |
67 | ], | |
68 | # Allows the test to run without hermetic cygwin on windows. | |
69 | 'msvs_cygwin_shell': 0, | |
70 | }, | |
71 | { | |
72 | 'action_name': 'action4', | |
73 | 'inputs': [ | |
74 | 'copy.py', | |
75 | 'input.txt', | |
76 | ], | |
77 | 'outputs': [ | |
78 | 'output4.txt', | |
79 | ], | |
80 | 'action': [ | |
81 | 'python', '<@(_inputs)', '<(_outputs)', '<(long_string)', | |
82 | ], | |
83 | # Allows the test to run without hermetic cygwin on windows. | |
84 | 'msvs_cygwin_shell': 0, | |
85 | }, | |
86 | ], | |
87 | }, | |
88 | { | |
89 | 'target_name': 'multiple_action_source_filter', | |
90 | 'type': 'executable', | |
91 | 'sources': [ | |
92 | 'main.c', | |
93 | # TODO(bradnelson): add foo.c here once this issue is fixed: | |
94 | # http://code.google.com/p/gyp/issues/detail?id=175 | |
95 | ], | |
96 | 'actions': [ | |
97 | { | |
98 | 'action_name': 'action1', | |
99 | 'inputs': [ | |
100 | 'foo.c', | |
101 | 'filter.py', | |
102 | ], | |
103 | 'outputs': [ | |
104 | 'output1.c', | |
105 | ], | |
106 | 'process_outputs_as_sources': 1, | |
107 | 'action': [ | |
108 | 'python', 'filter.py', 'foo', 'bar', 'foo.c', '<(_outputs)', | |
109 | ], | |
110 | # Allows the test to run without hermetic cygwin on windows. | |
111 | 'msvs_cygwin_shell': 0, | |
112 | }, | |
113 | { | |
114 | 'action_name': 'action2', | |
115 | 'inputs': [ | |
116 | 'foo.c', | |
117 | 'filter.py', | |
118 | ], | |
119 | 'outputs': [ | |
120 | 'output2.c', | |
121 | ], | |
122 | 'process_outputs_as_sources': 1, | |
123 | 'action': [ | |
124 | 'python', 'filter.py', 'foo', 'car', 'foo.c', '<(_outputs)', | |
125 | ], | |
126 | # Allows the test to run without hermetic cygwin on windows. | |
127 | 'msvs_cygwin_shell': 0, | |
128 | }, | |
129 | { | |
130 | 'action_name': 'action3', | |
131 | 'inputs': [ | |
132 | 'foo.c', | |
133 | 'filter.py', | |
134 | ], | |
135 | 'outputs': [ | |
136 | 'output3.c', | |
137 | ], | |
138 | 'process_outputs_as_sources': 1, | |
139 | 'action': [ | |
140 | 'python', 'filter.py', 'foo', 'dar', 'foo.c', '<(_outputs)', | |
141 | ], | |
142 | # Allows the test to run without hermetic cygwin on windows. | |
143 | 'msvs_cygwin_shell': 0, | |
144 | }, | |
145 | { | |
146 | 'action_name': 'action4', | |
147 | 'inputs': [ | |
148 | 'foo.c', | |
149 | 'filter.py', | |
150 | ], | |
151 | 'outputs': [ | |
152 | 'output4.c', | |
153 | ], | |
154 | 'process_outputs_as_sources': 1, | |
155 | 'action': [ | |
156 | 'python', 'filter.py', 'foo', 'ear', 'foo.c', '<(_outputs)', | |
157 | ], | |
158 | # Allows the test to run without hermetic cygwin on windows. | |
159 | 'msvs_cygwin_shell': 0, | |
160 | }, | |
161 | ], | |
162 | }, | |
163 | ], | |
164 | } |
0 | #!/usr/bin/python | |
1 | # Copyright (c) 2011 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 | import shutil | |
6 | import sys | |
7 | ||
8 | shutil.copyfile(sys.argv[1], sys.argv[2]) |
0 | #!/usr/bin/python | |
1 | # Copyright (c) 2011 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 | ||
6 | import sys | |
7 | ||
8 | data = open(sys.argv[3], 'r').read() | |
9 | fh = open(sys.argv[4], 'w') | |
10 | fh.write(data.replace(sys.argv[1], sys.argv[2])) | |
11 | fh.close() |
0 | /* | |
1 | * Copyright (c) 2011 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 | ||
6 | #include <stdio.h> | |
7 | ||
8 | void foo(void) { | |
9 | printf("foo\n"); | |
10 | } |
0 | hello there |
0 | /* | |
1 | * Copyright (c) 2011 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 | ||
6 | #include <stdio.h> | |
7 | ||
8 | void bar(void); | |
9 | void car(void); | |
10 | void dar(void); | |
11 | void ear(void); | |
12 | ||
13 | int main() { | |
14 | printf("{\n"); | |
15 | bar(); | |
16 | car(); | |
17 | dar(); | |
18 | ear(); | |
19 | printf("}\n"); | |
20 | return 0; | |
21 | } |
0 | /* Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | * Use of this source code is governed by a BSD-style license that can be | |
2 | * found in the LICENSE file. */ | |
3 | ||
4 | #include <stdio.h> | |
5 | ||
6 | int main(int argc, char *argv[]) | |
7 | { | |
8 | #ifdef __OPTIMIZE__ | |
9 | printf("Using an optimization flag\n"); | |
10 | #else | |
11 | printf("Using no optimization flag\n"); | |
12 | #endif | |
13 | return 0; | |
14 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'cflags', | |
8 | 'type': 'executable', | |
9 | 'opt': '-Os', | |
10 | 'sources': [ | |
11 | 'cflags.c', | |
12 | ], | |
13 | }, | |
14 | ], | |
15 | } |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Verifies build of an executable with C++ define specified by a gyp define, and | |
8 | the use of the environment during regeneration when the gyp file changes. | |
9 | """ | |
10 | ||
11 | import os | |
12 | import TestGyp | |
13 | ||
14 | env_stack = [] | |
15 | ||
16 | ||
17 | def PushEnv(): | |
18 | env_copy = os.environ.copy() | |
19 | env_stack.append(env_copy) | |
20 | ||
21 | def PopEnv(): | |
22 | os.eniron=env_stack.pop() | |
23 | ||
24 | # Regenerating build files when a gyp file changes is currently only supported | |
25 | # by the make generator. | |
26 | test = TestGyp.TestGyp(formats=['make']) | |
27 | ||
28 | try: | |
29 | PushEnv() | |
30 | os.environ['CFLAGS'] = '-O0' | |
31 | test.run_gyp('cflags.gyp') | |
32 | finally: | |
33 | # We clear the environ after calling gyp. When the auto-regeneration happens, | |
34 | # the same define should be reused anyway. Reset to empty string first in | |
35 | # case the platform doesn't support unsetenv. | |
36 | PopEnv() | |
37 | ||
38 | test.build('cflags.gyp') | |
39 | ||
40 | expect = """\ | |
41 | Using no optimization flag | |
42 | """ | |
43 | test.run_built_executable('cflags', stdout=expect) | |
44 | ||
45 | test.sleep() | |
46 | ||
47 | try: | |
48 | PushEnv() | |
49 | os.environ['CFLAGS'] = '-O2' | |
50 | test.run_gyp('cflags.gyp') | |
51 | finally: | |
52 | # We clear the environ after calling gyp. When the auto-regeneration happens, | |
53 | # the same define should be reused anyway. Reset to empty string first in | |
54 | # case the platform doesn't support unsetenv. | |
55 | PopEnv() | |
56 | ||
57 | test.build('cflags.gyp') | |
58 | ||
59 | expect = """\ | |
60 | Using an optimization flag | |
61 | """ | |
62 | test.run_built_executable('cflags', stdout=expect) | |
63 | ||
64 | test.pass_test() |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'actions': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'all_dependent_settings': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'configurations': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'dependencies': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'direct_dependent_settings': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Verifies build of an executable in three different configurations. | |
8 | """ | |
9 | ||
10 | import TestGyp | |
11 | ||
12 | # Keys that do not belong inside a configuration dictionary. | |
13 | invalid_configuration_keys = [ | |
14 | 'actions', | |
15 | 'all_dependent_settings', | |
16 | 'configurations', | |
17 | 'dependencies', | |
18 | 'direct_dependent_settings', | |
19 | 'libraries', | |
20 | 'link_settings', | |
21 | 'sources', | |
22 | 'target_name', | |
23 | 'type', | |
24 | ] | |
25 | ||
26 | test = TestGyp.TestGyp() | |
27 | ||
28 | if test.format == 'scons': | |
29 | test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n') | |
30 | ||
31 | for test_key in invalid_configuration_keys: | |
32 | test.run_gyp('%s.gyp' % test_key, status=1, stderr=None) | |
33 | expect = ['%s not allowed in the Debug configuration, found in target ' | |
34 | '%s.gyp:configurations#target' % (test_key, test_key)] | |
35 | test.must_contain_all_lines(test.stderr(), expect) | |
36 | ||
37 | test.pass_test() |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'libraries': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'link_settings': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'sources': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'target_name': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'configurations', | |
8 | 'type': 'none', | |
9 | 'configurations': { | |
10 | 'Debug': { | |
11 | 'type': [ | |
12 | ], | |
13 | }, | |
14 | } | |
15 | }, | |
16 | ], | |
17 | } |
0 | 0 | #include <stdio.h> |
1 | 1 | |
2 | extern void func1(void); | |
3 | ||
4 | int main(int argc, char *argv[]) { | |
5 | printf("hello from link1\n"); | |
6 | func1(); | |
7 | return 0; | |
2 | void func1(void) { | |
3 | printf("hello from func1\n"); | |
8 | 4 | } |
0 | 0 | #include <stdio.h> |
1 | 1 | |
2 | void func1(void) { | |
3 | printf("hello from func1\n"); | |
2 | extern void func1(void); | |
3 | ||
4 | int main(int argc, char *argv[]) { | |
5 | printf("hello from link1\n"); | |
6 | func1(); | |
7 | return 0; | |
4 | 8 | } |
0 | /* Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | * Use of this source code is governed by a BSD-style license that can be | |
2 | * found in the LICENSE file. */ | |
3 | ||
4 | #include <stdio.h> | |
5 | ||
6 | int main(int argc, char *argv[]) | |
7 | { | |
8 | #ifdef __OPTIMIZE__ | |
9 | printf("Using an optimization flag\n"); | |
10 | #else | |
11 | printf("Using no optimization flag\n"); | |
12 | #endif | |
13 | return 0; | |
14 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'cxxflags', | |
8 | 'type': 'executable', | |
9 | 'opt': '-Os', | |
10 | 'sources': [ | |
11 | 'cxxflags.cc', | |
12 | ], | |
13 | }, | |
14 | ], | |
15 | } |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Verifies build of an executable with C++ define specified by a gyp define, and | |
8 | the use of the environment during regeneration when the gyp file changes. | |
9 | """ | |
10 | ||
11 | import os | |
12 | import TestGyp | |
13 | ||
14 | env_stack = [] | |
15 | ||
16 | ||
17 | def PushEnv(): | |
18 | env_copy = os.environ.copy() | |
19 | env_stack.append(env_copy) | |
20 | ||
21 | def PopEnv(): | |
22 | os.eniron=env_stack.pop() | |
23 | ||
24 | # Regenerating build files when a gyp file changes is currently only supported | |
25 | # by the make generator. | |
26 | test = TestGyp.TestGyp(formats=['make']) | |
27 | ||
28 | try: | |
29 | PushEnv() | |
30 | os.environ['CXXFLAGS'] = '-O0' | |
31 | test.run_gyp('cxxflags.gyp') | |
32 | finally: | |
33 | # We clear the environ after calling gyp. When the auto-regeneration happens, | |
34 | # the same define should be reused anyway. Reset to empty string first in | |
35 | # case the platform doesn't support unsetenv. | |
36 | PopEnv() | |
37 | ||
38 | test.build('cxxflags.gyp') | |
39 | ||
40 | expect = """\ | |
41 | Using no optimization flag | |
42 | """ | |
43 | test.run_built_executable('cxxflags', stdout=expect) | |
44 | ||
45 | test.sleep() | |
46 | ||
47 | try: | |
48 | PushEnv() | |
49 | os.environ['CXXFLAGS'] = '-O2' | |
50 | test.run_gyp('cxxflags.gyp') | |
51 | finally: | |
52 | # We clear the environ after calling gyp. When the auto-regeneration happens, | |
53 | # the same define should be reused anyway. Reset to empty string first in | |
54 | # case the platform doesn't support unsetenv. | |
55 | PopEnv() | |
56 | ||
57 | test.build('cxxflags.gyp') | |
58 | ||
59 | expect = """\ | |
60 | Using an optimization flag | |
61 | """ | |
62 | test.run_built_executable('cxxflags', stdout=expect) | |
63 | ||
64 | test.pass_test() |
15 | 15 | |
16 | 16 | # Tests string literals, percents, and backslash escapes. |
17 | 17 | try: |
18 | os.environ['GYP_DEFINES'] = \ | |
19 | """test_format='%s\\n' test_args='"Simple test of %s with a literal"'""" | |
18 | os.environ['GYP_DEFINES'] = ( | |
19 | r"""test_format='\n%s\n' """ | |
20 | r"""test_args='"Simple test of %s with a literal"'""") | |
20 | 21 | test.run_gyp('defines-escaping.gyp') |
21 | 22 | finally: |
22 | 23 | del os.environ['GYP_DEFINES'] |
23 | 24 | |
24 | 25 | test.build('defines-escaping.gyp') |
25 | 26 | |
26 | expect = """\ | |
27 | expect = """ | |
27 | 28 | Simple test of %s with a literal |
28 | 29 | """ |
29 | 30 | test.run_built_executable('defines_escaping', stdout=expect) |
32 | 33 | # Test multiple comma-and-space-separated string literals. |
33 | 34 | try: |
34 | 35 | os.environ['GYP_DEFINES'] = \ |
35 | """test_format='%s and %s\\n' test_args='"foo", "bar"'""" | |
36 | r"""test_format='\n%s and %s\n' test_args='"foo", "bar"'""" | |
36 | 37 | test.run_gyp('defines-escaping.gyp') |
37 | 38 | finally: |
38 | 39 | del os.environ['GYP_DEFINES'] |
41 | 42 | test.touch('defines-escaping.c') |
42 | 43 | test.build('defines-escaping.gyp') |
43 | 44 | |
44 | expect = """\ | |
45 | expect = """ | |
45 | 46 | foo and bar |
46 | 47 | """ |
47 | 48 | test.run_built_executable('defines_escaping', stdout=expect) |
49 | 50 | |
50 | 51 | # Test string literals containing quotes. |
51 | 52 | try: |
52 | os.environ['GYP_DEFINES'] = \ | |
53 | ("""test_format='%s %s %s %s %s\\n' """ + | |
54 | """test_args='"\\"These,\\"",""" + | |
55 | """ "\\"words,\\"",""" | |
56 | """ "\\"are,\\"",""" + | |
57 | """ "\\"in,\\"",""" + | |
58 | """ "\\"quotes.\\""'""") | |
53 | os.environ['GYP_DEFINES'] = ( | |
54 | r"""test_format='\n%s %s %s %s %s\n' """ | |
55 | r"""test_args='"\"These,\"",""" | |
56 | r""" "\"words,\"",""" | |
57 | r""" "\"are,\"",""" | |
58 | r""" "\"in,\"",""" | |
59 | r""" "\"quotes.\""'""") | |
59 | 60 | test.run_gyp('defines-escaping.gyp') |
60 | 61 | finally: |
61 | 62 | del os.environ['GYP_DEFINES'] |
64 | 65 | test.touch('defines-escaping.c') |
65 | 66 | test.build('defines-escaping.gyp') |
66 | 67 | |
67 | expect = """\ | |
68 | expect = """ | |
68 | 69 | "These," "words," "are," "in," "quotes." |
69 | 70 | """ |
70 | 71 | test.run_built_executable('defines_escaping', stdout=expect) |
72 | 73 | |
73 | 74 | # Test string literals containing single quotes. |
74 | 75 | try: |
75 | os.environ['GYP_DEFINES'] = \ | |
76 | ("""test_format='%s %s %s %s %s\\n' """ + | |
77 | """test_args="\\"'These,'\\",""" + | |
78 | """ \\"'words,'\\",""" | |
79 | """ \\"'are,'\\",""" + | |
80 | """ \\"'in,'\\",""" + | |
81 | """ \\"'quotes.'\\"" """) | |
76 | os.environ['GYP_DEFINES'] = ( | |
77 | r"""test_format='\n%s %s %s %s %s\n' """ | |
78 | r"""test_args="\"'These,'\",""" | |
79 | r""" \"'words,'\",""" | |
80 | r""" \"'are,'\",""" | |
81 | r""" \"'in,'\",""" | |
82 | r""" \"'quotes.'\"" """) | |
82 | 83 | test.run_gyp('defines-escaping.gyp') |
83 | 84 | finally: |
84 | 85 | del os.environ['GYP_DEFINES'] |
87 | 88 | test.touch('defines-escaping.c') |
88 | 89 | test.build('defines-escaping.gyp') |
89 | 90 | |
90 | expect = """\ | |
91 | expect = """ | |
91 | 92 | 'These,' 'words,' 'are,' 'in,' 'quotes.' |
92 | 93 | """ |
93 | 94 | test.run_built_executable('defines_escaping', stdout=expect) |
96 | 97 | # Test string literals containing different numbers of backslashes before quotes |
97 | 98 | # (to exercise Windows' quoting behaviour). |
98 | 99 | try: |
99 | os.environ['GYP_DEFINES'] = \ | |
100 | ("""test_format='%s\\n%s\\n%s\\n' """ + | |
101 | """test_args='"\\\\\\"1 visible slash\\\\\\"",""" + | |
102 | """ "\\\\\\\\\\"2 visible slashes\\\\\\\\\\"",""" | |
103 | """ "\\\\\\\\\\\\\\"3 visible slashes\\\\\\\\\\\\\\""'""") | |
100 | os.environ['GYP_DEFINES'] = ( | |
101 | r"""test_format='\n%s\n%s\n%s\n' """ | |
102 | r"""test_args='"\\\"1 visible slash\\\"",""" | |
103 | r""" "\\\\\"2 visible slashes\\\\\"",""" | |
104 | r""" "\\\\\\\"3 visible slashes\\\\\\\""'""") | |
104 | 105 | test.run_gyp('defines-escaping.gyp') |
105 | 106 | finally: |
106 | 107 | del os.environ['GYP_DEFINES'] |
109 | 110 | test.touch('defines-escaping.c') |
110 | 111 | test.build('defines-escaping.gyp') |
111 | 112 | |
112 | expect = """\ | |
113 | \\"1 visible slash\\" | |
114 | \\\\"2 visible slashes\\\\" | |
115 | \\\\\\"3 visible slashes\\\\\\" | |
113 | expect = r""" | |
114 | \"1 visible slash\" | |
115 | \\"2 visible slashes\\" | |
116 | \\\"3 visible slashes\\\" | |
116 | 117 | """ |
117 | 118 | test.run_built_executable('defines_escaping', stdout=expect) |
118 | 119 | |
119 | 120 | |
120 | 121 | # Test that various scary sequences are passed unfettered. |
121 | 122 | try: |
122 | os.environ['GYP_DEFINES'] = \ | |
123 | ("""test_format='%s\\n' """ + | |
124 | """test_args='"%PATH%, $foo, " `foo`;"'""") | |
123 | os.environ['GYP_DEFINES'] = ( | |
124 | r"""test_format='\n%s\n' """ | |
125 | r"""test_args='"$foo, " `foo`;"'""") | |
125 | 126 | test.run_gyp('defines-escaping.gyp') |
126 | 127 | finally: |
127 | 128 | del os.environ['GYP_DEFINES'] |
130 | 131 | test.touch('defines-escaping.c') |
131 | 132 | test.build('defines-escaping.gyp') |
132 | 133 | |
133 | expect = """\ | |
134 | %PATH%, $foo, " `foo`; | |
134 | expect = """ | |
135 | $foo, " `foo`; | |
135 | 136 | """ |
136 | 137 | test.run_built_executable('defines_escaping', stdout=expect) |
138 | ||
139 | ||
140 | # VisualStudio 2010 can't handle passing %PATH% | |
141 | if not (test.format == 'msvs' and test.uses_msbuild): | |
142 | try: | |
143 | os.environ['GYP_DEFINES'] = ( | |
144 | """test_format='%s' """ | |
145 | """test_args='"%PATH%"'""") | |
146 | test.run_gyp('defines-escaping.gyp') | |
147 | finally: | |
148 | del os.environ['GYP_DEFINES'] | |
149 | ||
150 | test.sleep() | |
151 | test.touch('defines-escaping.c') | |
152 | test.build('defines-escaping.gyp') | |
153 | ||
154 | expect = "%PATH%" | |
155 | test.run_built_executable('defines_escaping', stdout=expect) | |
137 | 156 | |
138 | 157 | |
139 | 158 | # Test commas and semi-colons preceded by backslashes (to exercise Windows' |
140 | 159 | # quoting behaviour). |
141 | 160 | try: |
142 | os.environ['GYP_DEFINES'] = \ | |
143 | ("""test_format='%s\\n%s\\n' """ + | |
144 | """test_args='"\\\\, \\\\\\\\;",""" + | |
161 | os.environ['GYP_DEFINES'] = ( | |
162 | r"""test_format='\n%s\n%s\n' """ | |
163 | r"""test_args='"\\, \\\\;",""" | |
145 | 164 | # Same thing again, but enclosed in visible quotes. |
146 | """ "\\"\\\\, \\\\\\\\;\\""'""") | |
165 | r""" "\"\\, \\\\;\""'""") | |
147 | 166 | test.run_gyp('defines-escaping.gyp') |
148 | 167 | finally: |
149 | 168 | del os.environ['GYP_DEFINES'] |
152 | 171 | test.touch('defines-escaping.c') |
153 | 172 | test.build('defines-escaping.gyp') |
154 | 173 | |
155 | expect = """\ | |
156 | \\, \\\\; | |
157 | "\\, \\\\;" | |
174 | expect = r""" | |
175 | \, \\; | |
176 | "\, \\;" | |
158 | 177 | """ |
159 | 178 | test.run_built_executable('defines_escaping', stdout=expect) |
160 | 179 |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'hello', | |
8 | 'type': 'executable', | |
9 | 'sources': [ | |
10 | 'hello.c', | |
11 | 'bogus.c', | |
12 | 'also/not/real.c', | |
13 | 'also/not/real2.c', | |
14 | ], | |
15 | 'sources!': [ | |
16 | 'bogus.c', | |
17 | 'also/not/real.c', | |
18 | 'also/not/real2.c', | |
19 | ], | |
20 | }, | |
21 | ], | |
22 | } |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Verifies that exclusions (e.g. sources!) are respected. Excluded sources | |
8 | that do not exist should not prevent the build from succeeding. | |
9 | """ | |
10 | ||
11 | import TestGyp | |
12 | ||
13 | test = TestGyp.TestGyp() | |
14 | ||
15 | test.run_gyp('exclusion.gyp') | |
16 | test.build('exclusion.gyp') | |
17 | ||
18 | # executables | |
19 | test.built_file_must_exist('hello' + test._exe, test.EXECUTABLE, bare=True) | |
20 | ||
21 | test.pass_test() |
0 | /* Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | * Use of this source code is governed by a BSD-style license that can be | |
2 | * found in the LICENSE file. */ | |
3 | ||
4 | #include <stdio.h> | |
5 | ||
6 | int func1(void) { | |
7 | return 42; | |
8 | } | |
9 | ||
10 | int main(int argc, char *argv[]) { | |
11 | printf("Hello, world!\n"); | |
12 | printf("%d\n", func1()); | |
13 | return 0; | |
14 | } |
10 | 10 | |
11 | 11 | import TestGyp |
12 | 12 | |
13 | test = TestGyp.TestGyp() | |
13 | test = TestGyp.TestGyp(workdir='workarea_all') | |
14 | 14 | |
15 | 15 | test.run_gyp('hello.gyp') |
16 | 16 |
10 | 10 | |
11 | 11 | import TestGyp |
12 | 12 | |
13 | test = TestGyp.TestGyp() | |
13 | test = TestGyp.TestGyp(workdir='workarea_default') | |
14 | 14 | |
15 | 15 | test.run_gyp('hello.gyp') |
16 | 16 |
10 | 10 | |
11 | 11 | import TestGyp |
12 | 12 | |
13 | test = TestGyp.TestGyp() | |
13 | test = TestGyp.TestGyp(workdir='workarea_target') | |
14 | 14 | |
15 | 15 | test.run_gyp('hello.gyp') |
16 | 16 |
11 | 11 | |
12 | 12 | test = TestGyp.TestGyp() |
13 | 13 | |
14 | if test.format == 'scons': | |
15 | test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n') | |
16 | ||
14 | 17 | test.run_gyp('includes.gyp', chdir='src') |
15 | 18 | |
16 | 19 | test.relocate('src', 'relocate/src') |
22 | 25 | Hello from inc.h |
23 | 26 | Hello from include1.h |
24 | 27 | Hello from subdir/inc2/include2.h |
28 | Hello from shadow2/shadow.h | |
25 | 29 | """ |
26 | 30 | test.run_built_executable('includes', stdout=expect, chdir='relocate/src') |
27 | 31 |
11 | 11 | |
12 | 12 | test = TestGyp.TestGyp() |
13 | 13 | |
14 | if test.format == 'scons': | |
15 | test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n') | |
16 | ||
14 | 17 | test.run_gyp('includes.gyp', chdir='src') |
15 | 18 | |
16 | 19 | test.relocate('src', 'relocate/src') |
22 | 25 | Hello from inc.h |
23 | 26 | Hello from include1.h |
24 | 27 | Hello from subdir/inc2/include2.h |
28 | Hello from shadow2/shadow.h | |
25 | 29 | """ |
26 | 30 | test.run_built_executable('includes', stdout=expect, chdir='relocate/src') |
27 | 31 |
2 | 2 | #include "inc.h" |
3 | 3 | #include "include1.h" |
4 | 4 | #include "include2.h" |
5 | #include "shadow.h" | |
5 | 6 | |
6 | 7 | int main(int argc, char *argv[]) |
7 | 8 | { |
9 | 10 | printf("Hello from %s\n", INC_STRING); |
10 | 11 | printf("Hello from %s\n", INCLUDE1_STRING); |
11 | 12 | printf("Hello from %s\n", INCLUDE2_STRING); |
13 | /* Test that include_dirs happen first: The gyp file has a -Ishadow1 | |
14 | cflag and an include_dir of shadow2. Including shadow.h should get | |
15 | the shadow.h from the include_dir. */ | |
16 | printf("Hello from %s\n", SHADOW_STRING); | |
12 | 17 | return 0; |
13 | 18 | } |
9 | 9 | 'dependencies': [ |
10 | 10 | 'subdir/subdir_includes.gyp:subdir_includes', |
11 | 11 | ], |
12 | 'cflags': [ | |
13 | '-Ishadow1', | |
14 | ], | |
12 | 15 | 'include_dirs': [ |
13 | 16 | '.', |
14 | 17 | 'inc1', |
18 | 'shadow2', | |
15 | 19 | 'subdir/inc2', |
16 | 20 | ], |
17 | 21 | 'sources': [ |
0 | #define SHADOW_STRING "shadow1/shadow.h" |
0 | #define SHADOW_STRING "shadow2/shadow.h" |
407 | 407 | build_tool_list = [None, 'devenv.com'] |
408 | 408 | |
409 | 409 | def initialize_build_tool(self): |
410 | """ | |
411 | Initializes the Visual Studio .build_tool parameter, searching %PATH% | |
412 | and %PATHEXT% for a devenv.{exe,bat,...} executable, and falling | |
413 | back to a hard-coded default (on the current drive) if necessary. | |
410 | """ Initializes the Visual Studio .build_tool and .uses_msbuild parameters. | |
411 | ||
412 | We use the value specified by GYP_MSVS_VERSION. If not specified, we | |
413 | search %PATH% and %PATHEXT% for a devenv.{exe,bat,...} executable. | |
414 | Failing that, we search for likely deployment paths. | |
414 | 415 | """ |
415 | 416 | super(TestGypMSVS, self).initialize_build_tool() |
416 | if not self.build_tool: | |
417 | # We didn't find 'devenv' on the path. Just hard-code a default, | |
418 | # and revisit this if it becomes important. | |
419 | possible = [ | |
420 | # Note: if you're using this, set GYP_MSVS_VERSION=2008 | |
421 | # to get the tests to pass. | |
422 | ('C:\\Program Files (x86)', | |
423 | 'Microsoft Visual Studio 9.0', 'Common7', 'IDE', 'devenv.com'), | |
424 | ('C:\\Program Files', | |
425 | 'Microsoft Visual Studio 9.0', 'Common7', 'IDE', 'devenv.com'), | |
426 | ('C:\\Program Files (x86)', | |
427 | 'Microsoft Visual Studio 8', 'Common7', 'IDE', 'devenv.com'), | |
428 | ('C:\\Program Files', | |
429 | 'Microsoft Visual Studio 8', 'Common7', 'IDE', 'devenv.com'), | |
430 | ] | |
431 | for build_tool in possible: | |
432 | bt = os.path.join(*build_tool) | |
417 | possible_roots = ['C:\\Program Files (x86)', 'C:\\Program Files'] | |
418 | possible_paths = { | |
419 | '2010': r'Microsoft Visual Studio 10.0\Common7\IDE\devenv.com', | |
420 | '2008': r'Microsoft Visual Studio 9.0\Common7\IDE\devenv.com', | |
421 | '2005': r'Microsoft Visual Studio 8\Common7\IDE\devenv.com'} | |
422 | msvs_version = os.environ.get('GYP_MSVS_VERSION', 'auto') | |
423 | if msvs_version in possible_paths: | |
424 | # Check that the path to the specified GYP_MSVS_VERSION exists. | |
425 | path = possible_paths[msvs_version] | |
426 | for r in possible_roots: | |
427 | bt = os.path.join(r, path) | |
433 | 428 | if os.path.exists(bt): |
434 | 429 | self.build_tool = bt |
435 | break | |
430 | self.uses_msbuild = msvs_version >= '2010' | |
431 | return | |
432 | else: | |
433 | print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" ' | |
434 | 'but corresponding "%s" was not found.' % (msvs_version, path)) | |
435 | if self.build_tool: | |
436 | # We found 'devenv' on the path, use that and try to guess the version. | |
437 | for version, path in possible_paths.iteritems(): | |
438 | if self.build_tool.find(path) >= 0: | |
439 | self.uses_msbuild = version >= '2010' | |
440 | return | |
441 | else: | |
442 | # If not, assume not MSBuild. | |
443 | self.uses_msbuild = False | |
444 | return | |
445 | # Neither GYP_MSVS_VERSION nor the path help us out. Iterate through | |
446 | # the choices looking for a match. | |
447 | for version, path in possible_paths.iteritems(): | |
448 | for r in possible_roots: | |
449 | bt = os.path.join(r, path) | |
450 | if os.path.exists(bt): | |
451 | self.build_tool = bt | |
452 | self.uses_msbuild = msvs_version >= '2010' | |
453 | return | |
454 | print 'Error: could not find devenv' | |
455 | sys.exit(1) | |
436 | 456 | def build(self, gyp_file, target=None, rebuild=False, **kw): |
437 | 457 | """ |
438 | 458 | Runs a Visual Studio build using the configuration generated |
457 | 477 | def up_to_date(self, gyp_file, target=None, **kw): |
458 | 478 | """ |
459 | 479 | Verifies that a build of the specified Visual Studio target is up to date. |
480 | ||
481 | Beware that VS2010 will behave strangely if you build under | |
482 | C:\USERS\yourname\AppData\Local. It will cause needless work. The ouptut | |
483 | will be "1 succeeded and 0 up to date". MSBuild tracing reveals that: | |
484 | "Project 'C:\Users\...\AppData\Local\...vcxproj' not up to date because | |
485 | 'C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO 10.0\VC\BIN\1033\CLUI.DLL' | |
486 | was modified at 02/21/2011 17:03:30, which is newer than '' which was | |
487 | modified at 01/01/0001 00:00:00. | |
488 | ||
489 | The workaround is to specify a workdir when instantiating the test, e.g. | |
490 | test = TestGyp.TestGyp(workdir='workarea') | |
460 | 491 | """ |
461 | 492 | result = self.build(gyp_file, target, **kw) |
462 | 493 | if not result: |
463 | 494 | stdout = self.stdout() |
495 | ||
464 | 496 | m = self.up_to_date_re.search(stdout) |
465 | if not m or m.group(1) == '0': | |
497 | up_to_date = m and m.group(1) == '1' | |
498 | if not up_to_date: | |
466 | 499 | self.report_not_up_to_date() |
467 | 500 | self.fail_test() |
468 | 501 | return result |
594 | 627 | re.compile('__________Shutting down distcc-pump include server\n', re.S), |
595 | 628 | ] |
596 | 629 | |
597 | up_to_date_ending = 'Checking Dependencies...\n** BUILD SUCCEEDED **\n' | |
630 | up_to_date_endings = ( | |
631 | 'Checking Dependencies...\n** BUILD SUCCEEDED **\n', # Xcode 3.0/3.1 | |
632 | 'Check dependencies\n** BUILD SUCCEEDED **\n\n', # Xcode 3.2 | |
633 | ) | |
598 | 634 | |
599 | 635 | def build(self, gyp_file, target=None, **kw): |
600 | 636 | """ |
625 | 661 | output = self.stdout() |
626 | 662 | for expression in self.strip_up_to_date_expressions: |
627 | 663 | output = expression.sub('', output) |
628 | if not output.endswith(self.up_to_date_ending): | |
664 | if not output.endswith(self.up_to_date_endings): | |
629 | 665 | self.report_not_up_to_date() |
630 | 666 | self.fail_test() |
631 | 667 | return result |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Verifies that .so files that are order only dependencies are specified by | |
8 | their install location rather than by their alias. | |
9 | """ | |
10 | ||
11 | # Python 2.5 needs this for the with statement. | |
12 | from __future__ import with_statement | |
13 | ||
14 | import os | |
15 | import TestGyp | |
16 | ||
17 | test = TestGyp.TestGyp(formats=['make']) | |
18 | ||
19 | test.run_gyp('shared_dependency.gyp', | |
20 | chdir='src') | |
21 | test.relocate('src', 'relocate/src') | |
22 | ||
23 | test.build('shared_dependency.gyp', test.ALL, chdir='relocate/src') | |
24 | ||
25 | with open('relocate/src/Makefile') as makefile: | |
26 | make_contents = makefile.read() | |
27 | ||
28 | # If we remove the code to generate lib1, Make should still be able | |
29 | # to build lib2 since lib1.so already exists. | |
30 | make_contents = make_contents.replace('include lib1.target.mk', '') | |
31 | with open('relocate/src/Makefile', 'w') as makefile: | |
32 | makefile.write(make_contents) | |
33 | ||
34 | test.build('shared_dependency.gyp', test.ALL, chdir='relocate/src') | |
35 | ||
36 | test.pass_test() |
0 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'lib1', | |
8 | 'type': 'shared_library', | |
9 | 'sources': [ | |
10 | 'lib1.c', | |
11 | ], | |
12 | }, | |
13 | { | |
14 | 'target_name': 'lib2', | |
15 | 'type': 'shared_library', | |
16 | 'sources': [ | |
17 | 'lib2.c', | |
18 | ], | |
19 | 'dependencies': [ | |
20 | 'lib1', | |
21 | ], | |
22 | }, | |
23 | ], | |
24 | 'conditions': [ | |
25 | ['OS=="linux"', { | |
26 | 'target_defaults': { | |
27 | # Support 64-bit shared libs (also works fine for 32-bit). | |
28 | 'cflags': ['-fPIC'], | |
29 | }, | |
30 | }], | |
31 | ], | |
32 | } |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Put an object file on the sources list. | |
8 | Expect the result to link ok. | |
9 | """ | |
10 | ||
11 | import TestGyp | |
12 | ||
13 | # Currently only works under the make build. | |
14 | test = TestGyp.TestGyp(formats=['make']) | |
15 | ||
16 | test.run_gyp('link-objects.gyp') | |
17 | ||
18 | test.build('link-objects.gyp', test.ALL) | |
19 | ||
20 | test.run_built_executable('link-objects', stdout="PASS\n") | |
21 | ||
22 | test.up_to_date('link-objects.gyp', test.ALL) | |
23 | ||
24 | test.pass_test() |
0 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'link-objects', | |
8 | 'type': 'executable', | |
9 | 'actions': [ | |
10 | { | |
11 | 'action_name': 'build extra object', | |
12 | 'inputs': ['extra.c'], | |
13 | 'outputs': ['extra.o'], | |
14 | 'action': ['gcc', '-o', 'extra.o', '-c', 'extra.c'], | |
15 | 'process_outputs_as_sources': 1, | |
16 | }, | |
17 | ], | |
18 | 'sources': [ | |
19 | 'base.c', | |
20 | ], | |
21 | }, | |
22 | ], | |
23 | } |
0 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'main', | |
8 | 'type': 'executable', | |
9 | 'sources': [ | |
10 | 'main.cc', | |
11 | ], | |
12 | }, | |
13 | ], | |
14 | } |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Verifies that .d files and all.deps are properly generated. | |
8 | """ | |
9 | ||
10 | import os | |
11 | import TestGyp | |
12 | ||
13 | # .d files are only used by the make build. | |
14 | test = TestGyp.TestGyp(formats=['make']) | |
15 | ||
16 | test.run_gyp('dependencies.gyp') | |
17 | ||
18 | test.build('dependencies.gyp', test.ALL) | |
19 | ||
20 | deps_file = test.built_file_path(".deps/out/Default/obj.target/main/main.o.d") | |
21 | test.must_contain(deps_file, "main.h") | |
22 | ||
23 | # Build a second time to make sure we generate all.deps. | |
24 | test.build('dependencies.gyp', test.ALL) | |
25 | ||
26 | all_deps_file = test.built_file_path(".deps/all.deps") | |
27 | test.must_contain(all_deps_file, "main.h") | |
28 | test.must_contain(all_deps_file, "cmd_") | |
29 | ||
30 | test.pass_test() |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Tests the use of the NO_LOAD flag which makes loading sub .mk files | |
8 | optional. | |
9 | """ | |
10 | ||
11 | # Python 2.5 needs this for the with statement. | |
12 | from __future__ import with_statement | |
13 | ||
14 | import os | |
15 | import TestGyp | |
16 | ||
17 | test = TestGyp.TestGyp(formats=['make']) | |
18 | ||
19 | test.run_gyp('all.gyp', chdir='noload') | |
20 | ||
21 | test.relocate('noload', 'relocate/noload') | |
22 | ||
23 | test.build('build/all.gyp', test.ALL, chdir='relocate/noload') | |
24 | test.run_built_executable('exe', chdir='relocate/noload', | |
25 | stdout='Hello from shared.c.\n') | |
26 | ||
27 | # Just sanity test that NO_LOAD=lib doesn't break anything. | |
28 | test.build('build/all.gyp', test.ALL, chdir='relocate/noload', | |
29 | arguments=['NO_LOAD=lib']) | |
30 | test.run_built_executable('exe', chdir='relocate/noload', | |
31 | stdout='Hello from shared.c.\n') | |
32 | test.build('build/all.gyp', test.ALL, chdir='relocate/noload', | |
33 | arguments=['NO_LOAD=z']) | |
34 | test.run_built_executable('exe', chdir='relocate/noload', | |
35 | stdout='Hello from shared.c.\n') | |
36 | ||
37 | # Make sure we can rebuild without reloading the sub .mk file. | |
38 | with open('relocate/noload/main.c', 'a') as src_file: | |
39 | src_file.write("\n") | |
40 | test.build('build/all.gyp', test.ALL, chdir='relocate/noload', | |
41 | arguments=['NO_LOAD=lib']) | |
42 | test.run_built_executable('exe', chdir='relocate/noload', | |
43 | stdout='Hello from shared.c.\n') | |
44 | ||
45 | # Change shared.c, but verify that it doesn't get rebuild if we don't load it. | |
46 | with open('relocate/noload/lib/shared.c', 'w') as shared_file: | |
47 | shared_file.write( | |
48 | '#include "shared.h"\n' | |
49 | 'const char kSharedStr[] = "modified";\n' | |
50 | ) | |
51 | test.build('build/all.gyp', test.ALL, chdir='relocate/noload', | |
52 | arguments=['NO_LOAD=lib']) | |
53 | test.run_built_executable('exe', chdir='relocate/noload', | |
54 | stdout='Hello from shared.c.\n') | |
55 | ||
56 | test.pass_test() |
0 | /* Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | * Use of this source code is governed by a BSD-style license that can be | |
2 | * found in the LICENSE file. */ | |
3 | ||
4 | #include <stdio.h> | |
5 | ||
6 | #include "main.h" | |
7 | ||
8 | int main(int argc, char *argv[]) { | |
9 | printf("hello world\n"); | |
10 | return 0; | |
11 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'exe', | |
8 | 'type': 'executable', | |
9 | 'sources': [ | |
10 | 'main.c', | |
11 | ], | |
12 | 'dependencies': [ | |
13 | 'lib/shared.gyp:shared', | |
14 | ], | |
15 | }, | |
16 | ], | |
17 | } |
0 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'shared', | |
8 | 'type': 'shared_library', | |
9 | 'sources': [ | |
10 | 'shared.c', | |
11 | 'shared.h', | |
12 | ], | |
13 | }, | |
14 | ], | |
15 | } |
0 | extern const char kSharedStr[]; |
0 | #include <stdio.h> | |
1 | ||
2 | #include "lib/shared.h" | |
3 | ||
4 | int main(int argc, char *argv[]) | |
5 | { | |
6 | printf("Hello from %s.\n", kSharedStr); | |
7 | return 0; | |
8 | } |
13 | 13 | #if defined(PLATFORM_WIN) |
14 | 14 | #define MODULE_SUFFIX ".dll" |
15 | 15 | #elif defined(PLATFORM_MAC) |
16 | #define MODULE_SUFFIX ".dylib" | |
16 | #define MODULE_SUFFIX ".so" | |
17 | 17 | #elif defined(PLATFORM_LINUX) |
18 | 18 | #define MODULE_SUFFIX ".so" |
19 | 19 | #endif |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Verifies that precompiled headers can be specified. | |
8 | """ | |
9 | ||
10 | import TestGyp | |
11 | ||
12 | test = TestGyp.TestGyp(formats=['msvs'], workdir='workarea_all') | |
13 | ||
14 | test.run_gyp('hello.gyp') | |
15 | ||
16 | test.build('hello.gyp', 'hello') | |
17 | ||
18 | test.run_built_executable('hello', stdout="Hello, world!\nHello, two!\n") | |
19 | ||
20 | test.up_to_date('hello.gyp', test.ALL) | |
21 | ||
22 | test.pass_test() |
0 | /* Copyright (c) 2011 Google Inc. All rights reserved. | |
1 | * Use of this source code is governed by a BSD-style license that can be | |
2 | * found in the LICENSE file. */ | |
3 | ||
4 | // Note the abscence of a stdio.h include. This will be inserted because of the | |
5 | // precompiled header. | |
6 | ||
7 | extern int hello2(); | |
8 | ||
9 | int main(int argc, char *argv[]) { | |
10 | printf("Hello, world!\n"); | |
11 | hello2(); | |
12 | return 0; | |
13 | } |
0 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'hello', | |
8 | 'type': 'executable', | |
9 | 'sources': [ | |
10 | 'hello.c', | |
11 | 'hello2.c', | |
12 | 'precomp.c', | |
13 | ], | |
14 | 'msvs_precompiled_header': 'stdio.h', | |
15 | 'msvs_precompiled_source': 'precomp.c', | |
16 | }, | |
17 | ], | |
18 | } |
0 | /* Copyright (c) 2011 Google Inc. All rights reserved. | |
1 | * Use of this source code is governed by a BSD-style license that can be | |
2 | * found in the LICENSE file. */ | |
3 | ||
4 | // Unlike hello.c, this file specifies the headers. | |
5 | ||
6 | #include <windows.h> | |
7 | #include <stdio.h> | |
8 | ||
9 | int hello2() { | |
10 | printf("Hello, two!\n"); | |
11 | return 0; | |
12 | } |
0 | /* Copyright (c) 2011 Google Inc. All rights reserved. | |
1 | * Use of this source code is governed by a BSD-style license that can be | |
2 | * found in the LICENSE file. */ | |
3 | ||
4 | // The precompiled header does not have to be the first one in the file. | |
5 | ||
6 | #include <windows.h> | |
7 | #include <stdio.h> |
43 | 43 | test.must_match('relocate/src/subdir2/file1.out', "Hello from file1.in\n") |
44 | 44 | test.must_match('relocate/src/subdir2/file2.out', "Hello from file2.in\n") |
45 | 45 | |
46 | test.must_match('relocate/src/subdir2/file1.out2', "Hello from file1.in\n") | |
47 | test.must_match('relocate/src/subdir2/file2.out2', "Hello from file2.in\n") | |
48 | ||
46 | 49 | test.pass_test() |
43 | 43 | test.must_match('relocate/src/subdir2/file1.out', "Hello from file1.in\n") |
44 | 44 | test.must_match('relocate/src/subdir2/file2.out', "Hello from file2.in\n") |
45 | 45 | |
46 | test.must_match('relocate/src/subdir2/file1.out2', "Hello from file1.in\n") | |
47 | test.must_match('relocate/src/subdir2/file2.out2', "Hello from file2.in\n") | |
48 | ||
46 | 49 | test.pass_test() |
8 | 8 | 'type': 'none', |
9 | 9 | 'dependencies': [ |
10 | 10 | 'subdir1/executable.gyp:*', |
11 | 'subdir2/never_used.gyp:*', | |
12 | 'subdir2/no_inputs.gyp:*', | |
11 | 13 | 'subdir2/none.gyp:*', |
12 | 14 | 'subdir3/executable2.gyp:*', |
13 | 15 | ], |
0 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | # Test that the case where there is a rule that doesn't apply to anything. | |
5 | { | |
6 | 'targets': [ | |
7 | { | |
8 | 'target_name': 'files_no_input2', | |
9 | 'type': 'none', | |
10 | 'msvs_cygwin_shell': 0, | |
11 | 'sources': [ | |
12 | 'file1.in', | |
13 | 'file2.in', | |
14 | ], | |
15 | 'rules': [ | |
16 | { | |
17 | 'rule_name': 'copy_file3', | |
18 | 'extension': 'in2', | |
19 | 'outputs': [ | |
20 | '<(RULE_INPUT_ROOT).out3', | |
21 | ], | |
22 | 'action': [ | |
23 | 'python', '../copy-file.py', '<(RULE_INPUT_PATH)', '<@(_outputs)', | |
24 | ], | |
25 | 'process_outputs_as_sources': 1, | |
26 | }, | |
27 | ], | |
28 | }, | |
29 | ], | |
30 | } |
0 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | # Test that the case where there are no inputs (other than the | |
5 | # file the rule applies to). | |
6 | { | |
7 | 'targets': [ | |
8 | { | |
9 | 'target_name': 'files_no_input', | |
10 | 'type': 'none', | |
11 | 'msvs_cygwin_shell': 0, | |
12 | 'sources': [ | |
13 | 'file1.in', | |
14 | 'file2.in', | |
15 | ], | |
16 | 'rules': [ | |
17 | { | |
18 | 'rule_name': 'copy_file2', | |
19 | 'extension': 'in', | |
20 | 'outputs': [ | |
21 | '<(RULE_INPUT_ROOT).out2', | |
22 | ], | |
23 | 'action': [ | |
24 | 'python', '../copy-file.py', '<(RULE_INPUT_PATH)', '<@(_outputs)', | |
25 | ], | |
26 | 'process_outputs_as_sources': 1, | |
27 | }, | |
28 | ], | |
29 | }, | |
30 | ], | |
31 | } |
10 | 10 | |
11 | 11 | import TestGyp |
12 | 12 | |
13 | test = TestGyp.TestGyp() | |
14 | ||
15 | if test.format == 'msvs': | |
16 | msg = 'TODO: issue 120: disabled on MSVS due to test execution problems.\n' | |
17 | test.skip_test(msg) | |
13 | test = TestGyp.TestGyp(workdir='workarea_all') | |
18 | 14 | |
19 | 15 | test.run_gyp('same_target.gyp', chdir='src') |
20 | 16 |
10 | 10 | |
11 | 11 | import TestGyp |
12 | 12 | |
13 | test = TestGyp.TestGyp() | |
14 | ||
15 | if test.format == 'msvs': | |
16 | msg = 'TODO: issue 120: disabled on MSVS due to test execution problems.\n' | |
17 | test.skip_test(msg) | |
13 | test = TestGyp.TestGyp(workdir='workarea_default') | |
18 | 14 | |
19 | 15 | test.run_gyp('same_target.gyp', chdir='src') |
20 | 16 |
12 | 12 | { |
13 | 13 | 'rule_name': 'make_sources', |
14 | 14 | 'extension': 'in', |
15 | 'msvs_external_rule': 1, | |
16 | 15 | 'inputs': [ |
17 | 16 | 'make-sources.py', |
18 | 17 | ], |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Check that duplicate targets in a directory gives an error. | |
8 | """ | |
9 | ||
10 | import TestGyp | |
11 | ||
12 | test = TestGyp.TestGyp() | |
13 | ||
14 | # Require that gyp files with duplicate targets spit out an error. | |
15 | test.run_gyp('all.gyp', chdir='src', status=1, stderr=None) | |
16 | ||
17 | test.pass_test() |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'all_exes', | |
8 | 'type': 'none', | |
9 | 'dependencies': [ | |
10 | 'executable1.gyp:*', | |
11 | 'executable2.gyp:*', | |
12 | ], | |
13 | }, | |
14 | ], | |
15 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'program', | |
8 | 'type': 'executable', | |
9 | 'sources': [ | |
10 | 'main1.cc', | |
11 | ], | |
12 | }, | |
13 | ], | |
14 | } |
0 | # Copyright (c) 2010 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'program', | |
8 | 'type': 'executable', | |
9 | 'sources': [ | |
10 | 'main2.cc', | |
11 | ], | |
12 | }, | |
13 | ], | |
14 | } |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2011 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Runs small tests. | |
8 | """ | |
9 | ||
10 | import imp | |
11 | import os | |
12 | import sys | |
13 | import unittest | |
14 | ||
15 | import TestGyp | |
16 | ||
17 | ||
18 | test = TestGyp.TestGyp() | |
19 | ||
20 | # Add pylib/gyp to the import path (so tests can import their dependencies). | |
21 | sys.path.append(os.path.join(test._cwd, 'pylib', 'gyp')) | |
22 | ||
23 | # Add new test suites here. | |
24 | files_to_test = [ | |
25 | 'pylib/gyp/MSVSSettings_test.py', | |
26 | 'pylib/gyp/easy_xml_test.py', | |
27 | ] | |
28 | ||
29 | # Collect all the suites from the above files. | |
30 | suites = [] | |
31 | for filename in files_to_test: | |
32 | # Carve the module name out of the path. | |
33 | name = os.path.splitext(os.path.split(filename)[1])[0] | |
34 | # Find the complete module path. | |
35 | full_filename = os.path.join(test._cwd, filename) | |
36 | # Load the module. | |
37 | module = imp.load_source(name, full_filename) | |
38 | # Add it to the list of test suites. | |
39 | suites.append(unittest.defaultTestLoader.loadTestsFromModule(module)) | |
40 | # Create combined suite. | |
41 | all_tests = unittest.TestSuite(suites) | |
42 | ||
43 | # Run all the tests. | |
44 | result = unittest.TextTestRunner(verbosity=2).run(all_tests) | |
45 | if result.failures or result.errors: | |
46 | test.fail_test() | |
47 | ||
48 | test.pass_test() |
0 | #!/usr/bin/env python | |
1 | ||
2 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
3 | # Use of this source code is governed by a BSD-style license that can be | |
4 | # found in the LICENSE file. | |
5 | ||
6 | """ | |
7 | Verifies building a subsidiary dependent target from a .gyp file in a | |
8 | subdirectory, without specifying an explicit output build directory, | |
9 | and using the subdirectory's solution or project file as the entry point. | |
10 | """ | |
11 | ||
12 | import TestGyp | |
13 | import errno | |
14 | ||
15 | test = TestGyp.TestGyp(formats=['make']) | |
16 | ||
17 | # We want our Makefile to be one dir up from main.gyp. | |
18 | test.run_gyp('main.gyp', '--toplevel-dir=..', chdir='src/sub1') | |
19 | ||
20 | toplevel_dir = 'src' | |
21 | ||
22 | test.build('all', chdir=toplevel_dir) | |
23 | ||
24 | test.built_file_must_exist('prog1', type=test.EXECUTABLE, chdir=toplevel_dir) | |
25 | ||
26 | test.run_built_executable('prog1', | |
27 | chdir=toplevel_dir, | |
28 | stdout="Hello from prog1.c\n") | |
29 | ||
30 | test.pass_test() |
0 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'prog1', | |
8 | 'type': 'executable', | |
9 | 'dependencies': [ | |
10 | '<(DEPTH)/../sub2/prog2.gyp:prog2', | |
11 | ], | |
12 | 'sources': [ | |
13 | 'prog1.c', | |
14 | ], | |
15 | }, | |
16 | ], | |
17 | } |
0 | #include <stdio.h> | |
1 | ||
2 | int main(int argc, char *argv[]) | |
3 | { | |
4 | printf("Hello from prog1.c\n"); | |
5 | return 0; | |
6 | } |
0 | #include <stdio.h> | |
1 | ||
2 | int main(int argc, char *argv[]) | |
3 | { | |
4 | printf("Hello from prog2.c\n"); | |
5 | return 0; | |
6 | } |
0 | # Copyright (c) 2009 Google Inc. All rights reserved. | |
1 | # Use of this source code is governed by a BSD-style license that can be | |
2 | # found in the LICENSE file. | |
3 | ||
4 | { | |
5 | 'targets': [ | |
6 | { | |
7 | 'target_name': 'prog2', | |
8 | 'type': 'executable', | |
9 | 'sources': [ | |
10 | 'prog2.c', | |
11 | ], | |
12 | }, | |
13 | ], | |
14 | } |
0 | 0 | GENERAL: running with these options: |
1 | GENERAL: check: None | |
2 | GENERAL: circular_check: True | |
3 | GENERAL: debug: ['variables', 'general'] | |
4 | GENERAL: defines: None | |
5 | GENERAL: depth: '.' | |
6 | GENERAL: formats: ['gypd'] | |
7 | GENERAL: generator_flags: [] | |
8 | GENERAL: generator_output: None | |
9 | GENERAL: includes: None | |
1 | 10 | GENERAL: msvs_version: None |
2 | 11 | GENERAL: suffix: '' |
3 | GENERAL: includes: None | |
12 | GENERAL: toplevel_dir: None | |
4 | 13 | GENERAL: use_environment: True |
5 | GENERAL: depth: '.' | |
6 | GENERAL: generator_flags: [] | |
7 | GENERAL: generator_output: None | |
8 | GENERAL: formats: ['gypd'] | |
9 | GENERAL: debug: ['variables', 'general'] | |
10 | GENERAL: circular_check: True | |
11 | GENERAL: check: None | |
12 | GENERAL: defines: None | |
13 | 14 | GENERAL: cmdline_default_variables: {} |
14 | 15 | GENERAL: generator_flags: {} |
15 | 16 | VARIABLES: Expanding '0' to 0 |
0 | 0 | GENERAL: running with these options: |
1 | GENERAL: check: None | |
2 | GENERAL: circular_check: True | |
3 | GENERAL: debug: ['variables', 'general'] | |
4 | GENERAL: defines: None | |
5 | GENERAL: depth: '.' | |
6 | GENERAL: formats: ['gypd'] | |
7 | GENERAL: generator_flags: [] | |
8 | GENERAL: generator_output: None | |
9 | GENERAL: includes: None | |
1 | 10 | GENERAL: msvs_version: None |
2 | 11 | GENERAL: suffix: '' |
3 | GENERAL: includes: None | |
12 | GENERAL: toplevel_dir: None | |
4 | 13 | GENERAL: use_environment: False |
5 | GENERAL: depth: '.' | |
6 | GENERAL: generator_flags: [] | |
7 | GENERAL: generator_output: None | |
8 | GENERAL: formats: ['gypd'] | |
9 | GENERAL: debug: ['variables', 'general'] | |
10 | GENERAL: circular_check: True | |
11 | GENERAL: check: None | |
12 | GENERAL: defines: None | |
13 | 14 | GENERAL: cmdline_default_variables: {} |
14 | 15 | GENERAL: generator_flags: {} |
15 | 16 | VARIABLES: Expanding '0' to 0 |
0 | 0 | GENERAL: running with these options: |
1 | GENERAL: check: None | |
2 | GENERAL: circular_check: True | |
3 | GENERAL: debug: ['variables', 'general'] | |
4 | GENERAL: defines: None | |
5 | GENERAL: depth: '.' | |
6 | GENERAL: formats: ['gypd'] | |
7 | GENERAL: generator_flags: [] | |
8 | GENERAL: generator_output: None | |
9 | GENERAL: includes: None | |
1 | 10 | GENERAL: msvs_version: None |
2 | 11 | GENERAL: suffix: '' |
3 | GENERAL: includes: None | |
12 | GENERAL: toplevel_dir: None | |
4 | 13 | GENERAL: use_environment: True |
5 | GENERAL: depth: '.' | |
6 | GENERAL: generator_flags: [] | |
7 | GENERAL: generator_output: None | |
8 | GENERAL: formats: ['gypd'] | |
9 | GENERAL: debug: ['variables', 'general'] | |
10 | GENERAL: circular_check: True | |
11 | GENERAL: check: None | |
12 | GENERAL: defines: None | |
13 | 14 | GENERAL: cmdline_default_variables: {} |
14 | 15 | GENERAL: generator_flags: {} |
15 | 16 | VARIABLES: Expanding '0' to 0 |
0 | 0 | GENERAL: running with these options: |
1 | GENERAL: check: None | |
2 | GENERAL: circular_check: True | |
3 | GENERAL: debug: ['variables', 'general'] | |
4 | GENERAL: defines: None | |
5 | GENERAL: depth: '.' | |
6 | GENERAL: formats: ['gypd'] | |
7 | GENERAL: generator_flags: [] | |
8 | GENERAL: generator_output: None | |
9 | GENERAL: includes: None | |
1 | 10 | GENERAL: msvs_version: None |
2 | 11 | GENERAL: suffix: '' |
3 | GENERAL: includes: None | |
12 | GENERAL: toplevel_dir: None | |
4 | 13 | GENERAL: use_environment: True |
5 | GENERAL: depth: '.' | |
6 | GENERAL: generator_flags: [] | |
7 | GENERAL: generator_output: None | |
8 | GENERAL: formats: ['gypd'] | |
9 | GENERAL: debug: ['variables', 'general'] | |
10 | GENERAL: circular_check: True | |
11 | GENERAL: check: None | |
12 | GENERAL: defines: None | |
13 | 14 | GENERAL: cmdline_default_variables: {} |
14 | 15 | GENERAL: generator_flags: {} |
15 | 16 | VARIABLES: Expanding 'exclude' to 'exclude' |