blob: 707de4b912b9a2626e0f10f1f2f74b86a4473a16 [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 {
Ivan Lozanode252912019-09-06 15:29:52 -0700167 Linux_bionic struct {
168 Enabled *bool
169 }
170 }
171 }{}
Ivan Lozanode252912019-09-06 15:29:52 -0700172 disableTargets.Target.Linux_bionic.Enabled = proptools.BoolPtr(false)
173
174 ctx.AppendProperties(&disableTargets)
175 })
176
Ivan Lozanoffee3342019-08-27 12:03:00 -0700177 return mod
178}
179
180func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
181 return &Module{
182 hod: hod,
183 multilib: multilib,
184 }
185}
186func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
187 module := newBaseModule(hod, multilib)
188 return module
189}
190
191type ModuleContext interface {
192 android.ModuleContext
193 ModuleContextIntf
194}
195
196type BaseModuleContext interface {
197 android.BaseModuleContext
198 ModuleContextIntf
199}
200
201type DepsContext interface {
202 android.BottomUpMutatorContext
203 ModuleContextIntf
204}
205
206type ModuleContextIntf interface {
207 toolchain() config.Toolchain
208 baseModuleName() string
209 CrateName() string
210}
211
212type depsContext struct {
213 android.BottomUpMutatorContext
214 moduleContextImpl
215}
216
217type moduleContext struct {
218 android.ModuleContext
219 moduleContextImpl
220}
221
222type moduleContextImpl struct {
223 mod *Module
224 ctx BaseModuleContext
225}
226
227func (ctx *moduleContextImpl) toolchain() config.Toolchain {
228 return ctx.mod.toolchain(ctx.ctx)
229}
230
231func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
232 if mod.cachedToolchain == nil {
233 mod.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
234 }
235 return mod.cachedToolchain
236}
237
238func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
239}
240
241func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
242 ctx := &moduleContext{
243 ModuleContext: actx,
244 moduleContextImpl: moduleContextImpl{
245 mod: mod,
246 },
247 }
248 ctx.ctx = ctx
249
250 toolchain := mod.toolchain(ctx)
251
252 if !toolchain.Supported() {
253 // This toolchain's unsupported, there's nothing to do for this mod.
254 return
255 }
256
257 deps := mod.depsToPaths(ctx)
258 flags := Flags{
259 Toolchain: toolchain,
260 }
261
262 if mod.compiler != nil {
263 flags = mod.compiler.compilerFlags(ctx, flags)
264 outputFile := mod.compiler.compile(ctx, flags, deps)
265 mod.outputFile = android.OptionalPathForPath(outputFile)
266 mod.compiler.install(ctx, mod.outputFile.Path())
267 }
268}
269
270func (mod *Module) deps(ctx DepsContext) Deps {
271 deps := Deps{}
272
273 if mod.compiler != nil {
274 deps = mod.compiler.compilerDeps(ctx, deps)
275 }
276
277 deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
278 deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
279 deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
280 deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
281 deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
282
283 return deps
284
285}
286
287func (ctx *moduleContextImpl) baseModuleName() string {
288 return ctx.mod.ModuleBase.BaseModuleName()
289}
290
291func (ctx *moduleContextImpl) CrateName() string {
292 return ctx.mod.CrateName()
293}
294
295type dependencyTag struct {
296 blueprint.BaseDependencyTag
297 name string
298 library bool
299 proc_macro bool
300}
301
302var (
303 rlibDepTag = dependencyTag{name: "rlibTag", library: true}
304 dylibDepTag = dependencyTag{name: "dylib", library: true}
305 procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true}
306)
307
308func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
309 var depPaths PathDeps
310
311 directRlibDeps := []*Module{}
312 directDylibDeps := []*Module{}
313 directProcMacroDeps := []*Module{}
314 directSharedLibDeps := []*(cc.Module){}
315 directStaticLibDeps := []*(cc.Module){}
316
317 ctx.VisitDirectDeps(func(dep android.Module) {
318 depName := ctx.OtherModuleName(dep)
319 depTag := ctx.OtherModuleDependencyTag(dep)
Ivan Lozanoffee3342019-08-27 12:03:00 -0700320
321 if rustDep, ok := dep.(*Module); ok {
322 //Handle Rust Modules
Ivan Lozano70e0a072019-09-13 14:23:15 -0700323
Ivan Lozanoffee3342019-08-27 12:03:00 -0700324 linkFile := rustDep.outputFile
325 if !linkFile.Valid() {
326 ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
327 }
328
329 switch depTag {
330 case dylibDepTag:
331 dylib, ok := rustDep.compiler.(libraryInterface)
332 if !ok || !dylib.dylib() {
333 ctx.ModuleErrorf("mod %q not an dylib library", depName)
334 return
335 }
336 directDylibDeps = append(directDylibDeps, rustDep)
337 mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName)
338 case rlibDepTag:
339 rlib, ok := rustDep.compiler.(libraryInterface)
340 if !ok || !rlib.rlib() {
341 ctx.ModuleErrorf("mod %q not an rlib library", depName)
342 return
343 }
344 directRlibDeps = append(directRlibDeps, rustDep)
345 mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
346 case procMacroDepTag:
347 directProcMacroDeps = append(directProcMacroDeps, rustDep)
348 mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
349 }
350
351 //Append the dependencies exportedDirs
352 if lib, ok := rustDep.compiler.(*libraryDecorator); ok {
353 depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedDirs()...)
354 depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...)
Ivan Lozanoffee3342019-08-27 12:03:00 -0700355 }
356
357 // Append this dependencies output to this mod's linkDirs so they can be exported to dependencies
358 // This can be probably be refactored by defining a common exporter interface similar to cc's
359 if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
360 linkDir := linkPathFromFilePath(linkFile.Path())
361 if lib, ok := mod.compiler.(*libraryDecorator); ok {
362 lib.linkDirs = append(lib.linkDirs, linkDir)
363 } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok {
364 procMacro.linkDirs = append(procMacro.linkDirs, linkDir)
365 }
366 }
367
368 } else if ccDep, ok := dep.(*cc.Module); ok {
Ivan Lozanoffee3342019-08-27 12:03:00 -0700369 //Handle C dependencies
Ivan Lozano70e0a072019-09-13 14:23:15 -0700370
371 if ccDep.Target().Os != ctx.Os() {
372 ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
373 return
374 }
375 if ccDep.Target().Arch.ArchType != ctx.Arch().ArchType {
376 ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
377 return
378 }
379
Ivan Lozanoffee3342019-08-27 12:03:00 -0700380 linkFile := ccDep.OutputFile()
381 linkPath := linkPathFromFilePath(linkFile.Path())
382 libName := libNameFromFilePath(linkFile.Path())
383 if !linkFile.Valid() {
384 ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
385 }
386
387 exportDep := false
388
389 switch depTag {
390 case cc.StaticDepTag():
391 depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
392 depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
393 directStaticLibDeps = append(directStaticLibDeps, ccDep)
394 mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
395 case cc.SharedDepTag():
396 depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
397 depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
398 directSharedLibDeps = append(directSharedLibDeps, ccDep)
399 mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
400 exportDep = true
Ivan Lozanof1c84332019-09-20 11:00:37 -0700401 case cc.CrtBeginDepTag():
402 depPaths.CrtBegin = linkFile
403 case cc.CrtEndDepTag():
404 depPaths.CrtEnd = linkFile
Ivan Lozanoffee3342019-08-27 12:03:00 -0700405 }
406
407 // Make sure these dependencies are propagated
408 if lib, ok := mod.compiler.(*libraryDecorator); ok && (exportDep || lib.rlib()) {
409 lib.linkDirs = append(lib.linkDirs, linkPath)
410 lib.depFlags = append(lib.depFlags, "-l"+libName)
411 } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
412 procMacro.linkDirs = append(procMacro.linkDirs, linkPath)
413 procMacro.depFlags = append(procMacro.depFlags, "-l"+libName)
414 }
415
416 }
417 })
418
419 var rlibDepFiles RustLibraries
420 for _, dep := range directRlibDeps {
421 rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
422 }
423 var dylibDepFiles RustLibraries
424 for _, dep := range directDylibDeps {
425 dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
426 }
427 var procMacroDepFiles RustLibraries
428 for _, dep := range directProcMacroDeps {
429 procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
430 }
431
432 var staticLibDepFiles android.Paths
433 for _, dep := range directStaticLibDeps {
434 staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
435 }
436
437 var sharedLibDepFiles android.Paths
438 for _, dep := range directSharedLibDeps {
439 sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path())
440 }
441
442 depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
443 depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
444 depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibDepFiles...)
445 depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
446 depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
447
448 // Dedup exported flags from dependencies
449 depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
450 depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
451
452 return depPaths
453}
454
455func linkPathFromFilePath(filepath android.Path) string {
456 return strings.Split(filepath.String(), filepath.Base())[0]
457}
458func libNameFromFilePath(filepath android.Path) string {
459 libName := strings.Split(filepath.Base(), filepath.Ext())[0]
460 if strings.Contains(libName, "lib") {
461 libName = strings.Split(libName, "lib")[1]
462 }
463 return libName
464}
465func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
466 ctx := &depsContext{
467 BottomUpMutatorContext: actx,
468 moduleContextImpl: moduleContextImpl{
469 mod: mod,
470 },
471 }
472 ctx.ctx = ctx
473
474 deps := mod.deps(ctx)
475
476 actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, deps.Rlibs...)
477 actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "dylib"}}, dylibDepTag, deps.Dylibs...)
478
479 ccDepVariations := []blueprint.Variation{}
480 ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "version", Variation: ""})
481 if !mod.Host() {
482 ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "image", Variation: "core"})
483 }
484 actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "shared"}), cc.SharedDepTag(), deps.SharedLibs...)
485 actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "static"}), cc.StaticDepTag(), deps.StaticLibs...)
Ivan Lozano5ca5ef62019-09-23 10:10:40 -0700486
Ivan Lozanof1c84332019-09-20 11:00:37 -0700487 if deps.CrtBegin != "" {
488 actx.AddVariationDependencies(ccDepVariations, cc.CrtBeginDepTag(), deps.CrtBegin)
489 }
490 if deps.CrtEnd != "" {
491 actx.AddVariationDependencies(ccDepVariations, cc.CrtEndDepTag(), deps.CrtEnd)
492 }
493
Ivan Lozano5ca5ef62019-09-23 10:10:40 -0700494 // proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700495 actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
Ivan Lozanoffee3342019-08-27 12:03:00 -0700496}
497
498func (mod *Module) Name() string {
499 name := mod.ModuleBase.Name()
500 if p, ok := mod.compiler.(interface {
501 Name(string) string
502 }); ok {
503 name = p.Name(name)
504 }
505 return name
506}
507
508var Bool = proptools.Bool
509var BoolDefault = proptools.BoolDefault
510var String = proptools.String
511var StringPtr = proptools.StringPtr