1// 2// Copyright (C) 2021 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17package rustprebuilts 18 19import ( 20 "path" 21 "path/filepath" 22 "strings" 23 24 "github.com/google/blueprint/proptools" 25 26 "android/soong/android" 27 "android/soong/rust" 28 "android/soong/rust/config" 29) 30 31// This module is used to generate the rust host stdlib prebuilts 32// When RUST_PREBUILTS_VERSION is set, the library will generated 33// from the given Rust version. 34func init() { 35 android.RegisterModuleType("rust_stdlib_prebuilt_host", 36 rustHostPrebuiltSysrootLibraryFactory) 37 android.RegisterModuleType("rust_stdlib_prebuilt_filegroup_host", 38 rustToolchainFilegroupFactory) 39} 40 41func getRustPrebuiltVersion(ctx android.LoadHookContext) string { 42 return ctx.Config().GetenvWithDefault("RUST_PREBUILTS_VERSION", config.RustDefaultVersion) 43} 44 45func getRustLibDir(ctx android.LoadHookContext) string { 46 rustDir := getRustPrebuiltVersion(ctx) 47 return path.Join(rustDir, "lib", "rustlib") 48} 49 50// getPrebuilt returns the module relative Rust library path and the suffix hash. 51func getPrebuilt(ctx android.LoadHookContext, dir, lib, extension string) (string, string) { 52 globPath := path.Join(ctx.ModuleDir(), dir, lib) + "-*" + extension 53 libMatches := ctx.Glob(globPath, nil) 54 55 if len(libMatches) != 1 { 56 ctx.ModuleErrorf("Unexpected number of matches for prebuilt libraries at path %q, found %d matches", globPath, len(libMatches)) 57 return "", "" 58 } 59 60 // Collect the suffix by trimming the extension from the Base, then removing the library name and hyphen. 61 suffix := strings.TrimSuffix(libMatches[0].Base(), extension)[len(lib)+1:] 62 63 // Get the relative path from the match by trimming out the module directory. 64 relPath := strings.TrimPrefix(libMatches[0].String(), ctx.ModuleDir()+"/") 65 66 return relPath, suffix 67} 68 69type targetProps struct { 70 Suffix *string 71 Dylib struct { 72 Srcs []string 73 } 74 Rlib struct { 75 Srcs []string 76 } 77 Link_dirs []string 78 Enabled *bool 79} 80 81type props struct { 82 Enabled *bool 83 Target struct { 84 Linux_glibc_x86_64 targetProps 85 Linux_glibc_x86 targetProps 86 Linux_musl_x86_64 targetProps 87 Linux_musl_x86 targetProps 88 Darwin_x86_64 targetProps 89 } 90} 91 92func (target *targetProps) addPrebuiltToTarget(ctx android.LoadHookContext, libName, rustDir, platform, arch string, rlib, solib bool) { 93 dir := path.Join(platform, rustDir, arch, "lib") 94 target.Link_dirs = []string{dir} 95 target.Enabled = proptools.BoolPtr(true) 96 if rlib { 97 rlib, suffix := getPrebuilt(ctx, dir, libName, ".rlib") 98 target.Rlib.Srcs = []string{rlib} 99 target.Suffix = proptools.StringPtr(suffix) 100 } 101 if solib { 102 // The suffixes are the same between the dylib and the rlib, 103 // so it's okay if we overwrite the rlib suffix 104 var soSuffix string 105 if strings.Contains(platform, "darwin") { 106 soSuffix = ".dylib" 107 } else { 108 soSuffix = ".so" 109 } 110 dylib, suffix := getPrebuilt(ctx, dir, libName, soSuffix) 111 target.Dylib.Srcs = []string{dylib} 112 target.Suffix = proptools.StringPtr(suffix) 113 } 114} 115 116func constructLibProps(rlib, solib bool) func(ctx android.LoadHookContext) { 117 return func(ctx android.LoadHookContext) { 118 rustDir := getRustLibDir(ctx) 119 name := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()) 120 name = strings.Replace(name, ".rust_sysroot", "", -1) 121 122 p := props{} 123 p.Enabled = proptools.BoolPtr(false) 124 125 if ctx.Config().BuildOS == android.Linux { 126 p.Target.Linux_glibc_x86_64.addPrebuiltToTarget(ctx, name, rustDir, "linux-x86", "x86_64-unknown-linux-gnu", rlib, solib) 127 p.Target.Linux_glibc_x86.addPrebuiltToTarget(ctx, name, rustDir, "linux-x86", "i686-unknown-linux-gnu", rlib, solib) 128 } else if ctx.Config().BuildOS == android.LinuxMusl { 129 p.Target.Linux_musl_x86_64.addPrebuiltToTarget(ctx, name, rustDir, "linux-musl-x86", "x86_64-unknown-linux-musl", rlib, solib) 130 p.Target.Linux_musl_x86.addPrebuiltToTarget(ctx, name, rustDir, "linux-musl-x86", "i686-unknown-linux-musl", rlib, solib) 131 } else if ctx.Config().BuildOS == android.Darwin { 132 p.Target.Darwin_x86_64.addPrebuiltToTarget(ctx, name, rustDir, "darwin-x86", "x86_64-apple-darwin", rlib, solib) 133 } 134 135 ctx.AppendProperties(&p) 136 } 137} 138 139func rustHostPrebuiltSysrootLibraryFactory() android.Module { 140 module, _ := rust.NewPrebuiltLibrary(android.HostSupportedNoCross) 141 android.AddLoadHook(module, constructLibProps( /*rlib=*/ true /*solib=*/, true)) 142 return module.Init() 143} 144 145type toolchainFilegroupProperties struct { 146 // path to toolchain files, relative to the top of the toolchain source 147 Toolchain_srcs []string 148} 149 150func rustToolchainFilegroupFactory() android.Module { 151 module := android.FileGroupFactory() 152 module.AddProperties(&toolchainFilegroupProperties{}) 153 android.AddLoadHook(module, func(ctx android.LoadHookContext) { 154 var toolchainProps *toolchainFilegroupProperties 155 for _, p := range ctx.Module().GetProperties() { 156 toolchainProperties, ok := p.(*toolchainFilegroupProperties) 157 if ok { 158 toolchainProps = toolchainProperties 159 } 160 } 161 162 var archTriple string 163 if ctx.Config().BuildOS == android.Linux { 164 if ctx.Config().BuildArch == android.X86_64 { 165 archTriple = "x86_64-unknown-linux-gnu" 166 } else { 167 archTriple = "i686-unknown-linux-gnu" 168 } 169 } else if ctx.Config().BuildOS == android.LinuxMusl { 170 if ctx.Config().BuildArch == android.X86_64 { 171 archTriple = "x86_64-unknown-linux-musl" 172 } else { 173 archTriple = "i686-unknown-linux-musl" 174 } 175 176 } else if ctx.Config().BuildOS == android.Darwin { 177 if ctx.Config().BuildArch == android.X86_64 { 178 archTriple = "x86_64-apple-darwin" 179 } 180 } 181 182 prefix := filepath.Join(config.HostPrebuiltTag(ctx.Config()), rust.GetRustPrebuiltVersion(ctx), "lib", "rustlib", archTriple) 183 srcs := make([]string, 0, len(toolchainProps.Toolchain_srcs)) 184 for _, s := range toolchainProps.Toolchain_srcs { 185 srcs = append(srcs, path.Join(prefix, s)) 186 } 187 188 props := struct { 189 Srcs []string 190 }{ 191 Srcs: srcs, 192 } 193 ctx.AppendProperties(&props) 194 }) 195 return module 196} 197