• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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
5import os
6import glob
7import re
8import sys
9from shutil import copyfile
10
11# Helpers
12def ensureExists(path):
13    try:
14        os.makedirs(path)
15    except OSError:
16        pass
17
18def writeLinesToFile(lines, fileName):
19    ensureExists(os.path.dirname(fileName))
20    with open(fileName, "w") as f:
21        f.writelines(lines)
22
23def extractIdg(projFileName):
24    result = []
25    with open(projFileName) as projFile:
26        lines = iter(projFile)
27        for pLine in lines:
28            if "<ItemDefinitionGroup" in pLine:
29                while not "</ItemDefinitionGroup" in pLine:
30                    result.append(pLine)
31                    pLine = lines.next()
32                result.append(pLine)
33                return result
34
35# [ (name, hasSln), ... ]
36configs = []
37
38# Find all directories that can be used as configs (and record if they have VS
39# files present)
40for root, dirs, files in os.walk("out"):
41    for outDir in dirs:
42        gnFile = os.path.join("out", outDir, "build.ninja.d")
43        if os.path.exists(gnFile):
44            slnFile = os.path.join("out", outDir, "all.sln")
45            configs.append((outDir, os.path.exists(slnFile)))
46    break
47
48# Every project has a GUID that encodes the type. We only care about C++.
49cppTypeGuid = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
50
51# name -> [ (config, pathToProject, GUID), ... ]
52allProjects = {}
53projectPattern = (r'Project\("\{' + cppTypeGuid +
54                  r'\}"\) = "([^"]*)", "([^"]*)", "\{([^\}]*)\}"')
55
56for config in configs:
57    if config[1]:
58        slnLines = iter(open("out/" + config[0] + "/all.sln"))
59        for slnLine in slnLines:
60            matchObj = re.match(projectPattern, slnLine)
61            if matchObj:
62                projName = matchObj.group(1)
63                if not allProjects.has_key(projName):
64                    allProjects[projName] = []
65                allProjects[projName].append((config[0], matchObj.group(2),
66                                              matchObj.group(3)))
67
68# We need something to work with. Typically, this will fail if no GN folders
69# have IDE files
70if len(allProjects) == 0:
71    print "ERROR: At least one GN directory must have been built with --ide=vs"
72    sys.exit()
73
74# Create a new solution. We arbitrarily use the first config as the GUID source
75# (but we need to match that behavior later, when we copy/generate the project
76# files).
77newSlnLines = []
78newSlnLines.append(
79    'Microsoft Visual Studio Solution File, Format Version 12.00\n')
80newSlnLines.append('# Visual Studio 2015\n')
81for projName, projConfigs in allProjects.items():
82    newSlnLines.append('Project("{' + cppTypeGuid + '}") = "' + projName +
83                       '", "' + projConfigs[0][1] + '", "{' + projConfigs[0][2]
84                       + '}"\n')
85    newSlnLines.append('EndProject\n')
86
87newSlnLines.append('Global\n')
88newSlnLines.append(
89    '\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
90for config in configs:
91    newSlnLines.append('\t\t' + config[0] + '|x64 = ' + config[0] + '|x64\n')
92newSlnLines.append('\tEndGlobalSection\n')
93newSlnLines.append(
94    '\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
95for projName, projConfigs in allProjects.items():
96    projGuid = projConfigs[0][2]
97    for config in configs:
98        newSlnLines.append('\t\t{' + projGuid + '}.' + config[0] +
99                           '|x64.ActiveCfg = ' + config[0] + '|x64\n')
100        newSlnLines.append('\t\t{' + projGuid + '}.' + config[0] +
101                           '|x64.Build.0 = ' + config[0] + '|x64\n')
102newSlnLines.append('\tEndGlobalSection\n')
103newSlnLines.append('\tGlobalSection(SolutionProperties) = preSolution\n')
104newSlnLines.append('\t\tHideSolutionNode = FALSE\n')
105newSlnLines.append('\tEndGlobalSection\n')
106newSlnLines.append('\tGlobalSection(NestedProjects) = preSolution\n')
107newSlnLines.append('\tEndGlobalSection\n')
108newSlnLines.append('EndGlobal\n')
109
110# Write solution file
111writeLinesToFile(newSlnLines, "out/sln/skia.sln")
112
113idgHdr = "<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='"
114
115# Now, bring over the project files
116for projName, projConfigs in allProjects.items():
117    # Paths to project and filter file in src and dst locations
118    srcProjPath = os.path.join("out", projConfigs[0][0], projConfigs[0][1])
119    dstProjPath = os.path.join("out", "sln", projConfigs[0][1])
120    srcFilterPath = srcProjPath + ".filters"
121    dstFilterPath = dstProjPath + ".filters"
122
123    # Copy the filter file unmodified
124    ensureExists(os.path.dirname(dstProjPath))
125    copyfile(srcFilterPath, dstFilterPath)
126
127    # Bring over the project file, modified with extra configs
128    with open(srcProjPath) as srcProjFile:
129        projLines = iter(srcProjFile)
130        newProjLines = []
131        for line in projLines:
132            if "<ItemDefinitionGroup" in line:
133                # This is a large group that contains many settings. We need to
134                # replicate it, with conditions so it varies per configuration.
135                idgLines = []
136                while not "</ItemDefinitionGroup" in line:
137                    idgLines.append(line)
138                    line = projLines.next()
139                idgLines.append(line)
140                for projConfig in projConfigs:
141                    configIdgLines = extractIdg(os.path.join("out",
142                                                             projConfig[0],
143                                                             projConfig[1]))
144                    newProjLines.append(idgHdr + projConfig[0] + "|x64'\">\n")
145                    for idgLine in configIdgLines[1:]:
146                        newProjLines.append(idgLine)
147            elif "ProjectConfigurations" in line:
148                newProjLines.append(line)
149                projConfigLines = [
150                    projLines.next(),
151                    projLines.next(),
152                    projLines.next(),
153                    projLines.next() ]
154                for config in configs:
155                    for projConfigLine in projConfigLines:
156                        newProjLines.append(projConfigLine.replace("GN",
157                                                                   config[0]))
158            elif "<OutDir" in line:
159                newProjLines.append(line.replace(projConfigs[0][0],
160                                                 "$(Configuration)"))
161            else:
162                newProjLines.append(line)
163        with open(dstProjPath, "w") as newProj:
164            newProj.writelines(newProjLines)
165