@@ -25,6 +25,11 @@ use crate::util::restricted_names;
2525
2626use anyhow:: Context as _;
2727
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+
2833pub fn targets (
2934 features : & Features ,
3035 manifest : & TomlManifest ,
@@ -353,7 +358,10 @@ fn clean_bins(
353358 return Some ( path) ;
354359 }
355360
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" ) ;
357365 if path. exists ( ) {
358366 return Some ( path) ;
359367 }
@@ -370,7 +378,7 @@ fn clean_examples(
370378 warnings : & mut Vec < String > ,
371379 errors : & mut Vec < String > ,
372380) -> 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 ) ) ;
374382
375383 let targets = clean_targets (
376384 "example" ,
@@ -415,7 +423,7 @@ fn clean_tests(
415423 warnings : & mut Vec < String > ,
416424 errors : & mut Vec < String > ,
417425) -> 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 ) ) ;
419427
420428 let targets = clean_targets (
421429 "test" ,
@@ -590,7 +598,9 @@ fn inferred_bins(package_root: &Path, package_name: &str) -> Vec<(String, PathBu
590598 if main. exists ( ) {
591599 result. push ( ( package_name. to_string ( ) , main) ) ;
592600 }
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+ ) ) ;
594604
595605 result
596606}
@@ -812,6 +822,90 @@ fn configure(features: &Features, toml: &TomlTarget, target: &mut Target) -> Car
812822 Ok ( ( ) )
813823}
814824
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+
815909fn target_path (
816910 target : & TomlTarget ,
817911 inferred : & [ ( String , PathBuf ) ] ,
@@ -835,16 +929,32 @@ fn target_path(
835929 let second = matching. next ( ) ;
836930 match ( first, second) {
837931 ( 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) ) => {
839945 if edition == Edition :: Edition2015 {
840946 if let Some ( path) = legacy_path ( target) {
841947 return Ok ( path) ;
842948 }
843949 }
844950 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( ) ,
848958 ) )
849959 }
850960 ( None , Some ( _) ) => unreachable ! ( ) ,
0 commit comments