def _contribute_sysroot_tree(cfg, host, host_group, is_build, multilib):
    """Contribute the glibc installation to all required install trees."""
    host_b = host.build_cfg
    target_build = multilib.build_cfg
    tree = cfg.install_tree_fstree(target_build, 'glibc')
    # Copy or move executables to locations that do not conflict
    # between sysroots.
    tree = multilib.move_sysroot_executables(
        tree, ('sbin', 'usr/bin', 'usr/sbin', 'usr/libexec/getconf'))
    # Ensure lib directories exist so that GCC's use of paths such
    # as lib/../lib64 works.
    tree_lib = FSTreeMove(FSTreeEmpty(cfg.context), 'lib')
    tree_usr_lib = FSTreeMove(FSTreeEmpty(cfg.context), 'usr/lib')
    tree = FSTreeUnion(tree, tree_lib)
    tree = FSTreeUnion(tree, tree_usr_lib)
    # Some files are shared between multilibs sharing a sysroot, so
    # are handled separately.
    tree = FSTreeRemove(tree, _SYSROOT_SHARED_PATHS)
    # Headers must be unified for each sysroot headers suffix, so are
    # handled separately.
    tree = FSTreeRemove(tree, ['usr/include'])
    # Move the tree to its final location.
    tree = FSTreeMove(tree, multilib.sysroot_rel)
    if is_build:
        host_group.contribute_implicit_install(host_b, 'toolchain-2-before',
                                               tree)
        host_group.contribute_implicit_install(host_b, 'toolchain-2', tree)
    host_group.contribute_package(host, tree)
Beispiel #2
0
def _contribute_headers_tree(cfg, host, host_group, is_build):
    """Contribute the installed headers to all required install trees."""
    host_b = host.build_cfg
    build = cfg.build.get().build_cfg
    tree = cfg.install_tree_fstree(build, _INST_NAME)
    # headers_install installs empty .install files, and ..install.cmd
    # files that hardcode build directory paths; these are not useful
    # as part of the installed toolchain.
    tree = FSTreeRemove(tree, ['**/..install.cmd', '**/.install'])
    # headers_install puts headers in an include/ subdirectory of the
    # given path.  This must end up in usr/include for each sysroot
    # headers suffix for which a sysroot is shipped with the
    # toolchain.
    ctree = FSTreeEmpty(cfg.context)
    dirs = sorted({
        m.headers_rel
        for m in cfg.multilibs.get()
        if m.libc is not None and m.headers_rel is not None
    })
    for headers_dir in dirs:
        moved_tree = FSTreeMove(tree, '%s/usr' % headers_dir)
        ctree = FSTreeUnion(ctree, moved_tree)
    if is_build:
        host_group.contribute_implicit_install(host_b, 'toolchain-1-before',
                                               ctree)
        host_group.contribute_implicit_install(host_b, 'toolchain-1', ctree)
        host_group.contribute_implicit_install(host_b, 'toolchain-2-before',
                                               ctree)
        host_group.contribute_implicit_install(host_b, 'toolchain-2', ctree)
    host_group.contribute_package(host, ctree)
def _contribute_shared_tree(cfg, host, component, host_group, is_build):
    """Contribute sysroot-shared files to all required install trees.

    This is for files that are identical between multilibs sharing a
    sysroot, so should be unified between such multilibs (duplicates
    allowed).

    """
    build_b = cfg.build.get().build_cfg
    host_b = host.build_cfg
    inst_1 = cfg.install_tree_path(build_b, 'toolchain-1')
    bindir_1 = os.path.join(inst_1, cfg.bindir_rel.get())
    tree = FSTreeEmpty(cfg.context)
    for multilib in cfg.multilibs.get():
        if multilib.libc is component:
            this_tree = cfg.install_tree_fstree(multilib.build_cfg, 'glibc')
            this_tree = FSTreeExtract(this_tree, _SYSROOT_SHARED_PATHS)
            locales_tree = cfg.install_tree_fstree(build_b, 'glibc-locales')
            locale_tree = _FSTreeLocale(locales_tree, multilib, bindir_1)
            this_tree = FSTreeUnion(this_tree, locale_tree)
            this_tree = FSTreeMove(this_tree, multilib.sysroot_rel)
            tree = FSTreeUnion(tree, this_tree, True)
    if is_build:
        host_group.contribute_implicit_install(host_b, 'toolchain-2-before',
                                               tree)
        host_group.contribute_implicit_install(host_b, 'toolchain-2', tree)
    host_group.contribute_package(host, tree)
def _contribute_headers_tree(cfg, host, component, host_group, is_build):
    """Contribute the glibc headers to all required install trees."""
    host_b = host.build_cfg
    # Most glibc headers should be the same between multilibs, but
    # some headers (gnu/stubs.h, gnu/lib-names.h) are set up to have
    # per-ABI conditionals and include per-ABI header variants that
    # are only installed for glibc built for that ABI.  Thus, form a
    # union of all the headers for multilibs using a given headers
    # suffix, allowing duplicate files.  (Normally there should be
    # just one headers suffix for all glibc multilibs, since it isn't
    # useful to have more than one such suffix, given headers that
    # properly support all ABIs.)
    headers_trees = collections.defaultdict(lambda: FSTreeEmpty(cfg.context))
    for multilib in cfg.multilibs.get():
        if multilib.libc is component:
            tree = cfg.install_tree_fstree(multilib.build_cfg, 'glibc')
            tree = FSTreeExtract(tree, ['usr/include'])
            headers_trees[multilib.headers_rel] = FSTreeUnion(
                headers_trees[multilib.headers_rel], tree, True)
    for headers_rel, tree in sorted(headers_trees.items()):
        tree = FSTreeMove(tree, headers_rel)
        if is_build:
            host_group.contribute_implicit_install(host_b,
                                                   'toolchain-2-before', tree)
            host_group.contribute_implicit_install(host_b, 'toolchain-2', tree)
        host_group.contribute_package(host, tree)
Beispiel #5
0
 def add_build_tasks_for_first_host(cfg, host, component, host_group):
     task = BuildTask(cfg, host_group, 'first-host')
     host_b = host.build_cfg
     objdir = cfg.objdir_path(host_b, '%s-first' % component.copy_name)
     task.add_empty_dir(objdir)
     instdir_1 = cfg.install_tree_path(host_b, 'first-inst-1')
     task.add_empty_dir(instdir_1)
     task.provide_install(host_b, 'first-inst-1')
     instdir_2 = cfg.install_tree_path(host_b, 'first-inst-2')
     task.add_empty_dir(instdir_2)
     task.provide_install(host_b, 'first-inst-2')
     instdir_3 = cfg.install_tree_path(host_b, 'first-inst-3')
     task.add_empty_dir(instdir_3)
     task.provide_install(host_b, 'first-inst-3')
     task.add_command(['sh', '-c', 'echo a > %s/a' % instdir_1])
     task.add_command(['sh', '-c', 'echo b > %s/b' % instdir_2])
     task.add_command(['sh', '-c', 'echo c > %s/c' % instdir_3])
     tree_1 = cfg.install_tree_fstree(host_b, 'first-inst-1')
     tree_1 = FSTreeMove(tree_1, 'q')
     tree_2 = cfg.install_tree_fstree(host_b, 'first-inst-2')
     tree_3 = cfg.install_tree_fstree(host_b, 'first-inst-3')
     task.define_implicit_install(host_b, 'impl-def', tree_1)
     task.declare_implicit_install(host_b, 'impl-empty')
     task.declare_implicit_install(host_b, 'impl-one')
     task.contribute_implicit_install(host_b, 'impl-one', tree_2)
     task.declare_implicit_install(host_b, 'impl-two')
     task.contribute_implicit_install(host_b, 'impl-two', tree_2)
     task.contribute_implicit_install(host_b, 'impl-two', tree_3)
Beispiel #6
0
    def move_sysroot_executables(self, tree, dirs):
        """Move executables to a per-multilib directory such as usr/lib/bin.

        This is for the case where a sysroot is shared between
        multilibs, and so different multilibs have different library
        directories such as usr/lib and usr/lib64, but executables go
        in the same directory such as usr/bin for all multilibs.  To
        avoid conflicts between files for different multilibs, those
        executables are moved to per-multilib directories such as
        usr/lib/bin (this is an arrangement for packaging, with users
        of the sysroot expected to copy the preferred version of a
        binary back into directories such as usr/bin).  For user
        convenience, copies of the files are left in their original
        directories if there is only one multilib in the sysroot.

        dirs is a list of directories in the sysroot from which files
        are to be moved or copied.  tree is an FSTree for the sysroot;
        dir_src must exist therein.  An FSTree is returned; the
        directories in dirs still exist there, but may be empty.

        """
        if self.sysroot_suffix is None:
            self.context.error('move_sysroot_executables called for '
                               'non-sysroot multilib')
        if isinstance(dirs, str):
            self.context.error('dirs must be a list of strings, not a single '
                               'string')
        dir_dst = os.path.normpath(
            os.path.join('usr/lib', self.sysroot_osdir, 'bin'))
        num_multilibs = len([
            m for m in self._relcfg.multilibs.get()
            if m.sysroot_suffix == self.sysroot_suffix
        ])
        for dir_src in dirs:
            tree_src = FSTreeExtractOne(tree, dir_src)
            tree_moved = FSTreeMove(tree_src, dir_dst)
            if num_multilibs > 1:
                tree = FSTreeRemove(tree, [dir_src])
            tree = FSTreeUnion(tree, tree_moved)
            if num_multilibs > 1:
                # Keep the original binary directory present in the
                # packages, although empty (again for user convenience).
                empty = FSTreeMove(FSTreeEmpty(self.context), dir_src)
                tree = FSTreeUnion(tree, empty)
        return tree
 def add_build_tasks_for_first_host(cfg, host, component, host_group):
     # Install headers.  This is run only for the first mingw64
     # multilib.
     host_b = host.build_cfg
     multilib = _first_mingw64_multilib(cfg, component)
     if multilib is None:
         return
     multilib_b = multilib.build_cfg
     installdir = cfg.installdir.get()
     installdir_rel = cfg.installdir_rel.get()
     target = cfg.target.get()
     prefix = os.path.join(installdir, target)
     srcdir = component.vars.srcdir.get()
     add_host_cfg_build_tasks(cfg, multilib_b, component, host_group,
                              'mingw64-headers',
                              os.path.join(srcdir, 'mingw-w64-headers'),
                              prefix, (), None, None, 'install', True)
     tree = cfg.install_tree_fstree(multilib_b, 'mingw64-headers')
     # Unlike for some target OSes, libgcc files for Windows target
     # do not have inhibit_libc conditionals and thus the library
     # headers are needed before the first compiler is built.
     host_group.contribute_implicit_install(host_b, 'toolchain-1-before',
                                            tree)
     host_group.contribute_implicit_install(host_b, 'toolchain-1', tree)
     host_group.contribute_implicit_install(host_b, 'toolchain-2-before',
                                            tree)
     host_group.contribute_implicit_install(host_b, 'toolchain-2', tree)
     host_group.contribute_package(host, tree)
     # A symlink mingw -> . is needed for configuring GCC using
     # --with-build-sysroot to enable headers and libraries to be
     # found when not installed at the configured prefix.
     tree_link = FSTreeSymlink(cfg.context, '.')
     tree_link = FSTreeMove(tree_link,
                            os.path.join(installdir_rel, target, 'mingw'))
     host_group.contribute_implicit_install(host_b, 'toolchain-1-before',
                                            tree_link)
     host_group.contribute_implicit_install(host_b, 'toolchain-2-before',
                                            tree_link)
     # This is needed for toolchain-2 because that install tree is
     # used with --with-build-sysroot for hosts other than the
     # first, and although target libraries are not built in that
     # case, the specified directory is still used by fixincludes
     # fixing headers for that host.
     host_group.contribute_implicit_install(host_b, 'toolchain-2',
                                            tree_link)
     _contribute_crt_tree(cfg, host, component, host_group, True)
Beispiel #8
0
 def add_build_tasks_for_host(cfg, host, component, host_group):
     host_b = host.build_cfg
     build = cfg.build.get()
     build_b = build.build_cfg
     target = cfg.target.get()
     installdir = cfg.installdir.get()
     installdir_rel = cfg.installdir_rel.get()
     # If there are sysrooted multilibs, configure with the
     # corresponding sysroot.  If there are non-sysrooted
     # multilibs, also configure as sysrooted, so that
     # --with-build-sysroot can be used to find headers and
     # libraries when building the final GCC; in that case a usr ->
     # . symlink must also be created.  A mixture of sysrooted and
     # non-sysrooted multilibs is not permitted.
     sysrooted = False
     non_sysrooted = False
     have_glibc_multilib = False
     have_newlib_multilib = False
     for multilib in cfg.multilibs.get():
         if multilib.sysroot_suffix is None:
             non_sysrooted = True
         else:
             sysrooted = True
         if multilib.libc is not None:
             if multilib.libc.orig_name == 'glibc':
                 have_glibc_multilib = True
             if multilib.libc.orig_name == 'newlib':
                 have_newlib_multilib = True
     if sysrooted and non_sysrooted:
         cfg.context.error('both sysrooted and non-sysrooted multilibs')
     if sysrooted:
         sysroot = cfg.sysroot.get()
         sysroot_rel = cfg.sysroot_rel.get()
     else:
         sysroot = os.path.join(installdir, target)
         sysroot_rel = os.path.join(installdir_rel, target)
     bindir_rel = cfg.bindir_rel.get()
     inst_1_before = cfg.install_tree_path(build_b, 'toolchain-1-before')
     build_sysroot_1 = os.path.join(inst_1_before, sysroot_rel)
     bindir_1 = os.path.join(inst_1_before, bindir_rel)
     # Building GCC for a host other than the build system, even
     # without building target libraries, requires GCC (configured
     # the same way) built for the build system, because the GCC
     # build runs the compiler for some purposes (e.g. with
     # -dumpspecs).
     toolchain_2_before = ('toolchain-2-before'
                           if host == build
                           else 'toolchain-2')
     inst_2_before = cfg.install_tree_path(build_b, toolchain_2_before)
     build_sysroot_2 = os.path.join(inst_2_before, sysroot_rel)
     bindir_2 = os.path.join(inst_2_before, bindir_rel)
     build_time_tools_1 = os.path.join(inst_1_before, target, 'bin')
     build_time_tools_2 = os.path.join(inst_2_before, target, 'bin')
     opts_first = ['--enable-languages=c',
                   '--disable-shared',
                   '--disable-threads',
                   '--without-headers', '--with-newlib',
                   '--with-sysroot=%s' % sysroot,
                   '--with-build-sysroot=%s' % build_sysroot_1,
                   '--with-build-time-tools=%s' % build_time_tools_1,
                   '--disable-decimal-float',
                   '--disable-libatomic',
                   '--disable-libcilkrts',
                   '--disable-libffi',
                   '--disable-libgomp',
                   '--disable-libitm',
                   '--disable-libmpx',
                   '--disable-libquadmath',
                   '--disable-libsanitizer']
     if have_glibc_multilib:
         glibc_version_h = os.path.join(cfg.glibc.srcdir.get(), 'version.h')
         glibc_version = None
         with open(glibc_version_h, 'r', encoding='utf-8') as file:
             start = '#define VERSION "'
             for line in file:
                 if line.startswith(start):
                     line = line[len(start):].rstrip('"\n')
                     vers = line.split('.')
                     glibc_version = '.'.join(vers[0:2])
                     break
         if glibc_version is not None:
             opts_first.append('--with-glibc-version=%s' % glibc_version)
         else:
             cfg.context.error('could not determine glibc version')
     languages = ['c']
     languages.extend(component.vars.languages.get())
     opts_second = ['--enable-languages=%s' % ','.join(languages),
                    '--enable-shared',
                    '--enable-threads',
                    '--with-sysroot=%s' % sysroot,
                    '--with-build-sysroot=%s' % build_sysroot_2,
                    '--with-build-time-tools=%s' % build_time_tools_2]
     if have_newlib_multilib:
         opts_second.append('--with-newlib')
     if host == build:
         group = add_host_tool_cfg_build_tasks(
             cfg, host_b, component, host_group, name='gcc-first',
             pkg_cfg_opts=opts_first)
         group.depend_install(host_b, 'gmp')
         group.depend_install(host_b, 'mpfr')
         group.depend_install(host_b, 'mpc')
         if host_b.use_libiconv():
             group.depend_install(host_b, 'libiconv')
         if cfg.have_component('isl'):
             group.depend_install(host_b, 'isl')
         group.depend_install(host_b, 'toolchain-1-before')
         group.env_prepend('PATH', bindir_1)
         tree = cfg.install_tree_fstree(host_b, 'gcc-first')
         tree = FSTreeRemove(tree, [cfg.info_dir_rel.get()])
         host_group.contribute_implicit_install(host_b, 'toolchain-1', tree)
         # The compiler is not needed in toolchain-2-before (which
         # is only used to build GCC for the build system).
         # However, symlinks are needed in the non-sysrooted case
         # to make use of --with-build-sysroot.
         if not sysrooted:
             tree_link = FSTreeSymlink(cfg.context, '.')
             tree_link = FSTreeMove(tree_link, os.path.join(sysroot_rel,
                                                            'usr'))
             host_group.contribute_implicit_install(host_b,
                                                    'toolchain-2-before',
                                                    tree_link)
     make_target = None if host == build else 'all-host'
     install_target = 'install' if host == build else 'install-host'
     group = add_host_tool_cfg_build_tasks(
         cfg, host_b, component, host_group, name='gcc',
         pkg_cfg_opts=opts_second, make_target=make_target,
         install_target=install_target)
     group.depend_install(host_b, 'gmp')
     group.depend_install(host_b, 'mpfr')
     group.depend_install(host_b, 'mpc')
     if host_b.use_libiconv():
         group.depend_install(host_b, 'libiconv')
     if cfg.have_component('isl'):
         group.depend_install(host_b, 'isl')
     group.depend_install(build_b, toolchain_2_before)
     group.env_prepend('PATH', bindir_2)
     tree = cfg.install_tree_fstree(host_b, 'gcc')
     tree = FSTreeRemove(tree, [cfg.info_dir_rel.get()])
     tree_build = cfg.install_tree_fstree(build_b, 'gcc')
     # Packaged sysroots are most convenient for users if they
     # contain all shared libraries that may be implicitly used by
     # the toolchain; thus, such libraries installed by GCC should
     # be copied to the sysroots.  For consistency with libraries
     # built with libc, static libraries and object files are also
     # copied there, although not strictly required.  In most
     # cases, it is sufficient to move the files there without
     # keeping copies in the original location.  However, GCC
     # searches both multilib and non-multilib paths for libraries,
     # with the search of non-multilib paths being required in some
     # cases as explained in
     # <https://gcc.gnu.org/ml/gcc/2016-12/msg00013.html>.
     # Furthermore, the search of non-multilib non-sysroot paths
     # may come before sysroot paths.  In that case, if the default
     # GCC multilib does not have a sysroot into which libraries
     # can be moved, libraries for that multilib could be found
     # before libraries for other multilibs that had been moved
     # into their sysroots.  Thus, in the case where any multilib
     # does not have a sysroot into which libraries can be moved,
     # all sysroots have libraries copied there without being
     # removed from their original locations.  In any case, only
     # libraries from the <target>/lib or equivalent directory are
     # copied or moved; libraries from GCC's libsubdir (which are
     # only static libraries and object files, in the absence of
     # --enable-version-specific-runtime-libs) are left there.
     have_non_sysroot_multilib = False
     for multilib in cfg.multilibs.get():
         if multilib.sysroot_suffix is None or multilib.libc is None:
             have_non_sysroot_multilib = True
             break
     tree_sysroot_libs = FSTreeEmpty(cfg.context)
     for multilib in cfg.multilibs.get():
         if multilib.sysroot_suffix is None or multilib.libc is None:
             continue
         libs_dir = os.path.normpath('%s/%s/lib/%s' % (installdir_rel,
                                                       target,
                                                       multilib.osdir))
         libs_tree = FSTreeExtractOne(tree_build, libs_dir)
         libs_tree = FSTreeExtract(libs_tree, ['*.so*', '*.a', '*.o'])
         libgcc_tree = FSTreeExtract(libs_tree, ['libgcc*'])
         libs_tree = FSTreeRemove(libs_tree, ['libgcc*'])
         dst_lib = os.path.normpath(os.path.join(multilib.sysroot_rel,
                                                 'lib',
                                                 multilib.sysroot_osdir))
         dst_usrlib = os.path.normpath(os.path.join(multilib.sysroot_rel,
                                                    'usr/lib',
                                                    multilib.sysroot_osdir))
         tree_sysroot_libs = FSTreeUnion(tree_sysroot_libs,
                                         FSTreeMove(libgcc_tree, dst_lib))
         tree_sysroot_libs = FSTreeUnion(tree_sysroot_libs,
                                         FSTreeMove(libs_tree, dst_usrlib))
         if have_non_sysroot_multilib:
             continue
         # Remove the libraries from their original locations.
         if host == build:
             tree = FSTreeRemove(tree, ['%s/*.so*' % libs_dir,
                                        '%s/*.a' % libs_dir,
                                        '%s/*.o' % libs_dir])
         else:
             tree_build = FSTreeRemove(tree_build, ['%s/*.so*' % libs_dir,
                                                    '%s/*.a' % libs_dir,
                                                    '%s/*.o' % libs_dir])
     if host == build:
         host_group.contribute_implicit_install(host_b, 'toolchain-2', tree)
         host_group.contribute_implicit_install(host_b, 'toolchain-2',
                                                tree_sysroot_libs)
     if host != build:
         # Libraries built for the build system, and other files
         # installed with those libraries, are reused for other
         # hosts.  Headers in libsubdir/include are a special case:
         # some are installed from the gcc/ directory, so for all
         # hosts, while others are installed from library
         # directories, so only from the build system.  Thus,
         # extract the two sets of headers and form a union for
         # them allowing duplicates with identical contents.
         # libtool .la files contain paths with the configured
         # prefix hardcoded, so do not work in relocated
         # toolchains.
         tree_build = FSTreeRemove(tree_build, ['**/*.la'])
         tree_libs = FSTreeExtract(
             tree_build,
             ['%s/%s/include/c++' % (installdir_rel, target),
              '%s/%s/lib*' % (installdir_rel, target),
              '%s/lib/gcc/%s/*' % (installdir_rel, target),
              '%s/share/gcc-*' % installdir_rel,
              '%s/share/info/lib*' % installdir_rel,
              '%s/share/locale/*/*/lib*' % installdir_rel])
         tree_libs = FSTreeRemove(
             tree_libs,
             ['%s/lib/gcc/%s/*/include' % (installdir_rel, target),
              '%s/lib/gcc/%s/*/include-fixed' % (installdir_rel, target),
              '%s/lib/gcc/%s/*/install-tools' % (installdir_rel, target),
              '%s/lib/gcc/%s/*/plugin' % (installdir_rel, target)])
         tree_libsubdir_include_build = FSTreeExtract(
             tree_build,
             ['%s/lib/gcc/%s/*/include' % (installdir_rel, target)])
         tree_libsubdir_include_host = FSTreeExtract(
             tree,
             ['%s/lib/gcc/%s/*/include' % (installdir_rel, target)])
         tree_libsubdir_include = FSTreeUnion(tree_libsubdir_include_build,
                                              tree_libsubdir_include_host,
                                              True)
         tree = FSTreeRemove(
             tree,
             ['%s/lib/gcc/%s/*/include' % (installdir_rel, target)])
         host_group.contribute_package(host, tree_libs)
         host_group.contribute_package(host, tree_libsubdir_include)
     # libtool .la files contain paths with the configured prefix
     # hardcoded, so do not work in relocated toolchains.
     tree = FSTreeRemove(tree, ['**/*.la'])
     host_group.contribute_package(host, tree)
     host_group.contribute_package(host, tree_sysroot_libs)