blob: 9bd3a191c6043f1b06f5a4fe88d884df503d84e0 [file] [log] [blame]
Dan Willemsen218f6562015-07-08 18:13:11 -07001// 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 "io"
20 "io/ioutil"
21 "os"
22 "path/filepath"
23 "sort"
24
25 "android/soong"
26
27 "github.com/google/blueprint"
28)
29
30func init() {
31 soong.RegisterSingletonType("androidmk", AndroidMkSingleton)
32}
33
34type AndroidMkDataProvider interface {
35 AndroidMk() AndroidMkData
36}
37
38type AndroidMkData struct {
39 Class string
Dan Willemsen34cc69e2015-09-23 15:26:20 -070040 OutputFile OptionalPath
Dan Willemsen218f6562015-07-08 18:13:11 -070041
42 Custom func(w io.Writer, name, prefix string)
43
Dan Willemsen34cc69e2015-09-23 15:26:20 -070044 Extra func(name, prefix string, outputFile Path, arch Arch) []string
Dan Willemsen218f6562015-07-08 18:13:11 -070045}
46
47func AndroidMkSingleton() blueprint.Singleton {
48 return &androidMkSingleton{}
49}
50
51type androidMkSingleton struct{}
52
53func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
Dan Willemsende4c3e72015-12-07 12:56:59 -080054 dirModules := make(map[string][]blueprint.Module)
55 hasBPDir := make(map[string]bool)
56 bpDirs := []string{}
Dan Willemsen218f6562015-07-08 18:13:11 -070057
Dan Willemsen5ba07e82015-12-11 13:51:06 -080058 if !ctx.Config().(Config).EmbeddedInMake() {
59 return
60 }
61
Dan Willemsen34cc69e2015-09-23 15:26:20 -070062 ctx.SetNinjaBuildDir(pctx, filepath.Join(ctx.Config().(Config).buildDir, ".."))
Dan Willemsen218f6562015-07-08 18:13:11 -070063
64 ctx.VisitAllModules(func(module blueprint.Module) {
65 if _, ok := module.(AndroidModule); ok {
Dan Willemsende4c3e72015-12-07 12:56:59 -080066 bpDir := filepath.Dir(ctx.BlueprintFile(module))
Dan Willemsen218f6562015-07-08 18:13:11 -070067
Dan Willemsende4c3e72015-12-07 12:56:59 -080068 if !hasBPDir[bpDir] {
69 hasBPDir[bpDir] = true
70 bpDirs = append(bpDirs, bpDir)
Dan Willemsen218f6562015-07-08 18:13:11 -070071 }
72
Dan Willemsende4c3e72015-12-07 12:56:59 -080073 dirModules[bpDir] = append(dirModules[bpDir], module)
Dan Willemsen218f6562015-07-08 18:13:11 -070074 }
75 })
76
77 // Gather list of eligible Android modules for translation
78 androidMkModules := make(map[blueprint.Module]bool)
Dan Willemsende4c3e72015-12-07 12:56:59 -080079 sort.Strings(bpDirs)
80 for _, bpDir := range bpDirs {
Dan Willemsen34cc69e2015-09-23 15:26:20 -070081 mkFile := OptionalPathForSource(ctx, "androidmk", bpDir, "Android.mk")
82 if !mkFile.Valid() {
83 for _, mod := range dirModules[bpDir] {
84 androidMkModules[mod] = true
Dan Willemsen218f6562015-07-08 18:13:11 -070085 }
Dan Willemsen218f6562015-07-08 18:13:11 -070086 }
87 }
88
89 // Validate that all modules have proper dependencies
90 androidMkModulesList := make([]AndroidModule, 0, len(androidMkModules))
91 for mod := range androidMkModules {
92 ctx.VisitDepsDepthFirstIf(mod, isAndroidModule, func(module blueprint.Module) {
93 if !androidMkModules[module] {
94 ctx.Errorf("Module %q missing dependency for Android.mk: %q", ctx.ModuleName(mod), ctx.ModuleName(module))
95 }
96 })
97 if amod, ok := mod.(AndroidModule); ok {
98 androidMkModulesList = append(androidMkModulesList, amod)
99 }
100 }
101
Colin Crossd779da42015-12-17 18:00:23 -0800102 sort.Sort(AndroidModulesByName{androidMkModulesList, ctx})
103
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700104 transMk := PathForOutput(ctx, "Android.mk")
105 if ctx.Failed() {
106 return
107 }
Dan Willemsen218f6562015-07-08 18:13:11 -0700108
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700109 err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList)
Dan Willemsen218f6562015-07-08 18:13:11 -0700110 if err != nil {
111 ctx.Errorf(err.Error())
112 }
113
114 ctx.Build(pctx, blueprint.BuildParams{
115 Rule: blueprint.Phony,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700116 Outputs: []string{transMk.String()},
Dan Willemsen218f6562015-07-08 18:13:11 -0700117 Optional: true,
118 })
119}
120
121func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []AndroidModule) error {
122 buf := &bytes.Buffer{}
123
124 io.WriteString(buf, "LOCAL_PATH := $(TOP)\n")
125 io.WriteString(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n")
126
127 for _, mod := range mods {
128 err := translateAndroidMkModule(ctx, buf, mod)
129 if err != nil {
130 os.Remove(mkFile)
131 return err
132 }
133 }
134
135 // Don't write to the file if it hasn't changed
136 if _, err := os.Stat(mkFile); !os.IsNotExist(err) {
137 if data, err := ioutil.ReadFile(mkFile); err == nil {
138 matches := buf.Len() == len(data)
139
140 if matches {
141 for i, value := range buf.Bytes() {
142 if value != data[i] {
143 matches = false
144 break
145 }
146 }
147 }
148
149 if matches {
150 return nil
151 }
152 }
153 }
154
155 return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
156}
157
158func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error {
159 if mod != ctx.PrimaryModule(mod) {
160 // These will be handled by the primary module
161 return nil
162 }
163
164 name := ctx.ModuleName(mod)
165
166 type hostClass struct {
167 host bool
168 class string
169 multilib string
170 }
171
172 type archSrc struct {
173 arch Arch
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700174 src Path
Dan Willemsen218f6562015-07-08 18:13:11 -0700175 extra []string
176 }
177
178 srcs := make(map[hostClass][]archSrc)
179 var modules []hostClass
180
181 ctx.VisitAllModuleVariants(mod, func(m blueprint.Module) {
182 provider, ok := m.(AndroidMkDataProvider)
183 if !ok {
184 return
185 }
186
187 amod := m.(AndroidModule).base()
188 data := provider.AndroidMk()
189
Colin Cross1ef47562015-12-15 18:07:15 -0800190 if !amod.Enabled() {
191 return
192 }
193
Dan Willemsen218f6562015-07-08 18:13:11 -0700194 arch := amod.commonProperties.CompileArch
195
196 prefix := ""
197 if amod.HostOrDevice() == Host {
198 if arch.ArchType != ctx.Config().(Config).HostArches[amod.HostType()][0].ArchType {
199 prefix = "2ND_"
200 }
201 } else {
202 if arch.ArchType != ctx.Config().(Config).DeviceArches[0].ArchType {
203 prefix = "2ND_"
204 }
205 }
206
207 if data.Custom != nil {
208 data.Custom(w, name, prefix)
209 return
210 }
211
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700212 if !data.OutputFile.Valid() {
213 return
214 }
215
Dan Willemsen218f6562015-07-08 18:13:11 -0700216 hC := hostClass{
217 host: amod.HostOrDevice() == Host,
218 class: data.Class,
219 multilib: amod.commonProperties.Compile_multilib,
220 }
221
222 src := archSrc{
223 arch: arch,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700224 src: data.OutputFile.Path(),
Dan Willemsen218f6562015-07-08 18:13:11 -0700225 }
226
227 if data.Extra != nil {
228 src.extra = data.Extra(name, prefix, src.src, arch)
229 }
230
231 if srcs[hC] == nil {
232 modules = append(modules, hC)
233 }
234 srcs[hC] = append(srcs[hC], src)
235 })
236
237 for _, hC := range modules {
238 archSrcs := srcs[hC]
239
240 io.WriteString(w, "\ninclude $(CLEAR_VARS)\n")
241 io.WriteString(w, "LOCAL_MODULE := "+name+"\n")
242 io.WriteString(w, "LOCAL_MODULE_CLASS := "+hC.class+"\n")
243 io.WriteString(w, "LOCAL_MULTILIB := "+hC.multilib+"\n")
244
245 printed := make(map[string]bool)
246 for _, src := range archSrcs {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700247 io.WriteString(w, "LOCAL_SRC_FILES_"+src.arch.ArchType.String()+" := "+src.src.String()+"\n")
Dan Willemsen218f6562015-07-08 18:13:11 -0700248
249 for _, extra := range src.extra {
250 if !printed[extra] {
251 printed[extra] = true
252 io.WriteString(w, extra+"\n")
253 }
254 }
255 }
256
257 if hC.host {
258 // TODO: this isn't true for every module
259 io.WriteString(w, "LOCAL_ACP_UNAVAILABLE := true\n")
260
261 io.WriteString(w, "LOCAL_IS_HOST_MODULE := true\n")
262 }
263 io.WriteString(w, "include $(BUILD_PREBUILT)\n")
264 }
265
266 return nil
267}