<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
  <!ENTITY % general-entities SYSTEM "../general.ent">
  %general-entities;
]>

<sect1 id="ch-tools-gcc-pass1" role="wrap" xreflabel="第一遍的 GCC">
  <?dbhtml filename="gcc-pass1.html"?>

  <sect1info condition="script">
    <productname>gcc</productname>
    <productnumber>&gcc-version;</productnumber>
    <address>&gcc-url;</address>
  </sect1info>

  <title>GCC-&gcc-version; - 第一遍</title>

  <indexterm zone="ch-tools-gcc-pass1">
    <primary sortas="a-GCC">GCC</primary>
    <secondary>tools, pass 1</secondary>
  </indexterm>

  <sect2 role="package">
    <title/>

    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
    href="../chapter06/gcc.xml"
    xpointer="xpointer(/sect1/sect2[1]/para[1])"/>

    <segmentedlist>
      <segtitle>&buildtime;</segtitle>
      <segtitle>&diskspace;</segtitle>

      <seglistitem>
        <seg>&gcc-ch5p1-sbu;</seg>
        <seg>&gcc-ch5p1-du;</seg>
      </seglistitem>
    </segmentedlist>

  </sect2>

  <sect2 role="installation">
    <title>安装交叉工具链中的 GCC</title>

    <!--para>GCC now requires the GMP, MPFR and MPC packages. As these packages may
    not be included in your host distribution, they will be built with
    GCC.  Unpack each package into the GCC source directory and rename the
    resulting directories so the GCC build procedures will automatically
    use them:</para-->
    <para>目前 GCC 依赖于 GMP、MPFR 和 MPC 这三个包。
		由于宿主发行版未必包含它们，我们将它们和 GCC 一同构建。
		将它们都解压到 GCC 源码目录中，并重命名解压出的目录，
		这样 GCC 构建过程就能自动使用它们：</para>

    <note><!--para>There are frequent misunderstandings about this chapter.  The
    procedures are the same as every other chapter as explained earlier (<xref
    linkend='buildinstr'/>).  First extract the gcc tarball from the sources
    directory and then change to the directory created.  Only then should you
	proceed with the instructions below.</para-->
        <para>对于本章内容有一些很常见的误解。该软件包的构建过程就像之前
			(<xref linkend='buildinstr'/>) 解释的那样，
			首先解压 GCC 压缩包，切换到解压出的目录中，再执行下面的命令。
		</para>
	</note>

<screen><userinput remap="pre">tar -xf ../mpfr-&mpfr-version;.tar.xz
mv -v mpfr-&mpfr-version; mpfr
tar -xf ../gmp-&gmp-version;.tar.xz
mv -v gmp-&gmp-version; gmp
tar -xf ../mpc-&mpc-version;.tar.gz
mv -v mpc-&mpc-version; mpc</userinput></screen>

	<para>下面的命令修改 GCC 的默认动态链接器位置，以使用
		<filename class="directory">/tools</filename> 中的动态链接器。
		同时，从 GCC 的头文件搜索路径中删除
		<filename class="directory">/usr/include</filename> 。执行：</para>

<screen><userinput remap="pre">for file in gcc/config/{linux,i386/linux{,64}}.h
do
  cp -uv $file{,.orig}
  sed -e 's@/lib\(64\)\?\(32\)\?/ld@/tools&amp;@g' \
      -e 's@/usr@/tools@g' $file.orig &gt; $file
  echo '
#undef STANDARD_STARTFILE_PREFIX_1
#undef STANDARD_STARTFILE_PREFIX_2
#define STANDARD_STARTFILE_PREFIX_1 "/tools/lib/"
#define STANDARD_STARTFILE_PREFIX_2 ""' &gt;&gt; $file
  touch $file.orig
done</userinput></screen>

    <!--para>In case the above seems hard to follow, let's break it down a bit.
    First we copy the files <filename>gcc/config/linux.h</filename>,
    <filename>gcc/config/i386/linux.h</filename>, and
    <filename>gcc/config/i368/linux64.h</filename> to a file of
    the same name but with an added suffix of <quote>.orig</quote>. Then the
    first sed expression prepends <quote>/tools</quote> to every instance of
    <quote>/lib/ld</quote>, <quote>/lib64/ld</quote> or
    <quote>/lib32/ld</quote>, while the second one replaces hard-coded
    instances of <quote>/usr</quote>. Next, we add our define statements which
    alter the default startfile prefix to the end of the file. Note that the
    trailing <quote>/</quote> in <quote>/tools/lib/</quote> is required.
    Finally, we use <command>touch</command> to update the timestamp on the
    copied files.  When used in conjunction with <command>cp -u</command>, this
    prevents unexpected changes to the original files in case the commands are
	inadvertently run twice.</para-->
    <para>如果上面的命令看上去难以理解，把它分开来看。首先我们复制
		<filename>gcc/config/linux.h</filename>、
		<filename>gcc/config/i386/linux.h</filename>、
		<filename>gcc/config/i386/linux64.h</filename>，
		将它们备份为名称是原文件名加上 <quote>.orig</quote> 后缀的文件。
		然后第一个 sed 表达式将所有 <quote>/lib/ld</quote>、
		<quote>/lib64/ld</quote> 或者 <quote>/lib32/ld</quote>
		之前都加上 <quote>/tools</quote>，第二个将硬编码的
		<quote>/usr</quote> 替换掉。然后，我们在文件末尾增加自己的宏定义，
		修改默认的启动文件 (startfile) 前缀。注意，在
		<quote>/tools/lib/</quote> 中，最后的 <quote>/</quote> 是必要的。
		最后，使用 <command>touch</command> 命令更新被复制的文件的时间戳。
		这与 <command>cp -u</command> 命令结合起来，
		防止我们不小心把命令输入两次，从而对文件造成非预期的修改。</para>

    <!--para>Finally, on x86_64 hosts, set the default directory name for
    64-bit libraries to <quote>lib</quote>:</para-->
    <para>对于 x86_64 平台，还要设置存放 64 位库的默认目录为
		<quote>lib</quote>：</para>

<screen><userinput remap="pre">case $(uname -m) in
  x86_64)
    sed -e '/m64=/s/lib64/lib/' \
        -i.orig gcc/config/i386/t-linux64
 ;;
esac</userinput></screen>

<!--
    <para>GCC doesn't detect stack protection correctly, which causes problems
    for the build of Glibc-&glibc-version;, so fix that by issuing the following
    command:</para>

<screen><userinput remap="pre">sed -i '/k prot/agcc_cv_libc_provides_ssp=yes' gcc/configure</userinput></screen>
-->

<!--
    <para>Also fix a problem identified upstream:</para>

<screen><userinput remap="pre">sed -i 's/if \((code.*))\)/if (\1 \&amp;\&amp; \!DEBUG_INSN_P (insn))/' gcc/sched-deps.c</userinput></screen>
-->
    <!--para>The GCC documentation recommends building GCC 
    in a dedicated build directory:</para-->
    <para>GCC 文档建议在一个专用目录中构建 GCC：</para>

<screen><userinput remap="pre">mkdir -v build
cd       build</userinput></screen>

    <para>准备编译 GCC：</para>

<screen><userinput remap="configure">../configure                                       \
    --target=$LFS_TGT                              \
    --prefix=/tools                                \
    --with-glibc-version=2.11                      \
    --with-sysroot=$LFS                            \
    --with-newlib                                  \
    --without-headers                              \
    --with-local-prefix=/tools                     \
    --with-native-system-header-dir=/tools/include \
    --disable-nls                                  \
    --disable-shared                               \
    --disable-multilib                             \
    --disable-decimal-float                        \
    --disable-threads                              \
    --disable-libatomic                            \
    --disable-libgomp                              \
    --disable-libmpx                               \
    --disable-libquadmath                          \
    --disable-libssp                               \
    --disable-libvtv                               \
    --disable-libstdcxx                            \
    --enable-languages=c,c++</userinput></screen>
    <variablelist>
      <title>配置选项的含义：</title>

      <varlistentry>
        <term><parameter>--with-newlib</parameter></term>
        <listitem>
          <!--para>Since a working C library is not yet available, this ensures
          that the inhibit_libc constant is defined when building libgcc. This prevents
          the compiling of any code that requires libc support.</para-->
          <para>由于现在没有可用的 C 运行库，使用该选项保证构建 libgcc
			  时 inhibit_libc 常量被定义，
			  以防止编译任何需要 libc 支持的代码。</para>
		  <note><title>译注</title>
			  <para>这个选项对于嵌入式系统工程师来说显得很奇怪，
			  因为 LFS 和嵌入式系统中常用的 C 运行库 newlib 毫无关系。
			  参见译者和 GCC 开发者的讨论：

<ulink url="https://gcc.gnu.org/ml/gcc-help/2017-04/msg00029.html"/>。
		  
		  </para></note>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><parameter>--without-headers</parameter></term>
        <listitem>
          <!--para>When creating a complete cross-compiler, GCC requires
          standard headers compatible with the target system. For our
          purposes these headers will not be needed. This switch prevents
          GCC from looking for them.</para-->
	      <para>在创建完整的交叉编译器时，
			  GCC 需要与目标系统兼容的标准头文件。
			  由于我们的特殊目的，这些头文件并不必要。
			  这个开关防止 GCC 查找它们。</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><parameter>--with-local-prefix=/tools</parameter></term>
        <listitem>
          <!--para>The local prefix is the location in the system that GCC will search
          for locally installed include files. The default is <filename>/usr/local</filename>.
          Setting this to <filename>/tools</filename> helps keep the host location of
          <filename>/usr/local</filename> out of this GCC's search path.</para-->
          <para>本地前缀是 GCC 在系统中寻找本地安装的包含文件的位置，
			  它的默认值是
			  <filename class="directory">/usr/local</filename> 。
			  将它设置为 <filename class="directory">/tools</filename>，
			  从而将宿主系统的
			  <filename class="directory">/usr/local</filename>
			  排除在 GCC 搜索路径外。</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><parameter>--with-native-system-header-dir=/tools/include</parameter></term>
        <listitem>
          <!--para>By default GCC searches <filename>/usr/include</filename> for
          system headers. In conjunction with the sysroot switch, this would
          normally translate to <filename>$LFS/usr/include</filename>. However
          the headers that will be installed in the next two sections will go
          to <filename>$LFS/tools/include</filename>. This switch ensures that
          gcc will find them correctly. In the second pass of GCC, this same
          switch will ensure that no headers from the host system are
          found.</para-->
          <para>默认情况下，GCC 在
			  <filename class="directory">/usr/include</filename>
			  中搜索系统头文件。由于我们使用了 sysroot 开关，
			  它会被改写成
			  <filename class="directory">$LFS/usr/include</filename>。
			  然而，在之后的两节中，我们会把头文件安装在
			  <filename class="directory">$LFS/tools/include</filename>，
			  本开关保证 GCC 能够正确地找到它们。
			  在第二遍编译 GCC 时，这个开关保证不会查找宿主系统的头文件。
		  </para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><parameter>--disable-shared</parameter></term>
        <listitem>
          <!--para>This switch forces GCC to link its internal libraries
          statically. We do this to avoid possible issues with the host
          system.</para-->
	      <para>这个开关强制 GCC 静态链接它的内部库，
			  以防止宿主系统可能带来的问题。</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><parameter>--disable-decimal-float, --disable-threads,
        --disable-libatomic, --disable-libgomp, --disable-libmpx,
        --disable-libquadmath, --disable-libssp, --disable-libvtv,
        --disable-libstdcxx</parameter></term>
        <listitem>
          <!--para>These switches disable support for the decimal floating point
          extension, threading, libatomic, libgomp, libmpx, libquadmath, libssp,
          libvtv, and the C++ standard library respectively. These features
          will fail to compile when building a cross-compiler and are not
          necessary for the task of cross-compiling the temporary libc.</para-->
          <para>这些开关禁用对于十进制浮点数、线程、libatomic、libgomp、
			  libmpx、libquadmath、libssp、libvtv 和 C++ 标准库的支持。
			  在构建交叉编译器时它们的编译会失败，而且在交叉编译临时 libc
			  时并不需要它们。</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><parameter>--disable-multilib</parameter></term>
        <listitem>
          <!--para>On x86_64, LFS does not yet support a multilib configuration.
          This switch is harmless for x86.</para-->
          <para>在 x86_64 平台上，LFS 目前不支持 multilib 配置。
			  这个开关对于 x86 来说可有可无。</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term><parameter>--enable-languages=c,c++</parameter></term>
        <listitem>
          <!--para>This option ensures that only the C and C++ compilers are built.
		  These are the only languages needed now.</para-->
	      <para>这个选项保证只构建 C 和 C++ 编译器。目前只需要这两个语言。
		  </para>
        </listitem>
      </varlistentry>

    </variablelist>

    <para>执行以下命令编译 GCC：</para>

<screen><userinput remap="make">make</userinput></screen>

    <!--para>Compilation is now complete. At this point, the test suite would
    normally be run, but, as mentioned before, the test suite framework is
    not in place yet. The benefits of running the tests at this point
    are minimal since the programs from this first pass will soon be
    replaced.</para-->
    <para>现在我们编译完成了 GCC。此时，通常来说应该执行测试套件。
		然而正如前文所述，测试套件框架还没有就位，
		而且第一遍编译的 GCC 程序很快就会被替换，运行测试套件的收益极小。
	</para>

    <para>安装该软件包：</para>

<screen><userinput remap="install">make install</userinput></screen>
<!--
    <para>Using <parameter>- -disable-shared</parameter> means that the
    <filename>libgcc_eh.a</filename> file isn't created and installed. The
    Glibc package depends on this library as it uses
    <parameter>-lgcc_eh</parameter> within its build system. This dependency
    can be satisfied by creating a symlink to <filename>libgcc.a</filename>,
    since that file will end up containing the objects normally contained in
    <filename>libgcc_eh.a</filename>:</para>

<screen><userinput remap="install">ln -sv libgcc.a `$LFS_TGT-gcc -print-libgcc-file-name | sed 's/libgcc/&amp;_eh/'`</userinput></screen>
-->
  </sect2>

  <sect2 role="content">
    <title/>

    <para>该软件包的更多细节在
    <xref linkend="contents-gcc"/> 中可以找到。</para>

  </sect2>

</sect1>
