@@ -25,6 +25,11 @@ use crate::util::restricted_names;
25
25
26
26
use anyhow:: Context as _;
27
27
28
+ const DEFAULT_TEST_DIR_NAME : & ' static str = "tests" ;
29
+ const DEFAULT_BENCH_DIR_NAME : & ' static str = "benches" ;
30
+ const DEFAULT_EXAMPLE_DIR_NAME : & ' static str = "examples" ;
31
+ const DEFAULT_BIN_DIR_NAME : & ' static str = "bin" ;
32
+
28
33
pub fn targets (
29
34
features : & Features ,
30
35
manifest : & TomlManifest ,
@@ -353,7 +358,10 @@ fn clean_bins(
353
358
return Some ( path) ;
354
359
}
355
360
356
- let path = package_root. join ( "src" ) . join ( "bin" ) . join ( "main.rs" ) ;
361
+ let path = package_root
362
+ . join ( "src" )
363
+ . join ( DEFAULT_BIN_DIR_NAME )
364
+ . join ( "main.rs" ) ;
357
365
if path. exists ( ) {
358
366
return Some ( path) ;
359
367
}
@@ -370,7 +378,7 @@ fn clean_examples(
370
378
warnings : & mut Vec < String > ,
371
379
errors : & mut Vec < String > ,
372
380
) -> CargoResult < Vec < Target > > {
373
- let inferred = infer_from_directory ( & package_root. join ( "examples" ) ) ;
381
+ let inferred = infer_from_directory ( & package_root. join ( DEFAULT_EXAMPLE_DIR_NAME ) ) ;
374
382
375
383
let targets = clean_targets (
376
384
"example" ,
@@ -415,7 +423,7 @@ fn clean_tests(
415
423
warnings : & mut Vec < String > ,
416
424
errors : & mut Vec < String > ,
417
425
) -> CargoResult < Vec < Target > > {
418
- let inferred = infer_from_directory ( & package_root. join ( "tests" ) ) ;
426
+ let inferred = infer_from_directory ( & package_root. join ( DEFAULT_TEST_DIR_NAME ) ) ;
419
427
420
428
let targets = clean_targets (
421
429
"test" ,
@@ -590,7 +598,9 @@ fn inferred_bins(package_root: &Path, package_name: &str) -> Vec<(String, PathBu
590
598
if main. exists ( ) {
591
599
result. push ( ( package_name. to_string ( ) , main) ) ;
592
600
}
593
- result. extend ( infer_from_directory ( & package_root. join ( "src" ) . join ( "bin" ) ) ) ;
601
+ result. extend ( infer_from_directory (
602
+ & package_root. join ( "src" ) . join ( DEFAULT_BIN_DIR_NAME ) ,
603
+ ) ) ;
594
604
595
605
result
596
606
}
@@ -812,6 +822,90 @@ fn configure(features: &Features, toml: &TomlTarget, target: &mut Target) -> Car
812
822
Ok ( ( ) )
813
823
}
814
824
825
+ /// Build an error message for a target path that cannot be determined either
826
+ /// by auto-discovery or specifiying.
827
+ ///
828
+ /// This function tries to detect commonly wrong paths for targets:
829
+ ///
830
+ /// test -> tests/*.rs, tests/*/main.rs
831
+ /// bench -> benches/*.rs, benches/*/main.rs
832
+ /// example -> examples/*.rs, examples/*/main.rs
833
+ /// bin -> src/bin/*.rs, src/bin/*/main.rs
834
+ ///
835
+ /// Note that the logic need to sync with [`infer_from_directory`] if changes.
836
+ fn target_path_not_found_error_message (
837
+ package_root : & Path ,
838
+ target : & TomlTarget ,
839
+ target_kind : & str ,
840
+ ) -> String {
841
+ fn possible_target_paths ( name : & str , kind : & str , commonly_wrong : bool ) -> [ PathBuf ; 2 ] {
842
+ let mut target_path = PathBuf :: new ( ) ;
843
+ match ( kind, commonly_wrong) {
844
+ // commonly wrong paths
845
+ ( "test" | "bench" | "example" , true ) => target_path. push ( kind) ,
846
+ ( "bin" , true ) => {
847
+ target_path. push ( "src" ) ;
848
+ target_path. push ( "bins" ) ;
849
+ }
850
+ // default inferred paths
851
+ ( "test" , false ) => target_path. push ( DEFAULT_TEST_DIR_NAME ) ,
852
+ ( "bench" , false ) => target_path. push ( DEFAULT_BENCH_DIR_NAME ) ,
853
+ ( "example" , false ) => target_path. push ( DEFAULT_EXAMPLE_DIR_NAME ) ,
854
+ ( "bin" , false ) => {
855
+ target_path. push ( "src" ) ;
856
+ target_path. push ( DEFAULT_BIN_DIR_NAME ) ;
857
+ }
858
+ _ => unreachable ! ( "invalid target kind: {}" , kind) ,
859
+ }
860
+ target_path. push ( name) ;
861
+
862
+ let target_path_file = {
863
+ let mut path = target_path. clone ( ) ;
864
+ path. set_extension ( "rs" ) ;
865
+ path
866
+ } ;
867
+ let target_path_subdir = {
868
+ target_path. push ( "main.rs" ) ;
869
+ target_path
870
+ } ;
871
+ return [ target_path_file, target_path_subdir] ;
872
+ }
873
+
874
+ let target_name = target. name ( ) ;
875
+ let commonly_wrong_paths = possible_target_paths ( & target_name, target_kind, true ) ;
876
+ let possible_paths = possible_target_paths ( & target_name, target_kind, false ) ;
877
+ let existing_wrong_path_index = match (
878
+ package_root. join ( & commonly_wrong_paths[ 0 ] ) . exists ( ) ,
879
+ package_root. join ( & commonly_wrong_paths[ 1 ] ) . exists ( ) ,
880
+ ) {
881
+ ( true , _) => Some ( 0 ) ,
882
+ ( _, true ) => Some ( 1 ) ,
883
+ _ => None ,
884
+ } ;
885
+
886
+ if let Some ( i) = existing_wrong_path_index {
887
+ return format ! (
888
+ "\
889
+ can't find `{name}` {kind} at default paths, but found a file at `{wrong_path}`.
890
+ Perhaps rename the file to `{possible_path}` for target auto-discovery, \
891
+ or specify {kind}.path if you want to use a non-default path.",
892
+ name = target_name,
893
+ kind = target_kind,
894
+ wrong_path = commonly_wrong_paths[ i] . display( ) ,
895
+ possible_path = possible_paths[ i] . display( ) ,
896
+ ) ;
897
+ }
898
+
899
+ format ! (
900
+ "can't find `{name}` {kind} at `{path_file}` or `{path_dir}`. \
901
+ Please specify {kind}.path if you want to use a non-default path.",
902
+ name = target_name,
903
+ kind = target_kind,
904
+ path_file = possible_paths[ 0 ] . display( ) ,
905
+ path_dir = possible_paths[ 1 ] . display( ) ,
906
+ )
907
+ }
908
+
815
909
fn target_path (
816
910
target : & TomlTarget ,
817
911
inferred : & [ ( String , PathBuf ) ] ,
@@ -835,16 +929,32 @@ fn target_path(
835
929
let second = matching. next ( ) ;
836
930
match ( first, second) {
837
931
( Some ( path) , None ) => Ok ( path) ,
838
- ( None , None ) | ( Some ( _) , Some ( _) ) => {
932
+ ( None , None ) => {
933
+ if edition == Edition :: Edition2015 {
934
+ if let Some ( path) = legacy_path ( target) {
935
+ return Ok ( path) ;
936
+ }
937
+ }
938
+ Err ( target_path_not_found_error_message (
939
+ package_root,
940
+ target,
941
+ target_kind,
942
+ ) )
943
+ }
944
+ ( Some ( p0) , Some ( p1) ) => {
839
945
if edition == Edition :: Edition2015 {
840
946
if let Some ( path) = legacy_path ( target) {
841
947
return Ok ( path) ;
842
948
}
843
949
}
844
950
Err ( format ! (
845
- "can't find `{name}` {target_kind}, specify {target_kind}.path" ,
846
- name = name,
847
- target_kind = target_kind
951
+ "\
952
+ cannot infer path for `{}` {}
953
+ Cargo doesn't know which to use because multiple target files found at `{}` and `{}`." ,
954
+ target. name( ) ,
955
+ target_kind,
956
+ p0. strip_prefix( package_root) . unwrap_or( & p0) . display( ) ,
957
+ p1. strip_prefix( package_root) . unwrap_or( & p1) . display( ) ,
848
958
) )
849
959
}
850
960
( None , Some ( _) ) => unreachable ! ( ) ,
0 commit comments