]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/tools/link.jam
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / tools / build / src / tools / link.jam
1 # Copyright 2012 Steven Watanabe
2 # Distributed under the Boost Software License, Version 1.0.
3 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
4
5 import os ;
6 import targets ;
7 import project ;
8 import "class" : new ;
9 import virtual-target ;
10 import configure ;
11 import path ;
12 import property ;
13 import property-set ;
14 import common ;
15
16 rule get-root-project ( project )
17 {
18 # Find the root project.
19 local root-project = $(project) ;
20 root-project = [ $(root-project).project-module ] ;
21 while
22 [ project.attribute $(root-project) parent-module ] &&
23 [ project.attribute $(root-project) parent-module ] != user-config &&
24 [ project.attribute $(root-project) parent-module ] != project-config
25 {
26 root-project = [ project.attribute $(root-project) parent-module ] ;
27 }
28 return $(root-project) ;
29 }
30
31 TOUCH = [ common.file-touch-command ] ;
32
33 actions touch {
34 $(TOUCH) "$(<)"
35 }
36
37 rule can-symlink ( project : ps )
38 {
39 if ! $(.can-symlink)
40 {
41 local root-project = [ get-root-project $(project) ] ;
42
43 local source-target = [ new file-target test-symlink-source : :
44 $(project) : [ new action : link.touch ] ] ;
45 local target = [ new file-target test-symlink : :
46 $(project) : [ new action $(source-target) : link.mklink ] ] ;
47
48 if [ configure.try-build $(target) : $(ps) : "symlinks supported" ]
49 {
50 .can-symlink = true ;
51 }
52 else
53 {
54 .can-symlink = false ;
55 }
56 }
57 if $(.can-symlink) = true
58 {
59 return true ;
60 }
61 }
62
63 if [ os.name ] = NT
64 {
65
66 # Test for Windows junctions (mklink /J)
67 rule can-junction ( project : ps )
68 {
69 if ! $(.can-junction)
70 {
71 local root-project = [ get-root-project $(project) ] ;
72
73 local source-target = [ new file-target test-junction-source : :
74 $(project) : [ new action : common.mkdir ] ] ;
75 local target = [ new file-target test-junction : :
76 $(project) : [ new action $(source-target) : link.junction ] ] ;
77
78 if [ configure.try-build $(target) : $(ps) : "junctions supported" ]
79 {
80 .can-junction = true ;
81 }
82 else
83 {
84 .can-junction = false ;
85 }
86 }
87 if $(.can-junction) = true
88 {
89 return true ;
90 }
91 }
92
93 }
94 else
95 {
96
97 .can-junction = false ;
98
99 rule can-junction ( project : ps )
100 {
101 }
102
103 }
104
105 rule can-hardlink ( project : ps )
106 {
107 if ! $(.can-hardlink)
108 {
109 local root-project = [ get-root-project $(project) ] ;
110
111 local source-target = [ new file-target test-hardlink-source : :
112 $(project) : [ new action : link.touch ] ] ;
113 # Use <location-prefix> so that the destination link is created
114 # in a different directory. AFS refuses to make hard links
115 # between files in different directories, so we want to check
116 # it.
117 local target = [ new file-target test-hardlink : :
118 $(project) : [ new action $(source-target) : link.hardlink
119 : [ new property-set <location-prefix>symlink ]
120 ] ] ;
121
122 if [ configure.try-build $(target) : $(ps) : "hardlinks supported" ]
123 {
124 .can-hardlink = true ;
125 }
126 else
127 {
128 .can-hardlink = false ;
129 }
130 }
131 if $(.can-hardlink) = true
132 {
133 return true ;
134 }
135 }
136
137 class file-or-directory-reference : basic-target
138 {
139 import virtual-target ;
140 import property-set ;
141 import path ;
142
143 rule construct ( name : source-targets * : property-set )
144 {
145 return [ property-set.empty ] [ virtual-target.from-file $(self.name) :
146 [ location ] : $(self.project) ] ;
147 }
148
149 # Returns true if the referred file really exists.
150 rule exists ( )
151 {
152 location ;
153 return $(self.file-path) ;
154 }
155
156 # Returns the location of target. Needed by 'testing.jam'.
157 rule location ( )
158 {
159 if ! $(self.file-location)
160 {
161 local source-location = [ $(self.project).get source-location ] ;
162 for local src-dir in $(source-location)
163 {
164 if ! $(self.file-location)
165 {
166 local location = [ path.root $(self.name) $(src-dir) ] ;
167 if [ path.exists [ path.native $(location) ] ]
168 {
169 self.file-location = $(src-dir) ;
170 self.file-path = $(location) ;
171 }
172 }
173 }
174 }
175 return $(self.file-location) ;
176 }
177 }
178
179 class symlink-target-class : basic-target
180 {
181 import path ;
182 import virtual-target ;
183 import link ;
184 import os ;
185 import type ;
186 rule construct ( name : source-target : property-set )
187 {
188 local location = [ path.join
189 [ $(source-target).path ] [ $(source-target).name ] ] ;
190 local files = [ path.glob-tree $(location) : * ] ;
191 local targets ;
192
193 # If we have symlinks, don't bother checking
194 # for hardlinks and junctions.
195 if ! [ link.can-symlink $(self.project) : $(property-set) ]
196 {
197 link.can-junction $(self.project) : $(property-set) ;
198 link.can-hardlink $(self.project) : $(property-set) ;
199 }
200
201 if [ $(property-set).get <location> ]
202 {
203 property-set = [ property-set.create
204 [ property.select <location> : [ $(property-set).raw ] ] ] ;
205 }
206 else
207 {
208 local path,relative-to-build-dir = [ $(property-set).target-path ] ;
209 local path = $(path,relative-to-build-dir[1]) ;
210 local relative-to-build-dir = $(path,relative-to-build-dir[2]) ;
211
212 if $(relative-to-build-dir)
213 {
214 path = [ path.join [ $(self.project).build-dir ] $(path) ] ;
215 }
216
217 property-set = [ property-set.create <location>$(path) ] ;
218 }
219
220 local a = [ new non-scanning-action $(source-target) :
221 link.do-link-recursively : $(property-set) ] ;
222
223 local t = [ new notfile-target $(name)
224 : $(self.project) : $(a) ] ;
225
226 return [ property-set.empty ] [ virtual-target.register $(t) ] ;
227 }
228 }
229
230 rule do-file-link
231 {
232 local target = [ path.native [ path.relative-to [ path.pwd ] $(<) ] ] ;
233 local source = [ path.native [ path.relative-to [ path.pwd ] $(>) ] ] ;
234 local old-source = [ on $(target) return $(LINK-SOURCE) ] ;
235 if $(old-source)
236 {
237 import errors ;
238 errors.user-error
239 Cannot create link $(target) to $(source). :
240 Link previously defined to another file, $(old-source[1]). ;
241 }
242 LINK-SOURCE on $(target) = $(source) $(.current-target) ;
243 LOCATE on $(target) = . ;
244 DEPENDS $(.current-target) : $(target) ;
245 if $(.can-symlink) = true
246 {
247 DEPENDS $(target) : $(source) ;
248 link.mklink $(target) : $(source) ;
249 }
250 else if $(.can-hardlink) = true
251 {
252 DEPENDS $(target) : $(source) ;
253 link.hardlink $(target) : $(source) ;
254 }
255 else
256 {
257 DEPENDS $(target) : $(source) ;
258 common.copy $(target) : $(source) ;
259 }
260 }
261
262 rule do-link
263 {
264 local target = [ path.native [ path.relative-to [ path.pwd ] $(<) ] ] ;
265 local source = [ path.native [ path.relative-to [ path.pwd ] $(>) ] ] ;
266 local relative = [ path.native [ path.relative-to [ path.parent $(<) ] $(>) ] ] ;
267 if ! [ on $(target) return $(MKLINK_OR_DIR) ]
268 {
269 LOCATE on $(target) = . ;
270 DEPENDS $(.current-target) : $(target) ;
271 mklink-or-dir $(target) : $(source) ;
272 }
273 if [ os.name ] = NT
274 {
275 if $(.can-symlink) = true
276 {
277 MKLINK_OR_DIR on $(target) = mklink /D \"$(target)\" \"$(relative)\" ;
278 }
279 else
280 {
281 # This function should only be called
282 # if either symlinks or junctions are supported.
283 # To get here $(.can-junction) must be true.
284 mklink-opt = /J ;
285 MKLINK_OR_DIR on $(target) = mklink /J \"$(target)\" \"$(source)\" ;
286 }
287 }
288 else
289 {
290 MKLINK_OR_DIR on $(target) = ln -s $(relative) $(target) ;
291 }
292 }
293
294 rule force-update
295 {
296 local target = [ path.native [ path.relative-to [ path.pwd ] $(<) ] ] ;
297 ALWAYS $(target) ;
298 }
299
300 rule do-split
301 {
302 local target = [ path.native [ path.relative-to [ path.pwd ] $(<) ] ] ;
303 if ! [ on $(target) return $(MKLINK_OR_DIR) ]
304 {
305 LOCATE on $(target) = . ;
306 DEPENDS $(.current-target) : $(target) ;
307 common.mkdir $(target) ;
308 }
309 MKLINK_OR_DIR on $(target) = mkdir \"$(target)\" ;
310 }
311
312 rule do-rm
313 {
314 local target = [ path.native [ path.relative-to [ path.pwd ] $(<) ] ] ;
315 ALWAYS $(target) ;
316 RM on $(target) = rmdir ;
317 link.rm $(target) ;
318 }
319
320 rule mklink-or-dir
321 {
322 NOUPDATE $(<) ;
323 }
324
325 actions mklink-or-dir
326 {
327 $(MKLINK_OR_DIR)
328 }
329
330 rule link-entries ( target : files * : split ? : deleted ? )
331 {
332 for local s in $(files)
333 {
334 local t = [ path.join $(target) [ path.basename $(s) ] ] ;
335 if ! $(.known-dirs.$(t))
336 {
337 local t = [ path.native [ path.relative-to [ path.pwd ] $(t) ] ] ;
338 local s = [ path.native [ path.relative-to [ path.pwd ] $(target) ] ] ;
339 LOCATE on $(t) = . ;
340 DEPENDS $(t) : $(s) ;
341 NOUPDATE $(s) ;
342 }
343 if $(split)
344 {
345 link-recursively $(t) : $(s) : : $(deleted) ;
346 }
347 else
348 {
349 link-entries $(t) : [ path.glob $(s) : * ] ;
350 }
351 }
352 if ! $(.known-dirs.$(target))
353 {
354 .known-dirs.$(target) += $(files) ;
355 .known-dirs.base.$(target) = $(.current-target) ;
356 }
357 }
358
359 rule link-recursively ( target : source : no-recurse ? : deleted ? )
360 {
361 if $(deleted) {
362 force-update $(target) ;
363 }
364
365 local split ;
366 if [ CHECK_IF_FILE [ path.native $(source) ] ]
367 {
368 do-file-link $(target) : $(source) ;
369 }
370 else if $(.known-dirs.$(target)) && ! $(no-recurse)
371 {
372 split = true ;
373 if ! $(.split-dirs.$(target))
374 {
375 if [ READLINK [ path.native $(target) ] ]
376 {
377 if ! $(deleted) {
378 do-rm $(target) ;
379 deleted = true ;
380 .deleted-dirs.$(target) = true ;
381 }
382 }
383 local .current-target = $(.known-dirs.base.$(target)) ;
384 for local s in $(.known-dirs.$(target))
385 {
386 local t = [ path.join $(target) [ path.basename $(s) ] ] ;
387 link-recursively $(t) : $(s) : flat : $(deleted) ;
388 }
389 do-split $(target) ;
390 }
391 else if $(.deleted-dirs.$(target))
392 {
393 deleted = true ;
394 }
395 }
396 else if [ path.exists [ path.native $(target) ] ] && ! $(deleted)
397 {
398 local link-target = [ READLINK [ path.native $(target) ] ] ;
399 if $(link-target)
400 {
401 local full-path =
402 [ path.root [ path.make $(link-target) ] [ path.parent $(target) ] ] ;
403 # HACK: Take advantage of the fact that path.glob
404 # normalizes its arguments. If full-path and
405 # source are different, but both are empty, they
406 # will compare equal, but that's okay because
407 # for the purposes of this module, empty directories
408 # are equivalent.
409 if [ path.glob $(full-path) : * ] != [ path.glob $(source) : * ]
410 {
411 if ! $(deleted) {
412 do-rm $(target) ;
413 deleted = true ;
414 .deleted-dirs.$(target) = true ;
415 }
416 do-split $(target) ;
417 split = true ;
418 }
419 }
420 else
421 {
422 do-split $(target) ;
423 split = true ;
424 }
425 }
426 else if $(.can-symlink) = false && $(.can-junction) = false
427 {
428 if [ READLINK [ path.native $(target) ] ]
429 {
430 if ! $(deleted) {
431 do-rm $(target) ;
432 deleted = true ;
433 .deleted-dirs.$(target) = true ;
434 }
435 }
436 do-split $(target) ;
437 split = true ;
438 }
439 else
440 {
441 do-link $(target) : $(source) ;
442 }
443
444 if $(split)
445 {
446 .split-dirs.$(target) = true ;
447 }
448
449 if ! $(no-recurse)
450 {
451 link-entries $(target) : [ path.glob $(source) : * ] : $(split) : $(deleted) ;
452 }
453 }
454
455 rule do-link-recursively ( target : source : properties * )
456 {
457 local target-path = [ property.select <location> : $(properties) ] ;
458 local source-path = [ on $(source) return $(LOCATE) ] [ on $(source) return $(SEARCH) ] ;
459
460 local absolute-target = [ path.root
461 [ path.join [ path.make $(target-path[1]:G=) ]
462 [ path.basename [ path.make $(source:G=) ] ] ]
463 [ path.pwd ] ] ;
464
465 local absolute-source = [ path.root
466 [ path.root [ path.make $(source:G=) ]
467 [ path.make $(source-path[1]) ] ]
468 [ path.pwd ] ] ;
469
470 local .current-target = $(target) ;
471
472 link-recursively $(absolute-target) : $(absolute-source) ;
473 }
474
475 rule mklink
476 {
477 local target-path = [ on $(<) return $(LOCATE) ] [ on $(<) return $(SEARCH) ] . ;
478 local source-path = [ on $(>) return $(LOCATE) ] [ on $(>) return $(SEARCH) ] . ;
479 local relative-path = [ path.relative-to
480 [ path.parent [ path.join [ path.root [ path.make $(target-path[1]) ] [ path.pwd ] ] [ path.make $(<:G=) ] ] ]
481 [ path.join [ path.root [ path.make $(source-path[1]) ] [ path.pwd ] ] [ path.make $(>:G=) ] ] ] ;
482
483 PATH_TO_SOURCE on $(<) = [ path.native $(relative-path) ] ;
484 }
485
486 if [ os.name ] = NT
487 {
488
489 actions junction
490 {
491 if exist "$(<)" rmdir "$(<)"
492 mklink /J "$(<)" "$(>)"
493 }
494
495 actions mklink
496 {
497 if exist "$(<)" del "$(<)"
498 mklink "$(<)" "$(PATH_TO_SOURCE)"
499 }
500
501 actions hardlink
502 {
503 if exist "$(<)" del "$(<)"
504 mklink /H "$(<)" "$(>)"
505 }
506
507 actions rm
508 {
509 rmdir "$(<)"
510 }
511
512 }
513 else
514 {
515
516 actions mklink
517 {
518 ln -f -s "$(PATH_TO_SOURCE)" "$(<)"
519 }
520
521 actions hardlink
522 {
523 ln -f "$(>)" "$(<)"
524 }
525
526 actions rm
527 {
528 rm "$(<)"
529 }
530
531 }
532
533 rule link-directory ( name : sources : requirements * : default-build * : usage-requirements * )
534 {
535 local project = [ project.current ] ;
536 sources = [ new file-or-directory-reference $(sources) : $(project) ] ;
537 targets.main-target-alternative $(sources) ;
538 return [ targets.main-target-alternative
539 [ new symlink-target-class $(name) : $(project)
540 : [ targets.main-target-sources $(sources) : $(name) : no-renaming ]
541 : [ targets.main-target-requirements $(requirements) : $(project) ]
542 : [ targets.main-target-default-build : $(project) ]
543 : [ targets.main-target-usage-requirements $(usage-requirements) :
544 $(project) ] ] ] ;
545 }
546
547 IMPORT $(__name__) : link-directory : : link-directory ;