@@ -208,12 +208,72 @@ impl fmt::Display for Error {
208
208
ref command,
209
209
ref output,
210
210
} => {
211
- write ! (
211
+ let crate_name =
212
+ env:: var ( "CARGO_PKG_NAME" ) . unwrap_or ( String :: from ( "<NO CRATE NAME>" ) ) ;
213
+
214
+ writeln ! ( f, "" ) ?;
215
+
216
+ // Give a short explanation of what the error is
217
+ writeln ! (
212
218
f,
213
- "`{}` did not exit successfully: {}\n error: could not find system library '{}' required by the '{}' crate\n " ,
214
- command, output. status, name, env:: var( "CARGO_PKG_NAME" ) . unwrap_or_default( ) ,
219
+ "pkg-config {}" ,
220
+ match output. status. code( ) {
221
+ Some ( code) => format!( "exited with status code {}" , code) ,
222
+ None => "was terminated by signal" . to_string( ) ,
223
+ }
215
224
) ?;
216
- format_output ( output, f)
225
+
226
+ // Give the command run so users can reproduce the error
227
+ writeln ! ( f, "> {}\n " , command) ?;
228
+
229
+ // Explain how it was caused
230
+ writeln ! (
231
+ f,
232
+ "The system library `{}` required by crate `{}` was not found." ,
233
+ name, crate_name
234
+ ) ?;
235
+ writeln ! (
236
+ f,
237
+ "The file `{}.pc` needs to be installed and the PKG_CONFIG_PATH environment variable must contain its parent directory." ,
238
+ name
239
+ ) ?;
240
+
241
+ // There will be no status code if terminated by signal
242
+ if let Some ( _code) = output. status . code ( ) {
243
+ // NixOS uses a wrapper script for pkg-config that sets the custom
244
+ // environment variable PKG_CONFIG_PATH_FOR_TARGET
245
+ let search_path =
246
+ if let Ok ( path_for_target) = env:: var ( "PKG_CONFIG_PATH_FOR_TARGET" ) {
247
+ Some ( path_for_target)
248
+ } else if let Ok ( path) = env:: var ( "PKG_CONFIG_PATH" ) {
249
+ Some ( path)
250
+ } else {
251
+ None
252
+ } ;
253
+
254
+ // Guess the most reasonable course of action
255
+ let hint = if let Some ( search_path) = search_path {
256
+ writeln ! (
257
+ f,
258
+ "PKG_CONFIG_PATH contains the following:\n {}" ,
259
+ search_path
260
+ . split( ':' )
261
+ . map( |path| format!( " - {}" , path) )
262
+ . collect:: <Vec <String >>( )
263
+ . join( "\n " ) ,
264
+ ) ?;
265
+
266
+ format ! ( "you may need to install a package such as {name}, {name}-dev or {name}-devel." , name=name)
267
+ } else {
268
+ writeln ! ( f, "PKG_CONFIG_PATH environment variable is not set" ) ?;
269
+ format ! ( "If you have installed the library, try adding its parent directory to your PATH." )
270
+ } ;
271
+
272
+ // Try and nudge the user in the right direction so they don't get stuck
273
+ writeln ! ( f, "\n HINT: {}" , hint) ?;
274
+ }
275
+
276
+ Ok ( ( ) )
217
277
}
218
278
Error :: Failure {
219
279
ref command,
@@ -498,8 +558,34 @@ impl Config {
498
558
if output. status . success ( ) {
499
559
Ok ( output. stdout )
500
560
} else {
561
+ // Collect all explicitly-defined environment variables
562
+ // this is used to display the equivalent pkg-config shell invocation
563
+ let envs = cmd
564
+ . get_envs ( )
565
+ . map ( |( env, optional_arg) | {
566
+ if let Some ( arg) = optional_arg {
567
+ format ! ( "{}={}" , env. to_string_lossy( ) , arg. to_string_lossy( ) )
568
+ } else {
569
+ env. to_string_lossy ( ) . to_string ( )
570
+ }
571
+ } )
572
+ . collect :: < Vec < String > > ( ) ;
573
+
574
+ // Collect arguments for the same reason
575
+ let args = cmd
576
+ . get_args ( )
577
+ . map ( |arg| arg. to_string_lossy ( ) . to_string ( ) )
578
+ . collect :: < Vec < String > > ( ) ;
579
+
580
+ // This will look something like:
581
+ // PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs --cflags {library}
501
582
Err ( Error :: Failure {
502
- command : format ! ( "{:?}" , cmd) ,
583
+ command : format ! (
584
+ "{} {} {}" ,
585
+ envs. join( " " ) ,
586
+ cmd. get_program( ) . to_string_lossy( ) ,
587
+ args. join( " " )
588
+ ) ,
503
589
output,
504
590
} )
505
591
}
0 commit comments