2016-10-31 16:37:01 +00:00
|
|
|
# Copyright 2016 The Chromium Authors. All rights reserved.
|
|
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
|
|
# found in the LICENSE file.
|
|
|
|
|
|
|
|
import os
|
|
|
|
import glob
|
2016-11-21 15:41:20 +00:00
|
|
|
import re
|
2016-10-31 16:37:01 +00:00
|
|
|
import sys
|
|
|
|
from shutil import copyfile
|
|
|
|
|
2016-11-21 15:41:20 +00:00
|
|
|
# Helpers
|
|
|
|
def ensureExists(path):
|
|
|
|
try:
|
|
|
|
os.makedirs(path)
|
|
|
|
except OSError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
def writeLinesToFile(lines, fileName):
|
|
|
|
ensureExists(os.path.dirname(fileName))
|
|
|
|
with open(fileName, "w") as f:
|
|
|
|
f.writelines(lines)
|
|
|
|
|
|
|
|
def extractIdg(projFileName):
|
|
|
|
result = []
|
|
|
|
with open(projFileName) as projFile:
|
|
|
|
lines = iter(projFile)
|
|
|
|
for pLine in lines:
|
|
|
|
if "<ItemDefinitionGroup" in pLine:
|
|
|
|
while not "</ItemDefinitionGroup" in pLine:
|
|
|
|
result.append(pLine)
|
|
|
|
pLine = lines.next()
|
|
|
|
result.append(pLine)
|
|
|
|
return result
|
|
|
|
|
|
|
|
# [ (name, hasSln), ... ]
|
2016-10-31 16:37:01 +00:00
|
|
|
configs = []
|
2016-11-21 15:41:20 +00:00
|
|
|
|
|
|
|
# Find all directories that can be used as configs (and record if they have VS
|
|
|
|
# files present)
|
2016-10-31 16:37:01 +00:00
|
|
|
for root, dirs, files in os.walk("out"):
|
|
|
|
for outDir in dirs:
|
2016-11-18 18:38:13 +00:00
|
|
|
gnFile = os.path.join("out", outDir, "build.ninja.d")
|
|
|
|
if os.path.exists(gnFile):
|
2016-11-21 15:41:20 +00:00
|
|
|
slnFile = os.path.join("out", outDir, "all.sln")
|
|
|
|
configs.append((outDir, os.path.exists(slnFile)))
|
2016-10-31 16:37:01 +00:00
|
|
|
break
|
|
|
|
|
2016-11-21 15:41:20 +00:00
|
|
|
# Every project has a GUID that encodes the type. We only care about C++.
|
|
|
|
cppTypeGuid = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"
|
|
|
|
|
|
|
|
# name -> [ (config, pathToProject, GUID), ... ]
|
|
|
|
allProjects = {}
|
|
|
|
projectPattern = (r'Project\("\{' + cppTypeGuid +
|
|
|
|
r'\}"\) = "([^"]*)", "([^"]*)", "\{([^\}]*)\}"')
|
2018-06-01 19:15:13 +00:00
|
|
|
projectNamePattern = (r'obj/(.*)\.vcxproj')
|
2016-11-21 15:41:20 +00:00
|
|
|
|
|
|
|
for config in configs:
|
|
|
|
if config[1]:
|
|
|
|
slnLines = iter(open("out/" + config[0] + "/all.sln"))
|
|
|
|
for slnLine in slnLines:
|
|
|
|
matchObj = re.match(projectPattern, slnLine)
|
|
|
|
if matchObj:
|
2018-06-01 19:15:13 +00:00
|
|
|
projPath = matchObj.group(2)
|
|
|
|
nameObj = re.match(projectNamePattern, projPath)
|
|
|
|
if nameObj:
|
|
|
|
projName = nameObj.group(1).replace('/', '.')
|
|
|
|
if not allProjects.has_key(projName):
|
|
|
|
allProjects[projName] = []
|
|
|
|
allProjects[projName].append((config[0], projPath,
|
|
|
|
matchObj.group(3)))
|
2016-11-21 15:41:20 +00:00
|
|
|
|
|
|
|
# We need something to work with. Typically, this will fail if no GN folders
|
|
|
|
# have IDE files
|
|
|
|
if len(allProjects) == 0:
|
2016-11-18 18:38:13 +00:00
|
|
|
print "ERROR: At least one GN directory must have been built with --ide=vs"
|
|
|
|
sys.exit()
|
|
|
|
|
2016-11-21 15:41:20 +00:00
|
|
|
# Create a new solution. We arbitrarily use the first config as the GUID source
|
|
|
|
# (but we need to match that behavior later, when we copy/generate the project
|
|
|
|
# files).
|
|
|
|
newSlnLines = []
|
|
|
|
newSlnLines.append(
|
|
|
|
'Microsoft Visual Studio Solution File, Format Version 12.00\n')
|
|
|
|
newSlnLines.append('# Visual Studio 2015\n')
|
|
|
|
for projName, projConfigs in allProjects.items():
|
|
|
|
newSlnLines.append('Project("{' + cppTypeGuid + '}") = "' + projName +
|
|
|
|
'", "' + projConfigs[0][1] + '", "{' + projConfigs[0][2]
|
|
|
|
+ '}"\n')
|
|
|
|
newSlnLines.append('EndProject\n')
|
2016-10-31 16:37:01 +00:00
|
|
|
|
2016-11-21 15:41:20 +00:00
|
|
|
newSlnLines.append('Global\n')
|
|
|
|
newSlnLines.append(
|
|
|
|
'\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
|
|
|
|
for config in configs:
|
|
|
|
newSlnLines.append('\t\t' + config[0] + '|x64 = ' + config[0] + '|x64\n')
|
|
|
|
newSlnLines.append('\tEndGlobalSection\n')
|
|
|
|
newSlnLines.append(
|
|
|
|
'\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
|
|
|
|
for projName, projConfigs in allProjects.items():
|
|
|
|
projGuid = projConfigs[0][2]
|
|
|
|
for config in configs:
|
|
|
|
newSlnLines.append('\t\t{' + projGuid + '}.' + config[0] +
|
|
|
|
'|x64.ActiveCfg = ' + config[0] + '|x64\n')
|
|
|
|
newSlnLines.append('\t\t{' + projGuid + '}.' + config[0] +
|
|
|
|
'|x64.Build.0 = ' + config[0] + '|x64\n')
|
|
|
|
newSlnLines.append('\tEndGlobalSection\n')
|
|
|
|
newSlnLines.append('\tGlobalSection(SolutionProperties) = preSolution\n')
|
|
|
|
newSlnLines.append('\t\tHideSolutionNode = FALSE\n')
|
|
|
|
newSlnLines.append('\tEndGlobalSection\n')
|
|
|
|
newSlnLines.append('\tGlobalSection(NestedProjects) = preSolution\n')
|
|
|
|
newSlnLines.append('\tEndGlobalSection\n')
|
|
|
|
newSlnLines.append('EndGlobal\n')
|
2016-10-31 16:37:01 +00:00
|
|
|
|
2016-11-21 15:41:20 +00:00
|
|
|
# Write solution file
|
|
|
|
writeLinesToFile(newSlnLines, "out/sln/skia.sln")
|
|
|
|
|
|
|
|
idgHdr = "<ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='"
|
|
|
|
|
|
|
|
# Now, bring over the project files
|
|
|
|
for projName, projConfigs in allProjects.items():
|
|
|
|
# Paths to project and filter file in src and dst locations
|
|
|
|
srcProjPath = os.path.join("out", projConfigs[0][0], projConfigs[0][1])
|
|
|
|
dstProjPath = os.path.join("out", "sln", projConfigs[0][1])
|
|
|
|
srcFilterPath = srcProjPath + ".filters"
|
|
|
|
dstFilterPath = dstProjPath + ".filters"
|
|
|
|
|
|
|
|
# Copy the filter file unmodified
|
|
|
|
ensureExists(os.path.dirname(dstProjPath))
|
|
|
|
copyfile(srcFilterPath, dstFilterPath)
|
2016-10-31 16:37:01 +00:00
|
|
|
|
2016-11-21 15:41:20 +00:00
|
|
|
# Bring over the project file, modified with extra configs
|
|
|
|
with open(srcProjPath) as srcProjFile:
|
2016-10-31 16:37:01 +00:00
|
|
|
projLines = iter(srcProjFile)
|
|
|
|
newProjLines = []
|
|
|
|
for line in projLines:
|
2016-11-21 15:41:20 +00:00
|
|
|
if "<ItemDefinitionGroup" in line:
|
|
|
|
# This is a large group that contains many settings. We need to
|
|
|
|
# replicate it, with conditions so it varies per configuration.
|
|
|
|
idgLines = []
|
|
|
|
while not "</ItemDefinitionGroup" in line:
|
|
|
|
idgLines.append(line)
|
|
|
|
line = projLines.next()
|
|
|
|
idgLines.append(line)
|
|
|
|
for projConfig in projConfigs:
|
|
|
|
configIdgLines = extractIdg(os.path.join("out",
|
|
|
|
projConfig[0],
|
|
|
|
projConfig[1]))
|
|
|
|
newProjLines.append(idgHdr + projConfig[0] + "|x64'\">\n")
|
|
|
|
for idgLine in configIdgLines[1:]:
|
|
|
|
newProjLines.append(idgLine)
|
|
|
|
elif "ProjectConfigurations" in line:
|
2016-10-31 16:37:01 +00:00
|
|
|
newProjLines.append(line)
|
|
|
|
projConfigLines = [
|
|
|
|
projLines.next(),
|
|
|
|
projLines.next(),
|
|
|
|
projLines.next(),
|
|
|
|
projLines.next() ]
|
|
|
|
for config in configs:
|
|
|
|
for projConfigLine in projConfigLines:
|
2016-11-21 15:41:20 +00:00
|
|
|
newProjLines.append(projConfigLine.replace("GN",
|
|
|
|
config[0]))
|
2016-10-31 16:37:01 +00:00
|
|
|
elif "<OutDir" in line:
|
2016-11-21 15:41:20 +00:00
|
|
|
newProjLines.append(line.replace(projConfigs[0][0],
|
|
|
|
"$(Configuration)"))
|
2016-10-31 16:37:01 +00:00
|
|
|
else:
|
|
|
|
newProjLines.append(line)
|
2016-11-21 15:41:20 +00:00
|
|
|
with open(dstProjPath, "w") as newProj:
|
2016-10-31 16:37:01 +00:00
|
|
|
newProj.writelines(newProjLines)
|