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 15package common 16 17import ( 18 "bytes" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "sort" 25 26 "android/soong" 27 28 "github.com/google/blueprint" 29) 30 31func init() { 32 soong.RegisterSingletonType("androidmk", AndroidMkSingleton) 33} 34 35type AndroidMkDataProvider interface { 36 AndroidMk() (AndroidMkData, error) 37} 38 39type AndroidMkData struct { 40 Class string 41 SubName string 42 OutputFile OptionalPath 43 Disabled bool 44 45 Custom func(w io.Writer, name, prefix string) error 46 47 Extra []func(w io.Writer, outputFile Path) error 48} 49 50func AndroidMkSingleton() blueprint.Singleton { 51 return &androidMkSingleton{} 52} 53 54type androidMkSingleton struct{} 55 56func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) { 57 if !ctx.Config().(Config).EmbeddedInMake() { 58 return 59 } 60 61 ctx.SetNinjaBuildDir(pctx, filepath.Join(ctx.Config().(Config).buildDir, "..")) 62 63 var androidMkModulesList []AndroidModule 64 65 ctx.VisitAllModules(func(module blueprint.Module) { 66 if amod, ok := module.(AndroidModule); ok { 67 androidMkModulesList = append(androidMkModulesList, amod) 68 } 69 }) 70 71 sort.Sort(AndroidModulesByName{androidMkModulesList, ctx}) 72 73 transMk := PathForOutput(ctx, "Android.mk") 74 if ctx.Failed() { 75 return 76 } 77 78 err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList) 79 if err != nil { 80 ctx.Errorf(err.Error()) 81 } 82 83 ctx.Build(pctx, blueprint.BuildParams{ 84 Rule: blueprint.Phony, 85 Outputs: []string{transMk.String()}, 86 Optional: true, 87 }) 88} 89 90func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []AndroidModule) error { 91 buf := &bytes.Buffer{} 92 93 fmt.Fprintln(buf, "LOCAL_PATH := $(TOP)") 94 fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))") 95 96 for _, mod := range mods { 97 err := translateAndroidMkModule(ctx, buf, mod) 98 if err != nil { 99 os.Remove(mkFile) 100 return err 101 } 102 } 103 104 // Don't write to the file if it hasn't changed 105 if _, err := os.Stat(mkFile); !os.IsNotExist(err) { 106 if data, err := ioutil.ReadFile(mkFile); err == nil { 107 matches := buf.Len() == len(data) 108 109 if matches { 110 for i, value := range buf.Bytes() { 111 if value != data[i] { 112 matches = false 113 break 114 } 115 } 116 } 117 118 if matches { 119 return nil 120 } 121 } 122 } 123 124 return ioutil.WriteFile(mkFile, buf.Bytes(), 0666) 125} 126 127func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error { 128 name := ctx.ModuleName(mod) 129 130 provider, ok := mod.(AndroidMkDataProvider) 131 if !ok { 132 return nil 133 } 134 135 amod := mod.(AndroidModule).base() 136 data, err := provider.AndroidMk() 137 if err != nil { 138 return err 139 } 140 141 if !amod.Enabled() { 142 return err 143 } 144 145 if data.SubName != "" { 146 name += "_" + data.SubName 147 } 148 149 hostCross := false 150 if amod.Host() && amod.HostType() != CurrentHostType() { 151 hostCross = true 152 } 153 154 if data.Custom != nil { 155 prefix := "" 156 if amod.Host() { 157 if hostCross { 158 prefix = "HOST_CROSS_" 159 } else { 160 prefix = "HOST_" 161 } 162 if amod.Arch().ArchType != ctx.Config().(Config).HostArches[amod.HostType()][0].ArchType { 163 prefix = "2ND_" + prefix 164 } 165 } else { 166 prefix = "TARGET_" 167 if amod.Arch().ArchType != ctx.Config().(Config).DeviceArches[0].ArchType { 168 prefix = "2ND_" + prefix 169 } 170 } 171 172 return data.Custom(w, name, prefix) 173 } 174 175 if data.Disabled { 176 return nil 177 } 178 179 if !data.OutputFile.Valid() { 180 return err 181 } 182 183 fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") 184 fmt.Fprintln(w, "LOCAL_MODULE :=", name) 185 fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", data.Class) 186 fmt.Fprintln(w, "LOCAL_MULTILIB :=", amod.commonProperties.Compile_multilib) 187 fmt.Fprintln(w, "LOCAL_SRC_FILES :=", data.OutputFile.String()) 188 189 archStr := amod.Arch().ArchType.String() 190 if amod.Host() { 191 if hostCross { 192 fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr) 193 } else { 194 fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr) 195 196 // TODO: this isn't true for every module, only dependencies of ACP 197 fmt.Fprintln(w, "LOCAL_ACP_UNAVAILABLE := true") 198 } 199 fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", amod.HostType().String()) 200 fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true") 201 } else { 202 fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr) 203 } 204 205 for _, extra := range data.Extra { 206 err = extra(w, data.OutputFile.Path()) 207 if err != nil { 208 return err 209 } 210 } 211 212 fmt.Fprintln(w, "include $(BUILD_PREBUILT)") 213 214 return err 215} 216