blob: e66757ad8611c5a6028474e829946bda8cb33982 [file] [log] [blame]
Brian Osmanc20d34c2016-10-31 12:37:01 -04001# 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
Martin Vejdarskibeaaf472020-03-03 13:53:20 +07005from __future__ import print_function
6
Brian Osmanc20d34c2016-10-31 12:37:01 -04007import os
8import glob
Brian Osmane54d4ce2016-11-21 10:41:20 -05009import re
Brian Osmanc20d34c2016-10-31 12:37:01 -040010import sys
11from shutil import copyfile
12
Brian Osmane54d4ce2016-11-21 10:41:20 -050013# Helpers
14def ensureExists(path):
15 try:
16 os.makedirs(path)
17 except OSError:
18 pass
19
20def writeLinesToFile(lines, fileName):
21 ensureExists(os.path.dirname(fileName))
22 with open(fileName, "w") as f:
23 f.writelines(lines)
24
25def extractIdg(projFileName):
26 result = []
27 with open(projFileName) as projFile:
28 lines = iter(projFile)
29 for pLine in lines:
30 if "<ItemDefinitionGroup" in pLine:
31 while not "</ItemDefinitionGroup" in pLine:
32 result.append(pLine)
33 pLine = lines.next()
34 result.append(pLine)
35 return result
36
37# [ (name, hasSln), ... ]
Brian Osmanc20d34c2016-10-31 12:37:01 -040038configs = []
Brian Osmane54d4ce2016-11-21 10:41:20 -050039
40# Find all directories that can be used as configs (and record if they have VS
41# files present)
Brian Osmanc20d34c2016-10-31 12:37:01 -040042for root, dirs, files in os.walk("out"):
43 for outDir in dirs:
Brian Osman06e539a2016-11-18 13:38:13 -050044 gnFile = os.path.join("out", outDir, "build.ninja.d")
Brian Osman06e539a2016-11-18 13:38:13 -050045 if os.path.exists(gnFile):
Brian Osmane54d4ce2016-11-21 10:41:20 -050046 slnFile = os.path.join("out", outDir, "all.sln")
47 configs.append((outDir, os.path.exists(slnFile)))
Brian Osmanc20d34c2016-10-31 12:37:01 -040048 break
49
Brian Osmane54d4ce2016-11-21 10:41:20 -050050# Every project has a GUID that encodes the type. We only care about C++.
51cppTypeGuid = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
52
53# name -> [ (config, pathToProject, GUID), ... ]
54allProjects = {}
55projectPattern = (r'Project\("\{' + cppTypeGuid +
56 r'\}"\) = "([^"]*)", "([^"]*)", "\{([^\}]*)\}"')
Brian Osmanbc9f3b02018-06-01 15:15:13 -040057projectNamePattern = (r'obj/(.*)\.vcxproj')
Brian Osmane54d4ce2016-11-21 10:41:20 -050058
59for config in configs:
60 if config[1]:
61 slnLines = iter(open("out/" + config[0] + "/all.sln"))
62 for slnLine in slnLines:
63 matchObj = re.match(projectPattern, slnLine)
64 if matchObj:
Brian Osmanbc9f3b02018-06-01 15:15:13 -040065 projPath = matchObj.group(2)
66 nameObj = re.match(projectNamePattern, projPath)
67 if nameObj:
68 projName = nameObj.group(1).replace('/', '.')
69 if not allProjects.has_key(projName):
70 allProjects[projName] = []
71 allProjects[projName].append((config[0], projPath,
72 matchObj.group(3)))
Brian Osmane54d4ce2016-11-21 10:41:20 -050073
74# We need something to work with. Typically, this will fail if no GN folders
75# have IDE files
76if len(allProjects) == 0:
Martin Vejdarskibeaaf472020-03-03 13:53:20 +070077 print("ERROR: At least one GN directory must have been built with --ide=vs")
Brian Osman06e539a2016-11-18 13:38:13 -050078 sys.exit()
79
Brian Osmane54d4ce2016-11-21 10:41:20 -050080# Create a new solution. We arbitrarily use the first config as the GUID source
81# (but we need to match that behavior later, when we copy/generate the project
82# files).
Brian Osmanc20d34c2016-10-31 12:37:01 -040083newSlnLines = []
Brian Osmane54d4ce2016-11-21 10:41:20 -050084newSlnLines.append(
85 'Microsoft Visual Studio Solution File, Format Version 12.00\n')
86newSlnLines.append('# Visual Studio 2015\n')
87for projName, projConfigs in allProjects.items():
88 newSlnLines.append('Project("{' + cppTypeGuid + '}") = "' + projName +
89 '", "' + projConfigs[0][1] + '", "{' + projConfigs[0][2]
90 + '}"\n')
91 newSlnLines.append('EndProject\n')
Brian Osmanc20d34c2016-10-31 12:37:01 -040092
Brian Osmane54d4ce2016-11-21 10:41:20 -050093newSlnLines.append('Global\n')
94newSlnLines.append(
95 '\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
96for config in configs:
97 newSlnLines.append('\t\t' + config[0] + '|x64 = ' + config[0] + '|x64\n')
98newSlnLines.append('\tEndGlobalSection\n')
99newSlnLines.append(
100 '\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
101for projName, projConfigs in allProjects.items():
102 projGuid = projConfigs[0][2]
103 for config in configs:
104 newSlnLines.append('\t\t{' + projGuid + '}.' + config[0] +
105 '|x64.ActiveCfg = ' + config[0] + '|x64\n')
106 newSlnLines.append('\t\t{' + projGuid + '}.' + config[0] +
107 '|x64.Build.0 = ' + config[0] + '|x64\n')
108newSlnLines.append('\tEndGlobalSection\n')
109newSlnLines.append('\tGlobalSection(SolutionProperties) = preSolution\n')
110newSlnLines.append('\t\tHideSolutionNode = FALSE\n')
111newSlnLines.append('\tEndGlobalSection\n')
112newSlnLines.append('\tGlobalSection(NestedProjects) = preSolution\n')
113newSlnLines.append('\tEndGlobalSection\n')
114newSlnLines.append('EndGlobal\n')
Brian Osmanc20d34c2016-10-31 12:37:01 -0400115
Brian Osmane54d4ce2016-11-21 10:41:20 -0500116# Write solution file
117writeLinesToFile(newSlnLines, "out/sln/skia.sln")
Brian Osmanc20d34c2016-10-31 12:37:01 -0400118
Brian Osmane54d4ce2016-11-21 10:41:20 -0500119idgHdr = "<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='"
120
121# Now, bring over the project files
122for projName, projConfigs in allProjects.items():
123 # Paths to project and filter file in src and dst locations
124 srcProjPath = os.path.join("out", projConfigs[0][0], projConfigs[0][1])
125 dstProjPath = os.path.join("out", "sln", projConfigs[0][1])
126 srcFilterPath = srcProjPath + ".filters"
127 dstFilterPath = dstProjPath + ".filters"
128
129 # Copy the filter file unmodified
130 ensureExists(os.path.dirname(dstProjPath))
131 copyfile(srcFilterPath, dstFilterPath)
132
133 # Bring over the project file, modified with extra configs
134 with open(srcProjPath) as srcProjFile:
Brian Osmanc20d34c2016-10-31 12:37:01 -0400135 projLines = iter(srcProjFile)
136 newProjLines = []
137 for line in projLines:
Brian Osmane54d4ce2016-11-21 10:41:20 -0500138 if "<ItemDefinitionGroup" in line:
139 # This is a large group that contains many settings. We need to
140 # replicate it, with conditions so it varies per configuration.
141 idgLines = []
142 while not "</ItemDefinitionGroup" in line:
143 idgLines.append(line)
144 line = projLines.next()
145 idgLines.append(line)
146 for projConfig in projConfigs:
147 configIdgLines = extractIdg(os.path.join("out",
148 projConfig[0],
149 projConfig[1]))
150 newProjLines.append(idgHdr + projConfig[0] + "|x64'\">\n")
151 for idgLine in configIdgLines[1:]:
152 newProjLines.append(idgLine)
153 elif "ProjectConfigurations" in line:
Brian Osmanc20d34c2016-10-31 12:37:01 -0400154 newProjLines.append(line)
155 projConfigLines = [
156 projLines.next(),
157 projLines.next(),
158 projLines.next(),
159 projLines.next() ]
160 for config in configs:
161 for projConfigLine in projConfigLines:
Brian Osmane54d4ce2016-11-21 10:41:20 -0500162 newProjLines.append(projConfigLine.replace("GN",
163 config[0]))
Brian Osmanc20d34c2016-10-31 12:37:01 -0400164 elif "<OutDir" in line:
Brian Osmane54d4ce2016-11-21 10:41:20 -0500165 newProjLines.append(line.replace(projConfigs[0][0],
166 "$(Configuration)"))
Brian Osmanc20d34c2016-10-31 12:37:01 -0400167 else:
168 newProjLines.append(line)
Brian Osmane54d4ce2016-11-21 10:41:20 -0500169 with open(dstProjPath, "w") as newProj:
Brian Osmanc20d34c2016-10-31 12:37:01 -0400170 newProj.writelines(newProjLines)