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