xref: /aosp_15_r20/build/soong/cc/cmakelists.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage cc
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker
20*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
21*333d2b36SAndroid Build Coastguard Worker	"os"
22*333d2b36SAndroid Build Coastguard Worker	"path"
23*333d2b36SAndroid Build Coastguard Worker	"path/filepath"
24*333d2b36SAndroid Build Coastguard Worker	"strings"
25*333d2b36SAndroid Build Coastguard Worker)
26*333d2b36SAndroid Build Coastguard Worker
27*333d2b36SAndroid Build Coastguard Worker// This singleton generates CMakeLists.txt files. It does so for each blueprint Android.bp resulting in a cc.Module
28*333d2b36SAndroid Build Coastguard Worker// when either make, mm, mma, mmm or mmma is called. CMakeLists.txt files are generated in a separate folder
29*333d2b36SAndroid Build Coastguard Worker// structure (see variable CLionOutputProjectsDirectory for root).
30*333d2b36SAndroid Build Coastguard Worker
31*333d2b36SAndroid Build Coastguard Workerfunc init() {
32*333d2b36SAndroid Build Coastguard Worker	android.RegisterParallelSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton)
33*333d2b36SAndroid Build Coastguard Worker}
34*333d2b36SAndroid Build Coastguard Worker
35*333d2b36SAndroid Build Coastguard Workerfunc cMakeListsGeneratorSingleton() android.Singleton {
36*333d2b36SAndroid Build Coastguard Worker	return &cmakelistsGeneratorSingleton{}
37*333d2b36SAndroid Build Coastguard Worker}
38*333d2b36SAndroid Build Coastguard Worker
39*333d2b36SAndroid Build Coastguard Workertype cmakelistsGeneratorSingleton struct{}
40*333d2b36SAndroid Build Coastguard Worker
41*333d2b36SAndroid Build Coastguard Workerconst (
42*333d2b36SAndroid Build Coastguard Worker	cMakeListsFilename              = "CMakeLists.txt"
43*333d2b36SAndroid Build Coastguard Worker	cLionAggregateProjectsDirectory = "development" + string(os.PathSeparator) + "ide" + string(os.PathSeparator) + "clion"
44*333d2b36SAndroid Build Coastguard Worker	cLionOutputProjectsDirectory    = "out" + string(os.PathSeparator) + cLionAggregateProjectsDirectory
45*333d2b36SAndroid Build Coastguard Worker	minimumCMakeVersionSupported    = "3.5"
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Worker	// Environment variables used to modify behavior of this singleton.
48*333d2b36SAndroid Build Coastguard Worker	envVariableGenerateCMakeLists = "SOONG_GEN_CMAKEFILES"
49*333d2b36SAndroid Build Coastguard Worker	envVariableGenerateDebugInfo  = "SOONG_GEN_CMAKEFILES_DEBUG"
50*333d2b36SAndroid Build Coastguard Worker	envVariableTrue               = "1"
51*333d2b36SAndroid Build Coastguard Worker)
52*333d2b36SAndroid Build Coastguard Worker
53*333d2b36SAndroid Build Coastguard Worker// Instruct generator to trace how header include path and flags were generated.
54*333d2b36SAndroid Build Coastguard Worker// This is done to ease investigating bug reports.
55*333d2b36SAndroid Build Coastguard Workervar outputDebugInfo = false
56*333d2b36SAndroid Build Coastguard Worker
57*333d2b36SAndroid Build Coastguard Workerfunc (c *cmakelistsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
58*333d2b36SAndroid Build Coastguard Worker	if getEnvVariable(envVariableGenerateCMakeLists, ctx) != envVariableTrue {
59*333d2b36SAndroid Build Coastguard Worker		return
60*333d2b36SAndroid Build Coastguard Worker	}
61*333d2b36SAndroid Build Coastguard Worker
62*333d2b36SAndroid Build Coastguard Worker	outputDebugInfo = (getEnvVariable(envVariableGenerateDebugInfo, ctx) == envVariableTrue)
63*333d2b36SAndroid Build Coastguard Worker
64*333d2b36SAndroid Build Coastguard Worker	// Track which projects have already had CMakeLists.txt generated to keep the first
65*333d2b36SAndroid Build Coastguard Worker	// variant for each project.
66*333d2b36SAndroid Build Coastguard Worker	seenProjects := map[string]bool{}
67*333d2b36SAndroid Build Coastguard Worker
68*333d2b36SAndroid Build Coastguard Worker	ctx.VisitAllModules(func(module android.Module) {
69*333d2b36SAndroid Build Coastguard Worker		if ccModule, ok := module.(*Module); ok {
70*333d2b36SAndroid Build Coastguard Worker			if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok {
71*333d2b36SAndroid Build Coastguard Worker				generateCLionProject(compiledModule, ctx, ccModule, seenProjects)
72*333d2b36SAndroid Build Coastguard Worker			}
73*333d2b36SAndroid Build Coastguard Worker		}
74*333d2b36SAndroid Build Coastguard Worker	})
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Worker	// Link all handmade CMakeLists.txt aggregate from
77*333d2b36SAndroid Build Coastguard Worker	//     BASE/development/ide/clion to
78*333d2b36SAndroid Build Coastguard Worker	// BASE/out/development/ide/clion.
79*333d2b36SAndroid Build Coastguard Worker	dir := filepath.Join(android.AbsSrcDirForExistingUseCases(), cLionAggregateProjectsDirectory)
80*333d2b36SAndroid Build Coastguard Worker	filepath.Walk(dir, linkAggregateCMakeListsFiles)
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Worker	return
83*333d2b36SAndroid Build Coastguard Worker}
84*333d2b36SAndroid Build Coastguard Worker
85*333d2b36SAndroid Build Coastguard Workerfunc getEnvVariable(name string, ctx android.SingletonContext) string {
86*333d2b36SAndroid Build Coastguard Worker	// Using android.Config.Getenv instead of os.getEnv to guarantee soong will
87*333d2b36SAndroid Build Coastguard Worker	// re-run in case this environment variable changes.
88*333d2b36SAndroid Build Coastguard Worker	return ctx.Config().Getenv(name)
89*333d2b36SAndroid Build Coastguard Worker}
90*333d2b36SAndroid Build Coastguard Worker
91*333d2b36SAndroid Build Coastguard Workerfunc exists(path string) bool {
92*333d2b36SAndroid Build Coastguard Worker	_, err := os.Stat(path)
93*333d2b36SAndroid Build Coastguard Worker	if err == nil {
94*333d2b36SAndroid Build Coastguard Worker		return true
95*333d2b36SAndroid Build Coastguard Worker	}
96*333d2b36SAndroid Build Coastguard Worker	if os.IsNotExist(err) {
97*333d2b36SAndroid Build Coastguard Worker		return false
98*333d2b36SAndroid Build Coastguard Worker	}
99*333d2b36SAndroid Build Coastguard Worker	return true
100*333d2b36SAndroid Build Coastguard Worker}
101*333d2b36SAndroid Build Coastguard Worker
102*333d2b36SAndroid Build Coastguard Workerfunc linkAggregateCMakeListsFiles(path string, info os.FileInfo, err error) error {
103*333d2b36SAndroid Build Coastguard Worker
104*333d2b36SAndroid Build Coastguard Worker	if info == nil {
105*333d2b36SAndroid Build Coastguard Worker		return nil
106*333d2b36SAndroid Build Coastguard Worker	}
107*333d2b36SAndroid Build Coastguard Worker
108*333d2b36SAndroid Build Coastguard Worker	dst := strings.Replace(path, cLionAggregateProjectsDirectory, cLionOutputProjectsDirectory, 1)
109*333d2b36SAndroid Build Coastguard Worker	if info.IsDir() {
110*333d2b36SAndroid Build Coastguard Worker		// This is a directory to create
111*333d2b36SAndroid Build Coastguard Worker		os.MkdirAll(dst, os.ModePerm)
112*333d2b36SAndroid Build Coastguard Worker	} else {
113*333d2b36SAndroid Build Coastguard Worker		// This is a file to link
114*333d2b36SAndroid Build Coastguard Worker		os.Remove(dst)
115*333d2b36SAndroid Build Coastguard Worker		os.Symlink(path, dst)
116*333d2b36SAndroid Build Coastguard Worker	}
117*333d2b36SAndroid Build Coastguard Worker	return nil
118*333d2b36SAndroid Build Coastguard Worker}
119*333d2b36SAndroid Build Coastguard Worker
120*333d2b36SAndroid Build Coastguard Workerfunc generateCLionProject(compiledModule CompiledInterface, ctx android.SingletonContext, ccModule *Module,
121*333d2b36SAndroid Build Coastguard Worker	seenProjects map[string]bool) {
122*333d2b36SAndroid Build Coastguard Worker	srcs := compiledModule.Srcs()
123*333d2b36SAndroid Build Coastguard Worker	if len(srcs) == 0 {
124*333d2b36SAndroid Build Coastguard Worker		return
125*333d2b36SAndroid Build Coastguard Worker	}
126*333d2b36SAndroid Build Coastguard Worker
127*333d2b36SAndroid Build Coastguard Worker	// Only write CMakeLists.txt for the first variant of each architecture of each module
128*333d2b36SAndroid Build Coastguard Worker	clionprojectLocation := getCMakeListsForModule(ccModule, ctx)
129*333d2b36SAndroid Build Coastguard Worker	if seenProjects[clionprojectLocation] {
130*333d2b36SAndroid Build Coastguard Worker		return
131*333d2b36SAndroid Build Coastguard Worker	}
132*333d2b36SAndroid Build Coastguard Worker
133*333d2b36SAndroid Build Coastguard Worker	seenProjects[clionprojectLocation] = true
134*333d2b36SAndroid Build Coastguard Worker
135*333d2b36SAndroid Build Coastguard Worker	// Ensure the directory hosting the cmakelists.txt exists
136*333d2b36SAndroid Build Coastguard Worker	projectDir := path.Dir(clionprojectLocation)
137*333d2b36SAndroid Build Coastguard Worker	os.MkdirAll(projectDir, os.ModePerm)
138*333d2b36SAndroid Build Coastguard Worker
139*333d2b36SAndroid Build Coastguard Worker	// Create cmakelists.txt
140*333d2b36SAndroid Build Coastguard Worker	f, _ := os.Create(filepath.Join(projectDir, cMakeListsFilename))
141*333d2b36SAndroid Build Coastguard Worker	defer f.Close()
142*333d2b36SAndroid Build Coastguard Worker
143*333d2b36SAndroid Build Coastguard Worker	// Header.
144*333d2b36SAndroid Build Coastguard Worker	f.WriteString("# THIS FILE WAS AUTOMATICALY GENERATED!\n")
145*333d2b36SAndroid Build Coastguard Worker	f.WriteString("# ANY MODIFICATION WILL BE OVERWRITTEN!\n\n")
146*333d2b36SAndroid Build Coastguard Worker	f.WriteString("# To improve project view in Clion    :\n")
147*333d2b36SAndroid Build Coastguard Worker	f.WriteString("# Tools > CMake > Change Project Root  \n\n")
148*333d2b36SAndroid Build Coastguard Worker	f.WriteString(fmt.Sprintf("cmake_minimum_required(VERSION %s)\n", minimumCMakeVersionSupported))
149*333d2b36SAndroid Build Coastguard Worker	f.WriteString(fmt.Sprintf("project(%s)\n", ccModule.ModuleBase.Name()))
150*333d2b36SAndroid Build Coastguard Worker	f.WriteString(fmt.Sprintf("set(ANDROID_ROOT %s)\n\n", android.AbsSrcDirForExistingUseCases()))
151*333d2b36SAndroid Build Coastguard Worker
152*333d2b36SAndroid Build Coastguard Worker	pathToCC, _ := evalVariable(ctx, "${config.ClangBin}/")
153*333d2b36SAndroid Build Coastguard Worker	f.WriteString(fmt.Sprintf("set(CMAKE_C_COMPILER \"%s%s\")\n", buildCMakePath(pathToCC), "clang"))
154*333d2b36SAndroid Build Coastguard Worker	f.WriteString(fmt.Sprintf("set(CMAKE_CXX_COMPILER \"%s%s\")\n", buildCMakePath(pathToCC), "clang++"))
155*333d2b36SAndroid Build Coastguard Worker
156*333d2b36SAndroid Build Coastguard Worker	// Add all sources to the project.
157*333d2b36SAndroid Build Coastguard Worker	f.WriteString("list(APPEND\n")
158*333d2b36SAndroid Build Coastguard Worker	f.WriteString("     SOURCE_FILES\n")
159*333d2b36SAndroid Build Coastguard Worker	for _, src := range srcs {
160*333d2b36SAndroid Build Coastguard Worker		f.WriteString(fmt.Sprintf("    ${ANDROID_ROOT}/%s\n", src.String()))
161*333d2b36SAndroid Build Coastguard Worker	}
162*333d2b36SAndroid Build Coastguard Worker	f.WriteString(")\n")
163*333d2b36SAndroid Build Coastguard Worker
164*333d2b36SAndroid Build Coastguard Worker	// Add all header search path and compiler parameters (-D, -W, -f, -XXXX)
165*333d2b36SAndroid Build Coastguard Worker	f.WriteString("\n# GLOBAL ALL FLAGS:\n")
166*333d2b36SAndroid Build Coastguard Worker	globalAllParameters := parseCompilerParameters(ccModule.flags.Global.CommonFlags, ctx, f)
167*333d2b36SAndroid Build Coastguard Worker	translateToCMake(globalAllParameters, f, true, true)
168*333d2b36SAndroid Build Coastguard Worker
169*333d2b36SAndroid Build Coastguard Worker	f.WriteString("\n# LOCAL ALL FLAGS:\n")
170*333d2b36SAndroid Build Coastguard Worker	localAllParameters := parseCompilerParameters(ccModule.flags.Local.CommonFlags, ctx, f)
171*333d2b36SAndroid Build Coastguard Worker	translateToCMake(localAllParameters, f, true, true)
172*333d2b36SAndroid Build Coastguard Worker
173*333d2b36SAndroid Build Coastguard Worker	f.WriteString("\n# GLOBAL CFLAGS:\n")
174*333d2b36SAndroid Build Coastguard Worker	globalCParameters := parseCompilerParameters(ccModule.flags.Global.CFlags, ctx, f)
175*333d2b36SAndroid Build Coastguard Worker	translateToCMake(globalCParameters, f, true, true)
176*333d2b36SAndroid Build Coastguard Worker
177*333d2b36SAndroid Build Coastguard Worker	f.WriteString("\n# LOCAL CFLAGS:\n")
178*333d2b36SAndroid Build Coastguard Worker	localCParameters := parseCompilerParameters(ccModule.flags.Local.CFlags, ctx, f)
179*333d2b36SAndroid Build Coastguard Worker	translateToCMake(localCParameters, f, true, true)
180*333d2b36SAndroid Build Coastguard Worker
181*333d2b36SAndroid Build Coastguard Worker	f.WriteString("\n# GLOBAL C ONLY FLAGS:\n")
182*333d2b36SAndroid Build Coastguard Worker	globalConlyParameters := parseCompilerParameters(ccModule.flags.Global.ConlyFlags, ctx, f)
183*333d2b36SAndroid Build Coastguard Worker	translateToCMake(globalConlyParameters, f, true, false)
184*333d2b36SAndroid Build Coastguard Worker
185*333d2b36SAndroid Build Coastguard Worker	f.WriteString("\n# LOCAL C ONLY FLAGS:\n")
186*333d2b36SAndroid Build Coastguard Worker	localConlyParameters := parseCompilerParameters(ccModule.flags.Local.ConlyFlags, ctx, f)
187*333d2b36SAndroid Build Coastguard Worker	translateToCMake(localConlyParameters, f, true, false)
188*333d2b36SAndroid Build Coastguard Worker
189*333d2b36SAndroid Build Coastguard Worker	f.WriteString("\n# GLOBAL CPP FLAGS:\n")
190*333d2b36SAndroid Build Coastguard Worker	globalCppParameters := parseCompilerParameters(ccModule.flags.Global.CppFlags, ctx, f)
191*333d2b36SAndroid Build Coastguard Worker	translateToCMake(globalCppParameters, f, false, true)
192*333d2b36SAndroid Build Coastguard Worker
193*333d2b36SAndroid Build Coastguard Worker	f.WriteString("\n# LOCAL CPP FLAGS:\n")
194*333d2b36SAndroid Build Coastguard Worker	localCppParameters := parseCompilerParameters(ccModule.flags.Local.CppFlags, ctx, f)
195*333d2b36SAndroid Build Coastguard Worker	translateToCMake(localCppParameters, f, false, true)
196*333d2b36SAndroid Build Coastguard Worker
197*333d2b36SAndroid Build Coastguard Worker	f.WriteString("\n# GLOBAL SYSTEM INCLUDE FLAGS:\n")
198*333d2b36SAndroid Build Coastguard Worker	globalIncludeParameters := parseCompilerParameters(ccModule.flags.SystemIncludeFlags, ctx, f)
199*333d2b36SAndroid Build Coastguard Worker	translateToCMake(globalIncludeParameters, f, true, true)
200*333d2b36SAndroid Build Coastguard Worker
201*333d2b36SAndroid Build Coastguard Worker	// Add project executable.
202*333d2b36SAndroid Build Coastguard Worker	f.WriteString(fmt.Sprintf("\nadd_executable(%s ${SOURCE_FILES})\n",
203*333d2b36SAndroid Build Coastguard Worker		cleanExecutableName(ccModule.ModuleBase.Name())))
204*333d2b36SAndroid Build Coastguard Worker}
205*333d2b36SAndroid Build Coastguard Worker
206*333d2b36SAndroid Build Coastguard Workerfunc cleanExecutableName(s string) string {
207*333d2b36SAndroid Build Coastguard Worker	return strings.Replace(s, "@", "-", -1)
208*333d2b36SAndroid Build Coastguard Worker}
209*333d2b36SAndroid Build Coastguard Worker
210*333d2b36SAndroid Build Coastguard Workerfunc translateToCMake(c compilerParameters, f *os.File, cflags bool, cppflags bool) {
211*333d2b36SAndroid Build Coastguard Worker	writeAllIncludeDirectories(c.systemHeaderSearchPath, f, true)
212*333d2b36SAndroid Build Coastguard Worker	writeAllIncludeDirectories(c.headerSearchPath, f, false)
213*333d2b36SAndroid Build Coastguard Worker	if cflags {
214*333d2b36SAndroid Build Coastguard Worker		writeAllRelativeFilePathFlags(c.relativeFilePathFlags, f, "CMAKE_C_FLAGS")
215*333d2b36SAndroid Build Coastguard Worker		writeAllFlags(c.flags, f, "CMAKE_C_FLAGS")
216*333d2b36SAndroid Build Coastguard Worker	}
217*333d2b36SAndroid Build Coastguard Worker	if cppflags {
218*333d2b36SAndroid Build Coastguard Worker		writeAllRelativeFilePathFlags(c.relativeFilePathFlags, f, "CMAKE_CXX_FLAGS")
219*333d2b36SAndroid Build Coastguard Worker		writeAllFlags(c.flags, f, "CMAKE_CXX_FLAGS")
220*333d2b36SAndroid Build Coastguard Worker	}
221*333d2b36SAndroid Build Coastguard Worker	if c.sysroot != "" {
222*333d2b36SAndroid Build Coastguard Worker		f.WriteString(fmt.Sprintf("include_directories(SYSTEM \"%s\")\n", buildCMakePath(path.Join(c.sysroot, "usr", "include"))))
223*333d2b36SAndroid Build Coastguard Worker	}
224*333d2b36SAndroid Build Coastguard Worker
225*333d2b36SAndroid Build Coastguard Worker}
226*333d2b36SAndroid Build Coastguard Worker
227*333d2b36SAndroid Build Coastguard Workerfunc buildCMakePath(p string) string {
228*333d2b36SAndroid Build Coastguard Worker	if path.IsAbs(p) {
229*333d2b36SAndroid Build Coastguard Worker		return p
230*333d2b36SAndroid Build Coastguard Worker	}
231*333d2b36SAndroid Build Coastguard Worker	return fmt.Sprintf("${ANDROID_ROOT}/%s", p)
232*333d2b36SAndroid Build Coastguard Worker}
233*333d2b36SAndroid Build Coastguard Worker
234*333d2b36SAndroid Build Coastguard Workerfunc writeAllIncludeDirectories(includes []string, f *os.File, isSystem bool) {
235*333d2b36SAndroid Build Coastguard Worker	if len(includes) == 0 {
236*333d2b36SAndroid Build Coastguard Worker		return
237*333d2b36SAndroid Build Coastguard Worker	}
238*333d2b36SAndroid Build Coastguard Worker
239*333d2b36SAndroid Build Coastguard Worker	system := ""
240*333d2b36SAndroid Build Coastguard Worker	if isSystem {
241*333d2b36SAndroid Build Coastguard Worker		system = "SYSTEM"
242*333d2b36SAndroid Build Coastguard Worker	}
243*333d2b36SAndroid Build Coastguard Worker
244*333d2b36SAndroid Build Coastguard Worker	f.WriteString(fmt.Sprintf("include_directories(%s \n", system))
245*333d2b36SAndroid Build Coastguard Worker
246*333d2b36SAndroid Build Coastguard Worker	for _, include := range includes {
247*333d2b36SAndroid Build Coastguard Worker		f.WriteString(fmt.Sprintf("    \"%s\"\n", buildCMakePath(include)))
248*333d2b36SAndroid Build Coastguard Worker	}
249*333d2b36SAndroid Build Coastguard Worker	f.WriteString(")\n\n")
250*333d2b36SAndroid Build Coastguard Worker
251*333d2b36SAndroid Build Coastguard Worker	// Also add all headers to source files.
252*333d2b36SAndroid Build Coastguard Worker	f.WriteString("file (GLOB_RECURSE TMP_HEADERS\n")
253*333d2b36SAndroid Build Coastguard Worker	for _, include := range includes {
254*333d2b36SAndroid Build Coastguard Worker		f.WriteString(fmt.Sprintf("    \"%s/**/*.h\"\n", buildCMakePath(include)))
255*333d2b36SAndroid Build Coastguard Worker	}
256*333d2b36SAndroid Build Coastguard Worker	f.WriteString(")\n")
257*333d2b36SAndroid Build Coastguard Worker	f.WriteString("list (APPEND SOURCE_FILES ${TMP_HEADERS})\n\n")
258*333d2b36SAndroid Build Coastguard Worker}
259*333d2b36SAndroid Build Coastguard Worker
260*333d2b36SAndroid Build Coastguard Workertype relativeFilePathFlagType struct {
261*333d2b36SAndroid Build Coastguard Worker	flag             string
262*333d2b36SAndroid Build Coastguard Worker	relativeFilePath string
263*333d2b36SAndroid Build Coastguard Worker}
264*333d2b36SAndroid Build Coastguard Worker
265*333d2b36SAndroid Build Coastguard Workerfunc writeAllRelativeFilePathFlags(relativeFilePathFlags []relativeFilePathFlagType, f *os.File, tag string) {
266*333d2b36SAndroid Build Coastguard Worker	for _, flag := range relativeFilePathFlags {
267*333d2b36SAndroid Build Coastguard Worker		f.WriteString(fmt.Sprintf("set(%s \"${%s} %s=%s\")\n", tag, tag, flag.flag, buildCMakePath(flag.relativeFilePath)))
268*333d2b36SAndroid Build Coastguard Worker	}
269*333d2b36SAndroid Build Coastguard Worker}
270*333d2b36SAndroid Build Coastguard Worker
271*333d2b36SAndroid Build Coastguard Workerfunc writeAllFlags(flags []string, f *os.File, tag string) {
272*333d2b36SAndroid Build Coastguard Worker	for _, flag := range flags {
273*333d2b36SAndroid Build Coastguard Worker		f.WriteString(fmt.Sprintf("set(%s \"${%s} %s\")\n", tag, tag, flag))
274*333d2b36SAndroid Build Coastguard Worker	}
275*333d2b36SAndroid Build Coastguard Worker}
276*333d2b36SAndroid Build Coastguard Worker
277*333d2b36SAndroid Build Coastguard Workertype parameterType int
278*333d2b36SAndroid Build Coastguard Worker
279*333d2b36SAndroid Build Coastguard Workerconst (
280*333d2b36SAndroid Build Coastguard Worker	headerSearchPath parameterType = iota
281*333d2b36SAndroid Build Coastguard Worker	variable
282*333d2b36SAndroid Build Coastguard Worker	systemHeaderSearchPath
283*333d2b36SAndroid Build Coastguard Worker	flag
284*333d2b36SAndroid Build Coastguard Worker	systemRoot
285*333d2b36SAndroid Build Coastguard Worker	relativeFilePathFlag
286*333d2b36SAndroid Build Coastguard Worker)
287*333d2b36SAndroid Build Coastguard Worker
288*333d2b36SAndroid Build Coastguard Workertype compilerParameters struct {
289*333d2b36SAndroid Build Coastguard Worker	headerSearchPath       []string
290*333d2b36SAndroid Build Coastguard Worker	systemHeaderSearchPath []string
291*333d2b36SAndroid Build Coastguard Worker	flags                  []string
292*333d2b36SAndroid Build Coastguard Worker	sysroot                string
293*333d2b36SAndroid Build Coastguard Worker	// Must be in a=b/c/d format and can be split into "a" and "b/c/d"
294*333d2b36SAndroid Build Coastguard Worker	relativeFilePathFlags []relativeFilePathFlagType
295*333d2b36SAndroid Build Coastguard Worker}
296*333d2b36SAndroid Build Coastguard Worker
297*333d2b36SAndroid Build Coastguard Workerfunc makeCompilerParameters() compilerParameters {
298*333d2b36SAndroid Build Coastguard Worker	return compilerParameters{
299*333d2b36SAndroid Build Coastguard Worker		sysroot: "",
300*333d2b36SAndroid Build Coastguard Worker	}
301*333d2b36SAndroid Build Coastguard Worker}
302*333d2b36SAndroid Build Coastguard Worker
303*333d2b36SAndroid Build Coastguard Workerfunc categorizeParameter(parameter string) parameterType {
304*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(parameter, "-I") {
305*333d2b36SAndroid Build Coastguard Worker		return headerSearchPath
306*333d2b36SAndroid Build Coastguard Worker	}
307*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(parameter, "$") {
308*333d2b36SAndroid Build Coastguard Worker		return variable
309*333d2b36SAndroid Build Coastguard Worker	}
310*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(parameter, "-isystem") {
311*333d2b36SAndroid Build Coastguard Worker		return systemHeaderSearchPath
312*333d2b36SAndroid Build Coastguard Worker	}
313*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(parameter, "-isysroot") {
314*333d2b36SAndroid Build Coastguard Worker		return systemRoot
315*333d2b36SAndroid Build Coastguard Worker	}
316*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(parameter, "--sysroot") {
317*333d2b36SAndroid Build Coastguard Worker		return systemRoot
318*333d2b36SAndroid Build Coastguard Worker	}
319*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(parameter, "-fsanitize-ignorelist") {
320*333d2b36SAndroid Build Coastguard Worker		return relativeFilePathFlag
321*333d2b36SAndroid Build Coastguard Worker	}
322*333d2b36SAndroid Build Coastguard Worker	if strings.HasPrefix(parameter, "-fprofile-sample-use") {
323*333d2b36SAndroid Build Coastguard Worker		return relativeFilePathFlag
324*333d2b36SAndroid Build Coastguard Worker	}
325*333d2b36SAndroid Build Coastguard Worker	return flag
326*333d2b36SAndroid Build Coastguard Worker}
327*333d2b36SAndroid Build Coastguard Worker
328*333d2b36SAndroid Build Coastguard Worker// Flattens a list of strings potentially containing space characters into a list of string containing no
329*333d2b36SAndroid Build Coastguard Worker// spaces.
330*333d2b36SAndroid Build Coastguard Workerfunc normalizeParameters(params []string) []string {
331*333d2b36SAndroid Build Coastguard Worker	var flatParams []string
332*333d2b36SAndroid Build Coastguard Worker	for _, s := range params {
333*333d2b36SAndroid Build Coastguard Worker		s = strings.Trim(s, " ")
334*333d2b36SAndroid Build Coastguard Worker		if len(s) == 0 {
335*333d2b36SAndroid Build Coastguard Worker			continue
336*333d2b36SAndroid Build Coastguard Worker		}
337*333d2b36SAndroid Build Coastguard Worker		flatParams = append(flatParams, strings.Split(s, " ")...)
338*333d2b36SAndroid Build Coastguard Worker	}
339*333d2b36SAndroid Build Coastguard Worker	return flatParams
340*333d2b36SAndroid Build Coastguard Worker}
341*333d2b36SAndroid Build Coastguard Worker
342*333d2b36SAndroid Build Coastguard Workerfunc parseCompilerParameters(params []string, ctx android.SingletonContext, f *os.File) compilerParameters {
343*333d2b36SAndroid Build Coastguard Worker	var compilerParameters = makeCompilerParameters()
344*333d2b36SAndroid Build Coastguard Worker
345*333d2b36SAndroid Build Coastguard Worker	for i, str := range params {
346*333d2b36SAndroid Build Coastguard Worker		f.WriteString(fmt.Sprintf("# Raw param [%d] = '%s'\n", i, str))
347*333d2b36SAndroid Build Coastguard Worker	}
348*333d2b36SAndroid Build Coastguard Worker
349*333d2b36SAndroid Build Coastguard Worker	// Soong does not guarantee that each flag will be in an individual string. e.g: The
350*333d2b36SAndroid Build Coastguard Worker	// input received could be:
351*333d2b36SAndroid Build Coastguard Worker	// params = {"-isystem", "path/to/system"}
352*333d2b36SAndroid Build Coastguard Worker	// or it could be
353*333d2b36SAndroid Build Coastguard Worker	// params = {"-isystem path/to/system"}
354*333d2b36SAndroid Build Coastguard Worker	// To normalize the input, we split all strings with the "space" character and consolidate
355*333d2b36SAndroid Build Coastguard Worker	// all tokens into a flattened parameters list
356*333d2b36SAndroid Build Coastguard Worker	params = normalizeParameters(params)
357*333d2b36SAndroid Build Coastguard Worker
358*333d2b36SAndroid Build Coastguard Worker	for i := 0; i < len(params); i++ {
359*333d2b36SAndroid Build Coastguard Worker		param := params[i]
360*333d2b36SAndroid Build Coastguard Worker		if param == "" {
361*333d2b36SAndroid Build Coastguard Worker			continue
362*333d2b36SAndroid Build Coastguard Worker		}
363*333d2b36SAndroid Build Coastguard Worker
364*333d2b36SAndroid Build Coastguard Worker		switch categorizeParameter(param) {
365*333d2b36SAndroid Build Coastguard Worker		case headerSearchPath:
366*333d2b36SAndroid Build Coastguard Worker			compilerParameters.headerSearchPath =
367*333d2b36SAndroid Build Coastguard Worker				append(compilerParameters.headerSearchPath, strings.TrimPrefix(param, "-I"))
368*333d2b36SAndroid Build Coastguard Worker		case variable:
369*333d2b36SAndroid Build Coastguard Worker			if evaluated, error := evalVariable(ctx, param); error == nil {
370*333d2b36SAndroid Build Coastguard Worker				if outputDebugInfo {
371*333d2b36SAndroid Build Coastguard Worker					f.WriteString(fmt.Sprintf("# variable %s = '%s'\n", param, evaluated))
372*333d2b36SAndroid Build Coastguard Worker				}
373*333d2b36SAndroid Build Coastguard Worker
374*333d2b36SAndroid Build Coastguard Worker				paramsFromVar := parseCompilerParameters(strings.Split(evaluated, " "), ctx, f)
375*333d2b36SAndroid Build Coastguard Worker				concatenateParams(&compilerParameters, paramsFromVar)
376*333d2b36SAndroid Build Coastguard Worker
377*333d2b36SAndroid Build Coastguard Worker			} else {
378*333d2b36SAndroid Build Coastguard Worker				if outputDebugInfo {
379*333d2b36SAndroid Build Coastguard Worker					f.WriteString(fmt.Sprintf("# variable %s could NOT BE RESOLVED\n", param))
380*333d2b36SAndroid Build Coastguard Worker				}
381*333d2b36SAndroid Build Coastguard Worker			}
382*333d2b36SAndroid Build Coastguard Worker		case systemHeaderSearchPath:
383*333d2b36SAndroid Build Coastguard Worker			if i < len(params)-1 {
384*333d2b36SAndroid Build Coastguard Worker				compilerParameters.systemHeaderSearchPath =
385*333d2b36SAndroid Build Coastguard Worker					append(compilerParameters.systemHeaderSearchPath, params[i+1])
386*333d2b36SAndroid Build Coastguard Worker			} else if outputDebugInfo {
387*333d2b36SAndroid Build Coastguard Worker				f.WriteString("# Found a header search path marker with no path")
388*333d2b36SAndroid Build Coastguard Worker			}
389*333d2b36SAndroid Build Coastguard Worker			i = i + 1
390*333d2b36SAndroid Build Coastguard Worker		case flag:
391*333d2b36SAndroid Build Coastguard Worker			c := cleanupParameter(param)
392*333d2b36SAndroid Build Coastguard Worker			f.WriteString(fmt.Sprintf("# FLAG '%s' became %s\n", param, c))
393*333d2b36SAndroid Build Coastguard Worker			compilerParameters.flags = append(compilerParameters.flags, c)
394*333d2b36SAndroid Build Coastguard Worker		case systemRoot:
395*333d2b36SAndroid Build Coastguard Worker			if i < len(params)-1 {
396*333d2b36SAndroid Build Coastguard Worker				compilerParameters.sysroot = params[i+1]
397*333d2b36SAndroid Build Coastguard Worker			} else if outputDebugInfo {
398*333d2b36SAndroid Build Coastguard Worker				f.WriteString("# Found a system root path marker with no path")
399*333d2b36SAndroid Build Coastguard Worker			}
400*333d2b36SAndroid Build Coastguard Worker			i = i + 1
401*333d2b36SAndroid Build Coastguard Worker		case relativeFilePathFlag:
402*333d2b36SAndroid Build Coastguard Worker			flagComponents := strings.Split(param, "=")
403*333d2b36SAndroid Build Coastguard Worker			if len(flagComponents) == 2 {
404*333d2b36SAndroid Build Coastguard Worker				flagStruct := relativeFilePathFlagType{flag: flagComponents[0], relativeFilePath: flagComponents[1]}
405*333d2b36SAndroid Build Coastguard Worker				compilerParameters.relativeFilePathFlags = append(compilerParameters.relativeFilePathFlags, flagStruct)
406*333d2b36SAndroid Build Coastguard Worker			} else {
407*333d2b36SAndroid Build Coastguard Worker				if outputDebugInfo {
408*333d2b36SAndroid Build Coastguard Worker					f.WriteString(fmt.Sprintf("# Relative File Path Flag [%s] is not formatted as a=b/c/d \n", param))
409*333d2b36SAndroid Build Coastguard Worker				}
410*333d2b36SAndroid Build Coastguard Worker			}
411*333d2b36SAndroid Build Coastguard Worker		}
412*333d2b36SAndroid Build Coastguard Worker	}
413*333d2b36SAndroid Build Coastguard Worker	return compilerParameters
414*333d2b36SAndroid Build Coastguard Worker}
415*333d2b36SAndroid Build Coastguard Worker
416*333d2b36SAndroid Build Coastguard Workerfunc cleanupParameter(p string) string {
417*333d2b36SAndroid Build Coastguard Worker	// In the blueprint, c flags can be passed as:
418*333d2b36SAndroid Build Coastguard Worker	//  cflags: [ "-DLOG_TAG=\"libEGL\"", ]
419*333d2b36SAndroid Build Coastguard Worker	// which becomes:
420*333d2b36SAndroid Build Coastguard Worker	// '-DLOG_TAG="libEGL"' in soong.
421*333d2b36SAndroid Build Coastguard Worker	// In order to be injected in CMakelists.txt we need to:
422*333d2b36SAndroid Build Coastguard Worker	// - Remove the wrapping ' character
423*333d2b36SAndroid Build Coastguard Worker	// - Double escape all special \ and " characters.
424*333d2b36SAndroid Build Coastguard Worker	// For a end result like:
425*333d2b36SAndroid Build Coastguard Worker	// -DLOG_TAG=\\\"libEGL\\\"
426*333d2b36SAndroid Build Coastguard Worker	if !strings.HasPrefix(p, "'") || !strings.HasSuffix(p, "'") || len(p) < 3 {
427*333d2b36SAndroid Build Coastguard Worker		return p
428*333d2b36SAndroid Build Coastguard Worker	}
429*333d2b36SAndroid Build Coastguard Worker
430*333d2b36SAndroid Build Coastguard Worker	// Reverse wrapper quotes and escaping that may have happened in NinjaAndShellEscape
431*333d2b36SAndroid Build Coastguard Worker	// TODO:  It is ok to reverse here for now but if NinjaAndShellEscape becomes more complex,
432*333d2b36SAndroid Build Coastguard Worker	// we should create a method NinjaAndShellUnescape in escape.go and use that instead.
433*333d2b36SAndroid Build Coastguard Worker	p = p[1 : len(p)-1]
434*333d2b36SAndroid Build Coastguard Worker	p = strings.Replace(p, `'\''`, `'`, -1)
435*333d2b36SAndroid Build Coastguard Worker	p = strings.Replace(p, `$$`, `$`, -1)
436*333d2b36SAndroid Build Coastguard Worker
437*333d2b36SAndroid Build Coastguard Worker	p = doubleEscape(p)
438*333d2b36SAndroid Build Coastguard Worker	return p
439*333d2b36SAndroid Build Coastguard Worker}
440*333d2b36SAndroid Build Coastguard Worker
441*333d2b36SAndroid Build Coastguard Workerfunc escape(s string) string {
442*333d2b36SAndroid Build Coastguard Worker	s = strings.Replace(s, `\`, `\\`, -1)
443*333d2b36SAndroid Build Coastguard Worker	s = strings.Replace(s, `"`, `\"`, -1)
444*333d2b36SAndroid Build Coastguard Worker	return s
445*333d2b36SAndroid Build Coastguard Worker}
446*333d2b36SAndroid Build Coastguard Worker
447*333d2b36SAndroid Build Coastguard Workerfunc doubleEscape(s string) string {
448*333d2b36SAndroid Build Coastguard Worker	s = escape(s)
449*333d2b36SAndroid Build Coastguard Worker	s = escape(s)
450*333d2b36SAndroid Build Coastguard Worker	return s
451*333d2b36SAndroid Build Coastguard Worker}
452*333d2b36SAndroid Build Coastguard Worker
453*333d2b36SAndroid Build Coastguard Workerfunc concatenateParams(c1 *compilerParameters, c2 compilerParameters) {
454*333d2b36SAndroid Build Coastguard Worker	c1.headerSearchPath = append(c1.headerSearchPath, c2.headerSearchPath...)
455*333d2b36SAndroid Build Coastguard Worker	c1.systemHeaderSearchPath = append(c1.systemHeaderSearchPath, c2.systemHeaderSearchPath...)
456*333d2b36SAndroid Build Coastguard Worker	if c2.sysroot != "" {
457*333d2b36SAndroid Build Coastguard Worker		c1.sysroot = c2.sysroot
458*333d2b36SAndroid Build Coastguard Worker	}
459*333d2b36SAndroid Build Coastguard Worker	c1.flags = append(c1.flags, c2.flags...)
460*333d2b36SAndroid Build Coastguard Worker}
461*333d2b36SAndroid Build Coastguard Worker
462*333d2b36SAndroid Build Coastguard Workerfunc evalVariable(ctx android.SingletonContext, str string) (string, error) {
463*333d2b36SAndroid Build Coastguard Worker	evaluated, err := ctx.Eval(pctx, str)
464*333d2b36SAndroid Build Coastguard Worker	if err == nil {
465*333d2b36SAndroid Build Coastguard Worker		return evaluated, nil
466*333d2b36SAndroid Build Coastguard Worker	}
467*333d2b36SAndroid Build Coastguard Worker	return "", err
468*333d2b36SAndroid Build Coastguard Worker}
469*333d2b36SAndroid Build Coastguard Worker
470*333d2b36SAndroid Build Coastguard Workerfunc getCMakeListsForModule(module *Module, ctx android.SingletonContext) string {
471*333d2b36SAndroid Build Coastguard Worker	return filepath.Join(android.AbsSrcDirForExistingUseCases(),
472*333d2b36SAndroid Build Coastguard Worker		cLionOutputProjectsDirectory,
473*333d2b36SAndroid Build Coastguard Worker		path.Dir(ctx.BlueprintFile(module)),
474*333d2b36SAndroid Build Coastguard Worker		module.ModuleBase.Name()+"-"+
475*333d2b36SAndroid Build Coastguard Worker			module.ModuleBase.Arch().ArchType.Name+"-"+
476*333d2b36SAndroid Build Coastguard Worker			module.ModuleBase.Os().Name,
477*333d2b36SAndroid Build Coastguard Worker		cMakeListsFilename)
478*333d2b36SAndroid Build Coastguard Worker}
479