2 import os
, sys
, argparse
3 from collections
import OrderedDict
6 """Representation of a pkg-config file (.pc)"""
8 pc_variables
= OrderedDict()
9 pc_variables_expanded
= OrderedDict()
11 pc_keywords
= OrderedDict()
13 def __init__(self
, file):
15 self
.parse_pc_line(line
)
17 def parse_pc_line(self
, line
):
18 for i
, c
in enumerate(line
):
20 # This is a pkg-config variable line
21 key
= line
[:i
].strip()
22 val
= line
[(i
+ 1):].strip()
24 # Add unexpanded version of variable
25 self
.pc_variables
.update({ key
: val
})
27 # Add expanded version of variable
28 self
.pc_variables_expanded
.update({ key
: self
.expand_pc_vars(val
) })
31 # This is a pkg-config keyword line
32 key
= line
[:i
].strip()
33 val
= line
[(i
+ 1):].strip()
35 self
.pc_keywords
.update({ key
: val
})
38 def expand_pc_vars(self
, line
):
39 for key
, val
in self
.pc_variables_expanded
.items():
40 line
= line
.replace('${' + key
+ '}', val
)
43 def get_variable(self
, key
, expand
=True):
45 return self
.pc_variables_expanded
.get(key
, None)
47 return self
.pc_variables
.get(key
, None)
49 def get_keyword(self
, key
, expand
=True):
50 keyword
= self
.pc_keywords
.get(key
, None)
51 if expand
and keyword
!= None:
52 return self
.expand_pc_vars(keyword
)
56 def set_keyword(self
, key
, value
):
57 self
.pc_keywords
.update({ key
: value
})
59 def write(self
, file):
62 for key
, val
in self
.pc_variables
.items():
63 pc_contents
+= key
+ '=' + val
+ '\n'
66 for key
, val
in self
.pc_keywords
.items():
67 pc_contents
+= key
+ ': ' + val
+ '\n'
69 file.write(pc_contents
)
71 def remove_str_fix(text
, prefix
, suffix
):
72 start
= len(prefix
) if text
.startswith(prefix
) else 0
73 end_offset
= len(suffix
) if text
.endswith(suffix
) else 0
74 end
= len(text
) - end_offset
75 return text
[start
:end
]
77 def rewrite_abs_to_rel(pc_file
):
78 linker_args
= pc_file
.get_keyword('Libs', expand
=False)
79 if linker_args
is None:
80 raise KeyError('No "Libs" keyword in input .pc file found!')
81 linker_args_list
= linker_args
.split()
83 # Replace absolute library paths with relative ones
84 # i.e. /foo/bar/baz.a to -L/foo/bar -lbaz
87 for arg
in linker_args_list
:
88 if arg
.startswith('-L'):
90 path
= pc_file
.expand_pc_vars(path
)
91 lib_paths
.append(path
)
93 # Filter all absolute static library paths
94 if arg
.startswith('/') and arg
.endswith('.a'):
95 lib_path
= os
.path
.dirname(arg
)
96 lib_filename
= os
.path
.basename(arg
)
97 # Remove lib prefix and .a suffix
98 lib_name
= remove_str_fix(lib_filename
, 'lib', '.a')
99 if lib_path
not in lib_paths
:
100 out_args
.append('-L' + lib_path
)
101 lib_paths
.append(lib_path
)
102 out_args
.append('-l' + lib_name
)
106 linker_args
= ' '.join(out_args
)
107 pc_file
.set_keyword('Libs', linker_args
)
110 # Do argument parsing and other stuff needed
111 # for CLI usage here.
113 if not sys
.version_info
>= (3, 4):
114 print("Python version 3.4 or higher required!", file=sys
.stderr
)
118 parser
= argparse
.ArgumentParser()
119 parser
.add_argument('-i', '--input', required
=True)
120 parser
.add_argument('-o', '--output')
122 args
= parser
.parse_args()
124 # Default to input file (in-place editing) if no output file is given
125 args
.output
= args
.output
or args
.input
127 # Read .pc from input file
128 input_file
= sys
.stdin
if args
.input == '-' else open(args
.input, 'r')
129 pc_file
= PkgConfigFile(input_file
)
130 if input_file
is not sys
.stdin
:
133 rewrite_abs_to_rel(pc_file
)
136 output_file
= sys
.stdout
if args
.output
== '-' else open(args
.output
, 'w')
137 pc_file
.write(output_file
)
138 if output_file
is not sys
.stdout
:
143 if __name__
== "__main__":