blob: 9470b6b6b90391fcc1b533bde007ce2fbc238bc2 [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
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700102 transMk := PathForOutput(ctx, "Android.mk")
103 if ctx.Failed() {
104 return
105 }
Dan Willemsen218f6562015-07-08 18:13:11 -0700106
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700107 err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList)
Dan Willemsen218f6562015-07-08 18:13:11 -0700108 if err != nil {
109 ctx.Errorf(err.Error())
110 }
111
112 ctx.Build(pctx, blueprint.BuildParams{
113 Rule: blueprint.Phony,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700114 Outputs: []string{transMk.String()},
Dan Willemsen218f6562015-07-08 18:13:11 -0700115 Optional: true,
116 })
117}
118
119func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []AndroidModule) error {
120 buf := &bytes.Buffer{}
121
122 io.WriteString(buf, "LOCAL_PATH := $(TOP)\n")
123 io.WriteString(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n")
124
125 for _, mod := range mods {
126 err := translateAndroidMkModule(ctx, buf, mod)
127 if err != nil {
128 os.Remove(mkFile)
129 return err
130 }
131 }
132
133 // Don't write to the file if it hasn't changed
134 if _, err := os.Stat(mkFile); !os.IsNotExist(err) {
135 if data, err := ioutil.ReadFile(mkFile); err == nil {
136 matches := buf.Len() == len(data)
137
138 if matches {
139 for i, value := range buf.Bytes() {
140 if value != data[i] {
141 matches = false
142 break
143 }
144 }
145 }
146
147 if matches {
148 return nil
149 }
150 }
151 }
152
153 return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
154}
155
156func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error {
157 if mod != ctx.PrimaryModule(mod) {
158 // These will be handled by the primary module
159 return nil
160 }
161
162 name := ctx.ModuleName(mod)
163
164 type hostClass struct {
165 host bool
166 class string
167 multilib string
168 }
169
170 type archSrc struct {
171 arch Arch
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700172 src Path
Dan Willemsen218f6562015-07-08 18:13:11 -0700173 extra []string
174 }
175
176 srcs := make(map[hostClass][]archSrc)
177 var modules []hostClass
178
179 ctx.VisitAllModuleVariants(mod, func(m blueprint.Module) {
180 provider, ok := m.(AndroidMkDataProvider)
181 if !ok {
182 return
183 }
184
185 amod := m.(AndroidModule).base()
186 data := provider.AndroidMk()
187
188 arch := amod.commonProperties.CompileArch
189
190 prefix := ""
191 if amod.HostOrDevice() == Host {
192 if arch.ArchType != ctx.Config().(Config).HostArches[amod.HostType()][0].ArchType {
193 prefix = "2ND_"
194 }
195 } else {
196 if arch.ArchType != ctx.Config().(Config).DeviceArches[0].ArchType {
197 prefix = "2ND_"
198 }
199 }
200
201 if data.Custom != nil {
202 data.Custom(w, name, prefix)
203 return
204 }
205
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700206 if !data.OutputFile.Valid() {
207 return
208 }
209
Dan Willemsen218f6562015-07-08 18:13:11 -0700210 hC := hostClass{
211 host: amod.HostOrDevice() == Host,
212 class: data.Class,
213 multilib: amod.commonProperties.Compile_multilib,
214 }
215
216 src := archSrc{
217 arch: arch,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700218 src: data.OutputFile.Path(),
Dan Willemsen218f6562015-07-08 18:13:11 -0700219 }
220
221 if data.Extra != nil {
222 src.extra = data.Extra(name, prefix, src.src, arch)
223 }
224
225 if srcs[hC] == nil {
226 modules = append(modules, hC)
227 }
228 srcs[hC] = append(srcs[hC], src)
229 })
230
231 for _, hC := range modules {
232 archSrcs := srcs[hC]
233
234 io.WriteString(w, "\ninclude $(CLEAR_VARS)\n")
235 io.WriteString(w, "LOCAL_MODULE := "+name+"\n")
236 io.WriteString(w, "LOCAL_MODULE_CLASS := "+hC.class+"\n")
237 io.WriteString(w, "LOCAL_MULTILIB := "+hC.multilib+"\n")
238
239 printed := make(map[string]bool)
240 for _, src := range archSrcs {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700241 io.WriteString(w, "LOCAL_SRC_FILES_"+src.arch.ArchType.String()+" := "+src.src.String()+"\n")
Dan Willemsen218f6562015-07-08 18:13:11 -0700242
243 for _, extra := range src.extra {
244 if !printed[extra] {
245 printed[extra] = true
246 io.WriteString(w, extra+"\n")
247 }
248 }
249 }
250
251 if hC.host {
252 // TODO: this isn't true for every module
253 io.WriteString(w, "LOCAL_ACP_UNAVAILABLE := true\n")
254
255 io.WriteString(w, "LOCAL_IS_HOST_MODULE := true\n")
256 }
257 io.WriteString(w, "include $(BUILD_PREBUILT)\n")
258 }
259
260 return nil
261}