// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hal2vts
import (
"path/filepath"
"sort"
"strings"
"sync"
"android/soong/android"
"android/soong/genrule"
"github.com/google/blueprint"
)
func init() {
android.RegisterModuleType("hal2vts", hal2vtsFactory)
}
var (
pctx = android.NewPackageContext("android/soong/hal2vts")
hidlGen = pctx.HostBinToolVariable("hidlGen", "hidl-gen")
hidlGenCmd = "${hidlGen} -o ${genDir} -L vts ${args} " +
"${pckg}@${ver}::${halFile}"
hal2vtsRule = pctx.StaticRule("hal2vtsRule", blueprint.RuleParams{
Command: hidlGenCmd,
CommandDeps: []string{"${hidlGen}"},
Description: "hidl-gen -l vts $in => $out",
}, "genDir", "args", "pckg", "ver", "halFile")
)
type hal2vtsProperties struct {
Hidl_gen_args string
Srcs []string
Out []string
}
type hal2vts struct {
android.ModuleBase
properties hal2vtsProperties
exportedHeaderDirs android.Paths
generatedHeaders android.Paths
}
var _ genrule.SourceFileGenerator = (*hal2vts)(nil)
func (h *hal2vts) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Sort by name to match .hal to .vts file name.
sort.Strings(h.properties.Out)
srcFiles := ctx.ExpandSources(h.properties.Srcs, nil)
sort.SliceStable(srcFiles, func(i, j int) bool {
return strings.Compare(srcFiles[j].String(), srcFiles[i].String()) == 1
})
if len(srcFiles) != len(h.properties.Out) {
ctx.ModuleErrorf("Number of inputs must be equal to number of outputs.")
}
args := h.properties.Hidl_gen_args
genDir := android.PathForModuleGen(ctx, "").String()
vtsList := vtsList(ctx.AConfig())
vtsListMutex.Lock()
defer vtsListMutex.Unlock()
for i, src := range srcFiles {
out := android.PathForModuleGen(ctx, h.properties.Out[i])
if src.Ext() != ".hal" {
ctx.ModuleErrorf("Source file has to be a .hal file.")
}
relOut, err := filepath.Rel(genDir, out.String())
if err != nil {
ctx.ModuleErrorf("Cannot get relative output path.")
}
halDir := filepath.Dir(relOut)
halFile := strings.TrimSuffix(src.Base(), ".hal")
ver := filepath.Base(halDir)
// Need this to transform directory path to hal name.
// For example, audio/effect -> audio.effect
pckg := strings.Replace(filepath.Dir(halDir), "/", ".", -1)
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: hal2vtsRule,
Input: src,
Output: out,
Args: map[string]string{
"genDir": genDir,
"args": args,
"pckg": pckg,
"ver": ver,
"halFile": halFile,
},
})
h.generatedHeaders = append(h.generatedHeaders, out)
*vtsList = append(*vtsList, out)
}
h.exportedHeaderDirs = append(h.exportedHeaderDirs, android.PathForModuleGen(ctx, ""))
}
func (h *hal2vts) DepsMutator(ctx android.BottomUpMutatorContext) {
android.ExtractSourcesDeps(ctx, h.properties.Srcs)
}
func (h *hal2vts) GeneratedHeaderDirs() android.Paths {
return h.exportedHeaderDirs
}
func (h *hal2vts) GeneratedSourceFiles() android.Paths {
return nil
}
func (h *hal2vts) GeneratedDeps() android.Paths {
return h.generatedHeaders
}
func hal2vtsFactory() android.Module {
h := &hal2vts{}
h.AddProperties(&h.properties)
android.InitAndroidModule(h)
return h
}
func vtsList(config android.Config) *android.Paths {
return config.Once("vtsList", func() interface{} {
return &android.Paths{}
}).(*android.Paths)
}
var vtsListMutex sync.Mutex
func init() {
android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
}
func makeVarsProvider(ctx android.MakeVarsContext) {
vtsList := vtsList(ctx.Config()).Strings()
sort.Strings(vtsList)
ctx.Strict("VTS_SPEC_FILE_LIST", strings.Join(vtsList, " "))
}