@@ -265,6 +265,10 @@ fn cargo_build_command(
265265 bridge_model,
266266 & context. module_name ,
267267 python_interpreter,
268+ #[ cfg( feature = "zig" ) ]
269+ context. zig ,
270+ #[ cfg( feature = "zig" ) ]
271+ & context. target_dir ,
268272 ) ;
269273
270274 if context. strip {
@@ -325,14 +329,16 @@ fn configure_bin_lib_flags(
325329 }
326330}
327331
328- /// Configure platform-specific linker arguments (macOS PyO3, Emscripten).
332+ /// Configure platform-specific linker arguments (macOS PyO3, Emscripten, Windows GNU + zig ).
329333fn configure_platform_linker_args (
330334 cargo_rustc : & mut cargo_options:: Rustc ,
331335 rustflags : & mut cargo_config2:: Flags ,
332336 target : & Target ,
333337 bridge_model : & BridgeModel ,
334338 module_name : & str ,
335339 python_interpreter : Option < & PythonInterpreter > ,
340+ #[ cfg( feature = "zig" ) ] zig : bool ,
341+ #[ cfg( feature = "zig" ) ] target_dir : & Path ,
336342) {
337343 if target. is_macos ( ) {
338344 if let BridgeModel :: PyO3 { .. } = bridge_model {
@@ -346,6 +352,35 @@ fn configure_platform_linker_args(
346352 } else if target. is_emscripten ( ) {
347353 configure_emscripten_args ( cargo_rustc, rustflags, target) ;
348354 }
355+
356+ // When using zig as the linker for windows-gnu targets, the PyInit symbol
357+ // is not exported. Work around this by generating a .def file that explicitly
358+ // exports the symbol.
359+ // See https://github.com/PyO3/maturin/issues/922
360+ #[ cfg( feature = "zig" ) ]
361+ if zig
362+ && target. is_windows ( )
363+ && !target. is_msvc ( )
364+ && matches ! (
365+ bridge_model,
366+ BridgeModel :: PyO3 { .. } | BridgeModel :: Cffi | BridgeModel :: UniFfi
367+ )
368+ {
369+ let py_init = format ! ( "PyInit_{module_name}" ) ;
370+ let maturin_dir = ensure_target_maturin_dir ( target_dir) ;
371+ let def_path = maturin_dir. join ( format ! ( "{module_name}.def" ) ) ;
372+ let def_contents = format ! ( "LIBRARY {module_name}\n EXPORTS\n {py_init}\n " ) ;
373+ if let Err ( e) = fs:: write ( & def_path, def_contents) {
374+ eprintln ! ( "⚠️ Warning: Failed to write .def file for zig windows-gnu workaround: {e}" ) ;
375+ } else {
376+ debug ! (
377+ "Generated .def file at {} for zig windows-gnu export workaround" ,
378+ def_path. display( )
379+ ) ;
380+ rustflags. push ( "-C" ) ;
381+ rustflags. push ( & format ! ( "link-arg={}" , def_path. display( ) ) ) ;
382+ }
383+ }
349384}
350385
351386/// Configure macOS-specific linker arguments for PyO3 builds.
@@ -632,12 +667,11 @@ fn configure_pyo3_env(
632667 build_command. env ( "PYTHON_SYS_EXECUTABLE" , & interpreter. executable ) ;
633668 } else if bridge_model. is_pyo3 ( ) && env:: var_os ( "PYO3_CONFIG_FILE" ) . is_none ( ) {
634669 let pyo3_config = interpreter. pyo3_config_file ( ) ;
635- let maturin_target_dir = context. target_dir . join ( env ! ( "CARGO_PKG_NAME" ) ) ;
670+ let maturin_target_dir = ensure_target_maturin_dir ( & context. target_dir ) ;
636671 let config_file = maturin_target_dir. join ( format ! (
637672 "pyo3-config-{}-{}.{}.txt" ,
638673 target_triple, interpreter. major, interpreter. minor
639674 ) ) ;
640- fs:: create_dir_all ( & maturin_target_dir) ?;
641675 // We don't want to rewrite the file every time as that will make cargo
642676 // trigger a rebuild of the project every time
643677 let existing_pyo3_config = fs:: read_to_string ( & config_file) . unwrap_or_default ( ) ;
@@ -930,6 +964,14 @@ pub fn warn_missing_py_init(artifact: &Path, module_name: &str) -> Result<()> {
930964 Ok ( ( ) )
931965}
932966
967+ /// Ensures the `maturin` subdirectory inside the target directory exists
968+ /// and returns its path. This directory is used for maturin-generated artifacts.
969+ pub ( crate ) fn ensure_target_maturin_dir ( target_dir : & Path ) -> PathBuf {
970+ let dir = target_dir. join ( env ! ( "CARGO_PKG_NAME" ) ) ;
971+ let _ = fs:: create_dir_all ( & dir) ;
972+ dir
973+ }
974+
933975fn pyo3_version ( cargo_metadata : & cargo_metadata:: Metadata ) -> Option < ( u64 , u64 , u64 ) > {
934976 let packages: HashMap < & str , & cargo_metadata:: Package > = cargo_metadata
935977 . packages
0 commit comments