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