22
33use crate :: build:: CApiConfig ;
44use crate :: install:: InstallPaths ;
5- use std:: path:: { Component , Path , PathBuf } ;
5+ use std:: {
6+ collections:: HashSet ,
7+ path:: { Component , Path , PathBuf } ,
8+ } ;
69
710fn canonicalize < P : AsRef < Path > > ( path : P ) -> String {
811 let mut stack = Vec :: with_capacity ( 16 ) ;
@@ -57,6 +60,14 @@ fn canonicalize<P: AsRef<Path>>(path: P) -> String {
5760 }
5861}
5962
63+ use pkg_config;
64+
65+ #[ derive( Debug , Clone ) ]
66+ struct PkgConfigDedupInformation {
67+ requires : Vec < pkg_config:: Library > ,
68+ requires_private : Vec < pkg_config:: Library > ,
69+ }
70+
6071#[ derive( Debug , Clone ) ]
6172pub struct PkgConfig {
6273 prefix : PathBuf ,
@@ -77,6 +88,8 @@ pub struct PkgConfig {
7788 cflags : Vec < String > ,
7889
7990 conflicts : Vec < String > ,
91+
92+ dedup : PkgConfigDedupInformation ,
8093}
8194
8295impl PkgConfig {
@@ -99,19 +112,53 @@ impl PkgConfig {
99112 Some ( reqs) => reqs. split ( ',' ) . map ( |s| s. trim ( ) . to_string ( ) ) . collect ( ) ,
100113 _ => Vec :: new ( ) ,
101114 } ;
115+
116+ let requires_libs = {
117+ let cfg = {
118+ let mut c = pkg_config:: Config :: new ( ) ;
119+ // This is not sinkholed by cargo-c
120+ c. env_metadata ( false ) ;
121+
122+ c
123+ } ;
124+
125+ // TODO: log which probe fails
126+ requires
127+ . iter ( )
128+ . flat_map ( |req| cfg. probe ( req) )
129+ . collect :: < Vec < _ > > ( )
130+ } ;
131+
102132 let requires_private = match & capi_config. pkg_config . requires_private {
103133 Some ( reqs) => reqs. split ( ',' ) . map ( |s| s. trim ( ) . to_string ( ) ) . collect ( ) ,
104134 _ => Vec :: new ( ) ,
105135 } ;
106136
137+ let requires_private_libs = {
138+ let cfg = {
139+ let mut c = pkg_config:: Config :: new ( ) ;
140+ c. statik ( true ) ;
141+ // This is not sinkholed by cargo-c
142+ c. env_metadata ( false ) ;
143+
144+ c
145+ } ;
146+
147+ // TODO: log which probe fails
148+ requires_private
149+ . iter ( )
150+ . flat_map ( |req| cfg. probe ( req) )
151+ . collect :: < Vec < _ > > ( )
152+ } ;
153+
107154 let mut libdir = PathBuf :: new ( ) ;
108155 libdir. push ( "${libdir}" ) ;
109156 if let Some ( subdir) = & capi_config. library . install_subdir {
110157 libdir. push ( subdir) ;
111158 }
112159
113160 let libs = vec ! [
114- format!( "-L{}" , libdir. display( ) ) ,
161+ format!( "-L{}" , canonicalize ( libdir. display( ) . to_string ( ) ) ) ,
115162 format!( "-l{}" , capi_config. library. name) ,
116163 ] ;
117164
@@ -146,6 +193,11 @@ impl PkgConfig {
146193 cflags : vec ! [ cflags] ,
147194
148195 conflicts : Vec :: new ( ) ,
196+
197+ dedup : PkgConfigDedupInformation {
198+ requires : requires_libs,
199+ requires_private : requires_private_libs,
200+ } ,
149201 }
150202 }
151203
@@ -236,7 +288,75 @@ impl PkgConfig {
236288 self . render_help ( String :: with_capacity ( 1024 ) ) . unwrap ( )
237289 }
238290
291+ fn get_libs_cflags ( arg : & [ pkg_config:: Library ] ) -> ( HashSet < String > , HashSet < String > ) {
292+ let mut libs: HashSet < String > = HashSet :: new ( ) ;
293+ let mut cflags: HashSet < String > = HashSet :: new ( ) ;
294+
295+ for lib in arg. iter ( ) {
296+ for lib in lib. include_paths . iter ( ) {
297+ libs. insert ( format ! ( "-I{}" , lib. to_string_lossy( ) ) ) ;
298+ }
299+ for lib in lib. link_files . iter ( ) {
300+ libs. insert ( lib. to_string_lossy ( ) . to_string ( ) ) ;
301+ }
302+ for lib in lib. libs . iter ( ) {
303+ libs. insert ( format ! ( "-l{}" , lib) ) ;
304+ }
305+ for lib in lib. link_paths . iter ( ) {
306+ libs. insert ( format ! ( "-L{}" , lib. to_string_lossy( ) ) ) ;
307+ }
308+ for lib in lib. frameworks . iter ( ) {
309+ libs. insert ( format ! ( "-framework {}" , lib) ) ;
310+ }
311+ for lib in lib. framework_paths . iter ( ) {
312+ libs. insert ( format ! ( "-F{}" , lib. to_string_lossy( ) ) ) ;
313+ }
314+ for lib in lib. defines . iter ( ) {
315+ let v = match lib. 1 {
316+ Some ( v) => format ! ( "-D{}={}" , lib. 0 , v) ,
317+ None => format ! ( "D{}" , lib. 0 ) ,
318+ } ;
319+ libs. insert ( v) ;
320+ }
321+ for lib in lib. ld_args . iter ( ) {
322+ cflags. insert ( format ! ( "-Wl,{}" , lib. join( "," ) ) ) ;
323+ }
324+ }
325+
326+ ( libs, cflags)
327+ }
328+
329+ fn dedup_libs_cflags (
330+ requires : & [ pkg_config:: Library ] ,
331+ flags : & [ String ] ,
332+ ) -> ( String , String ) {
333+ let ( libs, cflags) = PkgConfig :: get_libs_cflags ( requires) ;
334+
335+ let libs = flags
336+ . iter ( )
337+ . filter ( |lib| !libs. contains ( lib. as_str ( ) ) )
338+ . map ( |lib| lib. as_str ( ) )
339+ . collect :: < Vec < _ > > ( )
340+ . join ( " " ) ;
341+ let cflags = flags
342+ . iter ( )
343+ . filter ( |lib| !cflags. contains ( lib. as_str ( ) ) )
344+ . map ( |lib| lib. as_str ( ) )
345+ . collect :: < Vec < _ > > ( )
346+ . join ( " " ) ;
347+
348+ ( libs, cflags)
349+ }
350+
239351 fn render_help < W : core:: fmt:: Write > ( & self , mut w : W ) -> Result < W , core:: fmt:: Error > {
352+ // Dedup
353+ // What libs are already known here?
354+ let ( dedup_libs, dedup_cflags) =
355+ PkgConfig :: dedup_libs_cflags ( & self . dedup . requires , & self . libs ) ;
356+
357+ let ( dedup_libs_private, dedup_cflags_private) =
358+ PkgConfig :: dedup_libs_cflags ( & self . dedup . requires_private , & self . libs_private ) ;
359+
240360 writeln ! ( w, "prefix={}" , canonicalize( & self . prefix) ) ?;
241361 writeln ! ( w, "exec_prefix={}" , canonicalize( & self . exec_prefix) ) ?;
242362 writeln ! ( w, "libdir={}" , canonicalize( & self . libdir) ) ?;
@@ -247,15 +367,15 @@ impl PkgConfig {
247367 writeln ! ( w, "Name: {}" , self . name) ?;
248368 writeln ! ( w, "Description: {}" , self . description. replace( '\n' , " " ) ) ?; // avoid endlines
249369 writeln ! ( w, "Version: {}" , self . version) ?;
250- writeln ! ( w, "Libs: {}" , self . libs . join ( " " ) ) ?;
251- writeln ! ( w, "Cflags: {}" , self . cflags . join ( " " ) ) ?;
370+ writeln ! ( w, "Libs: {}" , dedup_libs ) ?;
371+ writeln ! ( w, "Cflags: {}" , dedup_cflags ) ?;
252372
253373 if !self . libs_private . is_empty ( ) {
254- writeln ! ( w, "Libs.private: {}" , self . libs_private . join ( " " ) ) ?;
374+ writeln ! ( w, "Libs.private: {}" , dedup_libs_private ) ?;
255375 }
256376
257377 if !self . requires . is_empty ( ) {
258- writeln ! ( w, "Requires: {}" , self . requires . join ( ", " ) ) ?;
378+ writeln ! ( w, "Requires: {}" , dedup_cflags_private ) ?;
259379 }
260380
261381 if !self . requires_private . is_empty ( ) {
0 commit comments