1 // Copyright 2015 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 android 16 17 import ( 18 "bytes" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "sort" 25 "strings" 26 27 "github.com/google/blueprint" 28 "github.com/google/blueprint/proptools" 29 ) 30 31 func init() { 32 RegisterSingletonType("androidmk", AndroidMkSingleton) 33 } 34 35 type AndroidMkDataProvider interface { 36 AndroidMk() (AndroidMkData, error) 37 BaseModuleName() string 38 } 39 40 type AndroidMkData struct { 41 Class string 42 SubName string 43 OutputFile OptionalPath 44 Disabled bool 45 46 Custom func(w io.Writer, name, prefix, moduleDir string) error 47 48 Extra []func(w io.Writer, outputFile Path) error 49 } 50 51 func AndroidMkSingleton() blueprint.Singleton { 52 return &androidMkSingleton{} 53 } 54 55 type androidMkSingleton struct{} 56 57 func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) { 58 config := ctx.Config().(Config) 59 60 if !config.EmbeddedInMake() { 61 return 62 } 63 64 ctx.SetNinjaBuildDir(pctx, filepath.Join(config.buildDir, "..")) 65 66 var androidMkModulesList []Module 67 68 ctx.VisitAllModules(func(module blueprint.Module) { 69 if amod, ok := module.(Module); ok { 70 androidMkModulesList = append(androidMkModulesList, amod) 71 } 72 }) 73 74 sort.Sort(AndroidModulesByName{androidMkModulesList, ctx}) 75 76 transMk := PathForOutput(ctx, "Android"+proptools.String(config.ProductVariables.Make_suffix)+".mk") 77 if ctx.Failed() { 78 return 79 } 80 81 err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList) 82 if err != nil { 83 ctx.Errorf(err.Error()) 84 } 85 86 ctx.Build(pctx, blueprint.BuildParams{ 87 Rule: blueprint.Phony, 88 Outputs: []string{transMk.String()}, 89 Optional: true, 90 }) 91 } 92 93 func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []Module) error { 94 buf := &bytes.Buffer{} 95 96 fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))") 97 98 type_stats := make(map[string]int) 99 for _, mod := range mods { 100 err := translateAndroidMkModule(ctx, buf, mod) 101 if err != nil { 102 os.Remove(mkFile) 103 return err 104 } 105 106 if ctx.PrimaryModule(mod) == mod { 107 type_stats[ctx.ModuleType(mod)] += 1 108 } 109 } 110 111 keys := []string{} 112 fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=") 113 for k := range type_stats { 114 keys = append(keys, k) 115 } 116 sort.Strings(keys) 117 for _, mod_type := range keys { 118 fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type) 119 fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, type_stats[mod_type]) 120 } 121 122 // Don't write to the file if it hasn't changed 123 if _, err := os.Stat(mkFile); !os.IsNotExist(err) { 124 if data, err := ioutil.ReadFile(mkFile); err == nil { 125 matches := buf.Len() == len(data) 126 127 if matches { 128 for i, value := range buf.Bytes() { 129 if value != data[i] { 130 matches = false 131 break 132 } 133 } 134 } 135 136 if matches { 137 return nil 138 } 139 } 140 } 141 142 return ioutil.WriteFile(mkFile, buf.Bytes(), 0666) 143 } 144 145 func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error { 146 provider, ok := mod.(AndroidMkDataProvider) 147 if !ok { 148 return nil 149 } 150 151 name := provider.BaseModuleName() 152 amod := mod.(Module).base() 153 154 if !amod.Enabled() { 155 return nil 156 } 157 158 if amod.commonProperties.SkipInstall { 159 return nil 160 } 161 162 data, err := provider.AndroidMk() 163 if err != nil { 164 return err 165 } 166 167 // Make does not understand LinuxBionic 168 if amod.Os() == LinuxBionic { 169 return nil 170 } 171 172 if data.SubName != "" { 173 name += data.SubName 174 } 175 176 if data.Custom != nil { 177 prefix := "" 178 if amod.ArchSpecific() { 179 switch amod.Os().Class { 180 case Host: 181 prefix = "HOST_" 182 case HostCross: 183 prefix = "HOST_CROSS_" 184 case Device: 185 prefix = "TARGET_" 186 187 } 188 189 config := ctx.Config().(Config) 190 if amod.Arch().ArchType != config.Targets[amod.Os().Class][0].Arch.ArchType { 191 prefix = "2ND_" + prefix 192 } 193 } 194 195 return data.Custom(w, name, prefix, filepath.Dir(ctx.BlueprintFile(mod))) 196 } 197 198 if data.Disabled { 199 return nil 200 } 201 202 if !data.OutputFile.Valid() { 203 return err 204 } 205 206 fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") 207 fmt.Fprintln(w, "LOCAL_PATH :=", filepath.Dir(ctx.BlueprintFile(mod))) 208 fmt.Fprintln(w, "LOCAL_MODULE :=", name) 209 fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", data.Class) 210 fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", data.OutputFile.String()) 211 212 if len(amod.commonProperties.Required) > 0 { 213 fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(amod.commonProperties.Required, " ")) 214 } 215 216 archStr := amod.Arch().ArchType.String() 217 host := false 218 switch amod.Os().Class { 219 case Host: 220 fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr) 221 host = true 222 case HostCross: 223 fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr) 224 host = true 225 case Device: 226 fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr) 227 228 if len(amod.commonProperties.Logtags) > 0 { 229 fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES := ", strings.Join(amod.commonProperties.Logtags, " ")) 230 } 231 if len(amod.commonProperties.Init_rc) > 0 { 232 fmt.Fprintln(w, "LOCAL_INIT_RC := ", strings.Join(amod.commonProperties.Init_rc, " ")) 233 } 234 if amod.commonProperties.Proprietary { 235 fmt.Fprintln(w, "LOCAL_PROPRIETARY_MODULE := true") 236 } 237 if amod.commonProperties.Vendor { 238 fmt.Fprintln(w, "LOCAL_VENDOR_MODULE := true") 239 } 240 if amod.commonProperties.Owner != "" { 241 fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", amod.commonProperties.Owner) 242 } 243 } 244 245 if host { 246 fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", amod.Os().String()) 247 fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true") 248 } 249 250 for _, extra := range data.Extra { 251 err = extra(w, data.OutputFile.Path()) 252 if err != nil { 253 return err 254 } 255 } 256 257 fmt.Fprintln(w, "include $(BUILD_PREBUILT)") 258 259 return err 260 } 261