Skip to content

Commit 04ef28f

Browse files
committed
feat: Use zig dlltool when linking with zig cc
Maturin sets `ZIG_COMMAND` environment variable when it is using `zig cc` to link the output binary.
1 parent bb4c9a7 commit 04ef28f

File tree

1 file changed

+36
-10
lines changed

1 file changed

+36
-10
lines changed

src/lib.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#![deny(missing_docs)]
7777
#![allow(clippy::needless_doctest_main)]
7878

79+
use std::env;
7980
use std::fs::{create_dir_all, write};
8081
use std::io::{Error, ErrorKind, Result};
8182
use std::path::{Path, PathBuf};
@@ -242,13 +243,26 @@ enum DllToolCommand {
242243
/// MSVC `lib.exe` program (no prefix)
243244
LibExe { command: Command, machine: String },
244245
/// `zig dlltool` wrapper (no prefix)
245-
#[allow(dead_code)]
246246
Zig { command: Command, machine: String },
247247
}
248248

249249
impl DllToolCommand {
250250
/// Attempts to find the best matching `dlltool` flavor for the target.
251251
fn find_for_target(arch: &str, env: &str) -> Result<DllToolCommand> {
252+
// LLVM tools use their own target architecture names...
253+
let machine = match arch {
254+
"x86_64" => "i386:x86-64",
255+
"x86" => "i386",
256+
"aarch64" => "arm64",
257+
arch => arch,
258+
}
259+
.to_owned();
260+
261+
// If `zig cc` is used as the linker, `zig dlltool` is the best choice.
262+
if let Some(command) = find_zig() {
263+
return Ok(DllToolCommand::Zig { command, machine });
264+
}
265+
252266
match (arch, env) {
253267
// 64-bit MinGW-w64 (aka `x86_64-pc-windows-gnu`)
254268
("x86_64", "gnu") => Ok(DllToolCommand::Mingw {
@@ -274,15 +288,6 @@ impl DllToolCommand {
274288

275289
Ok(DllToolCommand::LibExe { command, machine })
276290
} else {
277-
// LLVM tools use their own target architecture names...
278-
let machine = match arch {
279-
"x86_64" => "i386:x86-64",
280-
"x86" => "i386",
281-
"aarch64" => "arm64",
282-
arch => arch,
283-
}
284-
.to_owned();
285-
286291
let command = Command::new(DLLTOOL_MSVC);
287292

288293
Ok(DllToolCommand::Llvm { command, machine })
@@ -352,6 +357,27 @@ impl DllToolCommand {
352357
}
353358
}
354359

360+
/// Finds the `zig` executable (when built by ``maturin --zig`).
361+
///
362+
/// Examines the `ZIG_COMMAND` environment variable
363+
/// to find out if `zig cc` is being used as the linker.
364+
fn find_zig() -> Option<Command> {
365+
// `ZIG_COMMAND` may contain simply `zig` or `/usr/bin/zig`,
366+
// or a more complex construct like `python3 -m ziglang`.
367+
let zig_command = env::var("ZIG_COMMAND").ok()?;
368+
369+
// Try to emulate `sh -c ${ZIG_COMMAND}`.
370+
let mut zig_cmdlet = zig_command.split_ascii_whitespace();
371+
372+
// Extract the main program component (e.g. `zig` or `python3`).
373+
let mut zig = Command::new(zig_cmdlet.next()?);
374+
375+
// Append the rest of the commandlet.
376+
zig.args(zig_cmdlet);
377+
378+
Some(zig)
379+
}
380+
355381
/// Finds Visual Studio `lib.exe` when running on Windows.
356382
#[cfg(windows)]
357383
fn find_lib_exe(arch: &str) -> Option<Command> {

0 commit comments

Comments
 (0)