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 15package cc 16 17// The platform needs to provide the following artifacts for the NDK: 18// 1. Bionic headers. 19// 2. Platform API headers. 20// 3. NDK stub shared libraries. 21// 4. Bionic static libraries. 22// 23// TODO(danalbert): All of the above need to include NOTICE files. 24// 25// Components 1 and 2: Headers 26// The bionic and platform API headers are generalized into a single 27// `ndk_headers` rule. This rule has a `from` property that indicates a base 28// directory from which headers are to be taken, and a `to` property that 29// indicates where in the sysroot they should reside relative to usr/include. 30// There is also a `srcs` property that is glob compatible for specifying which 31// headers to include. 32// 33// Component 3: Stub Libraries 34// The shared libraries in the NDK are not the actual shared libraries they 35// refer to (to prevent people from accidentally loading them), but stub 36// libraries with placeholder implementations of everything for use at build time 37// only. 38// 39// Since we don't actually need to know anything about the stub libraries aside 40// from a list of functions and globals to be exposed, we can create these for 41// every platform level in the current tree. This is handled by the 42// ndk_library rule. 43// 44// Component 4: Static Libraries 45// The NDK only provides static libraries for bionic, not the platform APIs. 46// Since these need to be the actual implementation, we can't build old versions 47// in the current platform tree. As such, legacy versions are checked in 48// prebuilt to development/ndk, and a current version is built and archived as 49// part of the platform build. The platfrom already builds these libraries, our 50// NDK build rules only need to archive them for retrieval so they can be added 51// to the prebuilts. 52// 53// TODO(danalbert): Write `ndk_static_library` rule. 54 55import ( 56 "android/soong/android" 57 "fmt" 58 "path/filepath" 59 "strings" 60 61 "github.com/google/blueprint" 62) 63 64var ( 65 verifyCCompat = pctx.AndroidStaticRule("verifyCCompat", 66 blueprint.RuleParams{ 67 Command: "$ccCmd -x c -fsyntax-only $flags $in && touch $out", 68 CommandDeps: []string{"$ccCmd"}, 69 }, 70 "ccCmd", 71 "flags", 72 ) 73) 74 75func init() { 76 RegisterNdkModuleTypes(android.InitRegistrationContext) 77} 78 79func RegisterNdkModuleTypes(ctx android.RegistrationContext) { 80 ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory) 81 ctx.RegisterModuleType("ndk_library", NdkLibraryFactory) 82 ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory) 83 ctx.RegisterParallelSingletonType("ndk", NdkSingleton) 84} 85 86func getNdkInstallBase(ctx android.PathContext) android.OutputPath { 87 return android.PathForNdkInstall(ctx) 88} 89 90// Returns the main install directory for the NDK sysroot. Usable with --sysroot. 91func getNdkSysrootBase(ctx android.PathContext) android.OutputPath { 92 return getNdkInstallBase(ctx).Join(ctx, "sysroot") 93} 94 95// The base timestamp file depends on the NDK headers and stub shared libraries, 96// but not the static libraries. This distinction is needed because the static 97// libraries themselves might need to depend on the base sysroot. 98func getNdkBaseTimestampFile(ctx android.PathContext) android.WritablePath { 99 return android.PathForOutput(ctx, "ndk_base.timestamp") 100} 101 102// The headers timestamp file depends only on the NDK headers. 103// This is used mainly for .tidy files that do not need any stub libraries. 104func getNdkHeadersTimestampFile(ctx android.PathContext) android.WritablePath { 105 return android.PathForOutput(ctx, "ndk_headers.timestamp") 106} 107 108// The full timestamp file depends on the base timestamp *and* the static 109// libraries. 110func getNdkFullTimestampFile(ctx android.PathContext) android.WritablePath { 111 return android.PathForOutput(ctx, "ndk.timestamp") 112} 113 114// The list of all NDK headers as they are located in the repo. 115// Used for ABI monitoring to track only structures defined in NDK headers. 116func getNdkABIHeadersFile(ctx android.PathContext) android.WritablePath { 117 return android.PathForOutput(ctx, "ndk_abi_headers.txt") 118} 119 120func verifyNdkHeaderIsCCompatible(ctx android.SingletonContext, 121 src android.Path, dest android.Path) android.Path { 122 sysrootInclude := getCurrentIncludePath(ctx) 123 baseOutputDir := android.PathForOutput(ctx, "c-compat-verification") 124 installRelPath, err := filepath.Rel(sysrootInclude.String(), dest.String()) 125 if err != nil { 126 ctx.Errorf("filepath.Rel(%q, %q) failed: %s", dest, sysrootInclude, err) 127 } 128 output := baseOutputDir.Join(ctx, installRelPath) 129 ctx.Build(pctx, android.BuildParams{ 130 Rule: verifyCCompat, 131 Description: fmt.Sprintf("Verifying C compatibility of %s", src), 132 Output: output, 133 Input: dest, 134 // Ensures that all the headers in the sysroot are already installed 135 // before testing any of the headers for C compatibility, and also that 136 // the check will be re-run whenever the sysroot changes. This is 137 // necessary because many of the NDK headers depend on other NDK 138 // headers, but we don't have explicit dependency tracking for that. 139 Implicits: []android.Path{getNdkHeadersTimestampFile(ctx)}, 140 Args: map[string]string{ 141 "ccCmd": "${config.ClangBin}/clang", 142 "flags": fmt.Sprintf( 143 // Ideally we'd check each ABI, multiple API levels, 144 // fortify/non-fortify, and a handful of other variations. It's 145 // a lot more difficult to do that though, and would eat up more 146 // build time. All the problems we've seen so far that this 147 // check would catch have been in arch-generic and 148 // minSdkVersion-generic code in frameworks though, so this is a 149 // good place to start. 150 "-target aarch64-linux-android%d --sysroot %s", 151 android.FutureApiLevel.FinalOrFutureInt(), 152 getNdkSysrootBase(ctx).String(), 153 ), 154 }, 155 }) 156 return output 157} 158 159func NdkSingleton() android.Singleton { 160 return &ndkSingleton{} 161} 162 163// Collect all NDK exported headers paths into a file that is used to 164// detect public types that should be ABI monitored. 165// 166// Assume that we have the following code in exported header: 167// 168// typedef struct Context Context; 169// typedef struct Output { 170// ... 171// } Output; 172// void DoSomething(Context* ctx, Output* output); 173// 174// If none of public headers exported to end-users contain definition of 175// "struct Context", then "struct Context" layout and members shouldn't be 176// monitored. However we use DWARF information from a real library, which 177// may have access to the definition of "string Context" from 178// implementation headers, and it will leak to ABI. 179// 180// STG tool doesn't access source and header files, only DWARF information 181// from compiled library. And the DWARF contains file name where a type is 182// defined. So we need a rule to build a list of paths to public headers, 183// so STG can distinguish private types from public and do not monitor 184// private types that are not accessible to library users. 185func writeNdkAbiSrcFilter(ctx android.BuilderContext, 186 headerSrcPaths android.Paths, outputFile android.WritablePath) { 187 var filterBuilder strings.Builder 188 filterBuilder.WriteString("[decl_file_allowlist]\n") 189 for _, headerSrcPath := range headerSrcPaths { 190 filterBuilder.WriteString(headerSrcPath.String()) 191 filterBuilder.WriteString("\n") 192 } 193 194 android.WriteFileRule(ctx, outputFile, filterBuilder.String()) 195} 196 197type ndkSingleton struct{} 198 199type srcDestPair struct { 200 src android.Path 201 dest android.Path 202} 203 204func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { 205 var staticLibInstallPaths android.Paths 206 var headerSrcPaths android.Paths 207 var headerInstallPaths android.Paths 208 var headersToVerify []srcDestPair 209 var headerCCompatVerificationTimestampPaths android.Paths 210 var installPaths android.Paths 211 var licensePaths android.Paths 212 ctx.VisitAllModules(func(module android.Module) { 213 if m, ok := module.(android.Module); ok && !m.Enabled(ctx) { 214 return 215 } 216 217 if m, ok := module.(*headerModule); ok { 218 headerSrcPaths = append(headerSrcPaths, m.srcPaths...) 219 headerInstallPaths = append(headerInstallPaths, m.installPaths...) 220 if !Bool(m.properties.Skip_verification) { 221 for i, installPath := range m.installPaths { 222 headersToVerify = append(headersToVerify, srcDestPair{ 223 src: m.srcPaths[i], 224 dest: installPath, 225 }) 226 } 227 } 228 installPaths = append(installPaths, m.installPaths...) 229 licensePaths = append(licensePaths, m.licensePath) 230 } 231 232 if m, ok := module.(*preprocessedHeadersModule); ok { 233 headerSrcPaths = append(headerSrcPaths, m.srcPaths...) 234 headerInstallPaths = append(headerInstallPaths, m.installPaths...) 235 if !Bool(m.properties.Skip_verification) { 236 for i, installPath := range m.installPaths { 237 headersToVerify = append(headersToVerify, srcDestPair{ 238 src: m.srcPaths[i], 239 dest: installPath, 240 }) 241 } 242 } 243 installPaths = append(installPaths, m.installPaths...) 244 licensePaths = append(licensePaths, m.licensePath) 245 } 246 247 if m, ok := module.(*Module); ok { 248 if installer, ok := m.installer.(*stubDecorator); ok && m.library.buildStubs() { 249 installPaths = append(installPaths, installer.installPath) 250 } 251 252 if library, ok := m.linker.(*libraryDecorator); ok { 253 if library.ndkSysrootPath != nil { 254 staticLibInstallPaths = append( 255 staticLibInstallPaths, library.ndkSysrootPath) 256 } 257 } 258 259 if object, ok := m.linker.(*objectLinker); ok { 260 if object.ndkSysrootPath != nil { 261 staticLibInstallPaths = append( 262 staticLibInstallPaths, object.ndkSysrootPath) 263 } 264 } 265 } 266 }) 267 268 // Include only a single copy of each license file. The Bionic NOTICE is 269 // long and is referenced by multiple Bionic modules. 270 licensePaths = android.FirstUniquePaths(licensePaths) 271 272 combinedLicense := getNdkInstallBase(ctx).Join(ctx, "NOTICE") 273 ctx.Build(pctx, android.BuildParams{ 274 Rule: android.Cat, 275 Description: "combine licenses", 276 Output: combinedLicense, 277 Inputs: licensePaths, 278 }) 279 280 baseDepPaths := append(installPaths, combinedLicense) 281 282 ctx.Build(pctx, android.BuildParams{ 283 Rule: android.Touch, 284 Output: getNdkBaseTimestampFile(ctx), 285 Implicits: baseDepPaths, 286 Validation: getNdkAbiDiffTimestampFile(ctx), 287 }) 288 289 ctx.Build(pctx, android.BuildParams{ 290 Rule: android.Touch, 291 Output: getNdkHeadersTimestampFile(ctx), 292 Implicits: headerInstallPaths, 293 }) 294 295 for _, srcDestPair := range headersToVerify { 296 headerCCompatVerificationTimestampPaths = append( 297 headerCCompatVerificationTimestampPaths, 298 verifyNdkHeaderIsCCompatible(ctx, srcDestPair.src, srcDestPair.dest)) 299 } 300 301 writeNdkAbiSrcFilter(ctx, headerSrcPaths, getNdkABIHeadersFile(ctx)) 302 303 fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx)) 304 305 // There's a phony "ndk" rule defined in core/main.mk that depends on this. 306 // `m ndk` will build the sysroots for the architectures in the current 307 // lunch target. `build/soong/scripts/build-ndk-prebuilts.sh` will build the 308 // sysroots for all the NDK architectures and package them so they can be 309 // imported into the NDK's build. 310 ctx.Build(pctx, android.BuildParams{ 311 Rule: android.Touch, 312 Output: getNdkFullTimestampFile(ctx), 313 Implicits: append(fullDepPaths, headerCCompatVerificationTimestampPaths...), 314 }) 315} 316