@@ -1203,6 +1203,107 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> {
1203
1203
None
1204
1204
}
1205
1205
1206
+ /// For tests using the `needs-llvm-zstd` directive:
1207
+ /// - for local LLVM builds, try to find the static zstd library in the llvm-config system libs.
1208
+ /// - for `download-ci-llvm`, see if `lld` was built with zstd support.
1209
+ pub fn llvm_has_libzstd ( config : & Config ) -> bool {
1210
+ // Strategy 1: works for local builds but not with `download-ci-llvm`.
1211
+ //
1212
+ // We check whether `llvm-config` returns the zstd library. Bootstrap's `llvm.libzstd` will only
1213
+ // ask to statically link it when building LLVM, so we only check if the list of system libs
1214
+ // contains a path to that static lib, and that it exists.
1215
+ //
1216
+ // See compiler/rustc_llvm/build.rs for more details and similar expectations.
1217
+ fn is_zstd_in_config ( llvm_bin_dir : & Path ) -> Option < ( ) > {
1218
+ let llvm_config_path = llvm_bin_dir. join ( "llvm-config" ) ;
1219
+ let output = Command :: new ( llvm_config_path) . arg ( "--system-libs" ) . output ( ) . ok ( ) ?;
1220
+ assert ! ( output. status. success( ) , "running llvm-config --system-libs failed" ) ;
1221
+
1222
+ let libs = String :: from_utf8 ( output. stdout ) . ok ( ) ?;
1223
+ for lib in libs. split_whitespace ( ) {
1224
+ if lib. ends_with ( "libzstd.a" ) && Path :: new ( lib) . exists ( ) {
1225
+ return Some ( ( ) ) ;
1226
+ }
1227
+ }
1228
+
1229
+ None
1230
+ }
1231
+
1232
+ // Strategy 2: `download-ci-llvm`'s `llvm-config --system-libs` will not return any libs to
1233
+ // use.
1234
+ //
1235
+ // The CI artifacts also don't contain the bootstrap config used to build them: otherwise we
1236
+ // could have looked at the `llvm.libzstd` config.
1237
+ //
1238
+ // We infer whether `LLVM_ENABLE_ZSTD` was used to build LLVM as a byproduct of testing whether
1239
+ // `lld` supports it. If not, an error will be emitted: "LLVM was not built with
1240
+ // LLVM_ENABLE_ZSTD or did not find zstd at build time".
1241
+ #[ cfg( unix) ]
1242
+ fn is_lld_built_with_zstd ( llvm_bin_dir : & Path ) -> Option < ( ) > {
1243
+ let lld_path = llvm_bin_dir. join ( "lld" ) ;
1244
+ if lld_path. exists ( ) {
1245
+ // We can't call `lld` as-is, it expects to be invoked by a compiler driver using a
1246
+ // different name. Prepare a temporary symlink to do that.
1247
+ let lld_symlink_path = llvm_bin_dir. join ( "ld.lld" ) ;
1248
+ if !lld_symlink_path. exists ( ) {
1249
+ std:: os:: unix:: fs:: symlink ( lld_path, & lld_symlink_path) . ok ( ) ?;
1250
+ }
1251
+
1252
+ // Run `lld` with a zstd flag. We expect this command to always error here, we don't
1253
+ // want to link actual files and don't pass any.
1254
+ let output = Command :: new ( & lld_symlink_path)
1255
+ . arg ( "--compress-debug-sections=zstd" )
1256
+ . output ( )
1257
+ . ok ( ) ?;
1258
+ assert ! ( !output. status. success( ) ) ;
1259
+
1260
+ // Look for a specific error caused by LLVM not being built with zstd support. We could
1261
+ // also look for the "no input files" message, indicating the zstd flag was accepted.
1262
+ let stderr = String :: from_utf8 ( output. stderr ) . ok ( ) ?;
1263
+ let zstd_available = !stderr. contains ( "LLVM was not built with LLVM_ENABLE_ZSTD" ) ;
1264
+
1265
+ // We don't particularly need to clean the link up (so the previous commands could fail
1266
+ // in theory but won't in practice), but we can try.
1267
+ std:: fs:: remove_file ( lld_symlink_path) . ok ( ) ?;
1268
+
1269
+ if zstd_available {
1270
+ return Some ( ( ) ) ;
1271
+ }
1272
+ }
1273
+
1274
+ None
1275
+ }
1276
+
1277
+ #[ cfg( not( unix) ) ]
1278
+ fn is_lld_built_with_zstd ( llvm_bin_dir : & Path ) -> Option < ( ) > {
1279
+ None
1280
+ }
1281
+
1282
+ if let Some ( llvm_bin_dir) = & config. llvm_bin_dir {
1283
+ // Strategy 1: for local LLVM builds.
1284
+ if is_zstd_in_config ( llvm_bin_dir) . is_some ( ) {
1285
+ return true ;
1286
+ }
1287
+
1288
+ // Strategy 2: for LLVM artifacts built on CI via `download-ci-llvm`.
1289
+ //
1290
+ // It doesn't work for cases where the artifacts don't contain the linker, but it's
1291
+ // best-effort: CI has `llvm.libzstd` and `lld` enabled on the x64 linux artifacts, so it
1292
+ // will at least work there.
1293
+ //
1294
+ // If this can be improved and expanded to less common cases in the future, it should.
1295
+ if config. target == "x86_64-unknown-linux-gnu"
1296
+ && config. host == config. target
1297
+ && is_lld_built_with_zstd ( llvm_bin_dir) . is_some ( )
1298
+ {
1299
+ return true ;
1300
+ }
1301
+ }
1302
+
1303
+ // Otherwise, all hope is lost.
1304
+ false
1305
+ }
1306
+
1206
1307
/// Takes a directive of the form "<version1> [- <version2>]",
1207
1308
/// returns the numeric representation of <version1> and <version2> as
1208
1309
/// tuple: (<version1> as u32, <version2> as u32)
0 commit comments