aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2016-11-21 10:41:20 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-11-21 16:35:39 +0000
commite54d4cefb7864a575c01894b2e5e0df16978c6e6 (patch)
tree2f0f72732f5ccf58420c815a8e3e4efa6a20df24
parent8d5f9cb5e7ea3d9ce77715a7f730f1c36222ae16 (diff)
VS script: Handle variation among configurations
The script now emits a meta-solution that include all projects across all configurations. For example, third party libraries may not be in all configurations, or certain targets are only present in some. Additionally, the ItemDefinitionGroup (which includes preprocessor definitions) is included from every configuration's project file, so syntax highlighting of inactive code works correctly. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=5085 Change-Id: I241d83aea3f076365811965161fc941f82c9714c Reviewed-on: https://skia-review.googlesource.com/5085 Reviewed-by: Greg Daniel <egdaniel@google.com> Reviewed-by: Cary Clark <caryclark@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
-rw-r--r--fix-gn-sln.py180
1 files changed, 127 insertions, 53 deletions
diff --git a/fix-gn-sln.py b/fix-gn-sln.py
index 2c814f8ae7..2cb4ae59ae 100644
--- a/fix-gn-sln.py
+++ b/fix-gn-sln.py
@@ -4,73 +4,147 @@
import os
import glob
+import re
import sys
from shutil import copyfile
-# Get list of existing directories to use as configs
+# 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), ... ]
configs = []
-configsWithSln = []
-srcDir = ""
-newestSlnTimestamp = 0
+
+# Find all directories that can be used as configs (and record if they have VS
+# files present)
for root, dirs, files in os.walk("out"):
for outDir in dirs:
gnFile = os.path.join("out", outDir, "build.ninja.d")
- slnFile = os.path.join("out", outDir, "all.sln")
if os.path.exists(gnFile):
- configs.append(outDir)
- if os.path.exists(slnFile):
- configsWithSln.append(outDir)
- slnTimestamp = os.path.getmtime(slnFile)
- if slnTimestamp > newestSlnTimestamp:
- newestSlnTimestamp = slnTimestamp
- srcDir = outDir
+ slnFile = os.path.join("out", outDir, "all.sln")
+ configs.append((outDir, os.path.exists(slnFile)))
break
-# We need at least one config with a solution
-if len(configsWithSln) == 0:
+# 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'\}"\) = "([^"]*)", "([^"]*)", "\{([^\}]*)\}"')
+
+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:
+ projName = matchObj.group(1)
+ if not allProjects.has_key(projName):
+ allProjects[projName] = []
+ allProjects[projName].append((config[0], matchObj.group(2),
+ matchObj.group(3)))
+
+# We need something to work with. Typically, this will fail if no GN folders
+# have IDE files
+if len(allProjects) == 0:
print "ERROR: At least one GN directory must have been built with --ide=vs"
sys.exit()
-# Ensure directories exist
-try:
- os.makedirs("out/sln/obj")
-except OSError:
- pass
+# 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')
-# Copy filter files unmodified
-for filterFile in glob.glob("out/" + srcDir + "/obj/*.filters"):
- copyfile(filterFile, filterFile.replace("out/" + srcDir, "out/sln"))
+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')
-# Copy Solution file, with additional configurations
-slnLines = iter(open("out/" + srcDir + "/all.sln"))
-newSlnLines = []
+# 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)
-for line in slnLines:
- newSlnLines.append(line)
- if "SolutionConfigurationPlatforms" in line:
- slnConfig = slnLines.next()
- for config in configs:
- newSlnLines.append(slnConfig.replace("GN", config))
- elif "ProjectConfigurationPlatforms" in line:
- activeCfg = slnLines.next()
- while "EndGlobalSection" not in activeCfg:
- buildCfg = slnLines.next()
- for config in configs:
- newSlnLines.append(activeCfg.replace("GN", config))
- newSlnLines.append(buildCfg.replace("GN", config))
- activeCfg = slnLines.next()
- newSlnLines.append(activeCfg)
-
-with open("out/sln/skia.sln", "w") as newSln:
- newSln.writelines(newSlnLines)
-
-# Now bring over all project files with modification
-for srcProjFilename in glob.glob("out/" + srcDir + "/obj/*.vcxproj"):
- with open(srcProjFilename) as srcProjFile:
+ # Bring over the project file, modified with extra configs
+ with open(srcProjPath) as srcProjFile:
projLines = iter(srcProjFile)
newProjLines = []
for line in projLines:
- if "ProjectConfigurations" in line:
+ 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:
newProjLines.append(line)
projConfigLines = [
projLines.next(),
@@ -79,12 +153,12 @@ for srcProjFilename in glob.glob("out/" + srcDir + "/obj/*.vcxproj"):
projLines.next() ]
for config in configs:
for projConfigLine in projConfigLines:
- newProjLines.append(
- projConfigLine.replace("GN", config))
+ newProjLines.append(projConfigLine.replace("GN",
+ config[0]))
elif "<OutDir" in line:
- newProjLines.append(line.replace(srcDir, "$(Configuration)"))
+ newProjLines.append(line.replace(projConfigs[0][0],
+ "$(Configuration)"))
else:
newProjLines.append(line)
- newName = "out/sln/obj/" + os.path.basename(srcProjFilename)
- with open(newName, "w") as newProj:
+ with open(dstProjPath, "w") as newProj:
newProj.writelines(newProjLines)