yann@2076: File.........: 5 - Using the toolchain.txt yann@2908: Copyright....: (C) 2010 Yann E. MORIN yann@2076: License......: Creative Commons Attribution Share Alike (CC-by-sa), v2.5 yann@2076: yann@2076: yann@2076: Using the toolchain / yann@2076: ____________________/ yann@2076: yann@2076: yann@2076: Using the toolchain is as simple as adding the toolchain's bin directory in yann@2076: your PATH, such as: yann@2076: export PATH="${PATH}:/your/toolchain/path/bin" yann@2076: twoerner@2753: and then using the '--host' tuple to tell the build systems to use your twoerner@2753: toolchain (if the software package uses the autotools system you should twoerner@2753: also pass --build, for completeness): twoerner@2753: ./configure --host=your-host-tuple --build=your-build-tuple yann@2076: or twoerner@2753: make CC=your-host-tuple-gcc yann@2076: or twoerner@2753: make CROSS_COMPILE=your-host-tuple- yann@2076: and so on... yann@2076: twoerner@2753: (Note: in the above example, 'host' refers to the host of your program, twoerner@2753: not the host of the toolchain; and 'build' refers to the machine where twoerner@2753: you build your program, that is the host of the toolchain.) twoerner@2753: twoerner@2764: twoerner@2764: Assembling a root filesystem / twoerner@2764: _____________________________/ twoerner@2764: twoerner@2764: twoerner@2764: Assembling a root filesystem for a target device requires the successive twoerner@2764: building of a set of software packages for the target architecture. Building twoerner@2764: a package potentially requires artifacts which were generated as part of an twoerner@2764: earlier build. Note that not all artifacts which are installed as part of a twoerner@2764: package are desirable on a target's root filesystem (e.g. man/info files, twoerner@2764: include files, etc.). Therefore we must distinguish between a 'staging' twoerner@2764: directory and a 'rootfs' directory. twoerner@2764: twoerner@2764: A 'staging' directory is a location into which we install all the build twoerner@2764: artifacts. We can then point future builds to this location so they can find twoerner@2764: the appropriate header and library files. A 'rootfs' directory is a location twoerner@2764: into which we place only the files we want to have on our target. twoerner@2764: twoerner@2764: There are four schools of thought here: twoerner@2764: twoerner@2764: 1) Install directly into the sysroot of the toolchain. twoerner@2764: twoerner@2764: By default (i.e. if you don't pass any arguments to the tools which twoerner@2764: would change this behaviour) the toolchain that is built by twoerner@2764: crosstool-NG will only look in its toolchain directories for system twoerner@2764: header and library files: twoerner@2764: twoerner@2764: #include "..." search starts here: twoerner@2764: #include <...> search starts here: twoerner@2764: /lib/gcc//4.5.2/include twoerner@2764: /lib/gcc//4.5.2/include-fixed twoerner@2764: /lib/gcc//4.5.2/../../../..//include twoerner@2764: //sysroot/usr/include twoerner@2764: twoerner@2764: In other words, the compiler will automagically find headers and twoerner@2764: libraries without extra flags if they are installed under the twoerner@2764: toolchain's sysroot directory. twoerner@2764: twoerner@2764: However, this is bad because the toolchain gets poluted, and can twoerner@2764: not be re-used. twoerner@2764: twoerner@2764: $ ./configure --build= --host= \ twoerner@2764: --prefix=/usr --enable-foo-bar... twoerner@2764: $ make twoerner@2764: $ make DESTDIR=///sysroot install twoerner@2764: twoerner@2764: 2) Copy the toolchain's sysroot to the 'staging' area. twoerner@2764: twoerner@2764: If you start off by copying the toolchain's sysroot directory to your twoerner@2764: staging area, you can simply proceed to install all your packages' twoerner@2764: artifacts to the same staging area. You then only need to specify a twoerner@2764: '--sysroot=' option to the compiler of any subsequent twoerner@2764: builds and all your required header and library files will be found/used. twoerner@2764: twoerner@2764: This is a viable option, but requires the user to always specify CFLAGS twoerner@2764: in order to include --sysroot=, or requires the use of a twoerner@2764: wrapper to a few select tools (gcc, ld...) to pass this flag. twoerner@2764: twoerner@2764: Instead of polluting the toolchain's sysroot you are copying its contents twoerner@2764: to a new location and polluting the contents in that new location. By twoerner@2764: specifying the --sysroot option you're effectively abandoning the default twoerner@2764: sysroot in favour of your own. twoerner@2764: twoerner@2764: Incidentally this is what buildroot does using a wrapper, when using an twoerner@2764: external toolchain. twoerner@2764: twoerner@2764: $ cp -a $(-gcc --your-cflags-except-sysroot -print-sysroot) \ twoerner@2764: /path/to/staging twoerner@2764: $ ./configure --build= --host= \ twoerner@2764: --prefix=/usr --enable-foo-bar... \ twoerner@2764: CC="-gcc --syroot=/path/to/staging" \ twoerner@2764: CXX="-g++ --sysroot=/path/to/staging" \ twoerner@2764: LD="-ld --sysroot=/path/to/staging" \ twoerner@2764: AND_SO_ON="tuple-andsoon --sysroot=/path/to/staging" twoerner@2764: $ make twoerner@2764: $ make DESTDIR=/path/to/staging install twoerner@2764: twoerner@2764: 3) Use separate staging and sysroot directories. twoerner@2764: twoerner@2764: In this scenario you use a staging area to install programs, but you do twoerner@2764: not pre-fill that staging area with the toolchain's sysroot. In this case twoerner@2764: the compiler will find the system includes and libraries in its sysroot twoerner@2764: area but you have to pass appropriate CPPFLAGS and LDFLAGS to tell it twoerner@2764: where to find your headers and libraries from your staging area (or use twoerner@2764: a wrapper). twoerner@2764: twoerner@2764: $ ./configure --build= --host= \ twoerner@2764: --prefix=/usr --enable-foo-bar... \ twoerner@2764: CPPFLAGS="-I/path/to/staging/usr/include" \ twoerner@2764: LDFLAGS="-L/path/to/staging/lib -L/path/to/staging/usr/lib" twoerner@2764: $ make twoerner@2764: $ make DESTDIR=/path/to/staging install twoerner@2764: twoerner@2764: 4) A mix of 2) and 3), using carefully crafted union mounts. twoerner@2764: twoerner@2764: The staging area is a union mount of: twoerner@2764: - the sysroot as a read-only branch twoerner@2764: - the real staging area as a read-write branch twoerner@2764: This also requires passing --sysroot to point to the union mount, but has twoerner@2764: other advantages, such as allowing per-package staging, and a few more twoerner@2764: obscure pros. It also has its disadvantages, as it potentially requires twoerner@2764: non-root users to create union mounts. Additionally, union mounts are not twoerner@2764: yet mainstream in the Linux kernel, so it requires patching. There is a twoerner@2764: FUSE-based unionfs implementation, but development is almost stalled, twoerner@2764: and there are a few gotchas... twoerner@2764: twoerner@2764: $ (good luck!) twoerner@2764: twoerner@2764: yann@2279: It is strongly advised not to use the toolchain sysroot directory as an twoerner@2764: install directory (i.e. option 1) for your programs/packages. If you do so, twoerner@2764: you will not be able to use your toolchain for another project. It is even twoerner@2764: strongly advised that your toolchain is chmod-ed to read-only once twoerner@2764: successfully install, so that you don't go polluting your toolchain with twoerner@2764: your programs'/packages' files. This can be achieved by selecting the twoerner@2764: "Render the toolchain read-only" from crosstool-NG's "Paths and misc options" twoerner@2764: configuration page. yann@2076: twoerner@2764: Thus, when you build a program/package, install it in a separate, staging, twoerner@2764: directory and let the cross-toolchain continue to use its own, pristine, twoerner@2764: sysroot directory. twoerner@2764: twoerner@2764: When you are done building and want to assemble your rootfs you could simply twoerner@2764: take the full contents of your staging directory and use the 'populate' twoerner@2764: script to add in the necessary files from the sysroot. However, the staging twoerner@2764: area you have created will include lots of build artifacts that you won't twoerner@2764: necessarily want/need on your target. For example: static libraries, header twoerner@2764: files, linking helper files, man/info pages. You'll also need to add various twoerner@2764: configuration files, scripts, and directories to the rootfs so it will boot. twoerner@2764: twoerner@2764: Therefore you'll probably end up creating a separate rootfs directory which twoerner@2764: you will populate from the staging area, necessary extras, and then use twoerner@2764: crosstool-NG's populate script to add the necessary sysroot libraries. yann@2076: yann@2076: yann@2076: The 'populate' script | yann@2076: ----------------------+ yann@2076: yann@2076: When your root directory is ready, it is still missing some important bits: the yann@2076: toolchain's libraries. To populate your root directory with those libs, just yann@2076: run: yann@2076: your-target-tuple-populate -s /your/root -d /your/root-populated yann@2076: yann@2076: This will copy /your/root into /your/root-populated, and put the needed and only antony@2564: the needed libraries there. Thus you don't pollute /your/root with any cruft that yann@2076: would no longer be needed should you have to remove stuff. /your/root always yann@2076: contains only those things you install in it. yann@2076: yann@2076: You can then use /your/root-populated to build up your file system image, a yann@2076: tarball, or to NFS-mount it from your target, or whatever you need. yann@2076: yann@2076: The populate script accepts the following options: yann@2076: yann@2076: -s src_dir yann@2076: Use 'src_dir' as the un-populated root directory. yann@2076: yann@2076: -d dst_dir yann@2076: Put the populated root directory in 'dst_dir'. yann@2076: yann@2076: -l lib1 [...] yann@2076: Always add specified libraries. yann@2076: yann@2076: -L file yann@2076: Always add libraries listed in 'file'. yann@2076: yann@2076: -f yann@2076: Remove 'dst_dir' if it previously existed; continue even if any library yann@2076: specified with -l or -L is missing. yann@2076: yann@2076: -v yann@2076: Be verbose, and tell what's going on (you can see exactly where libs are yann@2076: coming from). yann@2076: yann@2076: -h yann@2076: Print the help. yann@2076: yann@2076: See 'your-target-tuple-populate -h' for more information on the options. yann@2076: yann@2076: Here is how populate works: yann@2076: yann@2076: 1) performs some sanity checks: yann@2076: - src_dir and dst_dir are specified yann@2076: - src_dir exists yann@2076: - unless forced, dst_dir does not exist yann@2076: - src_dir != dst_dir yann@2076: yann@2076: 2) copy src_dir to dst_dir yann@2076: yann@2076: 3) add forced libraries to dst_dir yann@2076: - build the list from -l and -L options yann@2076: - get forced libraries from the sysroot (see below for heuristics) yann@2076: - abort on the first missing library, unless -f is specified yann@2076: yann@2076: 4) add all missing libraries to dst_dir yann@2076: - scan dst_dir for every ELF files that are 'executable' or yann@2076: 'shared object' yann@2076: - list the "NEEDED Shared library" fields yann@2076: - check if the library is already in dst_dir/lib or dst_dir/usr/lib yann@2076: - if not, get the library from the sysroot yann@2076: - if it's in sysroot/lib, copy it to dst_dir/lib yann@2076: - if it's in sysroot/usr/lib, copy it to dst_dir/usr/lib yann@2076: - in both cases, use the SONAME of the library to create the file yann@2076: in dst_dir yann@2076: - if it was not found in the sysroot, this is an error.