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