1// Copyright 2019 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 sh 16 17import ( 18 "fmt" 19 "path/filepath" 20 "strings" 21 22 "github.com/google/blueprint/proptools" 23 24 "android/soong/android" 25 "android/soong/tradefed" 26) 27 28// sh_binary is for shell scripts (and batch files) that are installed as 29// executable files into .../bin/ 30// 31// Do not use them for prebuilt C/C++/etc files. Use cc_prebuilt_binary 32// instead. 33 34var pctx = android.NewPackageContext("android/soong/sh") 35 36func init() { 37 pctx.Import("android/soong/android") 38 39 android.RegisterModuleType("sh_binary", ShBinaryFactory) 40 android.RegisterModuleType("sh_binary_host", ShBinaryHostFactory) 41 android.RegisterModuleType("sh_test", ShTestFactory) 42 android.RegisterModuleType("sh_test_host", ShTestHostFactory) 43} 44 45type shBinaryProperties struct { 46 // Source file of this prebuilt. 47 Src *string `android:"path,arch_variant"` 48 49 // optional subdirectory under which this file is installed into 50 Sub_dir *string `android:"arch_variant"` 51 52 // optional name for the installed file. If unspecified, name of the module is used as the file name 53 Filename *string `android:"arch_variant"` 54 55 // when set to true, and filename property is not set, the name for the installed file 56 // is the same as the file name of the source file. 57 Filename_from_src *bool `android:"arch_variant"` 58 59 // Whether this module is directly installable to one of the partitions. Default: true. 60 Installable *bool 61 62 // install symlinks to the binary 63 Symlinks []string `android:"arch_variant"` 64} 65 66type TestProperties struct { 67 // list of compatibility suites (for example "cts", "vts") that the module should be 68 // installed into. 69 Test_suites []string `android:"arch_variant"` 70 71 // the name of the test configuration (for example "AndroidTest.xml") that should be 72 // installed with the module. 73 Test_config *string `android:"path,arch_variant"` 74 75 // list of files or filegroup modules that provide data that should be installed alongside 76 // the test. 77 Data []string `android:"path,arch_variant"` 78 79 // Add RootTargetPreparer to auto generated test config. This guarantees the test to run 80 // with root permission. 81 Require_root *bool 82 83 // the name of the test configuration template (for example "AndroidTestTemplate.xml") that 84 // should be installed with the module. 85 Test_config_template *string `android:"path,arch_variant"` 86 87 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml 88 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true 89 // explicitly. 90 Auto_gen_config *bool 91} 92 93type ShBinary struct { 94 android.ModuleBase 95 96 properties shBinaryProperties 97 98 sourceFilePath android.Path 99 outputFilePath android.OutputPath 100 installedFile android.InstallPath 101} 102 103var _ android.HostToolProvider = (*ShBinary)(nil) 104 105type ShTest struct { 106 ShBinary 107 108 testProperties TestProperties 109 110 installDir android.InstallPath 111 112 data android.Paths 113 testConfig android.Path 114} 115 116func (s *ShBinary) HostToolPath() android.OptionalPath { 117 return android.OptionalPathForPath(s.installedFile) 118} 119 120func (s *ShBinary) DepsMutator(ctx android.BottomUpMutatorContext) { 121 if s.properties.Src == nil { 122 ctx.PropertyErrorf("src", "missing prebuilt source file") 123 } 124} 125 126func (s *ShBinary) OutputFile() android.OutputPath { 127 return s.outputFilePath 128} 129 130func (s *ShBinary) SubDir() string { 131 return proptools.String(s.properties.Sub_dir) 132} 133 134func (s *ShBinary) Installable() bool { 135 return s.properties.Installable == nil || proptools.Bool(s.properties.Installable) 136} 137 138func (s *ShBinary) Symlinks() []string { 139 return s.properties.Symlinks 140} 141 142func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) { 143 s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src)) 144 filename := proptools.String(s.properties.Filename) 145 filename_from_src := proptools.Bool(s.properties.Filename_from_src) 146 if filename == "" { 147 if filename_from_src { 148 filename = s.sourceFilePath.Base() 149 } else { 150 filename = ctx.ModuleName() 151 } 152 } else if filename_from_src { 153 ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true") 154 return 155 } 156 s.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath 157 158 // This ensures that outputFilePath has the correct name for others to 159 // use, as the source file may have a different name. 160 ctx.Build(pctx, android.BuildParams{ 161 Rule: android.CpExecutable, 162 Output: s.outputFilePath, 163 Input: s.sourceFilePath, 164 }) 165} 166 167func (s *ShBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) { 168 s.generateAndroidBuildActions(ctx) 169 installDir := android.PathForModuleInstall(ctx, "bin", proptools.String(s.properties.Sub_dir)) 170 s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath) 171} 172 173func (s *ShBinary) AndroidMkEntries() []android.AndroidMkEntries { 174 return []android.AndroidMkEntries{android.AndroidMkEntries{ 175 Class: "EXECUTABLES", 176 OutputFile: android.OptionalPathForPath(s.outputFilePath), 177 Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk", 178 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 179 func(entries *android.AndroidMkEntries) { 180 s.customAndroidMkEntries(entries) 181 entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir)) 182 }, 183 }, 184 }} 185} 186 187func (s *ShBinary) customAndroidMkEntries(entries *android.AndroidMkEntries) { 188 entries.SetString("LOCAL_MODULE_SUFFIX", "") 189 entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel()) 190 if len(s.properties.Symlinks) > 0 { 191 entries.SetString("LOCAL_MODULE_SYMLINKS", strings.Join(s.properties.Symlinks, " ")) 192 } 193} 194 195func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { 196 s.ShBinary.generateAndroidBuildActions(ctx) 197 testDir := "nativetest" 198 if ctx.Target().Arch.ArchType.Multilib == "lib64" { 199 testDir = "nativetest64" 200 } 201 if ctx.Target().NativeBridge == android.NativeBridgeEnabled { 202 testDir = filepath.Join(testDir, ctx.Target().NativeBridgeRelativePath) 203 } else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) { 204 testDir = filepath.Join(testDir, ctx.Arch().ArchType.String()) 205 } 206 if s.SubDir() != "" { 207 // Don't add the module name to the installation path if sub_dir is specified for backward 208 // compatibility. 209 s.installDir = android.PathForModuleInstall(ctx, testDir, s.SubDir()) 210 } else { 211 s.installDir = android.PathForModuleInstall(ctx, testDir, s.Name()) 212 } 213 s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath) 214 215 s.data = android.PathsForModuleSrc(ctx, s.testProperties.Data) 216 217 var configs []tradefed.Config 218 if Bool(s.testProperties.Require_root) { 219 configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) 220 } else { 221 options := []tradefed.Option{{Name: "force-root", Value: "false"}} 222 configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options}) 223 } 224 s.testConfig = tradefed.AutoGenShellTestConfig(ctx, s.testProperties.Test_config, 225 s.testProperties.Test_config_template, s.testProperties.Test_suites, configs, s.testProperties.Auto_gen_config, s.outputFilePath.Base()) 226} 227 228func (s *ShTest) InstallInData() bool { 229 return true 230} 231 232func (s *ShTest) AndroidMkEntries() []android.AndroidMkEntries { 233 return []android.AndroidMkEntries{android.AndroidMkEntries{ 234 Class: "NATIVE_TESTS", 235 OutputFile: android.OptionalPathForPath(s.outputFilePath), 236 Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk", 237 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 238 func(entries *android.AndroidMkEntries) { 239 s.customAndroidMkEntries(entries) 240 entries.SetPath("LOCAL_MODULE_PATH", s.installDir.ToMakePath()) 241 entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...) 242 if s.testConfig != nil { 243 entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig) 244 } 245 for _, d := range s.data { 246 rel := d.Rel() 247 path := d.String() 248 if !strings.HasSuffix(path, rel) { 249 panic(fmt.Errorf("path %q does not end with %q", path, rel)) 250 } 251 path = strings.TrimSuffix(path, rel) 252 entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel) 253 } 254 }, 255 }, 256 }} 257} 258 259func InitShBinaryModule(s *ShBinary) { 260 s.AddProperties(&s.properties) 261} 262 263// sh_binary is for a shell script or batch file to be installed as an 264// executable binary to <partition>/bin. 265func ShBinaryFactory() android.Module { 266 module := &ShBinary{} 267 InitShBinaryModule(module) 268 android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst) 269 return module 270} 271 272// sh_binary_host is for a shell script to be installed as an executable binary 273// to $(HOST_OUT)/bin. 274func ShBinaryHostFactory() android.Module { 275 module := &ShBinary{} 276 InitShBinaryModule(module) 277 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst) 278 return module 279} 280 281// sh_test defines a shell script based test module. 282func ShTestFactory() android.Module { 283 module := &ShTest{} 284 InitShBinaryModule(&module.ShBinary) 285 module.AddProperties(&module.testProperties) 286 287 android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst) 288 return module 289} 290 291// sh_test_host defines a shell script based test module that runs on a host. 292func ShTestHostFactory() android.Module { 293 module := &ShTest{} 294 InitShBinaryModule(&module.ShBinary) 295 module.AddProperties(&module.testProperties) 296 297 android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst) 298 return module 299} 300 301var Bool = proptools.Bool 302