1// Copyright 2020 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 cc
16
17import (
18	"path/filepath"
19
20	"android/soong/android"
21
22	"github.com/google/blueprint"
23	"github.com/google/blueprint/proptools"
24)
25
26func init() {
27	android.RegisterSdkMemberType(ccBinarySdkMemberType)
28}
29
30var ccBinarySdkMemberType = &binarySdkMemberType{
31	SdkMemberTypeBase: android.SdkMemberTypeBase{
32		PropertyName:    "native_binaries",
33		HostOsDependent: true,
34	},
35}
36
37type binarySdkMemberType struct {
38	android.SdkMemberTypeBase
39}
40
41func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
42	targets := mctx.MultiTargets()
43	for _, bin := range names {
44		for _, target := range targets {
45			variations := target.Variations()
46			if mctx.Device() {
47				variations = append(variations,
48					blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
49			}
50			mctx.AddFarVariationDependencies(variations, dependencyTag, bin)
51		}
52	}
53}
54
55func (mt *binarySdkMemberType) IsInstance(module android.Module) bool {
56	// Check the module to see if it can be used with this module type.
57	if m, ok := module.(*Module); ok {
58		for _, allowableMemberType := range m.sdkMemberTypes {
59			if allowableMemberType == mt {
60				return true
61			}
62		}
63	}
64
65	return false
66}
67
68func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
69	pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
70
71	ccModule := member.Variants()[0].(*Module)
72
73	if stl := ccModule.stl.Properties.Stl; stl != nil {
74		pbm.AddProperty("stl", proptools.String(stl))
75	}
76
77	return pbm
78}
79
80func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
81	return &nativeBinaryInfoProperties{}
82}
83
84const (
85	nativeBinaryDir = "bin"
86)
87
88// path to the native binary. Relative to <sdk_root>/<api_dir>
89func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
90	return filepath.Join(lib.OsPrefix(), lib.archType,
91		nativeBinaryDir, lib.outputFile.Base())
92}
93
94// nativeBinaryInfoProperties represents properties of a native binary
95//
96// The exported (capitalized) fields will be examined and may be changed during common value extraction.
97// The unexported fields will be left untouched.
98type nativeBinaryInfoProperties struct {
99	android.SdkMemberPropertiesBase
100
101	// archType is not exported as if set (to a non default value) it is always arch specific.
102	// This is "" for common properties.
103	archType string
104
105	// outputFile is not exported as it is always arch specific.
106	outputFile android.Path
107
108	// The set of shared libraries
109	//
110	// This field is exported as its contents may not be arch specific.
111	SharedLibs []string
112
113	// The set of system shared libraries
114	//
115	// This field is exported as its contents may not be arch specific.
116	SystemSharedLibs []string
117
118	// Arch specific flags.
119	StaticExecutable bool
120	Nocrt            bool
121}
122
123func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
124	ccModule := variant.(*Module)
125
126	p.archType = ccModule.Target().Arch.ArchType.String()
127	p.outputFile = getRequiredMemberOutputFile(ctx, ccModule)
128
129	binaryLinker := ccModule.linker.(*binaryDecorator)
130	p.StaticExecutable = binaryLinker.static()
131	p.Nocrt = Bool(binaryLinker.baseLinker.Properties.Nocrt)
132
133	if ccModule.linker != nil {
134		specifiedDeps := specifiedDeps{}
135		specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
136
137		p.SharedLibs = specifiedDeps.sharedLibs
138		p.SystemSharedLibs = specifiedDeps.systemSharedLibs
139	}
140}
141
142func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
143	builder := ctx.SnapshotBuilder()
144	if p.outputFile != nil {
145		propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
146
147		builder.CopyToSnapshot(p.outputFile, nativeBinaryPathFor(*p))
148	}
149
150	if len(p.SharedLibs) > 0 {
151		propertySet.AddPropertyWithTag("shared_libs", p.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
152	}
153
154	// SystemSharedLibs needs to be propagated if it's a list, even if it's empty,
155	// so check for non-nil instead of nonzero length.
156	if p.SystemSharedLibs != nil {
157		propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
158	}
159
160	if p.StaticExecutable {
161		propertySet.AddProperty("static_executable", p.StaticExecutable)
162	}
163	if p.Nocrt {
164		propertySet.AddProperty("nocrt", p.Nocrt)
165	}
166}
167