blob: 4f5e7fb92599a62c755ac2257083417ad41f8a8f [file] [log] [blame]
Ivan Lozanoffee3342019-08-27 12:03:00 -07001// Copyright 2019 The Android Open Source Project
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 rust
16
17import (
18 "strings"
19
20 "github.com/google/blueprint"
21 "github.com/google/blueprint/proptools"
22
23 "android/soong/android"
24 "android/soong/cc"
25 "android/soong/rust/config"
26)
27
28var pctx = android.NewPackageContext("android/soong/rust")
29
30func init() {
31 // Only allow rust modules to be defined for certain projects
Ivan Lozanoffee3342019-08-27 12:03:00 -070032
33 android.AddNeverAllowRules(
34 android.NeverAllow().
Ivan Lozanoe169ad72019-09-18 08:42:54 -070035 NotIn(config.RustAllowedPaths...).
36 ModuleType(config.RustModuleTypes...))
Ivan Lozanoffee3342019-08-27 12:03:00 -070037
38 android.RegisterModuleType("rust_defaults", defaultsFactory)
39 android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
40 ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
41 })
42 pctx.Import("android/soong/rust/config")
43}
44
45type Flags struct {
Ivan Lozanof1c84332019-09-20 11:00:37 -070046 GlobalRustFlags []string // Flags that apply globally to rust
47 GlobalLinkFlags []string // Flags that apply globally to linker
48 RustFlags []string // Flags that apply to rust
49 LinkFlags []string // Flags that apply to linker
50 RustFlagsDeps android.Paths // Files depended on by compiler flags
51 Toolchain config.Toolchain
Ivan Lozanoffee3342019-08-27 12:03:00 -070052}
53
54type BaseProperties struct {
55 AndroidMkRlibs []string
56 AndroidMkDylibs []string
57 AndroidMkProcMacroLibs []string
58 AndroidMkSharedLibs []string
59 AndroidMkStaticLibs []string
60}
61
62type Module struct {
63 android.ModuleBase
64 android.DefaultableModuleBase
65
66 Properties BaseProperties
67
68 hod android.HostOrDeviceSupported
69 multilib android.Multilib
70
71 compiler compiler
72 cachedToolchain config.Toolchain
73 subAndroidMkOnce map[subAndroidMkProvider]bool
74 outputFile android.OptionalPath
75}
76
77type Deps struct {
78 Dylibs []string
79 Rlibs []string
80 ProcMacros []string
81 SharedLibs []string
82 StaticLibs []string
83
84 CrtBegin, CrtEnd string
85}
86
87type PathDeps struct {
88 DyLibs RustLibraries
89 RLibs RustLibraries
90 SharedLibs android.Paths
91 StaticLibs android.Paths
92 ProcMacros RustLibraries
93 linkDirs []string
94 depFlags []string
95 //ReexportedDeps android.Paths
Ivan Lozanof1c84332019-09-20 11:00:37 -070096
97 CrtBegin android.OptionalPath
98 CrtEnd android.OptionalPath
Ivan Lozanoffee3342019-08-27 12:03:00 -070099}
100
101type RustLibraries []RustLibrary
102
103type RustLibrary struct {
104 Path android.Path
105 CrateName string
106}
107
108type compiler interface {
109 compilerFlags(ctx ModuleContext, flags Flags) Flags
110 compilerProps() []interface{}
111 compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path
112 compilerDeps(ctx DepsContext, deps Deps) Deps
113 crateName() string
114
115 install(ctx ModuleContext, path android.Path)
116 relativeInstallPath() string
117}
118
119func defaultsFactory() android.Module {
120 return DefaultsFactory()
121}
122
123type Defaults struct {
124 android.ModuleBase
125 android.DefaultsModuleBase
126}
127
128func DefaultsFactory(props ...interface{}) android.Module {
129 module := &Defaults{}
130
131 module.AddProperties(props...)
132 module.AddProperties(
133 &BaseProperties{},
134 &BaseCompilerProperties{},
135 &BinaryCompilerProperties{},
136 &LibraryCompilerProperties{},
137 &ProcMacroCompilerProperties{},
138 &PrebuiltProperties{},
139 )
140
141 android.InitDefaultsModule(module)
142 return module
143}
144
145func (mod *Module) CrateName() string {
146 if mod.compiler != nil && mod.compiler.crateName() != "" {
147 return mod.compiler.crateName()
148 }
149 // Default crate names replace '-' in the name to '_'
150 return strings.Replace(mod.BaseModuleName(), "-", "_", -1)
151}
152
153func (mod *Module) Init() android.Module {
154 mod.AddProperties(&mod.Properties)
155
156 if mod.compiler != nil {
157 mod.AddProperties(mod.compiler.compilerProps()...)
158 }
159 android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
160
161 android.InitDefaultableModule(mod)
162
Ivan Lozanode252912019-09-06 15:29:52 -0700163 // Explicitly disable unsupported targets.
164 android.AddLoadHook(mod, func(ctx android.LoadHookContext) {
165 disableTargets := struct {
166 Target struct {
167 Darwin struct {
168 Enabled *bool
169 }
170 Linux_bionic struct {
171 Enabled *bool
172 }
173 }
174 }{}
175 disableTargets.Target.Darwin.Enabled = proptools.BoolPtr(false)
176 disableTargets.Target.Linux_bionic.Enabled = proptools.BoolPtr(false)
177
178 ctx.AppendProperties(&disableTargets)
179 })
180
Ivan Lozanoffee3342019-08-27 12:03:00 -0700181 return mod
182}
183
184func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
185 return &Module{
186 hod: hod,
187 multilib: multilib,
188 }
189}
190func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
191 module := newBaseModule(hod, multilib)
192 return module
193}
194
195type ModuleContext interface {
196 android.ModuleContext
197 ModuleContextIntf
198}
199
200type BaseModuleContext interface {
201 android.BaseModuleContext
202 ModuleContextIntf
203}
204
205type DepsContext interface {
206 android.BottomUpMutatorContext
207 ModuleContextIntf
208}
209
210type ModuleContextIntf interface {
211 toolchain() config.Toolchain
212 baseModuleName() string
213 CrateName() string
214}
215
216type depsContext struct {
217 android.BottomUpMutatorContext
218 moduleContextImpl
219}
220
221type moduleContext struct {
222 android.ModuleContext
223 moduleContextImpl
224}
225
226type moduleContextImpl struct {
227 mod *Module
228 ctx BaseModuleContext
229}
230
231func (ctx *moduleContextImpl) toolchain() config.Toolchain {
232 return ctx.mod.toolchain(ctx.ctx)
233}
234
235func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
236 if mod.cachedToolchain == nil {
237 mod.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
238 }
239 return mod.cachedToolchain
240}
241
242func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
243}
244
245func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
246 ctx := &moduleContext{
247 ModuleContext: actx,
248 moduleContextImpl: moduleContextImpl{
249 mod: mod,
250 },
251 }
252 ctx.ctx = ctx
253
254 toolchain := mod.toolchain(ctx)
255
256 if !toolchain.Supported() {
257 // This toolchain's unsupported, there's nothing to do for this mod.
258 return
259 }
260
261 deps := mod.depsToPaths(ctx)
262 flags := Flags{
263 Toolchain: toolchain,
264 }
265
266 if mod.compiler != nil {
267 flags = mod.compiler.compilerFlags(ctx, flags)
268 outputFile := mod.compiler.compile(ctx, flags, deps)
269 mod.outputFile = android.OptionalPathForPath(outputFile)
270 mod.compiler.install(ctx, mod.outputFile.Path())
271 }
272}
273
274func (mod *Module) deps(ctx DepsContext) Deps {
275 deps := Deps{}
276
277 if mod.compiler != nil {
278 deps = mod.compiler.compilerDeps(ctx, deps)
279 }
280
281 deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
282 deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
283 deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
284 deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
285 deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
286
287 return deps
288
289}
290
291func (ctx *moduleContextImpl) baseModuleName() string {
292 return ctx.mod.ModuleBase.BaseModuleName()
293}
294
295func (ctx *moduleContextImpl) CrateName() string {
296 return ctx.mod.CrateName()
297}
298
299type dependencyTag struct {
300 blueprint.BaseDependencyTag
301 name string
302 library bool
303 proc_macro bool
304}
305
306var (
307 rlibDepTag = dependencyTag{name: "rlibTag", library: true}
308 dylibDepTag = dependencyTag{name: "dylib", library: true}
309 procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true}
310)
311
312func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
313 var depPaths PathDeps
314
315 directRlibDeps := []*Module{}
316 directDylibDeps := []*Module{}
317 directProcMacroDeps := []*Module{}
318 directSharedLibDeps := []*(cc.Module){}
319 directStaticLibDeps := []*(cc.Module){}
320
321 ctx.VisitDirectDeps(func(dep android.Module) {
322 depName := ctx.OtherModuleName(dep)
323 depTag := ctx.OtherModuleDependencyTag(dep)
Ivan Lozanoffee3342019-08-27 12:03:00 -0700324
325 if rustDep, ok := dep.(*Module); ok {
326 //Handle Rust Modules
Ivan Lozano70e0a072019-09-13 14:23:15 -0700327
Ivan Lozanoffee3342019-08-27 12:03:00 -0700328 linkFile := rustDep.outputFile
329 if !linkFile.Valid() {
330 ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
331 }
332
333 switch depTag {
334 case dylibDepTag:
335 dylib, ok := rustDep.compiler.(libraryInterface)
336 if !ok || !dylib.dylib() {
337 ctx.ModuleErrorf("mod %q not an dylib library", depName)
338 return
339 }
340 directDylibDeps = append(directDylibDeps, rustDep)
341 mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName)
342 case rlibDepTag:
343 rlib, ok := rustDep.compiler.(libraryInterface)
344 if !ok || !rlib.rlib() {
345 ctx.ModuleErrorf("mod %q not an rlib library", depName)
346 return
347 }
348 directRlibDeps = append(directRlibDeps, rustDep)
349 mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
350 case procMacroDepTag:
351 directProcMacroDeps = append(directProcMacroDeps, rustDep)
352 mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
353 }
354
355 //Append the dependencies exportedDirs
356 if lib, ok := rustDep.compiler.(*libraryDecorator); ok {
357 depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedDirs()...)
358 depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...)
Ivan Lozanoffee3342019-08-27 12:03:00 -0700359 }
360
361 // Append this dependencies output to this mod's linkDirs so they can be exported to dependencies
362 // This can be probably be refactored by defining a common exporter interface similar to cc's
363 if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
364 linkDir := linkPathFromFilePath(linkFile.Path())
365 if lib, ok := mod.compiler.(*libraryDecorator); ok {
366 lib.linkDirs = append(lib.linkDirs, linkDir)
367 } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok {
368 procMacro.linkDirs = append(procMacro.linkDirs, linkDir)
369 }
370 }
371
372 } else if ccDep, ok := dep.(*cc.Module); ok {
Ivan Lozanoffee3342019-08-27 12:03:00 -0700373 //Handle C dependencies
Ivan Lozano70e0a072019-09-13 14:23:15 -0700374
375 if ccDep.Target().Os != ctx.Os() {
376 ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
377 return
378 }
379 if ccDep.Target().Arch.ArchType != ctx.Arch().ArchType {
380 ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
381 return
382 }
383
Ivan Lozanoffee3342019-08-27 12:03:00 -0700384 linkFile := ccDep.OutputFile()
385 linkPath := linkPathFromFilePath(linkFile.Path())
386 libName := libNameFromFilePath(linkFile.Path())
387 if !linkFile.Valid() {
388 ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
389 }
390
391 exportDep := false
392
393 switch depTag {
394 case cc.StaticDepTag():
395 depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
396 depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
397 directStaticLibDeps = append(directStaticLibDeps, ccDep)
398 mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
399 case cc.SharedDepTag():
400 depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
401 depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
402 directSharedLibDeps = append(directSharedLibDeps, ccDep)
403 mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
404 exportDep = true
Ivan Lozanof1c84332019-09-20 11:00:37 -0700405 case cc.CrtBeginDepTag():
406 depPaths.CrtBegin = linkFile
407 case cc.CrtEndDepTag():
408 depPaths.CrtEnd = linkFile
Ivan Lozanoffee3342019-08-27 12:03:00 -0700409 }
410
411 // Make sure these dependencies are propagated
412 if lib, ok := mod.compiler.(*libraryDecorator); ok && (exportDep || lib.rlib()) {
413 lib.linkDirs = append(lib.linkDirs, linkPath)
414 lib.depFlags = append(lib.depFlags, "-l"+libName)
415 } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
416 procMacro.linkDirs = append(procMacro.linkDirs, linkPath)
417 procMacro.depFlags = append(procMacro.depFlags, "-l"+libName)
418 }
419
420 }
421 })
422
423 var rlibDepFiles RustLibraries
424 for _, dep := range directRlibDeps {
425 rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
426 }
427 var dylibDepFiles RustLibraries
428 for _, dep := range directDylibDeps {
429 dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
430 }
431 var procMacroDepFiles RustLibraries
432 for _, dep := range directProcMacroDeps {
433 procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
434 }
435
436 var staticLibDepFiles android.Paths
437 for _, dep := range directStaticLibDeps {
438 staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
439 }
440
441 var sharedLibDepFiles android.Paths
442 for _, dep := range directSharedLibDeps {
443 sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path())
444 }
445
446 depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
447 depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
448 depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibDepFiles...)
449 depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
450 depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
451
452 // Dedup exported flags from dependencies
453 depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
454 depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
455
456 return depPaths
457}
458
459func linkPathFromFilePath(filepath android.Path) string {
460 return strings.Split(filepath.String(), filepath.Base())[0]
461}
462func libNameFromFilePath(filepath android.Path) string {
463 libName := strings.Split(filepath.Base(), filepath.Ext())[0]
464 if strings.Contains(libName, "lib") {
465 libName = strings.Split(libName, "lib")[1]
466 }
467 return libName
468}
469func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
470 ctx := &depsContext{
471 BottomUpMutatorContext: actx,
472 moduleContextImpl: moduleContextImpl{
473 mod: mod,
474 },
475 }
476 ctx.ctx = ctx
477
478 deps := mod.deps(ctx)
479
480 actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, deps.Rlibs...)
481 actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "dylib"}}, dylibDepTag, deps.Dylibs...)
482
483 ccDepVariations := []blueprint.Variation{}
484 ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "version", Variation: ""})
485 if !mod.Host() {
486 ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "image", Variation: "core"})
487 }
488 actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "shared"}), cc.SharedDepTag(), deps.SharedLibs...)
489 actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "static"}), cc.StaticDepTag(), deps.StaticLibs...)
Ivan Lozano5ca5ef62019-09-23 10:10:40 -0700490
Ivan Lozanof1c84332019-09-20 11:00:37 -0700491 if deps.CrtBegin != "" {
492 actx.AddVariationDependencies(ccDepVariations, cc.CrtBeginDepTag(), deps.CrtBegin)
493 }
494 if deps.CrtEnd != "" {
495 actx.AddVariationDependencies(ccDepVariations, cc.CrtEndDepTag(), deps.CrtEnd)
496 }
497
Ivan Lozano5ca5ef62019-09-23 10:10:40 -0700498 // proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700499 actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
Ivan Lozanoffee3342019-08-27 12:03:00 -0700500}
501
502func (mod *Module) Name() string {
503 name := mod.ModuleBase.Name()
504 if p, ok := mod.compiler.(interface {
505 Name(string) string
506 }); ok {
507 name = p.Name(name)
508 }
509 return name
510}
511
512var Bool = proptools.Bool
513var BoolDefault = proptools.BoolDefault
514var String = proptools.String
515var StringPtr = proptools.StringPtr