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

Side by Side Diff: site_scons/site_tools/component_targets_msvs.py

Issue 9094: Adding in new software construction toolkit version. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:executable
+ *
OLDNEW
(Empty)
1 #!/usr/bin/python2.4
2 # Copyright 2008, Google Inc.
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met:
8 #
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
14 # distribution.
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 """Visual Studio solution output of component targets for SCons."""
32
33 import md5
34 import sys
35 import xml.dom
36 import xml.dom.minidom
37 import SCons
38
39
40 #------------------------------------------------------------------------------
41
42
43 def MakeGuid(name, seed='component_targets_msvs'):
44 """Returns a GUID for the specified target name.
45
46 Args:
47 name: Target name.
48 seed: Seed for MD5 hash.
49 Returns:
50 A GUID-line string calculated from the name and seed.
51
52 This generates something which looks like a GUID, but depends only on the
53 name and seed. This means the same name/seed will always generate the same
54 GUID, so that projects and solutions which refer to each other can explicitly
55 determine the GUID to refer to explicitly. It also means that the GUID will
56 not change when the project for a target is rebuilt.
57 """
58 # Calculate a MD5 signature for the seed and name.
59 d = md5.new(str(seed) + str(name)).hexdigest().upper()
60 # Convert most of the signature to GUID form (discard the rest)
61 guid = ('{' + d[:8] + '-' + d[8:12] + '-' + d[12:16] + '-' + d[16:20]
62 + '-' + d[20:32] + '}')
63 return guid
64
65 #------------------------------------------------------------------------------
66
67
68 def GetGuidFromVSProject(project_path):
69 """Reads the GUID from a Visual Studio project file.
70
71 Args:
72 project_path: Path to the Visual Studio project file.
73
74 Returns:
75 The GUID string from the file.
76 """
77 doc = xml.dom.minidom.parse(project_path)
78 try:
79 n_root = doc.documentElement
80 if n_root.nodeName != 'VisualStudioProject':
81 raise SCons.Errors.UserError('%s is not a Visual Studio project.' %
82 project_path)
83 return str(n_root.attributes['ProjectGUID'].nodeValue)
84 finally:
85 # Clean up doc
86 doc.unlink()
87
88 #------------------------------------------------------------------------------
89
90
91 def ComponentVSProjectBuilder(target, source, env):
92 """Visual Studio project builder.
93
94 Args:
95 target: Destination file.
96 source: List of sources to be added to the target.
97 env: Environment context.
98
99 Returns:
100 Zero if successful.
101 """
102 source = source # Silence gpylint
103
104 target_name = env['TARGET_NAME']
105 project_file = target[0].path
106 project_to_main = env.RelativePath(target[0].dir, env.Dir('$MAIN_DIR'),
107 sep='/')
108 hammer_bat = '$(ProjectDir)/%s/hammer.bat' % project_to_main
109
110 # Project header
111 xml_impl = xml.dom.getDOMImplementation()
112 doc = xml_impl.createDocument(None, 'VisualStudioProject', None)
113
114 n_root = doc.documentElement
115 n_root.setAttribute('ProjectType', 'Visual C++')
116 n_root.setAttribute('Version', '8.00')
117 n_root.setAttribute('Name', target_name)
118 n_root.setAttribute('ProjectGUID', MakeGuid(target_name))
119 n_root.setAttribute('RootNamespace', target_name)
120 n_root.setAttribute('Keyword', 'MakeFileProj')
121
122 n_platform = doc.createElement('Platforms')
123 n_root.appendChild(n_platform)
124 n = doc.createElement('Platform')
125 n.setAttribute('Name', 'Win32')
126 n_platform.appendChild(n)
127
128 n_root.appendChild(doc.createElement('ToolFiles'))
129
130 # One configuration per build mode supported by this target
131 n_configs = doc.createElement('Configurations')
132 n_root.appendChild(n_configs)
133
134 target_path = env['TARGET_PATH']
135 for mode, path in target_path.items():
136 n_config = doc.createElement('Configuration')
137 n_config.setAttribute('Name', '%s|Win32' % mode)
138 n_config.setAttribute('OutputDirectory',
139 '$(ProjectDir)/%s/%s/out' % (mode, target_name))
140 n_config.setAttribute('IntermediateDirectory',
141 '$(ProjectDir)/%s/%s/tmp' % (mode, target_name))
142 n_config.setAttribute('ConfigurationType', '0')
143 n_configs.appendChild(n_config)
144
145 n_tool = doc.createElement('Tool')
146 n_tool.setAttribute('Name', 'VCNMakeTool')
147 n_tool.setAttribute('IncludeSearchPath', '')
148 n_tool.setAttribute('ForcedIncludes', '')
149 n_tool.setAttribute('AssemblySearchPath', '')
150 n_tool.setAttribute('ForcedUsingAssemblies', '')
151 n_tool.setAttribute('CompileAsManaged', '')
152 n_tool.setAttribute('PreprocessorDefinitions', '')
153 if path:
154 n_tool.setAttribute(
155 'Output', env.RelativePath(target[0].dir, env.Entry(path), sep='/'))
156 build_cmd = '%s --mode=%s %s' % (hammer_bat, mode, target_name)
157 clean_cmd = '%s --mode=%s -c %s' % (hammer_bat, mode, target_name)
158 n_tool.setAttribute('BuildCommandLine', build_cmd)
159 n_tool.setAttribute('CleanCommandLine', clean_cmd)
160 n_tool.setAttribute('ReBuildCommandLine', clean_cmd + ' && ' + build_cmd)
161 n_config.appendChild(n_tool)
162
163 n_files = doc.createElement('Files')
164 n_root.appendChild(n_files)
165 # TODO(rspangler): Fill in files - at least, the .scons file invoking the
166 # target.
167
168 n_root.appendChild(doc.createElement('Globals'))
169
170 f = open(project_file, 'wt')
171 doc.writexml(f, encoding='Windows-1252', addindent=' ', newl='\n')
172 f.close()
173
174 return 0
175
176
177 def ComponentVSProject(self, target_name, **kwargs):
178 """Visual Studio project pseudo-builder for the specified target.
179
180 Args:
181 self: Environment context.
182 target_name: Name of the target.
183 kwargs: Optional keyword arguments override environment variables in the
184 derived environment used to create the project.
185
186 Returns:
187 A list of output nodes.
188 """
189 # Builder only works on Windows
190 if sys.platform not in ('win32', 'cygwin'):
191 return []
192
193 # Clone environment and add keyword args
194 env = self.Clone()
195 for k, v in kwargs.items():
196 env[k] = v
197
198 # Save the target name
199 env['TARGET_NAME'] = target_name
200
201 # Extract the target properties and save in the environment for use by the
202 # real builder.
203 t = GetTargets().get(target_name)
204 env['TARGET_PATH'] = {}
205 if t:
206 for mode, mode_properties in t.mode_properties.items():
207 # Since the target path is what Visual Studio will run, use the EXE
208 # property in preference to TARGET_PATH.
209 target_path = mode_properties.get('EXE',
210 mode_properties.get('TARGET_PATH'))
211 env.Append(TARGET_PATH={mode: target_path})
212 else:
213 # No modes declared for this target. Could be a custom alias created by
214 # a SConscript, rather than a component builder. Assume it can be built in
215 # all modes, but produces no output.
216 for mode in GetTargetModes():
217 env.Append(TARGET_PATH={mode: None})
218
219 # Call the real builder
220 return env.ComponentVSProjectBuilder(
221 '$COMPONENT_VS_PROJECT_DIR/${TARGET_NAME}', [])
222
223 #------------------------------------------------------------------------------
224
225
226 def ComponentVSSolutionBuilder(target, source, env):
227 """Visual Studio solution builder.
228
229 Args:
230 target: Destination file.
231 source: List of sources to be added to the target.
232 env: Environment context.
233
234 Returns:
235 Zero if successful.
236 """
237 source = source # Silence gpylint
238
239 solution_file = target[0].path
240 projects = env['SOLUTION_PROJECTS']
241 folders = env['SOLUTION_FOLDERS']
242
243 f = open(solution_file, 'wt')
244
245 f.write('Microsoft Visual Studio Solution File, Format Version 9.00\n')
246 f.write('# Visual Studio 2005\n')
247
248 # Projects generated by ComponentVSSolution()
249 for p in projects:
250 project_file = env.File(
251 '$COMPONENT_VS_PROJECT_DIR/%s$COMPONENT_VS_PROJECT_SUFFIX' % p)
252 f.write('Project("%s") = "%s", "%s", "%s"\nEndProject\n' % (
253 '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}', # External makefile GUID
254 p, # Project name
255 env.RelativePath(target[0].dir, project_file), # Path to project file
256 MakeGuid(p), # Project GUID
257 ))
258
259 # Projects generated elsewhere
260 for p in source:
261 f.write('Project("%s") = "%s", "%s", "%s"\nEndProject\n' % (
262 # TODO(rspangler): What if this project isn't type external makefile?
263 # How to tell what type it is?
264 '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}', # External makefile GUID
265 p, # Project name
266 env.RelativePath(target[0].dir, p), # Path to project file
267 GetGuidFromVSProject(p.abspath), # Project GUID
268 ))
269
270 # Folders from build groups
271 for folder in folders:
272 f.write('Project("%s") = "%s", "%s", "%s"\nEndProject\n' % (
273 '{2150E333-8FDC-42A3-9474-1A3956D46DE8}', # Solution folder GUID
274 folder, # Folder name
275 folder, # Folder name (again)
276 # Use a different seed so the folder won't get the same GUID as a
277 # project.
278 MakeGuid(folder, seed='folder'), # Project GUID
279 ))
280
281 f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
282 for mode in GetTargetModes():
283 f.write('\t\t%s|Win32 = %s|Win32\n' % (mode, mode))
284 f.write('\tEndGlobalSection\n')
285
286 f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
287 for p in projects:
288 for mode in GetTargetModes():
289 f.write('\t\t%s.%s|Win32.ActiveCfg = %s|Win32\n' % (
290 MakeGuid(p), # Project GUID
291 mode, # Solution build configuration
292 mode, # Project build config for that solution config
293 ))
294 t = GetTargets().get(p)
295 if t and mode in t.mode_properties:
296 # Target can be built in this mode
297 f.write('\t\t%s.%s|Win32.Build.0 = %s|Win32\n' % (
298 MakeGuid(p), # Project GUID
299 mode, # Solution build configuration
300 mode, # Project build config for that solution config
301 ))
302 f.write('\tEndGlobalSection\n')
303
304 f.write('\tGlobalSection(SolutionProperties) = preSolution\n')
305 f.write('\t\tHideSolutionNode = FALSE\n')
306 f.write('\tEndGlobalSection\n')
307
308 if folders:
309 f.write('\tGlobalSection(NestedProjects) = preSolution\n')
310 for p, folder in projects.items():
311 f.write('\t\t%s = %s\n' % (MakeGuid(p), MakeGuid(folder, seed='folder')))
312 f.write('\tEndGlobalSection\n')
313
314 f.write('EndGlobal\n')
315 f.close()
316
317 return 0
318
319
320 def ComponentVSSolution(self, solution_name, target_names, projects=None,
321 **kwargs):
322 """Visual Studio solution pseudo-builder.
323
324 Args:
325 self: Environment context.
326 solution_name: Name of the target.
327 target_names: Names of targets or target groups to include in the solution.
328 This will automatically build projects for them.
329 projects: List of aditional projects not generated by this solution to
330 include in the solution.
331 kwargs: Optional keyword arguments override environment variables in the
332 derived environment used to create the solution.
333
334 Returns:
335 The list of output nodes.
336 """
337 # TODO(rspangler): Should have option to build source project also. Perhaps
338 # select using a --source_project option, since it needs to use gather_inputs
339 # to scan the DAG and will blow up the null build time.
340 # TODO(rspangler): Should also have autobuild_projects option. If false,
341 # don't build them.
342 # TODO(rspangler): Should also be able to specify a target group directly
343 # (i.e. 'run_all_tests')
344
345 # Builder only works on Windows
346 if sys.platform not in ('win32', 'cygwin'):
347 return []
348
349 # Clone environment and add keyword args
350 env = self.Clone()
351 for k, v in kwargs.items():
352 env[k] = v
353
354 # Save the target name
355 env['SOLUTION_NAME'] = solution_name
356
357 # Get list of targets to make projects for. At this point we haven't
358 # determined whether they're groups or targets.
359 target_names = env.SubstList2(target_names)
360 env['SOLUTION_TARGETS'] = target_names
361
362 project_names = {}
363 folders = []
364 # Expand target_names into project names, and create project-to-folder
365 # mappings
366 if target_names:
367 # Expand target_names into project names
368 for target in target_names:
369 if target in GetTargetGroups():
370 # Add target to folders
371 folders.append(target)
372 # Add all project_names in the group
373 for t in GetTargetGroups()[target].GetTargetNames():
374 project_names[t] = target
375 elif target in GetTargets():
376 # Just a target name
377 project_names[target] = None
378 else:
379 print 'Warning: ignoring unknown target "%s"' % target
380 else:
381 # No target names specified, so use all projects
382 for t in GetTargets():
383 project_names[t] = None
384
385 env['SOLUTION_FOLDERS'] = folders
386 env['SOLUTION_PROJECTS'] = project_names
387
388 # Call the real builder
389 out_nodes = env.ComponentVSSolutionBuilder(
390 '$COMPONENT_VS_SOLUTION_DIR/${SOLUTION_NAME}', projects or [])
391
392 # Call the real builder for the projects we generate
393 for p in project_names:
394 out_nodes += env.ComponentVSProject(p)
395
396 # Add the solution target
397 # TODO(rspangler): Should really defer the rest of the work above, since
398 # otherwise we can't build a solution which has a target to rebuild itself.
399 env.Alias('all_solutions', env.Alias(solution_name, out_nodes))
400
401 # TODO(rspangler): To rebuild the solution properly, need to override its
402 # project configuration so it only has '--mode=all' (or some other way of
403 # setting the subset of modes which it should use to rebuild itself).
404 # Rebuilding with the property below will strip it down to just the current
405 # build mode, which isn't what we want.
406 # Let component_targets know this target is available in the current mode
407 #self.SetTargetProperty(solution_name, TARGET_PATH=out_nodes[0])
408
409 return out_nodes
410
411 #------------------------------------------------------------------------------
412
413
414 def generate(env):
415 # NOTE: SCons requires the use of this name, which fails gpylint.
416 """SCons entry point for this tool."""
417
418 # Add pseudo-builders to set up the project and solution builders. These
419 # need to be available on all platforms so that SConscripts which reference
420 # them will work.
421 env.AddMethod(ComponentVSProject)
422 env.AddMethod(ComponentVSSolution)
423
424 # If not on Windows, don't do anything else
425 if sys.platform not in ('win32', 'cygwin'):
426 return
427
428 # Include tools we need
429 env.Tool('gather_inputs')
430
431 env.SetDefault(
432 COMPONENT_VS_SOLUTION_DIR='$DESTINATION_ROOT/solution',
433 COMPONENT_VS_PROJECT_DIR='$COMPONENT_VS_SOLUTION_DIR/projects',
434 COMPONENT_VS_SOLUTION_SUFFIX='.sln',
435 COMPONENT_VS_PROJECT_SUFFIX='.vcproj',
436 )
437
438 AddTargetGroup('all_solutions', 'solutions can be built')
439
440 # Add builders
441 vcprojaction = SCons.Script.Action(ComponentVSProjectBuilder, varlist=[
442 'TARGET_NAME',
443 'TARGET_PATH',
444 ])
445 vcprojbuilder = SCons.Script.Builder(
446 action=vcprojaction,
447 suffix='$COMPONENT_VS_PROJECT_SUFFIX')
448
449 slnaction = SCons.Script.Action(ComponentVSSolutionBuilder, varlist=[
450 'SOLUTION_TARGETS',
451 'SOLUTION_FOLDERS',
452 'SOLUTION_PROJECTS',
453 ])
454 slnbuilder = SCons.Script.Builder(
455 action=slnaction,
456 suffix='$COMPONENT_VS_SOLUTION_SUFFIX')
457
458 env.Append(BUILDERS={
459 'ComponentVSProjectBuilder': vcprojbuilder,
460 'ComponentVSSolutionBuilder': slnbuilder,
461 })
OLDNEW
« no previous file with comments | « site_scons/site_tools/component_targets.py ('k') | site_scons/site_tools/component_targets_xml.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698