1###########################
2# this handles the magic we need to do for installing
3# with all the configure options that affect rpath and shared
4# library use
5
6import os
7from waflib import Utils, Errors
8from waflib.TaskGen import feature, before, after
9from samba_utils import LIB_PATH, MODE_755, install_rpath, build_rpath
10
11@feature('install_bin')
12@after('apply_core')
13@before('apply_link', 'apply_obj_vars')
14def install_binary(self):
15    '''install a binary, taking account of the different rpath variants'''
16    bld = self.bld
17
18    # get the ldflags we will use for install and build
19    install_ldflags = install_rpath(self)
20    build_ldflags   = build_rpath(bld)
21
22    if not self.bld.is_install:
23        # just need to set rpath if we are not installing
24        self.env.RPATH = build_ldflags
25        return
26
27    # work out the install path, expanding variables
28    install_path = getattr(self, 'samba_inst_path', None) or '${BINDIR}'
29    install_path = bld.EXPAND_VARIABLES(install_path)
30
31    orig_target = os.path.basename(self.target)
32
33    if install_ldflags != build_ldflags:
34        # we will be creating a new target name, and using that for the
35        # install link. That stops us from overwriting the existing build
36        # target, which has different ldflags
37        self.target += '.inst'
38
39    # setup the right rpath link flags for the install
40    self.env.RPATH = install_ldflags
41
42    if not self.samba_install:
43        # this binary is marked not to be installed
44        return
45
46    # tell waf to install the right binary
47    bld.install_as(os.path.join(install_path, orig_target),
48                   self.path.find_or_declare(self.target),
49                   chmod=MODE_755)
50
51
52
53@feature('install_lib')
54@after('apply_core')
55@before('apply_link', 'apply_obj_vars')
56def install_library(self):
57    '''install a library, taking account of the different rpath variants'''
58    if getattr(self, 'done_install_library', False):
59        return
60
61    bld = self.bld
62
63    default_env = bld.all_envs['default']
64    try:
65        install_ldflags = install_rpath(self)
66        build_ldflags   = build_rpath(bld)
67
68        if not self.bld.is_install or not getattr(self, 'samba_install', True):
69            # just need to set the build rpath if we are not installing
70            self.env.RPATH = build_ldflags
71            return
72
73        # setup the install path, expanding variables
74        install_path = getattr(self, 'samba_inst_path', None)
75        if install_path is None:
76            if getattr(self, 'private_library', False):
77                install_path = '${PRIVATELIBDIR}'
78            else:
79                install_path = '${LIBDIR}'
80        install_path = bld.EXPAND_VARIABLES(install_path)
81
82        target_name = self.target
83
84        if install_ldflags != build_ldflags:
85            # we will be creating a new target name, and using that for the
86            # install link. That stops us from overwriting the existing build
87            # target, which has different ldflags
88            self.done_install_library = True
89            t = self.clone(self.env)
90            t.posted = False
91            t.target += '.inst'
92            t.name = self.name + '.inst'
93            self.env.RPATH = build_ldflags
94        else:
95            t = self
96
97        t.env.RPATH = install_ldflags
98
99        dev_link     = None
100
101        # in the following the names are:
102        # - inst_name is the name with .inst. in it, in the build
103        #   directory
104        # - install_name is the name in the install directory
105        # - install_link is a symlink in the install directory, to install_name
106
107        if getattr(self, 'samba_realname', None):
108            install_name = self.samba_realname
109            install_link = None
110            if getattr(self, 'soname', ''):
111                install_link = self.soname
112            if getattr(self, 'samba_type', None) == 'PYTHON':
113                inst_name    = bld.make_libname(t.target, nolibprefix=True, python=True)
114            else:
115                inst_name    = bld.make_libname(t.target)
116        elif self.vnum:
117            vnum_base    = self.vnum.split('.')[0]
118            install_name = bld.make_libname(target_name, version=vnum_base)
119            install_link = bld.make_libname(target_name, version=vnum_base)
120            inst_name    = bld.make_libname(t.target)
121            if not self.private_library or not t.env.SONAME_ST:
122                # only generate the dev link for non-bundled libs
123                dev_link     = bld.make_libname(target_name)
124        elif getattr(self, 'soname', ''):
125            install_name = bld.make_libname(target_name)
126            install_link = self.soname
127            inst_name    = bld.make_libname(t.target)
128        else:
129            install_name = bld.make_libname(target_name)
130            install_link = None
131            inst_name    = bld.make_libname(t.target)
132
133        if t.env.SONAME_ST:
134            # ensure we get the right names in the library
135            if install_link:
136                t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_link)
137            else:
138                t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_name)
139            t.env.SONAME_ST = ''
140
141        # tell waf to install the library
142        bld.install_as(os.path.join(install_path, install_name),
143                       self.path.find_or_declare(inst_name),
144                       chmod=MODE_755)
145
146        if install_link and install_link != install_name:
147            # and the symlink if needed
148            bld.symlink_as(os.path.join(install_path, install_link), os.path.basename(install_name))
149        if dev_link:
150            bld.symlink_as(os.path.join(install_path, dev_link), os.path.basename(install_name))
151    finally:
152        bld.all_envs['default'] = default_env
153
154
155@feature('cshlib')
156@after('apply_implib')
157@before('apply_vnum')
158def apply_soname(self):
159    '''install a library, taking account of the different rpath variants'''
160
161    if self.env.SONAME_ST and getattr(self, 'soname', ''):
162        self.env.append_value('LINKFLAGS', self.env.SONAME_ST % self.soname)
163        self.env.SONAME_ST = ''
164
165@feature('cshlib')
166@after('apply_implib')
167@before('apply_vnum')
168def apply_vscript(self):
169    '''add version-script arguments to library build'''
170
171    if self.env.HAVE_LD_VERSION_SCRIPT and getattr(self, 'version_script', ''):
172        self.env.append_value('LINKFLAGS', "-Wl,--version-script=%s" %
173            self.version_script)
174        self.version_script = None
175
176
177##############################
178# handle the creation of links for libraries and binaries in the build tree
179
180@feature('symlink_lib')
181@after('apply_link')
182def symlink_lib(self):
183    '''symlink a shared lib'''
184
185    if self.target.endswith('.inst'):
186        return
187
188    blddir = os.path.dirname(self.bld.srcnode.abspath(self.bld.env))
189    libpath = self.link_task.outputs[0].abspath(self.env)
190
191    # calculat the link target and put it in the environment
192    soext=""
193    vnum = getattr(self, 'vnum', None)
194    if vnum is not None:
195        soext = '.' + vnum.split('.')[0]
196
197    link_target = getattr(self, 'link_name', '')
198    if link_target == '':
199        basename = os.path.basename(self.bld.make_libname(self.target, version=soext))
200        if getattr(self, "private_library", False):
201            link_target = '%s/private/%s' % (LIB_PATH, basename)
202        else:
203            link_target = '%s/%s' % (LIB_PATH, basename)
204
205    link_target = os.path.join(blddir, link_target)
206
207    if os.path.lexists(link_target):
208        if os.path.islink(link_target) and os.readlink(link_target) == libpath:
209            return
210        os.unlink(link_target)
211
212    link_container = os.path.dirname(link_target)
213    if not os.path.isdir(link_container):
214        os.makedirs(link_container)
215
216    os.symlink(libpath, link_target)
217
218
219@feature('symlink_bin')
220@after('apply_link')
221def symlink_bin(self):
222    '''symlink a binary into the build directory'''
223
224    if self.target.endswith('.inst'):
225        return
226
227    if not self.link_task.outputs or not self.link_task.outputs[0]:
228        raise Errors.WafError('no outputs found for %s in symlink_bin' % self.name)
229    binpath = self.link_task.outputs[0].abspath(self.env)
230    bldpath = os.path.join(self.bld.env.BUILD_DIRECTORY, self.link_task.outputs[0].name)
231
232    if os.path.lexists(bldpath):
233        if os.path.islink(bldpath) and os.readlink(bldpath) == binpath:
234            return
235        os.unlink(bldpath)
236    os.symlink(binpath, bldpath)
237