1// 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/pathtools" 22 23 "android/soong/android" 24 "android/soong/cc" 25) 26 27var ( 28 _ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc") 29 rustc = pctx.AndroidStaticRule("rustc", 30 blueprint.RuleParams{ 31 Command: "$envVars $rustcCmd " + 32 "-C linker=${config.RustLinker} " + 33 "-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " + 34 "--emit link -o $out --emit dep-info=$out.d $in ${libFlags} $rustcFlags", 35 CommandDeps: []string{"$rustcCmd"}, 36 // Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633 37 Deps: blueprint.DepsGCC, 38 Depfile: "$out.d", 39 }, 40 "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars") 41 42 _ = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver") 43 clippyDriver = pctx.AndroidStaticRule("clippy", 44 blueprint.RuleParams{ 45 Command: "$envVars $clippyCmd " + 46 // Because clippy-driver uses rustc as backend, we need to have some output even during the linting. 47 // Use the metadata output as it has the smallest footprint. 48 "--emit metadata -o $out $in ${libFlags} " + 49 "$rustcFlags $clippyFlags", 50 CommandDeps: []string{"$clippyCmd"}, 51 }, 52 "rustcFlags", "libFlags", "clippyFlags", "envVars") 53 54 zip = pctx.AndroidStaticRule("zip", 55 blueprint.RuleParams{ 56 Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp", 57 CommandDeps: []string{"${SoongZipCmd}"}, 58 Rspfile: "$out.rsp", 59 RspfileContent: "$in", 60 }) 61 62 cp = pctx.AndroidStaticRule("cp", 63 blueprint.RuleParams{ 64 Command: "cp `cat $outDir.rsp` $outDir", 65 Rspfile: "${outDir}.rsp", 66 RspfileContent: "$in", 67 }, 68 "outDir") 69) 70 71type buildOutput struct { 72 outputFile android.Path 73 coverageFile android.Path 74} 75 76func init() { 77 pctx.HostBinToolVariable("SoongZipCmd", "soong_zip") 78} 79 80func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, 81 outputFile android.WritablePath, linkDirs []string) buildOutput { 82 flags.RustFlags = append(flags.RustFlags, "-C lto") 83 84 return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", linkDirs) 85} 86 87func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, 88 outputFile android.WritablePath, linkDirs []string) buildOutput { 89 return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", linkDirs) 90} 91 92func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, 93 outputFile android.WritablePath, linkDirs []string) buildOutput { 94 return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", linkDirs) 95} 96 97func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, 98 outputFile android.WritablePath, linkDirs []string) buildOutput { 99 flags.RustFlags = append(flags.RustFlags, "-C lto") 100 return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", linkDirs) 101} 102 103func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, 104 outputFile android.WritablePath, linkDirs []string) buildOutput { 105 flags.RustFlags = append(flags.RustFlags, "-C lto") 106 return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", linkDirs) 107} 108 109func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps, 110 flags Flags, outputFile android.WritablePath, linkDirs []string) buildOutput { 111 return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", linkDirs) 112} 113 114func rustLibsToPaths(libs RustLibraries) android.Paths { 115 var paths android.Paths 116 for _, lib := range libs { 117 paths = append(paths, lib.Path) 118 } 119 return paths 120} 121 122func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags, 123 outputFile android.WritablePath, crate_type string, linkDirs []string) buildOutput { 124 125 var inputs android.Paths 126 var implicits android.Paths 127 var envVars []string 128 var output buildOutput 129 var libFlags, rustcFlags, linkFlags []string 130 var implicitOutputs android.WritablePaths 131 132 output.outputFile = outputFile 133 crate_name := ctx.RustModule().CrateName() 134 targetTriple := ctx.toolchain().RustTriple() 135 136 inputs = append(inputs, main) 137 138 // Collect rustc flags 139 rustcFlags = append(rustcFlags, flags.GlobalRustFlags...) 140 rustcFlags = append(rustcFlags, flags.RustFlags...) 141 rustcFlags = append(rustcFlags, "--crate-type="+crate_type) 142 if crate_name != "" { 143 rustcFlags = append(rustcFlags, "--crate-name="+crate_name) 144 } 145 if targetTriple != "" { 146 rustcFlags = append(rustcFlags, "--target="+targetTriple) 147 linkFlags = append(linkFlags, "-target "+targetTriple) 148 } 149 150 // Suppress an implicit sysroot 151 rustcFlags = append(rustcFlags, "--sysroot=/dev/null") 152 153 // Collect linker flags 154 linkFlags = append(linkFlags, flags.GlobalLinkFlags...) 155 linkFlags = append(linkFlags, flags.LinkFlags...) 156 157 // Collect library/crate flags 158 for _, lib := range deps.RLibs { 159 libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String()) 160 } 161 for _, lib := range deps.DyLibs { 162 libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String()) 163 } 164 for _, proc_macro := range deps.ProcMacros { 165 libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String()) 166 } 167 168 for _, path := range linkDirs { 169 libFlags = append(libFlags, "-L "+path) 170 } 171 172 // Collect dependencies 173 implicits = append(implicits, rustLibsToPaths(deps.RLibs)...) 174 implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...) 175 implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...) 176 implicits = append(implicits, deps.StaticLibs...) 177 implicits = append(implicits, deps.SharedLibs...) 178 179 if deps.CrtBegin.Valid() { 180 implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path()) 181 } 182 183 if flags.Coverage { 184 var gcnoFile android.WritablePath 185 // Provide consistency with cc gcda output, see cc/builder.go init() 186 profileEmitArg := strings.TrimPrefix(cc.PwdPrefix(), "PWD=") + "/" 187 188 if outputFile.Ext() != "" { 189 gcnoFile = android.PathForModuleOut(ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcno")) 190 rustcFlags = append(rustcFlags, "-Z profile-emit="+profileEmitArg+android.PathForModuleOut( 191 ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcda")).String()) 192 } else { 193 gcnoFile = android.PathForModuleOut(ctx, outputFile.Base()+".gcno") 194 rustcFlags = append(rustcFlags, "-Z profile-emit="+profileEmitArg+android.PathForModuleOut( 195 ctx, outputFile.Base()+".gcda").String()) 196 } 197 198 implicitOutputs = append(implicitOutputs, gcnoFile) 199 output.coverageFile = gcnoFile 200 } 201 202 if len(deps.SrcDeps) > 0 { 203 genSubDir := "out/" 204 moduleGenDir := android.PathForModuleOut(ctx, genSubDir) 205 var outputs android.WritablePaths 206 207 for _, genSrc := range deps.SrcDeps { 208 if android.SuffixInList(outputs.Strings(), genSubDir+genSrc.Base()) { 209 ctx.PropertyErrorf("srcs", 210 "multiple source providers generate the same filename output: "+genSrc.Base()) 211 } 212 outputs = append(outputs, android.PathForModuleOut(ctx, genSubDir+genSrc.Base())) 213 } 214 215 ctx.Build(pctx, android.BuildParams{ 216 Rule: cp, 217 Description: "cp " + moduleGenDir.Rel(), 218 Outputs: outputs, 219 Inputs: deps.SrcDeps, 220 Args: map[string]string{ 221 "outDir": moduleGenDir.String(), 222 }, 223 }) 224 implicits = append(implicits, outputs.Paths()...) 225 envVars = append(envVars, "OUT_DIR=$$PWD/"+moduleGenDir.String()) 226 } 227 228 if flags.Clippy { 229 clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy") 230 ctx.Build(pctx, android.BuildParams{ 231 Rule: clippyDriver, 232 Description: "clippy " + main.Rel(), 233 Output: clippyFile, 234 ImplicitOutputs: nil, 235 Inputs: inputs, 236 Implicits: implicits, 237 Args: map[string]string{ 238 "rustcFlags": strings.Join(rustcFlags, " "), 239 "libFlags": strings.Join(libFlags, " "), 240 "clippyFlags": strings.Join(flags.ClippyFlags, " "), 241 "envVars": strings.Join(envVars, " "), 242 }, 243 }) 244 // Declare the clippy build as an implicit dependency of the original crate. 245 implicits = append(implicits, clippyFile) 246 } 247 248 ctx.Build(pctx, android.BuildParams{ 249 Rule: rustc, 250 Description: "rustc " + main.Rel(), 251 Output: outputFile, 252 ImplicitOutputs: implicitOutputs, 253 Inputs: inputs, 254 Implicits: implicits, 255 Args: map[string]string{ 256 "rustcFlags": strings.Join(rustcFlags, " "), 257 "linkFlags": strings.Join(linkFlags, " "), 258 "libFlags": strings.Join(libFlags, " "), 259 "crtBegin": deps.CrtBegin.String(), 260 "crtEnd": deps.CrtEnd.String(), 261 "envVars": strings.Join(envVars, " "), 262 }, 263 }) 264 265 return output 266} 267 268func TransformCoverageFilesToZip(ctx ModuleContext, 269 covFiles android.Paths, baseName string) android.OptionalPath { 270 if len(covFiles) > 0 { 271 272 outputFile := android.PathForModuleOut(ctx, baseName+".zip") 273 274 ctx.Build(pctx, android.BuildParams{ 275 Rule: zip, 276 Description: "zip " + outputFile.Base(), 277 Inputs: covFiles, 278 Output: outputFile, 279 }) 280 281 return android.OptionalPathForPath(outputFile) 282 } 283 return android.OptionalPath{} 284} 285