1# Copyright 2003 Dave Abrahams
2# Copyright 2002, 2003 Rene Rivera
3# Copyright 2002, 2003, 2004, 2005 Vladimir Prus
4# Distributed under the Boost Software License, Version 1.0.
5# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
6
7# Defines the "symlink" special target. 'symlink' targets make symbolic links
8# to the sources.
9
10import targets modules path class os feature project property-set ;
11
12.count = 0 ;
13
14feature.feature symlink-location : project-relative build-relative : incidental ;
15
16# The class representing "symlink" targets.
17#
18class symlink-targets : basic-target
19{
20    import numbers modules class property project path ;
21
22    rule __init__ (
23      project
24        : targets *
25        : sources *
26    )
27    {
28        # Generate a fake name for now. Need unnamed targets eventually.
29        local c = [ modules.peek symlink : .count ] ;
30        modules.poke symlink : .count : [ numbers.increment $(c) ] ;
31        local fake-name = symlink#$(c) ;
32
33          basic-target.__init__ $(fake-name) : $(project) : $(sources) ;
34
35        # Remember the targets to map the sources onto. Pad or truncate
36        # to fit the sources given.
37        self.targets = ;
38        for local source in $(sources)
39        {
40            if $(targets)
41            {
42                self.targets += $(targets[1]) ;
43                targets = $(targets[2-]) ;
44            }
45            else
46            {
47                self.targets += $(source) ;
48            }
49        }
50
51        # The virtual targets corresponding to the given targets.
52        self.virtual-targets = ;
53    }
54
55    rule construct ( name : source-targets * : property-set )
56    {
57        local i = 1 ;
58        for local t in $(source-targets)
59        {
60            local s = $(self.targets[$(i)]) ;
61            local a = [ class.new action  $(t) : symlink.ln : $(property-set) ] ;
62            local vt = [ class.new file-target $(s:D=)
63              : [ $(t).type ] : $(self.project) : $(a) ] ;
64
65            # Place the symlink in the directory relative to the project
66            # location, instead of placing it in the build directory.
67            if [ property.select <symlink-location> : [ $(property-set).raw ] ] = <symlink-location>project-relative
68            {
69                $(vt).set-path [ path.root $(s:D) [ $(self.project).get location ] ] ;
70            }
71
72            self.virtual-targets += $(vt) ;
73            i = [ numbers.increment $(i) ] ;
74        }
75        return [ property-set.empty ] $(self.virtual-targets) ;
76    }
77}
78
79# Creates a symbolic link from a set of targets to a set of sources.
80# The targets and sources map one to one. The symlinks generated are
81# limited to be the ones given as the sources. That is, the targets
82# are either padded or trimmed to equate to the sources. The padding
83# is done with the name of the corresponding source. For example::
84#
85#     symlink : one two ;
86#
87# Is equal to::
88#
89#     symlink one two : one two ;
90#
91# Names for symlink are relative to the project location. They cannot
92# include ".." path components.
93rule symlink (
94    targets *
95    : sources *
96    )
97{
98    local project = [ project.current ] ;
99
100    return [ targets.main-target-alternative
101        [ class.new symlink-targets $(project) : $(targets) :
102          # Note: inline targets are not supported for symlink, intentionally,
103          # since it's used to linking existing non-local targets.
104          $(sources) ] ] ;
105}
106
107rule ln
108{
109    local os ;
110    if [ modules.peek : UNIX ] { os = UNIX ; }
111    else { os ?= [ os.name ] ; }
112    # Remember the path to make the link relative to where the symlink is located.
113    local path-to-source = [ path.relative-to
114        [ path.make [ on $(<) return $(LOCATE) ] ]
115        [ path.make [ on $(>) return $(LOCATE) ] ] ] ;
116    if $(path-to-source) = .
117    {
118        PATH_TO_SOURCE on $(<) = "" ;
119    }
120    else
121    {
122        PATH_TO_SOURCE on $(<) = [ path.native $(path-to-source) ] ;
123    }
124    ln-$(os) $(<) : $(>) ;
125}
126
127actions ln-UNIX
128{
129    ln -f -s '$(>:D=:R=$(PATH_TO_SOURCE))' '$(<)'
130}
131
132# there is a way to do this; we fall back to a copy for now
133actions ln-NT
134{
135    echo "NT symlinks not supported yet, making copy"
136    del /f /q "$(<)" 2>nul >nul
137    copy "$(>)" "$(<)" $(NULL_OUT)
138}
139
140IMPORT $(__name__) : symlink : : symlink ;
141