]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/tools/pkg-config.jam
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / tools / build / src / tools / pkg-config.jam
1 #|
2 Copyright 2019 Dmitry Arkhipov
3 Distributed under the Boost Software License, Version 1.0. (See
4 accompanying file LICENSE_1_0.txt or copy at
5 http://www.boost.org/LICENSE_1_0.txt)
6 |#
7
8
9 import "class" : new ;
10 import common ;
11 import errors ;
12 import feature ;
13 import os ;
14 import param ;
15 import project ;
16 import regex ;
17 import sequence ;
18 import string ;
19 import targets ;
20
21
22 #| tag::doc[]
23
24 = pkg-config
25 The *pkg-config* program is used to retrieve information about installed
26 libraries in the system. It retrieves information about packages from special
27 metadata files. These files are named after the package, and have a `.pc`
28 extension. The package name specified to *pkg-config* is defined to be the name
29 of the metadata file, minus the `.pc` extension.
30
31 |# # end::doc[]
32
33
34 #| tag::doc[]
35
36 == Feature: `pkg-config`
37
38 Selects one of the initialized `pkg-config` configurations. This feature is
39 `propagated` to dependencies. Its use is dicussed in
40 section <<pkg-config-init>>.
41
42 |# # end::doc[]
43
44 feature.feature pkg-config : : propagated ;
45
46
47 #| tag::doc[]
48
49 == Feature: `pkg-config-define`
50
51 This `free` feature adds a variable assignment to pkg-config invocation. For
52 example,
53
54 [source, jam]
55 ----
56 pkg-config.import mypackage : requirements <pkg-config-define>key=value ;
57 ----
58
59 is equivalent to invoking on the comand line
60
61 [source, shell]
62 ----
63 pkg-config --define-variable=key=value mypackage ;
64 ----
65
66 |# # end::doc[]
67
68 feature.feature pkg-config-define : : free ;
69
70
71 #| tag::doc[]
72
73 == Rule: `import`
74
75 Main target rule that imports a *pkg-config* package. When its consumer targets
76 are built, *pkg-config* command will be invoked with arguments that depend on
77 current property set. The features that have an effect are:
78
79 * `<pkg-config-define>`: adds a `--define-variable` argument;
80 * `<link>`: adds `--static` argument when `<link>static`;
81 * `<link>`: adds `--static` argument when `<link>static`;
82 * `<name>`: specifies package name (target name is used instead if the property
83 is not present);
84 * `<version>`: specifies package version range, can be used multiple times and
85 should be a dot-separated sequence of numbers optionally prefixed with `=`,
86 `<`, `>`, `<=` or `>=`.
87
88 Example:
89
90 [source, jam]
91 ----
92 pkg-config.import my-package
93 : requirements <name>my_package <version><4 <version>>=3.1 ;
94 ----
95
96 |# # end::doc[]
97
98
99 rule import
100 ( target-name
101 : sources *
102 : requirements *
103 : default-build *
104 : usage-requirements *
105 )
106 {
107 param.handle-named-params
108 sources requirements default-build usage-requirements ;
109 targets.create-metatarget pkg-config-target
110 : [ project.current ]
111 : $(target-name)
112 : $(sources)
113 : $(requirements)
114 : $(default-build)
115 : $(usage-requirements)
116 ;
117 }
118
119
120 #| tag::doc[]
121
122 == Initialization [[ pkg-config-init ]]
123
124 To use the `pkg-config` tool you need to declare it in a configuration file
125 with the `using` rule:
126
127 [source, jam]
128 ----
129 using pkg-config : [config] : [command] ... : [ options ] ... ;
130 ----
131
132
133 * `config`: the name of initialized configuration. The name can be omitted, in
134 which case the configuration will become the default one.
135 * `command`: the command, with any extra arguments, to execute. If no command
136 is given, first `PKG_CONFIG` environment variable is checked, and if its
137 empty the string `pkg-config` is used.
138 * `options`: options that modify `pkg-config` behavior. Allowed options are:
139 * `<path>`: sets `PKG_CONFIG_PATH` environment variable;
140 multiple occurences are allowed.
141 * `<libdir>`: sets `PKG_CONFIG_LIBDIR` environment variable;
142 multiple occurences are allowed.
143 * `<allow-system-cflags>`: sets `PKG_CONFIG_ALLOW_SYSTEM_CFLAGS`
144 environment variable; multiple occurences are allowed.
145 * `<allow-system-libs>`: sets `PKG_CONFIG_ALLOW_SYSTEM_LIBS`
146 environment variable; multiple occurences are allowed.
147 * `<sysroot>`: sets `PKG_CONFIG_SYSROOT_DIR` environment variable;
148 multiple occurences are allowed.
149 * `<variable>`: adds a variable definition argument to command invocation;
150 multiple occurences are allowed.
151
152 |# # end::doc[]
153
154 rule init ( config ? : command * : options * )
155 {
156 config ?= [ default-config ] ;
157
158 local tool = [ os.environ PKG_CONFIG ] ;
159 tool ?= pkg-config ;
160 command =
161 [ common.get-invocation-command pkg-config : $(tool) : $(command) ] ;
162
163 configure $(config) : $(command) : $(options) ;
164 $(.configs).use $(config) ;
165 }
166
167
168 rule run ( config ? : args * )
169 {
170 config ?= [ default-config ] ;
171
172 local command = [ $(.configs).get $(config) : command ] ;
173 command = "$(command) $(args:J= )" ;
174
175 local output = [ SHELL "$(command)" : exit-status ] ;
176 if 0 != $(output[2])
177 {
178 errors.error "pkg-config: command '$(command)' resulted in error:"
179 [ common.newline-char ] $(output[1]) ;
180 }
181
182 local ws = [ string.whitespace ] ;
183 output = [ regex.split $(output[1]) "[$(ws)]" ] ;
184 return [ sequence.filter non-empty : $(output) ] ;
185 }
186
187
188 #| tag::doc[]
189
190 == Class `pkg-config-target`
191
192 [source, jam]
193 ----
194 class pkg-config-target : alias-target-class {
195 rule construct ( name : sources * : property-set )
196 rule version ( property-set )
197 rule variable ( name : property-set )
198 }
199 ----
200
201 The class of objects returned by `import` rule. The objects themselves could be
202 useful in situations that require more complicated logic for consuming a
203 package. See <<pkg-config-tips>> for examples.
204
205 . `rule construct ( name : sources * : property-set )`
206 Overrides `alias-target.construct`.
207
208 . `rule version ( property-set )`
209 Returns the package's version, in the context of `property-set`.
210
211 . `rule variable ( name : property-set )`
212 Returns the value of variable `name` in the package, in the context of
213 `property-set`.
214
215
216 |# # end::doc[]
217
218 class pkg-config-target : alias-target-class
219 {
220 import pkg-config ;
221 import regex ;
222
223 rule construct ( name : sources * : property-set )
224 {
225 local config = [ $(property-set).get <pkg-config> ] ;
226 local args = [ common-arguments $(name) : $(property-set) ] ;
227 return
228 [ property-set.create
229 [ compile-flags $(config) $(property-set) : $(args) ]
230 [ link-flags $(config) $(property-set) : $(args) ]
231 ] ;
232 }
233
234 rule version ( property-set )
235 {
236 local config = [ $(property-set).get <pkg-config> ] ;
237 local args = [ common-arguments [ name ] : $(property-set) ] ;
238 local version = [ pkg-config.run $(config) : --modversion $(args) ] ;
239 return [ regex.split $(version) "\\." ] ;
240 }
241
242 rule variable ( name : property-set )
243 {
244 local config = [ $(property-set).get <pkg-config> ] ;
245 local args = [ common-arguments [ name ] : $(property-set) ] ;
246 return [ pkg-config.run $(config) : --variable=$(name) $(args) ] ;
247 }
248
249 local rule common-arguments ( name : property-set )
250 {
251 local defines = [ $(property-set).get <pkg-config-define> ] ;
252 local args = --define-variable=$(defines) ;
253 if [ $(property-set).get <link> ] = static
254 {
255 args += --static ;
256 }
257 return $(args) [ get-package-request $(property-set) $(name) ] ;
258 }
259
260 local rule get-package-request ( property-set name )
261 {
262 local pkg-name = [ $(property-set).get <name> ] ;
263 pkg-name ?= $(name) ;
264 if $(pkg-name[2])
265 {
266 errors.error "multiple package names were specified for target "
267 "'$(name)': $(pkg-name)" ;
268 }
269
270 local versions ;
271 for local version in [ $(property-set).get <version> ]
272 {
273 local match = [ MATCH "^(<=)(.*)" : $(version) ] ;
274 match ?= [ MATCH "^(>=)(.*)" : $(version) ] ;
275 match ?= [ MATCH "^([><=])(.*)" : $(version) ] ;
276 if $(match)
277 {
278 version = " $(match:J= )" ;
279 }
280 else
281 {
282 version = " = $(version)" ;
283 }
284 versions += $(version) ;
285 }
286 versions ?= "" ;
287
288 return "'$(pkg-name)"$(versions)"'" ;
289 }
290
291 local rule link-flags ( config property-set : args * )
292 {
293 local flags = [ pkg-config.run $(config) : --libs $(args) ] ;
294 return <linkflags>$(flags) ;
295 }
296
297 local rule compile-flags ( config property-set : args * )
298 {
299 local flags = [ pkg-config.run $(config) : --cflags $(args) ] ;
300 return <cflags>$(flags) ;
301 }
302 }
303
304
305 local rule default-config ( )
306 {
307 return default ;
308 }
309
310
311 local rule configure ( config : command + : options * )
312 {
313 $(.configs).register $(config) ;
314
315 local path ;
316 local libdir ;
317 local allow-system-cflags ;
318 local allow-system-libs ;
319 local sysroot ;
320 local defines ;
321 for local opt in $(options)
322 {
323 switch $(opt:G)
324 {
325 case <path> : path += $(opt:G=) ;
326 case <libdir> : libdir += $(opt:G=) ;
327 case <allow-system-cflags> : allow-system-cflags += $(opt:G=) ;
328 case <allow-system-libs> : allow-system-libs += $(opt:G=) ;
329 case <sysroot> : sysroot += $(opt:G=) ;
330 case <variable> : defines += $(opt:G=) ;
331 case * :
332 errors.error "pkg-config: invalid property '$(opt)' was "
333 "specified for configuration '$(config)'." ;
334 }
335 }
336
337 for local opt in allow-system-cflags allow-system-libs
338 {
339 if ! $($(opt)) in "on" off
340 {
341 errors.error "pkg-config: invalid value '$($(opt))' was specified "
342 "for option <$(opt)> of configuration '$(config)'."
343 [ common.newline-char ] "Available values are 'on' and 'off'" ;
344 }
345 }
346
347 if $(sysroot[2])
348 {
349 errors.error "pkg-config: several values were specified for option "
350 "<sysroot> of configuration '$(config)'."
351 [ common.newline-char ] "Only one value is allowed." ;
352 }
353
354 local sep = [ os.path-separator ] ;
355 path = [ envar-set-command PKG_CONFIG_PATH : $(path:J=$(sep)) ] ;
356 libdir = [ envar-set-command PKG_CONFIG_LIBDIR : $(libdir:J=$(sep)) ] ;
357 sysroot = [ envar-set-command PKG_CONFIG_SYSROOT_DIR : $(sysroot) ] ;
358 allow-cflags =
359 [ envar-set-command PKG_CONFIG_ALLOW_SYSTEM_CFLAGS
360 : $(allow-cflags)
361 : 1
362 ] ;
363 allow-libs =
364 [ envar-set-command PKG_CONFIG_ALLOW_SYSTEM_LIBS
365 : $(allow-libs)
366 : 1
367 ] ;
368
369 command += --print-errors --errors-to-stdout --define-variable=$(defines) ;
370 $(.configs).set $(config)
371 : command
372 : "$(path)$(libdir)$(sysroot)$(allow-cflags)$(allow-libs)$(command:J= )"
373 ;
374
375 feature.extend pkg-config : $(config) ;
376 }
377
378
379 local rule envar-set-command ( envar : value * : implied-value * )
380 {
381 if $(value)
382 {
383 if $(implied-value)
384 {
385 value = $(implied-value) ;
386 }
387 return [ common.path-variable-setting-command $(envar) : $(value) ] ;
388 }
389 else
390 {
391 return "" ;
392 }
393 }
394
395
396 local rule non-empty ( string )
397 {
398 if $(string) != "" { return true ; }
399 }
400
401
402 .configs = [ new configurations ] ;
403
404
405 #| tag::doc[]
406
407 == Tips [[pkg-config-tips]]
408
409
410 === Using several configurations
411
412 Suppose, you have 2 collections of `.pc` files: one for platform A, and another
413 for platform B. You can initialize 2 configurations of `pkg-config` tool each
414 corresponding to specific collection:
415
416 [source, jam]
417 ----
418 using pkg-config : A : : <libdir>path/to/collection/A ;
419 using pkg-config : B : : <libdir>path/to/collection/B ;
420 ----
421
422 Then, you can specify that builds for platform A should use configuration A,
423 while builds for B should use configuration B:
424
425 [source, jam]
426 ----
427 project
428 : requirements
429 <target-os>A-os,<architecture>A-arch:<pkg-config>A
430 <target-os>B-os,<architecture>B-arch:<pkg-config>B
431 ;
432 ----
433
434 Thanks to the fact, that `project-config`, `user-config` and `site-config`
435 modules are parents of jamroot module, you can put it in any of those files.o
436
437
438 === Choosing the package name based on the property set
439
440 Since a file for a package should be named after the package suffixed with
441 `.pc`, some projects came up with naming schemes in order to allow simultaneous
442 installation of several major versions or build variants. In order to pick the
443 specific name corresponding to the build request you can use `<conditional>`
444 property in requirements:
445
446 [source, jam]
447 ----
448 pkg-config.import mypackage : requirements <conditional>@infer-name ;
449
450 rule infer-name ( properties * )
451 {
452 local name = mypackage ;
453 local variant = [ property.select <variant> : $(properties) ] ;
454 if $(variant) = debug
455 {
456 name += -d ;
457 }
458 return <name>$(name) ;
459 }
460 ----
461
462 The `common.format-name` rule can be very useful in this situation.
463
464
465 === Modify usage requirements based on package version or variable
466
467 Sometimes you need to apply some logic based on package's version or a
468 variable that it defines. For that you can use `<conditional>` property in
469 usage requirements:
470
471 ----
472 mypackage =
473 [ pkg-config.import mypackage : usage-requirements <conditional>@define_ns
474 ] ;
475
476 rule extra-props ( properties * )
477 {
478 local ps = [ property-set.create $(properties) ] ;
479 local prefix = [ $(mypackage).variable name_prefix : $(ps) ] ;
480 prefix += [ $(mypackage).version $(ps) ] ;
481 return <define>$(prefix:J=_) ;
482 }
483 ----
484
485 |# # end::doc[]