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