github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/cc/ndk_headers.go (about) 1 // Copyright 2016 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 15 package cc 16 17 import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 "strings" 22 23 "github.com/google/blueprint" 24 25 "android/soong/android" 26 ) 27 28 var ( 29 preprocessBionicHeaders = pctx.AndroidStaticRule("preprocessBionicHeaders", 30 blueprint.RuleParams{ 31 // The `&& touch $out` isn't really necessary, but Blueprint won't 32 // let us have only implicit outputs. 33 Command: "$versionerCmd -o $outDir $srcDir $depsPath && touch $out", 34 CommandDeps: []string{"$versionerCmd"}, 35 }, 36 "depsPath", "srcDir", "outDir") 37 ) 38 39 func init() { 40 pctx.HostBinToolVariable("versionerCmd", "versioner") 41 } 42 43 // Returns the NDK base include path for use with sdk_version current. Usable with -I. 44 func getCurrentIncludePath(ctx android.ModuleContext) android.OutputPath { 45 return getNdkSysrootBase(ctx).Join(ctx, "usr/include") 46 } 47 48 type headerProperies struct { 49 // Base directory of the headers being installed. As an example: 50 // 51 // ndk_headers { 52 // name: "foo", 53 // from: "include", 54 // to: "", 55 // srcs: ["include/foo/bar/baz.h"], 56 // } 57 // 58 // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead 59 // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h. 60 From *string 61 62 // Install path within the sysroot. This is relative to usr/include. 63 To *string 64 65 // List of headers to install. Glob compatible. Common case is "include/**/*.h". 66 Srcs []string 67 68 // Path to the NOTICE file associated with the headers. 69 License *string 70 } 71 72 type headerModule struct { 73 android.ModuleBase 74 75 properties headerProperies 76 77 installPaths android.Paths 78 licensePath android.ModuleSrcPath 79 } 80 81 func (m *headerModule) DepsMutator(ctx android.BottomUpMutatorContext) { 82 } 83 84 func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string, 85 to string) android.OutputPath { 86 // Output path is the sysroot base + "usr/include" + to directory + directory component 87 // of the file without the leading from directory stripped. 88 // 89 // Given: 90 // sysroot base = "ndk/sysroot" 91 // from = "include/foo" 92 // to = "bar" 93 // header = "include/foo/woodly/doodly.h" 94 // output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h" 95 96 // full/platform/path/to/include/foo 97 fullFromPath := android.PathForModuleSrc(ctx, from) 98 99 // full/platform/path/to/include/foo/woodly 100 headerDir := filepath.Dir(header.String()) 101 102 // woodly 103 strippedHeaderDir, err := filepath.Rel(fullFromPath.String(), headerDir) 104 if err != nil { 105 ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s", headerDir, 106 fullFromPath.String(), err) 107 } 108 109 // full/platform/path/to/sysroot/usr/include/bar/woodly 110 installDir := getCurrentIncludePath(ctx).Join(ctx, to, strippedHeaderDir) 111 112 // full/platform/path/to/sysroot/usr/include/bar/woodly/doodly.h 113 return installDir 114 } 115 116 func (m *headerModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 117 if String(m.properties.License) == "" { 118 ctx.PropertyErrorf("license", "field is required") 119 } 120 121 m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License)) 122 123 // When generating NDK prebuilts, skip installing MIPS headers, 124 // but keep them when doing regular platform build. 125 // Ndk_abis property is only set to true with build/soong/scripts/build-ndk-prebuilts.sh 126 // TODO: Revert this once MIPS is supported in NDK again. 127 if Bool(ctx.AConfig().Ndk_abis) && strings.Contains(ctx.ModuleName(), "mips") { 128 return 129 } 130 131 srcFiles := ctx.ExpandSources(m.properties.Srcs, nil) 132 for _, header := range srcFiles { 133 installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), 134 String(m.properties.To)) 135 installedPath := ctx.InstallFile(installDir, header.Base(), header) 136 installPath := installDir.Join(ctx, header.Base()) 137 if installPath != installedPath { 138 panic(fmt.Sprintf( 139 "expected header install path (%q) not equal to actual install path %q", 140 installPath, installedPath)) 141 } 142 m.installPaths = append(m.installPaths, installPath) 143 } 144 145 if len(m.installPaths) == 0 { 146 ctx.ModuleErrorf("srcs %q matched zero files", m.properties.Srcs) 147 } 148 } 149 150 func ndkHeadersFactory() android.Module { 151 module := &headerModule{} 152 module.AddProperties(&module.properties) 153 android.InitAndroidModule(module) 154 return module 155 } 156 157 type preprocessedHeaderProperies struct { 158 // Base directory of the headers being installed. As an example: 159 // 160 // preprocessed_ndk_headers { 161 // name: "foo", 162 // from: "include", 163 // to: "", 164 // } 165 // 166 // Will install $SYSROOT/usr/include/foo/bar/baz.h. If `from` were instead 167 // "include/foo", it would have installed $SYSROOT/usr/include/bar/baz.h. 168 From *string 169 170 // Install path within the sysroot. This is relative to usr/include. 171 To *string 172 173 // Path to the NOTICE file associated with the headers. 174 License *string 175 } 176 177 // Like ndk_headers, but preprocesses the headers with the bionic versioner: 178 // https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md. 179 // 180 // Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the 181 // module does not have the srcs property, and operates on a full directory (the `from` property). 182 // 183 // Note that this is really only built to handle bionic/libc/include. 184 type preprocessedHeaderModule struct { 185 android.ModuleBase 186 187 properties preprocessedHeaderProperies 188 189 installPaths android.Paths 190 licensePath android.ModuleSrcPath 191 } 192 193 func (m *preprocessedHeaderModule) DepsMutator(ctx android.BottomUpMutatorContext) { 194 } 195 196 func (m *preprocessedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 197 if String(m.properties.License) == "" { 198 ctx.PropertyErrorf("license", "field is required") 199 } 200 201 m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License)) 202 203 fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From)) 204 toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To)) 205 srcFiles := ctx.GlobFiles(filepath.Join(fromSrcPath.String(), "**/*.h"), nil) 206 var installPaths []android.WritablePath 207 for _, header := range srcFiles { 208 installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To)) 209 installPath := installDir.Join(ctx, header.Base()) 210 installPaths = append(installPaths, installPath) 211 m.installPaths = append(m.installPaths, installPath) 212 } 213 214 if len(m.installPaths) == 0 { 215 ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From)) 216 } 217 218 processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths) 219 } 220 221 func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path, srcFiles android.Paths, installPaths []android.WritablePath) android.Path { 222 // The versioner depends on a dependencies directory to simplify determining include paths 223 // when parsing headers. This directory contains architecture specific directories as well 224 // as a common directory, each of which contains symlinks to the actually directories to 225 // be included. 226 // 227 // ctx.Glob doesn't follow symlinks, so we need to do this ourselves so we correctly 228 // depend on these headers. 229 // TODO(http://b/35673191): Update the versioner to use a --sysroot. 230 depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies") 231 depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil) 232 for i, path := range depsGlob { 233 fileInfo, err := os.Lstat(path.String()) 234 if err != nil { 235 ctx.ModuleErrorf("os.Lstat(%q) failed: %s", path.String, err) 236 } 237 if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink { 238 dest, err := os.Readlink(path.String()) 239 if err != nil { 240 ctx.ModuleErrorf("os.Readlink(%q) failed: %s", 241 path.String, err) 242 } 243 // Additional .. to account for the symlink itself. 244 depsGlob[i] = android.PathForSource( 245 ctx, filepath.Clean(filepath.Join(path.String(), "..", dest))) 246 } 247 } 248 249 timestampFile := android.PathForModuleOut(ctx, "versioner.timestamp") 250 ctx.Build(pctx, android.BuildParams{ 251 Rule: preprocessBionicHeaders, 252 Description: "versioner preprocess " + srcDir.Rel(), 253 Output: timestampFile, 254 Implicits: append(srcFiles, depsGlob...), 255 ImplicitOutputs: installPaths, 256 Args: map[string]string{ 257 "depsPath": depsPath.String(), 258 "srcDir": srcDir.String(), 259 "outDir": outDir.String(), 260 }, 261 }) 262 263 return timestampFile 264 } 265 266 func preprocessedNdkHeadersFactory() android.Module { 267 module := &preprocessedHeaderModule{} 268 269 module.AddProperties(&module.properties) 270 271 // Host module rather than device module because device module install steps 272 // do not get run when embedded in make. We're not any of the existing 273 // module types that can be exposed via the Android.mk exporter, so just use 274 // a host module. 275 android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibFirst) 276 277 return module 278 }