~ubuntu-branches/ubuntu/oneiric/mozc/oneiric

« back to all changes in this revision

Viewing changes to mozc_build_tools/gyp/pylib/gyp/MSVSNew.py

  • Committer: Bazaar Package Importer
  • Author(s): Nobuhiro Iwamatsu
  • Date: 2010-07-14 03:26:47 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100714032647-13qjisj6m8cm8jdx
Tags: 0.12.410.102-1
* New upstream release (Closes: #588971).
  - Add mozc-server, mozc-utils-gui and scim-mozc packages.
* Update debian/rules.
  Add --gypdir option to build_mozc.py.
* Update debian/control.
  - Bumped standards-version to 3.9.0.
  - Update description.
* Add mozc icon (Closes: #588972).
* Add patch which revises issue 18.
  ibus_mozc_issue18.patch
* kFreeBSD build support.
  support_kfreebsd.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python2.4
 
2
 
 
3
# Copyright (c) 2009 Google Inc. All rights reserved.
 
4
# Use of this source code is governed by a BSD-style license that can be
 
5
# found in the LICENSE file.
 
6
 
 
7
"""New implementation of Visual Studio project generation for SCons."""
 
8
 
 
9
import common
 
10
import os
 
11
import random
 
12
 
 
13
# hashlib is supplied as of Python 2.5 as the replacement interface for md5
 
14
# and other secure hashes.  In 2.6, md5 is deprecated.  Import hashlib if
 
15
# available, avoiding a deprecation warning under 2.6.  Import md5 otherwise,
 
16
# preserving 2.4 compatibility.
 
17
try:
 
18
  import hashlib
 
19
  _new_md5 = hashlib.md5
 
20
except ImportError:
 
21
  import md5
 
22
  _new_md5 = md5.new
 
23
 
 
24
 
 
25
# Initialize random number generator
 
26
random.seed()
 
27
 
 
28
# GUIDs for project types
 
29
ENTRY_TYPE_GUIDS = {
 
30
    'project': '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}',
 
31
    'folder': '{2150E333-8FDC-42A3-9474-1A3956D46DE8}',
 
32
}
 
33
 
 
34
#------------------------------------------------------------------------------
 
35
# Helper functions
 
36
 
 
37
 
 
38
def MakeGuid(name, seed='msvs_new'):
 
39
  """Returns a GUID for the specified target name.
 
40
 
 
41
  Args:
 
42
    name: Target name.
 
43
    seed: Seed for MD5 hash.
 
44
  Returns:
 
45
    A GUID-line string calculated from the name and seed.
 
46
 
 
47
  This generates something which looks like a GUID, but depends only on the
 
48
  name and seed.  This means the same name/seed will always generate the same
 
49
  GUID, so that projects and solutions which refer to each other can explicitly
 
50
  determine the GUID to refer to explicitly.  It also means that the GUID will
 
51
  not change when the project for a target is rebuilt.
 
52
  """
 
53
  # Calculate a MD5 signature for the seed and name.
 
54
  d = _new_md5(str(seed) + str(name)).hexdigest().upper()
 
55
  # Convert most of the signature to GUID form (discard the rest)
 
56
  guid = ('{' + d[:8] + '-' + d[8:12] + '-' + d[12:16] + '-' + d[16:20]
 
57
          + '-' + d[20:32] + '}')
 
58
  return guid
 
59
 
 
60
#------------------------------------------------------------------------------
 
61
 
 
62
 
 
63
class MSVSFolder:
 
64
  """Folder in a Visual Studio project or solution."""
 
65
 
 
66
  def __init__(self, path, name = None, entries = None,
 
67
               guid = None, items = None):
 
68
    """Initializes the folder.
 
69
 
 
70
    Args:
 
71
      path: Full path to the folder.
 
72
      name: Name of the folder.
 
73
      entries: List of folder entries to nest inside this folder.  May contain
 
74
          Folder or Project objects.  May be None, if the folder is empty.
 
75
      guid: GUID to use for folder, if not None.
 
76
      items: List of solution items to include in the folder project.  May be
 
77
          None, if the folder does not directly contain items.
 
78
    """
 
79
    if name:
 
80
      self.name = name
 
81
    else:
 
82
      # Use last layer.
 
83
      self.name = os.path.basename(path)
 
84
 
 
85
    self.path = path
 
86
    self.guid = guid
 
87
 
 
88
    # Copy passed lists (or set to empty lists)
 
89
    self.entries = list(entries or [])
 
90
    self.items = list(items or [])
 
91
 
 
92
    self.entry_type_guid = ENTRY_TYPE_GUIDS['folder']
 
93
 
 
94
  def get_guid(self):
 
95
    if self.guid is None:
 
96
      # Use consistent guids for folders (so things don't regenerate).
 
97
      self.guid = MakeGuid(self.path, seed='msvs_folder')
 
98
    return self.guid
 
99
 
 
100
 
 
101
#------------------------------------------------------------------------------
 
102
 
 
103
 
 
104
class MSVSProject:
 
105
  """Visual Studio project."""
 
106
 
 
107
  def __init__(self, path, name = None, dependencies = None, guid = None,
 
108
               config_platform_overrides = None):
 
109
    """Initializes the project.
 
110
 
 
111
    Args:
 
112
      path: Relative path to project file.
 
113
      name: Name of project.  If None, the name will be the same as the base
 
114
          name of the project file.
 
115
      dependencies: List of other Project objects this project is dependent
 
116
          upon, if not None.
 
117
      guid: GUID to use for project, if not None.
 
118
      config_platform_overrides: optional dict of configuration platforms to
 
119
          used in place of the default for this target.
 
120
    """
 
121
    self.path = path
 
122
    self.guid = guid
 
123
 
 
124
    if name:
 
125
      self.name = name
 
126
    else:
 
127
      # Use project filename
 
128
      self.name = os.path.splitext(os.path.basename(path))[0]
 
129
 
 
130
    # Copy passed lists (or set to empty lists)
 
131
    self.dependencies = list(dependencies or [])
 
132
 
 
133
    self.entry_type_guid = ENTRY_TYPE_GUIDS['project']
 
134
 
 
135
    if config_platform_overrides:
 
136
      self.config_platform_overrides = config_platform_overrides
 
137
    else:
 
138
      self.config_platform_overrides = {}
 
139
 
 
140
  def get_guid(self):
 
141
    if self.guid is None:
 
142
      # Set GUID from path
 
143
      # TODO(rspangler): This is fragile.
 
144
      # 1. We can't just use the project filename sans path, since there could
 
145
      #    be multiple projects with the same base name (for example,
 
146
      #    foo/unittest.vcproj and bar/unittest.vcproj).
 
147
      # 2. The path needs to be relative to $SOURCE_ROOT, so that the project
 
148
      #    GUID is the same whether it's included from base/base.sln or
 
149
      #    foo/bar/baz/baz.sln.
 
150
      # 3. The GUID needs to be the same each time this builder is invoked, so
 
151
      #    that we don't need to rebuild the solution when the project changes.
 
152
      # 4. We should be able to handle pre-built project files by reading the
 
153
      #    GUID from the files.
 
154
      self.guid = MakeGuid(self.name)
 
155
    return self.guid
 
156
 
 
157
#------------------------------------------------------------------------------
 
158
 
 
159
 
 
160
class MSVSSolution:
 
161
  """Visual Studio solution."""
 
162
 
 
163
  def __init__(self, path, version, entries=None, variants=None,
 
164
               websiteProperties=True):
 
165
    """Initializes the solution.
 
166
 
 
167
    Args:
 
168
      path: Path to solution file.
 
169
      version: Format version to emit.
 
170
      entries: List of entries in solution.  May contain Folder or Project
 
171
          objects.  May be None, if the folder is empty.
 
172
      variants: List of build variant strings.  If none, a default list will
 
173
          be used.
 
174
      websiteProperties: Flag to decide if the website properties section
 
175
          is generated.
 
176
    """
 
177
    self.path = path
 
178
    self.websiteProperties = websiteProperties
 
179
    self.version = version
 
180
 
 
181
    # Copy passed lists (or set to empty lists)
 
182
    self.entries = list(entries or [])
 
183
 
 
184
    if variants:
 
185
      # Copy passed list
 
186
      self.variants = variants[:]
 
187
    else:
 
188
      # Use default
 
189
      self.variants = ['Debug|Win32', 'Release|Win32']
 
190
    # TODO(rspangler): Need to be able to handle a mapping of solution config
 
191
    # to project config.  Should we be able to handle variants being a dict,
 
192
    # or add a separate variant_map variable?  If it's a dict, we can't
 
193
    # guarantee the order of variants since dict keys aren't ordered.
 
194
 
 
195
 
 
196
    # TODO(rspangler): Automatically write to disk for now; should delay until
 
197
    # node-evaluation time.
 
198
    self.Write()
 
199
 
 
200
 
 
201
  def Write(self, writer=common.WriteOnDiff):
 
202
    """Writes the solution file to disk.
 
203
 
 
204
    Raises:
 
205
      IndexError: An entry appears multiple times.
 
206
    """
 
207
    # Walk the entry tree and collect all the folders and projects.
 
208
    all_entries = []
 
209
    entries_to_check = self.entries[:]
 
210
    while entries_to_check:
 
211
      # Pop from the beginning of the list to preserve the user's order.
 
212
      e = entries_to_check.pop(0)
 
213
 
 
214
      # A project or folder can only appear once in the solution's folder tree.
 
215
      # This also protects from cycles.
 
216
      if e in all_entries:
 
217
        #raise IndexError('Entry "%s" appears more than once in solution' %
 
218
        #                 e.name)
 
219
        continue
 
220
 
 
221
      all_entries.append(e)
 
222
 
 
223
      # If this is a folder, check its entries too.
 
224
      if isinstance(e, MSVSFolder):
 
225
        entries_to_check += e.entries
 
226
 
 
227
    # Sort by name then guid (so things are in order on vs2008).
 
228
    def NameThenGuid(a, b):
 
229
      if a.name < b.name: return -1
 
230
      if a.name > b.name: return 1
 
231
      if a.get_guid() < b.get_guid(): return -1
 
232
      if a.get_guid() > b.get_guid(): return 1
 
233
      return 0
 
234
 
 
235
    all_entries = sorted(all_entries, NameThenGuid)
 
236
 
 
237
    # Open file and print header
 
238
    f = writer(self.path)
 
239
    f.write('Microsoft Visual Studio Solution File, '
 
240
            'Format Version %s\r\n' % self.version.SolutionVersion())
 
241
    f.write('# %s\r\n' % self.version.Description())
 
242
 
 
243
    # Project entries
 
244
    for e in all_entries:
 
245
      f.write('Project("%s") = "%s", "%s", "%s"\r\n' % (
 
246
          e.entry_type_guid,          # Entry type GUID
 
247
          e.name,                     # Folder name
 
248
          e.path.replace('/', '\\'),  # Folder name (again)
 
249
          e.get_guid(),               # Entry GUID
 
250
      ))
 
251
 
 
252
      # TODO(rspangler): Need a way to configure this stuff
 
253
      if self.websiteProperties:
 
254
        f.write('\tProjectSection(WebsiteProperties) = preProject\r\n'
 
255
                '\t\tDebug.AspNetCompiler.Debug = "True"\r\n'
 
256
                '\t\tRelease.AspNetCompiler.Debug = "False"\r\n'
 
257
                '\tEndProjectSection\r\n')
 
258
 
 
259
      if isinstance(e, MSVSFolder):
 
260
        if e.items:
 
261
          f.write('\tProjectSection(SolutionItems) = preProject\r\n')
 
262
          for i in e.items:
 
263
            f.write('\t\t%s = %s\r\n' % (i, i))
 
264
          f.write('\tEndProjectSection\r\n')
 
265
 
 
266
      if isinstance(e, MSVSProject):
 
267
        if e.dependencies:
 
268
          f.write('\tProjectSection(ProjectDependencies) = postProject\r\n')
 
269
          for d in e.dependencies:
 
270
            f.write('\t\t%s = %s\r\n' % (d.get_guid(), d.get_guid()))
 
271
          f.write('\tEndProjectSection\r\n')
 
272
 
 
273
      f.write('EndProject\r\n')
 
274
 
 
275
    # Global section
 
276
    f.write('Global\r\n')
 
277
 
 
278
    # Configurations (variants)
 
279
    f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n')
 
280
    for v in self.variants:
 
281
      f.write('\t\t%s = %s\r\n' % (v, v))
 
282
    f.write('\tEndGlobalSection\r\n')
 
283
 
 
284
    # Sort config guids for easier diffing of solution changes.
 
285
    config_guids = []
 
286
    config_guids_overrides = {}
 
287
    for e in all_entries:
 
288
      if isinstance(e, MSVSProject):
 
289
        config_guids.append(e.get_guid())
 
290
        config_guids_overrides[e.get_guid()] = e.config_platform_overrides
 
291
    config_guids.sort()
 
292
 
 
293
    f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n')
 
294
    for g in config_guids:
 
295
      for v in self.variants:
 
296
        nv = config_guids_overrides[g].get(v, v)
 
297
        # Pick which project configuration to build for this solution
 
298
        # configuration.
 
299
        f.write('\t\t%s.%s.ActiveCfg = %s\r\n' % (
 
300
            g,              # Project GUID
 
301
            v,              # Solution build configuration
 
302
            nv,             # Project build config for that solution config
 
303
        ))
 
304
 
 
305
        # Enable project in this solution configuration.
 
306
        f.write('\t\t%s.%s.Build.0 = %s\r\n' % (
 
307
            g,              # Project GUID
 
308
            v,              # Solution build configuration
 
309
            nv,             # Project build config for that solution config
 
310
        ))
 
311
    f.write('\tEndGlobalSection\r\n')
 
312
 
 
313
    # TODO(rspangler): Should be able to configure this stuff too (though I've
 
314
    # never seen this be any different)
 
315
    f.write('\tGlobalSection(SolutionProperties) = preSolution\r\n')
 
316
    f.write('\t\tHideSolutionNode = FALSE\r\n')
 
317
    f.write('\tEndGlobalSection\r\n')
 
318
 
 
319
    # Folder mappings
 
320
    # TODO(rspangler): Should omit this section if there are no folders
 
321
    f.write('\tGlobalSection(NestedProjects) = preSolution\r\n')
 
322
    for e in all_entries:
 
323
      if not isinstance(e, MSVSFolder):
 
324
        continue        # Does not apply to projects, only folders
 
325
      for subentry in e.entries:
 
326
        f.write('\t\t%s = %s\r\n' % (subentry.get_guid(), e.get_guid()))
 
327
    f.write('\tEndGlobalSection\r\n')
 
328
 
 
329
    f.write('EndGlobal\r\n')
 
330
 
 
331
    f.close()