@@ -9,6 +9,7 @@ use std::{
99 io:: { Read , Write } ,
1010 num:: NonZero ,
1111 path:: PathBuf ,
12+ process:: Command ,
1213 str:: FromStr ,
1314 time:: Duration ,
1415} ;
@@ -121,14 +122,76 @@ enum LinuxLibC {
121122}
122123
123124impl LinuxLibC {
125+ fn get_musl_version ( ) -> Option < Version > {
126+ // This is a simplified check for musl version.
127+ // In practice, determining the musl version may require more complex logic,
128+ // such as parsing the output of `ldd --version` or checking for specific symbols in the C library.
129+ if let Ok ( output) = Command :: new ( "ldd" ) . arg ( "--version" ) . output ( ) {
130+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
131+ let mut is_musl = false ;
132+ for line in stdout. lines ( ) {
133+ let line = line. trim ( ) . to_lowercase ( ) ;
134+ // Output of `ldd --version` on musl typically looks like:
135+ // ```shell
136+ // musl libc (x86_64)
137+ // Version 1.2.2
138+ // Dynamic Program Loader
139+ // ```
140+ // So, first look for "musl" in the output.
141+ // Then, look for a version number if "musl" is found.
142+ if !is_musl && line. contains ( "musl" ) {
143+ is_musl = true ;
144+ }
145+ if is_musl
146+ && line. contains ( "version" )
147+ && let Some ( version_str) = line. split_whitespace ( ) . last ( )
148+ && let Ok ( version) = Version :: parse ( version_str)
149+ {
150+ return Some ( version) ;
151+ }
152+ }
153+ }
154+ // If we can't determine the musl version, assume it's compatible with musllinux wheels.
155+ None
156+ }
157+
158+ fn get_glibc_version ( ) -> Option < Version > {
159+ if let Ok ( output) = Command :: new ( "ldd" ) . arg ( "--version" ) . output ( ) {
160+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
161+ for line in stdout. lines ( ) {
162+ let line = line. trim ( ) . to_lowercase ( ) ;
163+ // Output of `ldd --version` on glibc typically looks like:
164+ // ```shell
165+ // ldd (Ubuntu GLIBC 2.39-0ubuntu8.7) 2.39
166+ // Copyright (C) 2024 Free Software Foundation, Inc.
167+ // ```
168+ // So, look for the version on the line that contains "glibc" in the output.
169+ if line. contains ( "glibc" )
170+ && let Some ( version_str) = line. split_whitespace ( ) . last ( )
171+ && let Some ( ( major, minor) ) = version_str. split_once ( '.' )
172+ && let Ok ( major) = major. parse :: < u64 > ( )
173+ && let Ok ( minor) = minor. parse :: < u64 > ( )
174+ {
175+ return Some ( Version :: new ( major, minor, 0 ) ) ;
176+ }
177+ }
178+ }
179+ None
180+ }
181+
124182 /// Checks if the [LinuxLibC] is compatible with the current system.
125183 pub fn is_compatible_with_system ( & self ) -> bool {
126184 match self {
127- #[ cfg( target_env = "musl" ) ]
128- LinuxLibC :: Musl { .. } => true ,
129- #[ cfg( not( target_env = "musl" ) ) ]
130- LinuxLibC :: Glibc { .. } => true ,
131- _ => false ,
185+ LinuxLibC :: Musl {
186+ version : pkg_musl_version,
187+ } => Self :: get_musl_version ( )
188+ . map ( |sys_musl_version| * pkg_musl_version >= sys_musl_version)
189+ . unwrap_or ( false ) ,
190+ LinuxLibC :: Glibc {
191+ version : pkg_glibc_version,
192+ } => Self :: get_glibc_version ( )
193+ . map ( |sys_glibc_version| * pkg_glibc_version >= sys_glibc_version)
194+ . unwrap_or ( false ) ,
132195 }
133196 }
134197}
@@ -145,10 +208,10 @@ impl PlatformOs {
145208 /// Checks if the [PlatformOs] is compatible with the current system.
146209 pub fn is_compatible_with_system ( & self ) -> bool {
147210 match self {
148- PlatformOs :: Windows => std :: env :: consts :: OS == "windows" ,
149- PlatformOs :: MacOS => std :: env :: consts :: OS == "macos" ,
211+ PlatformOs :: Windows => cfg ! ( target_os = "windows" ) ,
212+ PlatformOs :: MacOS => cfg ! ( target_os = "macos" ) ,
150213 PlatformOs :: Linux { lib_c } => {
151- std :: env :: consts :: OS == "linux" && lib_c. is_compatible_with_system ( )
214+ cfg ! ( target_os = "linux" ) && lib_c. is_compatible_with_system ( )
152215 }
153216 }
154217 }
0 commit comments