xref: /openbmc/openbmc/poky/meta/lib/oe/sdk.py (revision 40c92f2f)
1#
2# SPDX-License-Identifier: GPL-2.0-only
3#
4
5from abc import ABCMeta, abstractmethod
6from oe.utils import execute_pre_post_process
7from oe.manifest import *
8from oe.package_manager import *
9import os
10import shutil
11import glob
12import traceback
13
14class Sdk(object, metaclass=ABCMeta):
15    def __init__(self, d, manifest_dir):
16        self.d = d
17        self.sdk_output = self.d.getVar('SDK_OUTPUT')
18        self.sdk_native_path = self.d.getVar('SDKPATHNATIVE').strip('/')
19        self.target_path = self.d.getVar('SDKTARGETSYSROOT').strip('/')
20        self.sysconfdir = self.d.getVar('sysconfdir').strip('/')
21
22        self.sdk_target_sysroot = os.path.join(self.sdk_output, self.target_path)
23        self.sdk_host_sysroot = self.sdk_output
24
25        if manifest_dir is None:
26            self.manifest_dir = self.d.getVar("SDK_DIR")
27        else:
28            self.manifest_dir = manifest_dir
29
30        self.remove(self.sdk_output, True)
31
32        self.install_order = Manifest.INSTALL_ORDER
33
34    @abstractmethod
35    def _populate(self):
36        pass
37
38    def populate(self):
39        self.mkdirhier(self.sdk_output)
40
41        # call backend dependent implementation
42        self._populate()
43
44        # Don't ship any libGL in the SDK
45        self.remove(os.path.join(self.sdk_output, self.sdk_native_path,
46                         self.d.getVar('libdir_nativesdk').strip('/'),
47                         "libGL*"))
48
49        # Fix or remove broken .la files
50        self.remove(os.path.join(self.sdk_output, self.sdk_native_path,
51                         self.d.getVar('libdir_nativesdk').strip('/'),
52                         "*.la"))
53
54        # Link the ld.so.cache file into the hosts filesystem
55        link_name = os.path.join(self.sdk_output, self.sdk_native_path,
56                                 self.sysconfdir, "ld.so.cache")
57        self.mkdirhier(os.path.dirname(link_name))
58        os.symlink("/etc/ld.so.cache", link_name)
59
60        execute_pre_post_process(self.d, self.d.getVar('SDK_POSTPROCESS_COMMAND'))
61
62    def movefile(self, sourcefile, destdir):
63        try:
64            # FIXME: this check of movefile's return code to None should be
65            # fixed within the function to use only exceptions to signal when
66            # something goes wrong
67            if (bb.utils.movefile(sourcefile, destdir) == None):
68                raise OSError("moving %s to %s failed"
69                        %(sourcefile, destdir))
70        #FIXME: using umbrella exc catching because bb.utils method raises it
71        except Exception as e:
72            bb.debug(1, "printing the stack trace\n %s" %traceback.format_exc())
73            bb.error("unable to place %s in final SDK location" % sourcefile)
74
75    def mkdirhier(self, dirpath):
76        try:
77            bb.utils.mkdirhier(dirpath)
78        except OSError as e:
79            bb.debug(1, "printing the stack trace\n %s" %traceback.format_exc())
80            bb.fatal("cannot make dir for SDK: %s" % dirpath)
81
82    def remove(self, path, recurse=False):
83        try:
84            bb.utils.remove(path, recurse)
85        #FIXME: using umbrella exc catching because bb.utils method raises it
86        except Exception as e:
87            bb.debug(1, "printing the stack trace\n %s" %traceback.format_exc())
88            bb.warn("cannot remove SDK dir: %s" % path)
89
90    def install_locales(self, pm):
91        linguas = self.d.getVar("SDKIMAGE_LINGUAS")
92        if linguas:
93            import fnmatch
94            # Install the binary locales
95            if linguas == "all":
96                pm.install_glob("nativesdk-glibc-binary-localedata-*.utf-8", sdk=True)
97            else:
98                pm.install(["nativesdk-glibc-binary-localedata-%s.utf-8" % \
99                           lang for lang in linguas.split()])
100            # Generate a locale archive of them
101            target_arch = self.d.getVar('SDK_ARCH')
102            rootfs = oe.path.join(self.sdk_host_sysroot, self.sdk_native_path)
103            localedir = oe.path.join(rootfs, self.d.getVar("libdir_nativesdk"), "locale")
104            generate_locale_archive(self.d, rootfs, target_arch, localedir)
105            # And now delete the binary locales
106            pkgs = fnmatch.filter(pm.list_installed(), "nativesdk-glibc-binary-localedata-*.utf-8")
107            pm.remove(pkgs)
108        else:
109            # No linguas so do nothing
110            pass
111
112
113class RpmSdk(Sdk):
114    def __init__(self, d, manifest_dir=None, rpm_workdir="oe-sdk-repo"):
115        super(RpmSdk, self).__init__(d, manifest_dir)
116
117        self.target_manifest = RpmManifest(d, self.manifest_dir,
118                                           Manifest.MANIFEST_TYPE_SDK_TARGET)
119        self.host_manifest = RpmManifest(d, self.manifest_dir,
120                                         Manifest.MANIFEST_TYPE_SDK_HOST)
121
122        rpm_repo_workdir = "oe-sdk-repo"
123        if "sdk_ext" in d.getVar("BB_RUNTASK"):
124            rpm_repo_workdir = "oe-sdk-ext-repo"
125
126        self.target_pm = RpmPM(d,
127                               self.sdk_target_sysroot,
128                               self.d.getVar('TARGET_VENDOR'),
129                               'target',
130                               rpm_repo_workdir=rpm_repo_workdir
131                               )
132
133        self.host_pm = RpmPM(d,
134                             self.sdk_host_sysroot,
135                             self.d.getVar('SDK_VENDOR'),
136                             'host',
137                             "SDK_PACKAGE_ARCHS",
138                             "SDK_OS",
139                             rpm_repo_workdir=rpm_repo_workdir
140                             )
141
142    def _populate_sysroot(self, pm, manifest):
143        pkgs_to_install = manifest.parse_initial_manifest()
144
145        pm.create_configs()
146        pm.write_index()
147        pm.update()
148
149        pkgs = []
150        pkgs_attempt = []
151        for pkg_type in pkgs_to_install:
152            if pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY:
153                pkgs_attempt += pkgs_to_install[pkg_type]
154            else:
155                pkgs += pkgs_to_install[pkg_type]
156
157        pm.install(pkgs)
158
159        pm.install(pkgs_attempt, True)
160
161    def _populate(self):
162        execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_PRE_TARGET_COMMAND"))
163
164        bb.note("Installing TARGET packages")
165        self._populate_sysroot(self.target_pm, self.target_manifest)
166
167        self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
168
169        self.target_pm.run_intercepts(populate_sdk='target')
170
171        execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
172
173        if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
174            self.target_pm.remove_packaging_data()
175
176        bb.note("Installing NATIVESDK packages")
177        self._populate_sysroot(self.host_pm, self.host_manifest)
178        self.install_locales(self.host_pm)
179
180        self.host_pm.run_intercepts(populate_sdk='host')
181
182        execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND"))
183
184        if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
185            self.host_pm.remove_packaging_data()
186
187        # Move host RPM library data
188        native_rpm_state_dir = os.path.join(self.sdk_output,
189                                            self.sdk_native_path,
190                                            self.d.getVar('localstatedir_nativesdk').strip('/'),
191                                            "lib",
192                                            "rpm"
193                                            )
194        self.mkdirhier(native_rpm_state_dir)
195        for f in glob.glob(os.path.join(self.sdk_output,
196                                        "var",
197                                        "lib",
198                                        "rpm",
199                                        "*")):
200            self.movefile(f, native_rpm_state_dir)
201
202        self.remove(os.path.join(self.sdk_output, "var"), True)
203
204        # Move host sysconfig data
205        native_sysconf_dir = os.path.join(self.sdk_output,
206                                          self.sdk_native_path,
207                                          self.d.getVar('sysconfdir',
208                                                        True).strip('/'),
209                                          )
210        self.mkdirhier(native_sysconf_dir)
211        for f in glob.glob(os.path.join(self.sdk_output, "etc", "rpm*")):
212            self.movefile(f, native_sysconf_dir)
213        for f in glob.glob(os.path.join(self.sdk_output, "etc", "dnf", "*")):
214            self.movefile(f, native_sysconf_dir)
215        self.remove(os.path.join(self.sdk_output, "etc"), True)
216
217
218class OpkgSdk(Sdk):
219    def __init__(self, d, manifest_dir=None):
220        super(OpkgSdk, self).__init__(d, manifest_dir)
221
222        self.target_conf = self.d.getVar("IPKGCONF_TARGET")
223        self.host_conf = self.d.getVar("IPKGCONF_SDK")
224
225        self.target_manifest = OpkgManifest(d, self.manifest_dir,
226                                            Manifest.MANIFEST_TYPE_SDK_TARGET)
227        self.host_manifest = OpkgManifest(d, self.manifest_dir,
228                                          Manifest.MANIFEST_TYPE_SDK_HOST)
229
230        ipk_repo_workdir = "oe-sdk-repo"
231        if "sdk_ext" in d.getVar("BB_RUNTASK"):
232            ipk_repo_workdir = "oe-sdk-ext-repo"
233
234        self.target_pm = OpkgPM(d, self.sdk_target_sysroot, self.target_conf,
235                                self.d.getVar("ALL_MULTILIB_PACKAGE_ARCHS"),
236                                ipk_repo_workdir=ipk_repo_workdir)
237
238        self.host_pm = OpkgPM(d, self.sdk_host_sysroot, self.host_conf,
239                              self.d.getVar("SDK_PACKAGE_ARCHS"),
240                                ipk_repo_workdir=ipk_repo_workdir)
241
242    def _populate_sysroot(self, pm, manifest):
243        pkgs_to_install = manifest.parse_initial_manifest()
244
245        if (self.d.getVar('BUILD_IMAGES_FROM_FEEDS') or "") != "1":
246            pm.write_index()
247
248        pm.update()
249
250        for pkg_type in self.install_order:
251            if pkg_type in pkgs_to_install:
252                pm.install(pkgs_to_install[pkg_type],
253                           [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
254
255    def _populate(self):
256        execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_PRE_TARGET_COMMAND"))
257
258        bb.note("Installing TARGET packages")
259        self._populate_sysroot(self.target_pm, self.target_manifest)
260
261        self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
262
263        self.target_pm.run_intercepts(populate_sdk='target')
264
265        execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
266
267        if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
268            self.target_pm.remove_packaging_data()
269
270        bb.note("Installing NATIVESDK packages")
271        self._populate_sysroot(self.host_pm, self.host_manifest)
272        self.install_locales(self.host_pm)
273
274        self.host_pm.run_intercepts(populate_sdk='host')
275
276        execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND"))
277
278        if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
279            self.host_pm.remove_packaging_data()
280
281        target_sysconfdir = os.path.join(self.sdk_target_sysroot, self.sysconfdir)
282        host_sysconfdir = os.path.join(self.sdk_host_sysroot, self.sysconfdir)
283
284        self.mkdirhier(target_sysconfdir)
285        shutil.copy(self.target_conf, target_sysconfdir)
286        os.chmod(os.path.join(target_sysconfdir,
287                              os.path.basename(self.target_conf)), 0o644)
288
289        self.mkdirhier(host_sysconfdir)
290        shutil.copy(self.host_conf, host_sysconfdir)
291        os.chmod(os.path.join(host_sysconfdir,
292                              os.path.basename(self.host_conf)), 0o644)
293
294        native_opkg_state_dir = os.path.join(self.sdk_output, self.sdk_native_path,
295                                             self.d.getVar('localstatedir_nativesdk').strip('/'),
296                                             "lib", "opkg")
297        self.mkdirhier(native_opkg_state_dir)
298        for f in glob.glob(os.path.join(self.sdk_output, "var", "lib", "opkg", "*")):
299            self.movefile(f, native_opkg_state_dir)
300
301        self.remove(os.path.join(self.sdk_output, "var"), True)
302
303
304class DpkgSdk(Sdk):
305    def __init__(self, d, manifest_dir=None):
306        super(DpkgSdk, self).__init__(d, manifest_dir)
307
308        self.target_conf_dir = os.path.join(self.d.getVar("APTCONF_TARGET"), "apt")
309        self.host_conf_dir = os.path.join(self.d.getVar("APTCONF_TARGET"), "apt-sdk")
310
311        self.target_manifest = DpkgManifest(d, self.manifest_dir,
312                                            Manifest.MANIFEST_TYPE_SDK_TARGET)
313        self.host_manifest = DpkgManifest(d, self.manifest_dir,
314                                          Manifest.MANIFEST_TYPE_SDK_HOST)
315
316        deb_repo_workdir = "oe-sdk-repo"
317        if "sdk_ext" in d.getVar("BB_RUNTASK"):
318            deb_repo_workdir = "oe-sdk-ext-repo"
319
320        self.target_pm = DpkgPM(d, self.sdk_target_sysroot,
321                                self.d.getVar("PACKAGE_ARCHS"),
322                                self.d.getVar("DPKG_ARCH"),
323                                self.target_conf_dir,
324                                deb_repo_workdir=deb_repo_workdir)
325
326        self.host_pm = DpkgPM(d, self.sdk_host_sysroot,
327                              self.d.getVar("SDK_PACKAGE_ARCHS"),
328                              self.d.getVar("DEB_SDK_ARCH"),
329                              self.host_conf_dir,
330                              deb_repo_workdir=deb_repo_workdir)
331
332    def _copy_apt_dir_to(self, dst_dir):
333        staging_etcdir_native = self.d.getVar("STAGING_ETCDIR_NATIVE")
334
335        self.remove(dst_dir, True)
336
337        shutil.copytree(os.path.join(staging_etcdir_native, "apt"), dst_dir)
338
339    def _populate_sysroot(self, pm, manifest):
340        pkgs_to_install = manifest.parse_initial_manifest()
341
342        pm.write_index()
343        pm.update()
344
345        for pkg_type in self.install_order:
346            if pkg_type in pkgs_to_install:
347                pm.install(pkgs_to_install[pkg_type],
348                           [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
349
350    def _populate(self):
351        execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_PRE_TARGET_COMMAND"))
352
353        bb.note("Installing TARGET packages")
354        self._populate_sysroot(self.target_pm, self.target_manifest)
355
356        self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
357
358        self.target_pm.run_intercepts(populate_sdk='target')
359
360        execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
361
362        self._copy_apt_dir_to(os.path.join(self.sdk_target_sysroot, "etc", "apt"))
363
364        if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
365            self.target_pm.remove_packaging_data()
366
367        bb.note("Installing NATIVESDK packages")
368        self._populate_sysroot(self.host_pm, self.host_manifest)
369        self.install_locales(self.host_pm)
370
371        self.host_pm.run_intercepts(populate_sdk='host')
372
373        execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND"))
374
375        self._copy_apt_dir_to(os.path.join(self.sdk_output, self.sdk_native_path,
376                                           "etc", "apt"))
377
378        if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
379            self.host_pm.remove_packaging_data()
380
381        native_dpkg_state_dir = os.path.join(self.sdk_output, self.sdk_native_path,
382                                             "var", "lib", "dpkg")
383        self.mkdirhier(native_dpkg_state_dir)
384        for f in glob.glob(os.path.join(self.sdk_output, "var", "lib", "dpkg", "*")):
385            self.movefile(f, native_dpkg_state_dir)
386        self.remove(os.path.join(self.sdk_output, "var"), True)
387
388
389
390def sdk_list_installed_packages(d, target, rootfs_dir=None):
391    if rootfs_dir is None:
392        sdk_output = d.getVar('SDK_OUTPUT')
393        target_path = d.getVar('SDKTARGETSYSROOT').strip('/')
394
395        rootfs_dir = [sdk_output, os.path.join(sdk_output, target_path)][target is True]
396
397    img_type = d.getVar('IMAGE_PKGTYPE')
398    if img_type == "rpm":
399        arch_var = ["SDK_PACKAGE_ARCHS", None][target is True]
400        os_var = ["SDK_OS", None][target is True]
401        return RpmPkgsList(d, rootfs_dir).list_pkgs()
402    elif img_type == "ipk":
403        conf_file_var = ["IPKGCONF_SDK", "IPKGCONF_TARGET"][target is True]
404        return OpkgPkgsList(d, rootfs_dir, d.getVar(conf_file_var)).list_pkgs()
405    elif img_type == "deb":
406        return DpkgPkgsList(d, rootfs_dir).list_pkgs()
407
408def populate_sdk(d, manifest_dir=None):
409    env_bkp = os.environ.copy()
410
411    img_type = d.getVar('IMAGE_PKGTYPE')
412    if img_type == "rpm":
413        RpmSdk(d, manifest_dir).populate()
414    elif img_type == "ipk":
415        OpkgSdk(d, manifest_dir).populate()
416    elif img_type == "deb":
417        DpkgSdk(d, manifest_dir).populate()
418
419    os.environ.clear()
420    os.environ.update(env_bkp)
421
422def get_extra_sdkinfo(sstate_dir):
423    """
424    This function is going to be used for generating the target and host manifest files packages of eSDK.
425    """
426    import math
427
428    extra_info = {}
429    extra_info['tasksizes'] = {}
430    extra_info['filesizes'] = {}
431    for root, _, files in os.walk(sstate_dir):
432        for fn in files:
433            if fn.endswith('.tgz'):
434                fsize = int(math.ceil(float(os.path.getsize(os.path.join(root, fn))) / 1024))
435                task = fn.rsplit(':',1)[1].split('_',1)[1].split(',')[0]
436                origtotal = extra_info['tasksizes'].get(task, 0)
437                extra_info['tasksizes'][task] = origtotal + fsize
438                extra_info['filesizes'][fn] = fsize
439    return extra_info
440
441if __name__ == "__main__":
442    pass
443