summary refs log tree commit diff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/cross-compilation.xml153
-rw-r--r--doc/manual.xml1
-rw-r--r--doc/stdenv.xml92
3 files changed, 209 insertions, 37 deletions
diff --git a/doc/cross-compilation.xml b/doc/cross-compilation.xml
new file mode 100644
index 000000000000..e93d1a98f7fd
--- /dev/null
+++ b/doc/cross-compilation.xml
@@ -0,0 +1,153 @@
+<chapter xmlns="http://docbook.org/ns/docbook"
+         xmlns:xlink="http://www.w3.org/1999/xlink"
+         xml:id="chap-cross">
+
+<title>Cross-compilation</title>
+
+<section xml:id="sec-cross-intro">
+  <title>Introduction</title>
+  <para>
+    "Cross-compilation" means compiling a program on one machine for another type of machine.
+    For example, a typical use of cross compilation is to compile programs for embedded devices.
+    These devices often don't have the computing power and memory to compile their own programs.
+    One might think that cross-compilation is a fairly niche concern, but there are advantages to being rigorous about distinguishing build-time vs run-time environments even when one is developing and deploying on the same machine.
+    Nixpkgs is increasingly adopting this opinion in that packages should be written with cross-compilation in mind, and nixpkgs should evaluate in a similar way (by minimizing cross-compilation-specific special cases) whether or not one is cross-compiling.
+  </para>
+
+  <para>
+    This chapter will be organized in three parts.
+    First, it will describe the basics of how to package software in a way that supports cross-compilation.
+    Second, it will describe how to use Nixpkgs when cross-compiling.
+    Third, it will describe the internal infrastructure supporting cross-compilation.
+  </para>
+</section>
+
+<!--============================================================-->
+
+<section xml:id="sec-cross-packaging">
+  <title>Packing in a cross-friendly manner</title>
+
+  <section>
+    <title>Platform parameters</title>
+    <para>
+      The three GNU Autoconf platforms, <wordasword>build</wordasword>, <wordasword>host</wordasword>, and <wordasword>cross</wordasword>, are historically the result of much confusion.
+      <link xlink:href="https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html" /> clears this up somewhat but there is more to be said.
+      An important advice to get out the way is, unless you are packaging a compiler or other build tool, just worry about the build and host platforms.
+      Dealing with just two platforms usually better matches people's preconceptions, and in this case is completely correct.
+    </para>
+    <para>
+      In Nixpkgs, these three platforms are defined as attribute sets under the names <literal>buildPlatform</literal>, <literal>hostPlatform</literal>, and <literal>targetPlatform</literal>.
+      All are guaranteed to contain at least a <varname>platform</varname> field, which contains detailed information on the platform.
+      All three are always defined at the top level, so one can get at them just like a dependency in a function that is imported with <literal>callPackage</literal>:
+      <programlisting>{ stdenv, buildPlatform, hostPlatform, fooDep, barDep, .. }: ...</programlisting>
+    </para>
+    <warning><para>
+      These platforms should all have the same structure in all scenarios, but that is currently not the case.
+      When not cross-compiling, they will each contain a <literal>system</literal> field with a short 2-part, hyphen-separated summering string name for the platform.
+      But, when when cross compiling, <literal>hostPlatform</literal> and <literal>targetPlatform</literal> may instead contain <literal>config</literal> with a fuller 3- or 4-part string in the manner of LLVM.
+      We should have all 3 platforms always contain both, and maybe give <literal>config</literal> a better name while we are at it.
+    </para></warning>
+    <variablelist>
+      <varlistentry>
+        <term><varname>buildPlatform</varname></term>
+        <listitem><para>
+          The "build platform" is the platform on which a package is built.
+          Once someone has a built package, or pre-built binary package, the build platform should not matter and be safe to ignore.
+        </para></listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>hostPlatform</varname></term>
+        <listitem><para>
+          The "host platform" is the platform on which a package is run.
+          This is the simplest platform to understand, but also the one with the worst name.
+        </para></listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>targetPlatform</varname></term>
+        <listitem>
+          <para>
+            The "target platform" is black sheep.
+            The other two intrinsically apply to all compiled software—or any build process with a notion of "build-time" followed by "run-time".
+            The target platform only applies to programming tools, and even then only is a good for for some of them.
+            Briefly, GCC, Binutils, GHC, and certain other tools are written in such a way such that a single build can only compiler code for a single platform.
+            Thus, when building them, one must think ahead about what platforms they wish to use the tool to produce machine code for, and build binaries for each.
+          </para>
+          <para>
+            There is no fundamental need to think about the target ahead of time like this.
+            LLVM, for example, was designed from the beginning with cross-compilation in mind, and so a normal LLVM binary will support every architecture that LLVM supports.
+            If the tool supports modular or pluggable backends, one might imagine specifying a <emphasis>set</emphasis> of target platforms / backends one wishes to support, rather than a single one.
+          </para>
+          <para>
+            The biggest reason for mess, if there is one, is that many compilers have the bad habit a build process that builds the compiler and standard library/runtime together.
+            Then the specifying target platform is essential, because it determines the host platform of the standard library/runtime.
+            Nixpkgs tries to avoid this where possible too, but still, because the concept of a target platform is so ingrained now in Autoconf and other tools, it is best to support it as is.
+            Tools like LLVM that don't need up-front target platforms can safely ignore it like normal packages, and it will do no harm.
+          </para>
+          </listitem>
+      </varlistentry>
+    </variablelist>
+    <note><para>
+      If you dig around nixpkgs, you may notice there is also <varname>stdenv.cross</varname>.
+      This field defined as <varname>hostPlatform</varname> when the host and build platforms differ, but otherwise not defined at all.
+      This field is obsolete and will soon disappear—please do not use it.
+    </para></note>
+  </section>
+
+  <section>
+    <title>Specifying Dependencies</title>
+    <para>
+      As mentioned in the introduction to this chapter, one can think about a build time vs run time distinction whether cross-compiling or not.
+      In the case of cross-compilation, this corresponds with whether a derivation running on the native or foreign platform is produced.
+      An interesting thing to think about is how this corresponds with the three Autoconf platforms.
+      In the run-time case, the depending and depended-on package simply have matching build, host, and target platforms.
+      But in the build-time case, one can imagine "sliding" the platforms one over.
+      The depended-on package's host and target platforms (respectively) become the depending package's build and host platforms.
+      This is the most important guiding principle behind cross-compilation with Nixpkgs, and will be called the <wordasword>sliding window principle</wordasword>.
+      In this manner, given the 3 platforms for one package, we can determine the three platforms for all its transitive dependencies.
+    </para>
+    <note><para>
+      The depending package's target platform is unconstrained by the sliding window principle, which makes sense in that one can in principle build cross compilers targeting arbitrary platforms.
+    </para></note>
+    <warning><para>
+      From the above, one would surmise that if a package is being built with a <literal>(build, host, target)</literal> platform triple of <literal>(foo, bar, bar)</literal>, then its build-time dependencies would have a triple of <literal>(foo, foo, bar)</literal>, and <emphasis>those packages'</emphasis> build-time dependencies would have triple of <literal>(foo, foo, foo)</literal>.
+      In other words, it should take two "rounds" of following build-time dependency edges before one reaches a fixed point where, by the sliding window principle, the platform triple no longer changes.
+      Unfortunately, at the moment, we do <emphasis>not</emphasis> implement this correctly, and after only one round of following build-time dependencies is the fixed point reached, with target incorrectly kept different than the others.
+    </para></warning>
+    <para>
+      How does this work in practice? Nixpkgs is now structured so that build-time dependencies are taken from from <varname>buildPackages</varname>, whereas run-time dependencies are taken from the top level attribute set.
+      For example, <varname>buildPackages.gcc</varname> should be used at build time, while <varname>gcc</varname> should be used at run time.
+      Now, for most of Nixpkgs's history, there was no <varname>buildPackages</varname>, and most packages have not been refactored to use it explicitly.
+      Instead, one can use the four attributes used for specifying dependencies as documented in <link linkend="ssec-stdenv-attributes" />.
+      We "splice" together the run-time and build-time package sets with <varname>callPackage</varname>, and then <varname>mkDerivation</varname> for each of four attributes pulls the right derivation out.
+      This splicing can be skipped when not cross compiling as the package sets are the same, but is a bit slow for cross compiling.
+      Because of this, a best-of-both-worlds solution is in the works with no splicing or explicit access of <varname>buildPackages</varname> needed.
+      For now, feel free to use either method.
+    </para>
+  </section>
+
+</section>
+
+<!--============================================================-->
+
+<section xml:id="sec-cross-usage">
+  <title>Cross-building packages</title>
+  <para>
+    To be written.
+    This is basically unchanged so see the old wiki for now.
+  </para>
+</section>
+
+<!--============================================================-->
+
+<section xml:id="sec-cross-infra">
+  <title>Cross-compilation infrastructure</title>
+  <para>To be written.</para>
+  <note><para>
+    If one explores nixpkgs, they will see derivations with names like <literal>gccCross</literal>.
+    Such <literal>*Cross</literal> derivations is a holdover from before we properly distinguished between the host and target platforms
+    —the derivation with "Cross" in the name covered the <literal>build = host != target</literal> case, while the other covered the <literal>host = target</literal>, with build platform the same or not based on whether one was using its <literal>.nativeDrv</literal> or <literal>.crossDrv</literal>.
+    This ugliness will disappear soon.
+  </para></note>
+</section>
+
+</chapter>
diff --git a/doc/manual.xml b/doc/manual.xml
index 1c0dac6e4df7..75bd21557fd1 100644
--- a/doc/manual.xml
+++ b/doc/manual.xml
@@ -13,6 +13,7 @@
   <xi:include href="quick-start.xml" />
   <xi:include href="stdenv.xml" />
   <xi:include href="multiple-output.xml" />
+  <xi:include href="cross-compilation.xml" />
   <xi:include href="configuration.xml" />
   <xi:include href="functions.xml" />
   <xi:include href="meta.xml" />
diff --git a/doc/stdenv.xml b/doc/stdenv.xml
index 44a0e4601fc1..6ec5c9f2814f 100644
--- a/doc/stdenv.xml
+++ b/doc/stdenv.xml
@@ -194,33 +194,52 @@ genericBuild
     tools.</para></listitem>
   </varlistentry>
 
+</variablelist>
+
+<variablelist>
+  <title>Variables specifying dependencies</title>
+
+  <varlistentry>
+    <term><varname>nativeBuildInputs</varname></term>
+    <listitem><para>
+      A list of dependencies used by the new derivation at <emphasis>build</emphasis>-time.
+      I.e. these dependencies should not make it into the package's runtime-closure, though this is currently not checked.
+      For each dependency <replaceable>dir</replaceable>, the directory <filename><replaceable>dir</replaceable>/bin</filename>, if it exists, is added to the <envar>PATH</envar> environment variable.
+      Other environment variables are also set up via a pluggable mechanism.
+      For instance, if <varname>buildInputs</varname> contains Perl, then the <filename>lib/site_perl</filename> subdirectory of each input is added to the <envar>PERL5LIB</envar> environment variable.
+      See <xref linkend="ssec-setup-hooks"/> for details.
+    </para></listitem>
+  </varlistentry>
+
   <varlistentry>
     <term><varname>buildInputs</varname></term>
-    <listitem><para>A list of dependencies used by
-    <literal>stdenv</literal> to set up the environment for the build.
-    For each dependency <replaceable>dir</replaceable>, the directory
-    <filename><replaceable>dir</replaceable>/bin</filename>, if it
-    exists, is added to the <envar>PATH</envar> environment variable.
-    Other environment variables are also set up via a pluggable
-    mechanism.  For instance, if <varname>buildInputs</varname>
-    contains Perl, then the <filename>lib/site_perl</filename>
-    subdirectory of each input is added to the <envar>PERL5LIB</envar>
-    environment variable.  See <xref linkend="ssec-setup-hooks"/> for
-    details.</para></listitem>
-  </varlistentry>
-  
+    <listitem><para>
+      A list of dependencies used by the new derivation at <emphasis>run</emphasis>-time.
+      Currently, the build-time environment is modified in the exact same way as with <varname>nativeBuildInputs</varname>.
+      This is problematic in that when cross-compiling, foreign executables can clobber native ones on the <envar>PATH</envar>.
+      Even more confusing is static-linking.
+      A statically-linked library should be listed here because ultimately that generated machine code will be used at run-time, even though a derivation containing the object files or static archives will only be used at build-time.
+      A less confusing solution to this would be nice.
+    </para></listitem>
+  </varlistentry>
+
+
+  <varlistentry>
+    <term><varname>propagatedNativeBuildInputs</varname></term>
+    <listitem><para>
+      Like <varname>nativeBuildInputs</varname>, but these dependencies are <emphasis>propagated</emphasis>:
+      that is, the dependencies listed here are added to the <varname>nativeBuildInputs</varname> of any package that uses <emphasis>this</emphasis> package as a dependency.
+      So if package Y has <literal>propagatedBuildInputs = [X]</literal>, and package Z has <literal>buildInputs = [Y]</literal>, then package X will appear in Z’s build environment automatically.
+    </para></listitem>
+  </varlistentry>
+
   <varlistentry>
     <term><varname>propagatedBuildInputs</varname></term>
-    <listitem><para>Like <varname>buildInputs</varname>, but these
-    dependencies are <emphasis>propagated</emphasis>: that is, the
-    dependencies listed here are added to the
-    <varname>buildInputs</varname> of any package that uses
-    <emphasis>this</emphasis> package as a dependency.  So if package
-    Y has <literal>propagatedBuildInputs = [X]</literal>, and package
-    Z has <literal>buildInputs = [Y]</literal>, then package X will
-    appear in Z’s build environment automatically.</para></listitem>
+    <listitem><para>
+      Like <varname>buildInputs</varname>, but propagated just like <varname>propagatedNativeBuildInputs</varname>.
+      This inherits <varname>buildInputs</varname>'s flaws of clobbering native executables when cross-compiling and being confusing for static linking.
+    </para></listitem>
   </varlistentry>
-  
 
 </variablelist>
 
@@ -322,7 +341,7 @@ executed and in what order:
       $preInstallPhases installPhase fixupPhase $preDistPhases
       distPhase $postPhases</literal>.
       </para>
-      
+
       <para>Usually, if you just want to add a few phases, it’s more
       convenient to set one of the variables below (such as
       <varname>preInstallPhases</varname>), as you then don’t specify
@@ -706,7 +725,7 @@ makeFlagsArray=(CFLAGS="-O0 -g" LDFLAGS="-lfoo -lbar")
 </variablelist>
 
 
-<para> 
+<para>
 You can set flags for <command>make</command> through the
 <varname>makeFlags</varname> variable.</para>
 
@@ -773,7 +792,7 @@ doCheck = true;</programlisting>
 
 </variablelist>
 
-  
+
 </section>
 
 
@@ -840,12 +859,12 @@ install phase.  The default <function>fixupPhase</function> does the
 following:
 
 <itemizedlist>
-      
+
   <listitem><para>It moves the <filename>man/</filename>,
   <filename>doc/</filename> and <filename>info/</filename>
   subdirectories of <envar>$out</envar> to
   <filename>share/</filename>.</para></listitem>
-      
+
   <listitem><para>It strips libraries and executables of debug
   information.</para></listitem>
 
@@ -1091,13 +1110,13 @@ functions.</para>
 
 <variablelist>
 
-  
+
   <varlistentry xml:id='fun-substitute'>
     <term><function>substitute</function>
     <replaceable>infile</replaceable>
     <replaceable>outfile</replaceable>
     <replaceable>subs</replaceable></term>
-    
+
     <listitem>
       <para>Performs string substitution on the contents of
       <replaceable>infile</replaceable>, writing the result to
@@ -1125,7 +1144,7 @@ functions.</para>
             <literal>@<replaceable>...</replaceable>@</literal> in the
             template as placeholders.</para></listitem>
           </varlistentry>
-          
+
           <varlistentry>
             <term><option>--subst-var-by</option>
             <replaceable>varName</replaceable>
@@ -1134,7 +1153,7 @@ functions.</para>
             <literal>@<replaceable>varName</replaceable>@</literal> by
             the string <replaceable>s</replaceable>.</para></listitem>
           </varlistentry>
-          
+
         </variablelist>
 
       </para>
@@ -1162,7 +1181,7 @@ substitute ./foo.in ./foo.out \
 
     </listitem>
   </varlistentry>
-  
+
 
   <varlistentry xml:id='fun-substituteInPlace'>
     <term><function>substituteInPlace</function>
@@ -1173,7 +1192,7 @@ substitute ./foo.in ./foo.out \
     <replaceable>file</replaceable>.</para></listitem>
   </varlistentry>
 
-  
+
   <varlistentry xml:id='fun-substituteAll'>
     <term><function>substituteAll</function>
     <replaceable>infile</replaceable>
@@ -1233,7 +1252,7 @@ echo @foo@
     <listitem><para>Strips the directory and hash part of a store
     path, outputting the name part to <literal>stdout</literal>.
     For example:
-    
+
 <programlisting>
 # prints coreutils-8.24
 stripHash "/nix/store/9s9r019176g7cvn2nvcw41gsp862y6b4-coreutils-8.24"
@@ -1241,7 +1260,7 @@ stripHash "/nix/store/9s9r019176g7cvn2nvcw41gsp862y6b4-coreutils-8.24"
 
     If you wish to store the result in another variable, then the
     following idiom may be useful:
-    
+
 <programlisting>
 name="/nix/store/9s9r019176g7cvn2nvcw41gsp862y6b4-coreutils-8.24"
 someVar=$(stripHash $name)
@@ -1250,7 +1269,7 @@ someVar=$(stripHash $name)
     </para></listitem>
   </varlistentry>
 
-  
+
 </variablelist>
 
 </section>
@@ -1607,4 +1626,3 @@ Arch Wiki</link>.
 </section>
 
 </chapter>
-