5959use std:: fs:: create_dir_all;
6060use std:: fs:: File ;
6161use std:: io:: { BufWriter , Error , ErrorKind , Result , Write } ;
62- use std:: path:: PathBuf ;
62+ use std:: path:: { Path , PathBuf } ;
6363use std:: process:: Command ;
6464
6565/// Stable ABI Python DLL file name
6666const DLL_FILE : & str = "python3.dll" ;
6767
68- /// Canonical `python3.dll` import library file name for MinGW-w64
69- const IMPLIB_FILE : & str = "python3.dll.a" ;
70-
7168/// Module-Definition file name for `python3.dll`
7269const DEF_FILE : & str = "python3.def" ;
7370
71+ /// Canonical `python3.dll` import library file name for the GNU environment ABI (MinGW-w64)
72+ const IMPLIB_FILE_GNU : & str = "python3.dll.a" ;
73+
74+ /// Canonical `python3.dll` import library file name for the MSVC environment ABI
75+ const IMPLIB_FILE_MSVC : & str = "python3.lib" ;
76+
7477/// Canonical MinGW-w64 `dlltool` program name
75- const DLLTOOL : & str = "x86_64-w64-mingw32-dlltool" ;
78+ const DLLTOOL_GNU : & str = "x86_64-w64-mingw32-dlltool" ;
7679
7780/// Canonical MinGW-w64 `dlltool` program name (32-bit version)
78- const DLLTOOL_32 : & str = "i686-w64-mingw32-dlltool" ;
81+ const DLLTOOL_GNU_32 : & str = "i686-w64-mingw32-dlltool" ;
82+
83+ /// Canonical `dlltool` program name for the MSVC environment ABI (LLVM dlltool)
84+ const DLLTOOL_MSVC : & str = "llvm-dlltool" ;
7985
8086/// Python Stable ABI symbol defs from the CPython repository
8187///
@@ -96,10 +102,7 @@ const STABLE_ABI_DEFS: &str = include_str!("../Misc/stable_abi.txt");
96102pub fn generate_implib_for_target ( out_dir : & str , arch : & str , env : & str ) -> Result < ( ) > {
97103 create_dir_all ( out_dir) ?;
98104
99- let mut libpath = PathBuf :: from ( out_dir) ;
100- let mut defpath = libpath. clone ( ) ;
101-
102- libpath. push ( IMPLIB_FILE ) ;
105+ let mut defpath = PathBuf :: from ( out_dir) ;
103106 defpath. push ( DEF_FILE ) ;
104107
105108 let stable_abi_exports = parse_stable_abi_defs ( STABLE_ABI_DEFS ) ;
@@ -111,21 +114,19 @@ pub fn generate_implib_for_target(out_dir: &str, arch: &str, env: &str) -> Resul
111114 // Try to guess the `dlltool` executable name from the target triple.
112115 let dlltool = match ( arch, env) {
113116 // 64-bit MinGW-w64 (aka x86_64-pc-windows-gnu)
114- ( "x86_64" , "gnu" ) => DLLTOOL ,
117+ ( "x86_64" , "gnu" ) => DLLTOOL_GNU ,
115118 // 32-bit MinGW-w64 (aka i686-pc-windows-gnu)
116- ( "x86" , "gnu" ) => DLLTOOL_32 ,
119+ ( "x86" , "gnu" ) => DLLTOOL_GNU_32 ,
120+ // MSVC ABI (multiarch)
121+ ( _, "msvc" ) => DLLTOOL_MSVC ,
117122 _ => {
118123 let msg = format ! ( "Unsupported target arch '{arch}' or env ABI '{env}'" ) ;
119124 return Err ( Error :: new ( ErrorKind :: Other , msg) ) ;
120125 }
121126 } ;
122127
123- let status = Command :: new ( dlltool)
124- . arg ( "--input-def" )
125- . arg ( defpath)
126- . arg ( "--output-lib" )
127- . arg ( libpath)
128- . status ( ) ?;
128+ // Run the selected `dlltool` executable to generate the import library.
129+ let status = build_dlltool_command ( dlltool, arch, & defpath, out_dir) . status ( ) ?;
129130
130131 if status. success ( ) {
131132 Ok ( ( ) )
@@ -135,6 +136,45 @@ pub fn generate_implib_for_target(out_dir: &str, arch: &str, env: &str) -> Resul
135136 }
136137}
137138
139+ /// Generates the complete `dlltool` executable invocation command.
140+ ///
141+ /// Supports both LLVM and MinGW `dlltool` flavors.
142+ fn build_dlltool_command ( dlltool : & str , arch : & str , defpath : & Path , out_dir : & str ) -> Command {
143+ let mut libpath = PathBuf :: from ( out_dir) ;
144+ let mut command = Command :: new ( dlltool) ;
145+
146+ // Check whether we are using LLVM `dlltool` or MinGW `dlltool`.
147+ if dlltool == DLLTOOL_MSVC {
148+ libpath. push ( IMPLIB_FILE_MSVC ) ;
149+
150+ // LLVM tools use their own target architecture names...
151+ let machine = match arch {
152+ "x86_64" => "i386:x86-64" ,
153+ "x86" => "i386" ,
154+ "aarch64" => "arm64" ,
155+ _ => arch,
156+ } ;
157+
158+ command
159+ . arg ( "-m" )
160+ . arg ( machine)
161+ . arg ( "-d" )
162+ . arg ( defpath)
163+ . arg ( "-l" )
164+ . arg ( libpath) ;
165+ } else {
166+ libpath. push ( IMPLIB_FILE_GNU ) ;
167+
168+ command
169+ . arg ( "--input-def" )
170+ . arg ( defpath)
171+ . arg ( "--output-lib" )
172+ . arg ( libpath) ;
173+ }
174+
175+ command
176+ }
177+
138178/// Generates `python3.dll` import library directly from the embedded
139179/// Python Stable ABI definitions data for the default 64-bit MinGW-w64
140180/// compile target.
0 commit comments