@@ -555,7 +555,7 @@ impl Config {
555555 . clone ( )
556556 . unwrap_or_else ( || PathBuf :: from ( getenv_unwrap ( "OUT_DIR" ) ) ) ;
557557
558- let build_dir = try_canonicalize ( & dst. join ( "build" ) ) ;
558+ let build_dir = fix_build_dir ( & dst. join ( "build" ) ) ;
559559
560560 self . maybe_clear ( & build_dir) ;
561561 let _ = fs:: create_dir_all ( & build_dir) ;
@@ -1004,7 +1004,10 @@ impl Config {
10041004 // CMake will apparently store canonicalized paths which normally
10051005 // isn't relevant to us but we canonicalize it here to ensure
10061006 // we're both checking the same thing.
1007- let path = try_canonicalize ( & self . path ) ;
1007+ let path = self
1008+ . path
1009+ . canonicalize ( )
1010+ . unwrap_or_else ( |_| self . path . to_owned ( ) ) ;
10081011
10091012 let mut f = match File :: open ( dir. join ( "CMakeCache.txt" ) ) {
10101013 Ok ( f) => f,
@@ -1139,32 +1142,51 @@ fn uses_named_pipe_jobserver(makeflags: &OsStr) -> bool {
11391142 . contains ( "--jobserver-auth=fifo:" )
11401143}
11411144
1142- /// Attempt to canonicalize; fall back to the original path if unsuccessful, in case `cmake` knows
1143- /// something we don't.
1144- fn try_canonicalize ( path : & Path ) -> PathBuf {
1145- let path = path. canonicalize ( ) . unwrap_or_else ( |_| path. to_owned ( ) ) ;
1146- // On Windows, attempt to remove the verbatim prefix from the canonicalized path.
1147- // FIXME(ChrisDenton): once MSRV is >=1.79 use `std::path::absolute` instead of canonicalize.
1148- // That will avoid the need for this hack.
1149- #[ cfg( windows) ]
1150- {
1151- use std:: os:: windows:: ffi:: { OsStrExt , OsStringExt } ;
1152- let mut wide: Vec < u16 > = path. as_os_str ( ) . encode_wide ( ) . collect ( ) ;
1153- if wide. starts_with ( & [ b'\\' as u16 , b'\\' as u16 , b'?' as u16 , b'\\' as u16 ] ) {
1154- if wide. get ( 5 ..7 ) == Some ( & [ b':' as u16 , b'\\' as u16 ] ) {
1155- // Convert \\?\C:\ to C:\
1156- wide. copy_within ( 4 .., 0 ) ;
1157- wide. truncate ( wide. len ( ) - 4 ) ;
1158- } else if wide. get ( 4 ..8 ) == Some ( & [ b'U' as u16 , b'N' as u16 , b'C' as u16 , b'\\' as u16 ] )
1159- {
1160- // Convert \\?\UNC\ to \\
1161- wide. copy_within ( 8 .., 2 ) ;
1162- wide. truncate ( wide. len ( ) - ( 8 - 2 ) ) ;
1163- }
1164- return OsString :: from_wide ( & wide) . into ( ) ;
1145+ #[ cfg( not( windows) ) ]
1146+ fn fix_build_dir ( path : & Path ) -> PathBuf {
1147+ path. into ( )
1148+ }
1149+
1150+ // Change relative paths to absolute to workaround #200 where
1151+ // some flavors of CMake on Windows otherwise fail with
1152+ // `error MSB1009: Project file does not exist`
1153+ #[ cfg( windows) ]
1154+ fn fix_build_dir ( path : & Path ) -> PathBuf {
1155+ use std:: os:: windows:: ffi:: { OsStrExt , OsStringExt } ;
1156+ use std:: ptr:: null_mut;
1157+ if path. is_absolute ( ) {
1158+ return path. into ( ) ;
1159+ }
1160+ #[ link( name = "kernel32" , kind = "raw-dylib" ) ]
1161+ extern "system" {
1162+ fn GetFullPathNameW (
1163+ lpfilename : * const u16 ,
1164+ nbufferlength : u32 ,
1165+ lpbuffer : * mut u16 ,
1166+ lpfilepart : * mut * mut u16 ,
1167+ ) -> u32 ;
1168+ }
1169+
1170+ // FIXME(ChrisDenton): once MSRV is >=1.79 use `std::path::absolute` instead of this.
1171+ let path_utf16: Vec < u16 > = path. as_os_str ( ) . encode_wide ( ) . chain ( [ 0 ] ) . collect ( ) ;
1172+ unsafe {
1173+ // Calling `GetFullPathNameW` with a buffer of length zero will return the necessary buffer size.
1174+ let expected_len = GetFullPathNameW ( path_utf16. as_ptr ( ) , 0 , null_mut ( ) , null_mut ( ) ) ;
1175+ let mut buffer = vec ! [ 0 ; expected_len as usize ] ;
1176+ let len = GetFullPathNameW (
1177+ path_utf16. as_ptr ( ) ,
1178+ expected_len,
1179+ buffer. as_mut_ptr ( ) ,
1180+ null_mut ( ) ,
1181+ ) as usize ;
1182+ if len == 0 || len > buffer. len ( ) {
1183+ // Failed to get the absolute path. Fallback to using the original path.
1184+ return path. into ( ) ;
11651185 }
1186+ // If successful then `len` will be the length of the path that was written to the buffer.
1187+ buffer. truncate ( len) ;
1188+ OsString :: from_wide ( & buffer) . into ( )
11661189 }
1167- path
11681190}
11691191
11701192#[ cfg( windows) ]
0 commit comments