@@ -31,12 +31,49 @@ const LICENSES: &[&str] = &[
31
31
// tidy-alphabetical-end
32
32
] ;
33
33
34
+ type ExceptionList = & ' static [ ( & ' static str , & ' static str ) ] ;
35
+
36
+ /// The workspaces to check for licensing and optionally permitted dependencies.
37
+ ///
38
+ /// Each entry consists of a tuple with the following elements:
39
+ ///
40
+ /// * The path to the workspace root Cargo.toml file.
41
+ /// * The list of license exceptions.
42
+ /// * Optionally a tuple of:
43
+ /// * A list of crates for which dependencies need to be explicitly allowed.
44
+ /// * The list of allowed dependencies.
45
+ // FIXME auto detect all cargo workspaces
46
+ pub ( crate ) const WORKSPACES : & [ ( & str , ExceptionList , Option < ( & [ & str ] , & [ & str ] ) > ) ] = & [
47
+ // The root workspace has to be first for check_rustfix to work.
48
+ ( "." , EXCEPTIONS , Some ( ( & [ "rustc-main" ] , PERMITTED_RUSTC_DEPENDENCIES ) ) ) ,
49
+ // Outside of the alphabetical section because rustfmt formats it using multiple lines.
50
+ (
51
+ "compiler/rustc_codegen_cranelift" ,
52
+ EXCEPTIONS_CRANELIFT ,
53
+ Some ( ( & [ "rustc_codegen_cranelift" ] , PERMITTED_CRANELIFT_DEPENDENCIES ) ) ,
54
+ ) ,
55
+ // tidy-alphabetical-start
56
+ //("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), // FIXME uncomment once all deps are vendored
57
+ //("library/backtrace", &[], None), // FIXME uncomment once rust-lang/backtrace#562 has been synced back to the rust repo
58
+ //("library/portable-simd", &[], None), // FIXME uncomment once rust-lang/portable-simd#363 has been synced back to the rust repo
59
+ //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo
60
+ ( "src/bootstrap" , EXCEPTIONS_BOOTSTRAP , None ) ,
61
+ ( "src/ci/docker/host-x86_64/test-various/uefi_qemu_test" , EXCEPTIONS_UEFI_QEMU_TEST , None ) ,
62
+ //("src/etc/test-float-parse", &[], None), // FIXME uncomment once all deps are vendored
63
+ ( "src/tools/cargo" , EXCEPTIONS_CARGO , None ) ,
64
+ //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored
65
+ //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored
66
+ ( "src/tools/rust-analyzer" , EXCEPTIONS_RUST_ANALYZER , None ) ,
67
+ ( "src/tools/x" , & [ ] , None ) ,
68
+ // tidy-alphabetical-end
69
+ ] ;
70
+
34
71
/// These are exceptions to Rust's permissive licensing policy, and
35
72
/// should be considered bugs. Exceptions are only allowed in Rust
36
73
/// tooling. It is _crucial_ that no exception crates be dependencies
37
74
/// of the Rust runtime (std/test).
38
75
#[ rustfmt:: skip]
39
- const EXCEPTIONS : & [ ( & str , & str ) ] = & [
76
+ const EXCEPTIONS : ExceptionList = & [
40
77
// tidy-alphabetical-start
41
78
( "ar_archive_writer" , "Apache-2.0 WITH LLVM-exception" ) , // rustc
42
79
( "colored" , "MPL-2.0" ) , // rustfmt
@@ -49,13 +86,24 @@ const EXCEPTIONS: &[(&str, &str)] = &[
49
86
( "openssl" , "Apache-2.0" ) , // opt-dist
50
87
( "option-ext" , "MPL-2.0" ) , // cargo-miri (via `directories`)
51
88
( "rustc_apfloat" , "Apache-2.0 WITH LLVM-exception" ) , // rustc (license is the same as LLVM uses)
52
- ( "ryu" , "Apache-2.0 OR BSL-1.0" ) , // cargo/... (because of serde)
89
+ ( "ryu" , "Apache-2.0 OR BSL-1.0" ) , // BSL is not acceptble, but we use it under Apache-2.0 // cargo/... (because of serde)
53
90
( "self_cell" , "Apache-2.0" ) , // rustc (fluent translations)
54
91
( "snap" , "BSD-3-Clause" ) , // rustc
55
92
// tidy-alphabetical-end
56
93
] ;
57
94
58
- const EXCEPTIONS_CARGO : & [ ( & str , & str ) ] = & [
95
+ // FIXME uncomment once rust-lang/stdarch#1462 lands
96
+ /*
97
+ const EXCEPTIONS_STDARCH: ExceptionList = &[
98
+ // tidy-alphabetical-start
99
+ ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0
100
+ ("wasmparser", "Apache-2.0 WITH LLVM-exception"),
101
+ ("wasmprinter", "Apache-2.0 WITH LLVM-exception"),
102
+ // tidy-alphabetical-end
103
+ ];
104
+ */
105
+
106
+ const EXCEPTIONS_CARGO : ExceptionList = & [
59
107
// tidy-alphabetical-start
60
108
( "bitmaps" , "MPL-2.0+" ) ,
61
109
( "bytesize" , "Apache-2.0" ) ,
@@ -69,7 +117,7 @@ const EXCEPTIONS_CARGO: &[(&str, &str)] = &[
69
117
( "im-rc" , "MPL-2.0+" ) ,
70
118
( "normalize-line-endings" , "Apache-2.0" ) ,
71
119
( "openssl" , "Apache-2.0" ) ,
72
- ( "ryu" , "Apache-2.0 OR BSL-1.0" ) ,
120
+ ( "ryu" , "Apache-2.0 OR BSL-1.0" ) , // BSL is not acceptble, but we use it under Apache-2.0
73
121
( "sha1_smol" , "BSD-3-Clause" ) ,
74
122
( "similar" , "Apache-2.0" ) ,
75
123
( "sized-chunks" , "MPL-2.0+" ) ,
@@ -78,7 +126,20 @@ const EXCEPTIONS_CARGO: &[(&str, &str)] = &[
78
126
// tidy-alphabetical-end
79
127
] ;
80
128
81
- const EXCEPTIONS_CRANELIFT : & [ ( & str , & str ) ] = & [
129
+ const EXCEPTIONS_RUST_ANALYZER : ExceptionList = & [
130
+ // tidy-alphabetical-start
131
+ ( "anymap" , "BlueOak-1.0.0 OR MIT OR Apache-2.0" ) , // BlueOak is not acceptable, but we use it under MIT OR Apache-2 .0
132
+ ( "dissimilar" , "Apache-2.0" ) ,
133
+ ( "instant" , "BSD-3-Clause" ) ,
134
+ ( "notify" , "CC0-1.0" ) ,
135
+ ( "pulldown-cmark-to-cmark" , "Apache-2.0" ) ,
136
+ ( "ryu" , "Apache-2.0 OR BSL-1.0" ) , // BSL is not acceptble, but we use it under Apache-2.0
137
+ ( "scip" , "Apache-2.0" ) ,
138
+ ( "snap" , "BSD-3-Clause" ) ,
139
+ // tidy-alphabetical-end
140
+ ] ;
141
+
142
+ const EXCEPTIONS_CRANELIFT : ExceptionList = & [
82
143
// tidy-alphabetical-start
83
144
( "cranelift-bforest" , "Apache-2.0 WITH LLVM-exception" ) ,
84
145
( "cranelift-codegen" , "Apache-2.0 WITH LLVM-exception" ) ,
@@ -99,8 +160,22 @@ const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
99
160
// tidy-alphabetical-end
100
161
] ;
101
162
102
- const EXCEPTIONS_BOOTSTRAP : & [ ( & str , & str ) ] = & [
103
- ( "ryu" , "Apache-2.0 OR BSL-1.0" ) , // through serde
163
+ // FIXME uncomment once all deps are vendored
164
+ /*
165
+ const EXCEPTIONS_GCC: ExceptionList = &[
166
+ // tidy-alphabetical-start
167
+ ("gccjit", "GPL-3.0"),
168
+ ("gccjit_sys", "GPL-3.0"),
169
+ // tidy-alphabetical-end
170
+ ];
171
+ */
172
+
173
+ const EXCEPTIONS_BOOTSTRAP : ExceptionList = & [
174
+ ( "ryu" , "Apache-2.0 OR BSL-1.0" ) , // through serde. BSL is not acceptble, but we use it under Apache-2.0
175
+ ] ;
176
+
177
+ const EXCEPTIONS_UEFI_QEMU_TEST : ExceptionList = & [
178
+ ( "r-efi" , "MIT OR Apache-2.0 OR LGPL-2.1-or-later" ) , // LGPL is not acceptible, but we use it under MIT OR Apache-2.0
104
179
] ;
105
180
106
181
/// These are the root crates that are part of the runtime. The licenses for
@@ -185,6 +260,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
185
260
"is-terminal" ,
186
261
"itertools" ,
187
262
"itoa" ,
263
+ "jemalloc-sys" ,
188
264
"jobserver" ,
189
265
"lazy_static" ,
190
266
"libc" ,
@@ -383,65 +459,90 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
383
459
/// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
384
460
/// to the cargo executable.
385
461
pub fn check ( root : & Path , cargo : & Path , bad : & mut bool ) {
386
- let mut cmd = cargo_metadata:: MetadataCommand :: new ( ) ;
387
- cmd. cargo_path ( cargo)
388
- . manifest_path ( root. join ( "Cargo.toml" ) )
389
- . features ( cargo_metadata:: CargoOpt :: AllFeatures ) ;
390
- let metadata = t ! ( cmd. exec( ) ) ;
391
- let runtime_ids = compute_runtime_crates ( & metadata) ;
392
- check_license_exceptions ( & metadata, EXCEPTIONS , runtime_ids, bad) ;
393
- check_permitted_dependencies (
394
- & metadata,
395
- "rustc" ,
396
- PERMITTED_RUSTC_DEPENDENCIES ,
397
- & [ "rustc_driver" , "rustc_codegen_llvm" ] ,
398
- bad,
399
- ) ;
400
-
401
- // Check cargo independently as it has it's own workspace.
402
- let mut cmd = cargo_metadata:: MetadataCommand :: new ( ) ;
403
- cmd. cargo_path ( cargo)
404
- . manifest_path ( root. join ( "src/tools/cargo/Cargo.toml" ) )
405
- . features ( cargo_metadata:: CargoOpt :: AllFeatures ) ;
406
- let cargo_metadata = t ! ( cmd. exec( ) ) ;
407
- let runtime_ids = HashSet :: new ( ) ;
408
- check_license_exceptions ( & cargo_metadata, EXCEPTIONS_CARGO , runtime_ids, bad) ;
409
- check_rustfix ( & metadata, & cargo_metadata, bad) ;
410
-
411
- // Check rustc_codegen_cranelift independently as it has it's own workspace.
412
- let mut cmd = cargo_metadata:: MetadataCommand :: new ( ) ;
413
- cmd. cargo_path ( cargo)
414
- . manifest_path ( root. join ( "compiler/rustc_codegen_cranelift/Cargo.toml" ) )
415
- . features ( cargo_metadata:: CargoOpt :: AllFeatures ) ;
416
- let metadata = t ! ( cmd. exec( ) ) ;
417
- let runtime_ids = HashSet :: new ( ) ;
418
- check_license_exceptions ( & metadata, EXCEPTIONS_CRANELIFT , runtime_ids, bad) ;
419
- check_permitted_dependencies (
420
- & metadata,
421
- "cranelift" ,
422
- PERMITTED_CRANELIFT_DEPENDENCIES ,
423
- & [ "rustc_codegen_cranelift" ] ,
424
- bad,
425
- ) ;
426
-
427
- let mut cmd = cargo_metadata:: MetadataCommand :: new ( ) ;
428
- cmd. cargo_path ( cargo)
429
- . manifest_path ( root. join ( "src/bootstrap/Cargo.toml" ) )
430
- . features ( cargo_metadata:: CargoOpt :: AllFeatures ) ;
431
- let metadata = t ! ( cmd. exec( ) ) ;
432
- let runtime_ids = HashSet :: new ( ) ;
433
- check_license_exceptions ( & metadata, EXCEPTIONS_BOOTSTRAP , runtime_ids, bad) ;
462
+ let mut checked_runtime_licenses = false ;
463
+ let mut rust_metadata = None ;
464
+
465
+ for & ( workspace, exceptions, permitted_deps) in WORKSPACES {
466
+ if !root. join ( workspace) . join ( "Cargo.lock" ) . exists ( ) {
467
+ tidy_error ! ( bad, "the `{workspace}` workspace doesn't have a Cargo.lock" ) ;
468
+ continue ;
469
+ }
470
+
471
+ let mut cmd = cargo_metadata:: MetadataCommand :: new ( ) ;
472
+ cmd. cargo_path ( cargo)
473
+ . manifest_path ( root. join ( workspace) . join ( "Cargo.toml" ) )
474
+ . features ( cargo_metadata:: CargoOpt :: AllFeatures )
475
+ . other_options ( vec ! [ "--locked" . to_owned( ) ] ) ;
476
+ let metadata = t ! ( cmd. exec( ) ) ;
477
+
478
+ check_license_exceptions ( & metadata, exceptions, bad) ;
479
+ if let Some ( ( crates, permitted_deps) ) = permitted_deps {
480
+ check_permitted_dependencies ( & metadata, workspace, permitted_deps, crates, bad) ;
481
+ }
482
+
483
+ if workspace == "." {
484
+ let runtime_ids = compute_runtime_crates ( & metadata) ;
485
+ check_runtime_license_exceptions ( & metadata, runtime_ids, bad) ;
486
+ checked_runtime_licenses = true ;
487
+ rust_metadata = Some ( metadata) ;
488
+ } else if workspace == "src/tools/cargo" {
489
+ check_rustfix (
490
+ rust_metadata
491
+ . as_ref ( )
492
+ . expect ( "The root workspace should be the first to be checked" ) ,
493
+ & metadata,
494
+ bad,
495
+ ) ;
496
+ }
497
+ }
498
+
499
+ // Sanity check to ensure we don't accidentally remove the workspace containing the runtime
500
+ // crates.
501
+ assert ! ( checked_runtime_licenses) ;
434
502
}
435
503
436
- /// Check that all licenses are in the valid list in `LICENSES`.
504
+ /// Check that all licenses of runtime dependencies are in the valid list in `LICENSES`.
437
505
///
438
- /// Packages listed in `exceptions` are allowed for tools.
439
- fn check_license_exceptions (
506
+ /// Unlike for tools we don't allow exceptions to the `LICENSES` list for the runtime with the sole
507
+ /// exception of `fortanix-sgx-abi` which is only used on x86_64-fortanix-unknown-sgx.
508
+ fn check_runtime_license_exceptions (
440
509
metadata : & Metadata ,
441
- exceptions : & [ ( & str , & str ) ] ,
442
510
runtime_ids : HashSet < & PackageId > ,
443
511
bad : & mut bool ,
444
512
) {
513
+ for pkg in & metadata. packages {
514
+ if !runtime_ids. contains ( & pkg. id ) {
515
+ // Only checking dependencies of runtime libraries here.
516
+ continue ;
517
+ }
518
+ if pkg. source . is_none ( ) {
519
+ // No need to check local packages.
520
+ continue ;
521
+ }
522
+ let license = match & pkg. license {
523
+ Some ( license) => license,
524
+ None => {
525
+ tidy_error ! ( bad, "dependency `{}` does not define a license expression" , pkg. id) ;
526
+ continue ;
527
+ }
528
+ } ;
529
+ if !LICENSES . contains ( & license. as_str ( ) ) {
530
+ // This is a specific exception because SGX is considered "third party".
531
+ // See https://github.com/rust-lang/rust/issues/62620 for more.
532
+ // In general, these should never be added and this exception
533
+ // should not be taken as precedent for any new target.
534
+ if pkg. name == "fortanix-sgx-abi" && pkg. license . as_deref ( ) == Some ( "MPL-2.0" ) {
535
+ continue ;
536
+ }
537
+ tidy_error ! ( bad, "invalid license `{}` in `{}`" , license, pkg. id) ;
538
+ }
539
+ }
540
+ }
541
+
542
+ /// Check that all licenses of tool dependencies are in the valid list in `LICENSES`.
543
+ ///
544
+ /// Packages listed in `exceptions` are allowed for tools.
545
+ fn check_license_exceptions ( metadata : & Metadata , exceptions : & [ ( & str , & str ) ] , bad : & mut bool ) {
445
546
// Validate the EXCEPTIONS list hasn't changed.
446
547
for ( name, license) in exceptions {
447
548
// Check that the package actually exists.
@@ -483,7 +584,7 @@ fn check_license_exceptions(
483
584
// No need to check local packages.
484
585
continue ;
485
586
}
486
- if !runtime_ids . contains ( & pkg . id ) && exception_names. contains ( & pkg. name . as_str ( ) ) {
587
+ if exception_names. contains ( & pkg. name . as_str ( ) ) {
487
588
continue ;
488
589
}
489
590
let license = match & pkg. license {
@@ -494,13 +595,6 @@ fn check_license_exceptions(
494
595
}
495
596
} ;
496
597
if !LICENSES . contains ( & license. as_str ( ) ) {
497
- if pkg. name == "fortanix-sgx-abi" {
498
- // This is a specific exception because SGX is considered
499
- // "third party". See
500
- // https://github.com/rust-lang/rust/issues/62620 for more. In
501
- // general, these should never be added.
502
- continue ;
503
- }
504
598
tidy_error ! ( bad, "invalid license `{}` in `{}`" , license, pkg. id) ;
505
599
}
506
600
}
0 commit comments