Skip to content

Commit 0187762

Browse files
trolleymanalexcrichton
authored andcommitted
Add CUDA support for MSVC (#426)
Tested building https://github.com/trolleyman/cuda-macros with this (the `cuda-macros-test` crate) and it builds & links correctly. Haven't had a chance to test that this runs yet, but will in the morning. I wasn't sure that this way is the most elegant, but this seemed like the way that did the least amount of changes. I am also not sure that this is the correct way of doing this, especially regarding cross-compiling, but it gets it up and running at least. To test you can do a `cargo build` in the root of the repo linked above. The build stuff is a bit hacky, but essentially it generates the CUDA function below & calls it. ```c extern "C" __global__ void hello(int32_t* x, int32_t y) { printf("Hello from block %d, thread %d (y=%d)\n", blockIdx.x, threadIdx.x, y); *x = 2; } ``` ```rust extern "C" unsafe fn hello(x: *mut i32, y: i32); ```
1 parent 5c0dc67 commit 0187762

File tree

3 files changed

+93
-117
lines changed

3 files changed

+93
-117
lines changed

src/lib.rs

+68-94
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ impl ToolFamily {
209209
fn add_debug_flags(&self, cmd: &mut Tool) {
210210
match *self {
211211
ToolFamily::Msvc { .. } => {
212-
cmd.push_cc_arg("/Z7".into());
212+
cmd.push_cc_arg("-Z7".into());
213213
}
214214
ToolFamily::Gnu | ToolFamily::Clang => {
215215
cmd.push_cc_arg("-g".into());
@@ -218,26 +218,10 @@ impl ToolFamily {
218218
}
219219
}
220220

221-
/// What the flag to include directories into header search path looks like
222-
fn include_flag(&self) -> &'static str {
223-
match *self {
224-
ToolFamily::Msvc { .. } => "/I",
225-
ToolFamily::Gnu | ToolFamily::Clang => "-I",
226-
}
227-
}
228-
229-
/// What the flag to request macro-expanded source output looks like
230-
fn expand_flag(&self) -> &'static str {
231-
match *self {
232-
ToolFamily::Msvc { .. } => "/E",
233-
ToolFamily::Gnu | ToolFamily::Clang => "-E",
234-
}
235-
}
236-
237221
/// What the flags to enable all warnings
238222
fn warnings_flags(&self) -> &'static str {
239223
match *self {
240-
ToolFamily::Msvc { .. } => "/W4",
224+
ToolFamily::Msvc { .. } => "-W4",
241225
ToolFamily::Gnu | ToolFamily::Clang => "-Wall",
242226
}
243227
}
@@ -253,29 +237,11 @@ impl ToolFamily {
253237
/// What the flag to turn warning into errors
254238
fn warnings_to_errors_flag(&self) -> &'static str {
255239
match *self {
256-
ToolFamily::Msvc { .. } => "/WX",
240+
ToolFamily::Msvc { .. } => "-WX",
257241
ToolFamily::Gnu | ToolFamily::Clang => "-Werror",
258242
}
259243
}
260244

261-
/// NVCC-specific. Device code debug info flag. This is separate from the
262-
/// debug info flag passed to the C++ compiler.
263-
fn nvcc_debug_flag(&self) -> &'static str {
264-
match *self {
265-
ToolFamily::Msvc { .. } => unimplemented!(),
266-
ToolFamily::Gnu | ToolFamily::Clang => "-G",
267-
}
268-
}
269-
270-
/// NVCC-specific. Redirect the following flag to the underlying C++
271-
/// compiler.
272-
fn nvcc_redirect_flag(&self) -> &'static str {
273-
match *self {
274-
ToolFamily::Msvc { .. } => unimplemented!(),
275-
ToolFamily::Gnu | ToolFamily::Clang => "-Xcompiler",
276-
}
277-
}
278-
279245
fn verbose_stderr(&self) -> bool {
280246
*self == ToolFamily::Clang
281247
}
@@ -454,12 +420,19 @@ impl Build {
454420

455421
let mut cmd = compiler.to_command();
456422
let is_arm = target.contains("aarch64") || target.contains("arm");
457-
command_add_output_file(&mut cmd, &obj, target.contains("msvc"), false, is_arm);
423+
command_add_output_file(
424+
&mut cmd,
425+
&obj,
426+
self.cuda,
427+
target.contains("msvc"),
428+
false,
429+
is_arm,
430+
);
458431

459432
// We need to explicitly tell msvc not to link and create an exe
460433
// in the root directory of the crate
461-
if target.contains("msvc") {
462-
cmd.arg("/c");
434+
if target.contains("msvc") && !self.cuda {
435+
cmd.arg("-c");
463436
}
464437

465438
cmd.arg(&src);
@@ -500,7 +473,6 @@ impl Build {
500473
/// .shared_flag(true)
501474
/// .compile("libfoo.so");
502475
/// ```
503-
504476
pub fn shared_flag(&mut self, shared_flag: bool) -> &mut Build {
505477
self.shared_flag = Some(shared_flag);
506478
self
@@ -595,7 +567,7 @@ impl Build {
595567
/// Set warnings flags.
596568
///
597569
/// Adds some flags:
598-
/// - "/Wall" for MSVC.
570+
/// - "-Wall" for MSVC.
599571
/// - "-Wall", "-Wextra" for GNU and Clang.
600572
///
601573
/// Enabled by default.
@@ -1008,10 +980,10 @@ impl Build {
1008980
)
1009981
};
1010982
let is_arm = target.contains("aarch64") || target.contains("arm");
1011-
command_add_output_file(&mut cmd, &obj.dst, msvc, is_asm, is_arm);
983+
command_add_output_file(&mut cmd, &obj.dst, self.cuda, msvc, is_asm, is_arm);
1012984
// armasm and armasm64 don't requrie -c option
1013985
if !msvc || !is_asm || !is_arm {
1014-
cmd.arg(if msvc { "/c" } else { "-c" });
986+
cmd.arg("-c");
1015987
}
1016988
cmd.arg(&obj.src);
1017989

@@ -1026,7 +998,7 @@ impl Build {
1026998
for &(ref a, ref b) in self.env.iter() {
1027999
cmd.env(a, b);
10281000
}
1029-
cmd.arg(compiler.family.expand_flag());
1001+
cmd.arg("-E");
10301002

10311003
assert!(
10321004
self.files.len() <= 1,
@@ -1116,7 +1088,7 @@ impl Build {
11161088
}
11171089

11181090
for directory in self.include_directories.iter() {
1119-
cmd.args.push(cmd.family.include_flag().into());
1091+
cmd.args.push("-I".into());
11201092
cmd.args.push(directory.into());
11211093
}
11221094

@@ -1153,15 +1125,10 @@ impl Build {
11531125
}
11541126

11551127
for &(ref key, ref value) in self.definitions.iter() {
1156-
let lead = if let ToolFamily::Msvc { .. } = cmd.family {
1157-
"/"
1158-
} else {
1159-
"-"
1160-
};
11611128
if let Some(ref value) = *value {
1162-
cmd.args.push(format!("{}D{}={}", lead, key, value).into());
1129+
cmd.args.push(format!("-D{}={}", key, value).into());
11631130
} else {
1164-
cmd.args.push(format!("{}D{}", lead, key).into());
1131+
cmd.args.push(format!("-D{}", key).into());
11651132
}
11661133
}
11671134

@@ -1183,32 +1150,29 @@ impl Build {
11831150
// If the flag is not conditioned on target variable, it belongs here :)
11841151
match cmd.family {
11851152
ToolFamily::Msvc { .. } => {
1186-
assert!(!self.cuda,
1187-
"CUDA C++ compilation not supported for MSVC, yet... but you are welcome to implement it :)");
1188-
1189-
cmd.args.push("/nologo".into());
1153+
cmd.push_cc_arg("-nologo".into());
11901154

11911155
let crt_flag = match self.static_crt {
1192-
Some(true) => "/MT",
1193-
Some(false) => "/MD",
1156+
Some(true) => "-MT",
1157+
Some(false) => "-MD",
11941158
None => {
11951159
let features = self
11961160
.getenv("CARGO_CFG_TARGET_FEATURE")
11971161
.unwrap_or(String::new());
11981162
if features.contains("crt-static") {
1199-
"/MT"
1163+
"-MT"
12001164
} else {
1201-
"/MD"
1165+
"-MD"
12021166
}
12031167
}
12041168
};
1205-
cmd.args.push(crt_flag.into());
1169+
cmd.push_cc_arg(crt_flag.into());
12061170

12071171
match &opt_level[..] {
12081172
// Msvc uses /O1 to enable all optimizations that minimize code size.
1209-
"z" | "s" | "1" => cmd.push_opt_unless_duplicate("/O1".into()),
1173+
"z" | "s" | "1" => cmd.push_opt_unless_duplicate("-O1".into()),
12101174
// -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2.
1211-
"2" | "3" => cmd.push_opt_unless_duplicate("/O2".into()),
1175+
"2" | "3" => cmd.push_opt_unless_duplicate("-O2".into()),
12121176
_ => {}
12131177
}
12141178
}
@@ -1226,7 +1190,10 @@ impl Build {
12261190
cmd.push_cc_arg("-fdata-sections".into());
12271191
}
12281192
// Disable generation of PIC on RISC-V for now: rust-lld doesn't support this yet
1229-
if self.pic.unwrap_or(!target.contains("windows-gnu") && !target.contains("riscv")) {
1193+
if self
1194+
.pic
1195+
.unwrap_or(!target.contains("windows-gnu") && !target.contains("riscv"))
1196+
{
12301197
cmd.push_cc_arg("-fPIC".into());
12311198
// PLT only applies if code is compiled with PIC support,
12321199
// and only for ELF targets.
@@ -1239,8 +1206,8 @@ impl Build {
12391206

12401207
if self.get_debug() {
12411208
if self.cuda {
1242-
let nvcc_debug_flag = cmd.family.nvcc_debug_flag().into();
1243-
cmd.args.push(nvcc_debug_flag);
1209+
// NVCC debug flag
1210+
cmd.args.push("-G".into());
12441211
}
12451212
let family = cmd.family;
12461213
family.add_debug_flags(cmd);
@@ -1257,13 +1224,13 @@ impl Build {
12571224
cmd.args.push("-m64".into());
12581225
} else if target.contains("86") {
12591226
cmd.args.push("-m32".into());
1260-
cmd.args.push("/arch:IA32".into());
1227+
cmd.push_cc_arg("-arch:IA32".into());
12611228
} else {
1262-
cmd.args.push(format!("--target={}", target).into());
1229+
cmd.push_cc_arg(format!("--target={}", target).into());
12631230
}
12641231
} else {
12651232
if target.contains("i586") {
1266-
cmd.args.push("/ARCH:IA32".into());
1233+
cmd.push_cc_arg("-arch:IA32".into());
12671234
}
12681235
}
12691236

@@ -1278,7 +1245,7 @@ impl Build {
12781245
// Windows SDK it is required.
12791246
if target.contains("arm") || target.contains("thumb") {
12801247
cmd.args
1281-
.push("/D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1".into());
1248+
.push("-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1".into());
12821249
}
12831250
}
12841251
ToolFamily::Gnu => {
@@ -1502,18 +1469,18 @@ impl Build {
15021469
};
15031470
let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool));
15041471
for directory in self.include_directories.iter() {
1505-
cmd.arg("/I").arg(directory);
1472+
cmd.arg("-I").arg(directory);
15061473
}
15071474
for &(ref key, ref value) in self.definitions.iter() {
15081475
if let Some(ref value) = *value {
1509-
cmd.arg(&format!("/D{}={}", key, value));
1476+
cmd.arg(&format!("-D{}={}", key, value));
15101477
} else {
1511-
cmd.arg(&format!("/D{}", key));
1478+
cmd.arg(&format!("-D{}", key));
15121479
}
15131480
}
15141481

15151482
if target.contains("i686") || target.contains("i586") {
1516-
cmd.arg("/safeseh");
1483+
cmd.arg("-safeseh");
15171484
}
15181485
for flag in self.flags.iter() {
15191486
cmd.arg(flag);
@@ -1531,9 +1498,9 @@ impl Build {
15311498
let target = self.get_target()?;
15321499
if target.contains("msvc") {
15331500
let (mut cmd, program) = self.get_ar()?;
1534-
let mut out = OsString::from("/OUT:");
1501+
let mut out = OsString::from("-out:");
15351502
out.push(dst);
1536-
cmd.arg(out).arg("/nologo");
1503+
cmd.arg(out).arg("-nologo");
15371504

15381505
// Similar to https://github.com/rust-lang/rust/pull/47507
15391506
// and https://github.com/rust-lang/rust/pull/48548
@@ -1632,19 +1599,21 @@ impl Build {
16321599
}
16331600
};
16341601

1635-
let min_version = std::env::var("IPHONEOS_DEPLOYMENT_TARGET")
1636-
.unwrap_or_else(|_| "7.0".into());
1602+
let min_version =
1603+
std::env::var("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "7.0".into());
16371604

16381605
let sdk = match arch {
16391606
ArchSpec::Device(arch) => {
16401607
cmd.args.push("-arch".into());
16411608
cmd.args.push(arch.into());
1642-
cmd.args.push(format!("-miphoneos-version-min={}", min_version).into());
1609+
cmd.args
1610+
.push(format!("-miphoneos-version-min={}", min_version).into());
16431611
"iphoneos"
16441612
}
16451613
ArchSpec::Simulator(arch) => {
16461614
cmd.args.push(arch.into());
1647-
cmd.args.push(format!("-mios-simulator-version-min={}", min_version).into());
1615+
cmd.args
1616+
.push(format!("-mios-simulator-version-min={}", min_version).into());
16481617
"iphonesimulator"
16491618
}
16501619
};
@@ -1776,13 +1745,14 @@ impl Build {
17761745
}
17771746
} else if target.contains("cloudabi") {
17781747
format!("{}-{}", target, traditional)
1779-
} else if target == "wasm32-wasi" ||
1780-
target == "wasm32-unknown-wasi" ||
1781-
target == "wasm32-unknown-unknown" {
1748+
} else if target == "wasm32-wasi"
1749+
|| target == "wasm32-unknown-wasi"
1750+
|| target == "wasm32-unknown-unknown"
1751+
{
17821752
"clang".to_string()
17831753
} else if target.contains("vxworks") {
1784-
"wr-c++".to_string()
1785-
} else if self.get_host()? != target {
1754+
"wr=c++".to_string()
1755+
} else if self.get_host()? != target {
17861756
// CROSS_COMPILE is of the form: "arm-linux-gnueabi-"
17871757
let cc_env = self.getenv("CROSS_COMPILE");
17881758
let cross_compile = cc_env.as_ref().map(|s| s.trim_right_matches('-'));
@@ -1880,6 +1850,7 @@ impl Build {
18801850
nvcc_tool
18811851
.args
18821852
.push(format!("-ccbin={}", tool.path.display()).into());
1853+
nvcc_tool.family = tool.family;
18831854
nvcc_tool
18841855
} else {
18851856
tool
@@ -2185,7 +2156,7 @@ impl Tool {
21852156
/// with a "-Xcompiler" flag to get passed to the underlying C++ compiler.
21862157
fn push_cc_arg(&mut self, flag: OsString) {
21872158
if self.cuda {
2188-
self.args.push(self.family.nvcc_redirect_flag().into());
2159+
self.args.push("-Xcompiler".into());
21892160
}
21902161
self.args.push(flag);
21912162
}
@@ -2441,13 +2412,16 @@ fn fail(s: &str) -> ! {
24412412
std::process::exit(1);
24422413
}
24432414

2444-
fn command_add_output_file(cmd: &mut Command, dst: &Path, msvc: bool, is_asm: bool, is_arm: bool) {
2445-
if msvc && is_asm && is_arm {
2446-
cmd.arg("-o").arg(&dst);
2447-
} else if msvc && is_asm {
2448-
cmd.arg("/Fo").arg(dst);
2449-
} else if msvc {
2450-
let mut s = OsString::from("/Fo");
2415+
fn command_add_output_file(
2416+
cmd: &mut Command,
2417+
dst: &Path,
2418+
cuda: bool,
2419+
msvc: bool,
2420+
is_asm: bool,
2421+
is_arm: bool,
2422+
) {
2423+
if msvc && !cuda && !(is_asm && is_arm) {
2424+
let mut s = OsString::from("-Fo");
24512425
s.push(&dst);
24522426
cmd.arg(s);
24532427
} else {

0 commit comments

Comments
 (0)