blob: 06aa30c5d3d1430ea962c37b0b09c13a660b3345 [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 Willemsen34cc69e2015-09-23 15:26:20 -070058 ctx.SetNinjaBuildDir(pctx, filepath.Join(ctx.Config().(Config).buildDir, ".."))
Dan Willemsen218f6562015-07-08 18:13:11 -070059
60 ctx.VisitAllModules(func(module blueprint.Module) {
61 if _, ok := module.(AndroidModule); ok {
Dan Willemsende4c3e72015-12-07 12:56:59 -080062 bpDir := filepath.Dir(ctx.BlueprintFile(module))
Dan Willemsen218f6562015-07-08 18:13:11 -070063
Dan Willemsende4c3e72015-12-07 12:56:59 -080064 if !hasBPDir[bpDir] {
65 hasBPDir[bpDir] = true
66 bpDirs = append(bpDirs, bpDir)
Dan Willemsen218f6562015-07-08 18:13:11 -070067 }
68
Dan Willemsende4c3e72015-12-07 12:56:59 -080069 dirModules[bpDir] = append(dirModules[bpDir], module)
Dan Willemsen218f6562015-07-08 18:13:11 -070070 }
71 })
72
73 // Gather list of eligible Android modules for translation
74 androidMkModules := make(map[blueprint.Module]bool)
Dan Willemsende4c3e72015-12-07 12:56:59 -080075 sort.Strings(bpDirs)
76 for _, bpDir := range bpDirs {
Dan Willemsen34cc69e2015-09-23 15:26:20 -070077 mkFile := OptionalPathForSource(ctx, "androidmk", bpDir, "Android.mk")
78 if !mkFile.Valid() {
79 for _, mod := range dirModules[bpDir] {
80 androidMkModules[mod] = true
Dan Willemsen218f6562015-07-08 18:13:11 -070081 }
Dan Willemsen218f6562015-07-08 18:13:11 -070082 }
83 }
84
85 // Validate that all modules have proper dependencies
86 androidMkModulesList := make([]AndroidModule, 0, len(androidMkModules))
87 for mod := range androidMkModules {
88 ctx.VisitDepsDepthFirstIf(mod, isAndroidModule, func(module blueprint.Module) {
89 if !androidMkModules[module] {
90 ctx.Errorf("Module %q missing dependency for Android.mk: %q", ctx.ModuleName(mod), ctx.ModuleName(module))
91 }
92 })
93 if amod, ok := mod.(AndroidModule); ok {
94 androidMkModulesList = append(androidMkModulesList, amod)
95 }
96 }
97
Dan Willemsen34cc69e2015-09-23 15:26:20 -070098 transMk := PathForOutput(ctx, "Android.mk")
99 if ctx.Failed() {
100 return
101 }
Dan Willemsen218f6562015-07-08 18:13:11 -0700102
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700103 err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList)
Dan Willemsen218f6562015-07-08 18:13:11 -0700104 if err != nil {
105 ctx.Errorf(err.Error())
106 }
107
108 ctx.Build(pctx, blueprint.BuildParams{
109 Rule: blueprint.Phony,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700110 Outputs: []string{transMk.String()},
Dan Willemsen218f6562015-07-08 18:13:11 -0700111 Optional: true,
112 })
113}
114
115func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []AndroidModule) error {
116 buf := &bytes.Buffer{}
117
118 io.WriteString(buf, "LOCAL_PATH := $(TOP)\n")
119 io.WriteString(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n")
120
121 for _, mod := range mods {
122 err := translateAndroidMkModule(ctx, buf, mod)
123 if err != nil {
124 os.Remove(mkFile)
125 return err
126 }
127 }
128
129 // Don't write to the file if it hasn't changed
130 if _, err := os.Stat(mkFile); !os.IsNotExist(err) {
131 if data, err := ioutil.ReadFile(mkFile); err == nil {
132 matches := buf.Len() == len(data)
133
134 if matches {
135 for i, value := range buf.Bytes() {
136 if value != data[i] {
137 matches = false
138 break
139 }
140 }
141 }
142
143 if matches {
144 return nil
145 }
146 }
147 }
148
149 return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
150}
151
152func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error {
153 if mod != ctx.PrimaryModule(mod) {
154 // These will be handled by the primary module
155 return nil
156 }
157
158 name := ctx.ModuleName(mod)
159
160 type hostClass struct {
161 host bool
162 class string
163 multilib string
164 }
165
166 type archSrc struct {
167 arch Arch
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700168 src Path
Dan Willemsen218f6562015-07-08 18:13:11 -0700169 extra []string
170 }
171
172 srcs := make(map[hostClass][]archSrc)
173 var modules []hostClass
174
175 ctx.VisitAllModuleVariants(mod, func(m blueprint.Module) {
176 provider, ok := m.(AndroidMkDataProvider)
177 if !ok {
178 return
179 }
180
181 amod := m.(AndroidModule).base()
182 data := provider.AndroidMk()
183
184 arch := amod.commonProperties.CompileArch
185
186 prefix := ""
187 if amod.HostOrDevice() == Host {
188 if arch.ArchType != ctx.Config().(Config).HostArches[amod.HostType()][0].ArchType {
189 prefix = "2ND_"
190 }
191 } else {
192 if arch.ArchType != ctx.Config().(Config).DeviceArches[0].ArchType {
193 prefix = "2ND_"
194 }
195 }
196
197 if data.Custom != nil {
198 data.Custom(w, name, prefix)
199 return
200 }
201
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700202 if !data.OutputFile.Valid() {
203 return
204 }
205
Dan Willemsen218f6562015-07-08 18:13:11 -0700206 hC := hostClass{
207 host: amod.HostOrDevice() == Host,
208 class: data.Class,
209 multilib: amod.commonProperties.Compile_multilib,
210 }
211
212 src := archSrc{
213 arch: arch,
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700214 src: data.OutputFile.Path(),
Dan Willemsen218f6562015-07-08 18:13:11 -0700215 }
216
217 if data.Extra != nil {
218 src.extra = data.Extra(name, prefix, src.src, arch)
219 }
220
221 if srcs[hC] == nil {
222 modules = append(modules, hC)
223 }
224 srcs[hC] = append(srcs[hC], src)
225 })
226
227 for _, hC := range modules {
228 archSrcs := srcs[hC]
229
230 io.WriteString(w, "\ninclude $(CLEAR_VARS)\n")
231 io.WriteString(w, "LOCAL_MODULE := "+name+"\n")
232 io.WriteString(w, "LOCAL_MODULE_CLASS := "+hC.class+"\n")
233 io.WriteString(w, "LOCAL_MULTILIB := "+hC.multilib+"\n")
234
235 printed := make(map[string]bool)
236 for _, src := range archSrcs {
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700237 io.WriteString(w, "LOCAL_SRC_FILES_"+src.arch.ArchType.String()+" := "+src.src.String()+"\n")
Dan Willemsen218f6562015-07-08 18:13:11 -0700238
239 for _, extra := range src.extra {
240 if !printed[extra] {
241 printed[extra] = true
242 io.WriteString(w, extra+"\n")
243 }
244 }
245 }
246
247 if hC.host {
248 // TODO: this isn't true for every module
249 io.WriteString(w, "LOCAL_ACP_UNAVAILABLE := true\n")
250
251 io.WriteString(w, "LOCAL_IS_HOST_MODULE := true\n")
252 }
253 io.WriteString(w, "include $(BUILD_PREBUILT)\n")
254 }
255
256 return nil
257}