@@ -103,6 +103,7 @@ pub struct Build {
103
103
cpp_link_stdlib : Option < Option < String > > ,
104
104
cpp_set_stdlib : Option < String > ,
105
105
cuda : bool ,
106
+ cudart : Option < String > ,
106
107
target : Option < String > ,
107
108
host : Option < String > ,
108
109
out_dir : Option < PathBuf > ,
@@ -298,6 +299,7 @@ impl Build {
298
299
cpp_link_stdlib : None ,
299
300
cpp_set_stdlib : None ,
300
301
cuda : false ,
302
+ cudart : None ,
301
303
target : None ,
302
304
host : None ,
303
305
out_dir : None ,
@@ -611,6 +613,20 @@ impl Build {
611
613
self . cuda = cuda;
612
614
if cuda {
613
615
self . cpp = true ;
616
+ self . cudart = Some ( "static" . to_string ( ) ) ;
617
+ }
618
+ self
619
+ }
620
+
621
+ /// Link CUDA run-time.
622
+ ///
623
+ /// This option mimics the `--cudart` NVCC command-line option. Just like
624
+ /// the original it accepts `{none|shared|static}`, with default being
625
+ /// `static`. The method has to be invoked after `.cuda(true)`, or not
626
+ /// at all, if the default is right for the project.
627
+ pub fn cudart ( & mut self , cudart : & str ) -> & mut Build {
628
+ if self . cuda {
629
+ self . cudart = Some ( cudart. to_string ( ) ) ;
614
630
}
615
631
self
616
632
}
@@ -996,6 +1012,56 @@ impl Build {
996
1012
}
997
1013
}
998
1014
1015
+ let cudart = match & self . cudart {
1016
+ Some ( opt) => opt. as_str ( ) , // {none|shared|static}
1017
+ None => "none" ,
1018
+ } ;
1019
+ if cudart != "none" {
1020
+ if let Some ( nvcc) = which ( & self . get_compiler ( ) . path ) {
1021
+ // Try to figure out the -L search path. If it fails,
1022
+ // it's on user to specify one by passing it through
1023
+ // RUSTFLAGS environment variable.
1024
+ let mut libtst = false ;
1025
+ let mut libdir = nvcc;
1026
+ libdir. pop ( ) ; // remove 'nvcc'
1027
+ libdir. push ( ".." ) ;
1028
+ let target_arch = env:: var ( "CARGO_CFG_TARGET_ARCH" ) . unwrap ( ) ;
1029
+ if cfg ! ( target_os = "linux" ) {
1030
+ libdir. push ( "targets" ) ;
1031
+ libdir. push ( target_arch. to_owned ( ) + "-linux" ) ;
1032
+ libdir. push ( "lib" ) ;
1033
+ libtst = true ;
1034
+ } else if cfg ! ( target_env = "msvc" ) {
1035
+ libdir. push ( "lib" ) ;
1036
+ match target_arch. as_str ( ) {
1037
+ "x86_64" => {
1038
+ libdir. push ( "x64" ) ;
1039
+ libtst = true ;
1040
+ }
1041
+ "x86" => {
1042
+ libdir. push ( "Win32" ) ;
1043
+ libtst = true ;
1044
+ }
1045
+ _ => libtst = false ,
1046
+ }
1047
+ }
1048
+ if libtst && libdir. is_dir ( ) {
1049
+ println ! (
1050
+ "cargo:rustc-link-search=native={}" ,
1051
+ libdir. to_str( ) . unwrap( )
1052
+ ) ;
1053
+ }
1054
+
1055
+ // And now the -l flag.
1056
+ let lib = match cudart {
1057
+ "shared" => "cudart" ,
1058
+ "static" => "cudart_static" ,
1059
+ bad => panic ! ( "unsupported cudart option: {}" , bad) ,
1060
+ } ;
1061
+ println ! ( "cargo:rustc-link-lib={}" , lib) ;
1062
+ }
1063
+ }
1064
+
999
1065
Ok ( ( ) )
1000
1066
}
1001
1067
@@ -1205,6 +1271,9 @@ impl Build {
1205
1271
if !msvc || !is_asm || !is_arm {
1206
1272
cmd. arg ( "-c" ) ;
1207
1273
}
1274
+ if self . cuda && self . files . len ( ) > 1 {
1275
+ cmd. arg ( "--device-c" ) ;
1276
+ }
1208
1277
cmd. arg ( & obj. src ) ;
1209
1278
if cfg ! ( target_os = "macos" ) {
1210
1279
self . fix_env_for_apple_os ( & mut cmd) ?;
@@ -1811,6 +1880,21 @@ impl Build {
1811
1880
self . assemble_progressive ( dst, chunk) ?;
1812
1881
}
1813
1882
1883
+ if self . cuda {
1884
+ // Link the device-side code and add it to the target library,
1885
+ // so that non-CUDA linker can link the final binary.
1886
+
1887
+ let out_dir = self . get_out_dir ( ) ?;
1888
+ let dlink = out_dir. join ( lib_name. to_owned ( ) + "_dlink.o" ) ;
1889
+ let mut nvcc = self . get_compiler ( ) . to_command ( ) ;
1890
+ nvcc. arg ( "--device-link" )
1891
+ . arg ( "-o" )
1892
+ . arg ( dlink. clone ( ) )
1893
+ . arg ( dst) ;
1894
+ run ( & mut nvcc, "nvcc" ) ?;
1895
+ self . assemble_progressive ( dst, & [ dlink] ) ?;
1896
+ }
1897
+
1814
1898
let target = self . get_target ( ) ?;
1815
1899
if target. contains ( "msvc" ) {
1816
1900
// The Rust compiler will look for libfoo.a and foo.lib, but the
@@ -3100,3 +3184,23 @@ fn map_darwin_target_from_rust_to_compiler_architecture(target: &str) -> Option<
3100
3184
None
3101
3185
}
3102
3186
}
3187
+
3188
+ fn which ( tool : & Path ) -> Option < PathBuf > {
3189
+ fn check_exe ( exe : & mut PathBuf ) -> bool {
3190
+ let exe_ext = std:: env:: consts:: EXE_EXTENSION ;
3191
+ exe. exists ( ) || ( !exe_ext. is_empty ( ) && exe. set_extension ( exe_ext) && exe. exists ( ) )
3192
+ }
3193
+
3194
+ // If |tool| is not just one "word," assume it's an actual path...
3195
+ if tool. components ( ) . count ( ) > 1 {
3196
+ let mut exe = PathBuf :: from ( tool) ;
3197
+ return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3198
+ }
3199
+
3200
+ // Loop through PATH entries searching for the |tool|.
3201
+ let path_entries = env:: var_os ( "PATH" ) ?;
3202
+ env:: split_paths ( & path_entries) . find_map ( |path_entry| {
3203
+ let mut exe = path_entry. join ( tool) ;
3204
+ return if check_exe ( & mut exe) { Some ( exe) } else { None } ;
3205
+ } )
3206
+ }
0 commit comments