yann@2076
|
1 |
File.........: 5 - Using the toolchain.txt
|
yann@2908
|
2 |
Copyright....: (C) 2010 Yann E. MORIN <yann.morin.1998@free.fr>
|
yann@2076
|
3 |
License......: Creative Commons Attribution Share Alike (CC-by-sa), v2.5
|
yann@2076
|
4 |
|
yann@2076
|
5 |
|
yann@2076
|
6 |
Using the toolchain /
|
yann@2076
|
7 |
____________________/
|
yann@2076
|
8 |
|
yann@2076
|
9 |
|
yann@2076
|
10 |
Using the toolchain is as simple as adding the toolchain's bin directory in
|
yann@2076
|
11 |
your PATH, such as:
|
yann@2076
|
12 |
export PATH="${PATH}:/your/toolchain/path/bin"
|
yann@2076
|
13 |
|
twoerner@2753
|
14 |
and then using the '--host' tuple to tell the build systems to use your
|
twoerner@2753
|
15 |
toolchain (if the software package uses the autotools system you should
|
twoerner@2753
|
16 |
also pass --build, for completeness):
|
twoerner@2753
|
17 |
./configure --host=your-host-tuple --build=your-build-tuple
|
yann@2076
|
18 |
or
|
twoerner@2753
|
19 |
make CC=your-host-tuple-gcc
|
yann@2076
|
20 |
or
|
twoerner@2753
|
21 |
make CROSS_COMPILE=your-host-tuple-
|
yann@2076
|
22 |
and so on...
|
yann@2076
|
23 |
|
twoerner@2753
|
24 |
(Note: in the above example, 'host' refers to the host of your program,
|
twoerner@2753
|
25 |
not the host of the toolchain; and 'build' refers to the machine where
|
twoerner@2753
|
26 |
you build your program, that is the host of the toolchain.)
|
twoerner@2753
|
27 |
|
twoerner@2764
|
28 |
|
twoerner@2764
|
29 |
Assembling a root filesystem /
|
twoerner@2764
|
30 |
_____________________________/
|
twoerner@2764
|
31 |
|
twoerner@2764
|
32 |
|
twoerner@2764
|
33 |
Assembling a root filesystem for a target device requires the successive
|
twoerner@2764
|
34 |
building of a set of software packages for the target architecture. Building
|
twoerner@2764
|
35 |
a package potentially requires artifacts which were generated as part of an
|
twoerner@2764
|
36 |
earlier build. Note that not all artifacts which are installed as part of a
|
twoerner@2764
|
37 |
package are desirable on a target's root filesystem (e.g. man/info files,
|
twoerner@2764
|
38 |
include files, etc.). Therefore we must distinguish between a 'staging'
|
twoerner@2764
|
39 |
directory and a 'rootfs' directory.
|
twoerner@2764
|
40 |
|
twoerner@2764
|
41 |
A 'staging' directory is a location into which we install all the build
|
twoerner@2764
|
42 |
artifacts. We can then point future builds to this location so they can find
|
twoerner@2764
|
43 |
the appropriate header and library files. A 'rootfs' directory is a location
|
twoerner@2764
|
44 |
into which we place only the files we want to have on our target.
|
twoerner@2764
|
45 |
|
twoerner@2764
|
46 |
There are four schools of thought here:
|
twoerner@2764
|
47 |
|
twoerner@2764
|
48 |
1) Install directly into the sysroot of the toolchain.
|
twoerner@2764
|
49 |
|
twoerner@2764
|
50 |
By default (i.e. if you don't pass any arguments to the tools which
|
twoerner@2764
|
51 |
would change this behaviour) the toolchain that is built by
|
twoerner@2764
|
52 |
crosstool-NG will only look in its toolchain directories for system
|
twoerner@2764
|
53 |
header and library files:
|
twoerner@2764
|
54 |
|
twoerner@2764
|
55 |
#include "..." search starts here:
|
twoerner@2764
|
56 |
#include <...> search starts here:
|
twoerner@2764
|
57 |
<ct-ng install path>/lib/gcc/<host tuple>/4.5.2/include
|
twoerner@2764
|
58 |
<ct-ng install path>/lib/gcc/<host tuple>/4.5.2/include-fixed
|
twoerner@2764
|
59 |
<ct-ng install path>/lib/gcc/<host tuple>/4.5.2/../../../../<host tuple>/include
|
twoerner@2764
|
60 |
<ct-ng install path>/<host tuple>/sysroot/usr/include
|
twoerner@2764
|
61 |
|
twoerner@2764
|
62 |
In other words, the compiler will automagically find headers and
|
twoerner@2764
|
63 |
libraries without extra flags if they are installed under the
|
twoerner@2764
|
64 |
toolchain's sysroot directory.
|
twoerner@2764
|
65 |
|
twoerner@2764
|
66 |
However, this is bad because the toolchain gets poluted, and can
|
twoerner@2764
|
67 |
not be re-used.
|
twoerner@2764
|
68 |
|
twoerner@2764
|
69 |
$ ./configure --build=<build tuple> --host=<host tuple> \
|
twoerner@2764
|
70 |
--prefix=/usr --enable-foo-bar...
|
twoerner@2764
|
71 |
$ make
|
twoerner@2764
|
72 |
$ make DESTDIR=/<ct-ng install path>/<host tuple>/sysroot install
|
twoerner@2764
|
73 |
|
twoerner@2764
|
74 |
2) Copy the toolchain's sysroot to the 'staging' area.
|
twoerner@2764
|
75 |
|
twoerner@2764
|
76 |
If you start off by copying the toolchain's sysroot directory to your
|
twoerner@2764
|
77 |
staging area, you can simply proceed to install all your packages'
|
twoerner@2764
|
78 |
artifacts to the same staging area. You then only need to specify a
|
twoerner@2764
|
79 |
'--sysroot=<staging area>' option to the compiler of any subsequent
|
twoerner@2764
|
80 |
builds and all your required header and library files will be found/used.
|
twoerner@2764
|
81 |
|
twoerner@2764
|
82 |
This is a viable option, but requires the user to always specify CFLAGS
|
twoerner@2764
|
83 |
in order to include --sysroot=<staging area>, or requires the use of a
|
twoerner@2764
|
84 |
wrapper to a few select tools (gcc, ld...) to pass this flag.
|
twoerner@2764
|
85 |
|
twoerner@2764
|
86 |
Instead of polluting the toolchain's sysroot you are copying its contents
|
twoerner@2764
|
87 |
to a new location and polluting the contents in that new location. By
|
twoerner@2764
|
88 |
specifying the --sysroot option you're effectively abandoning the default
|
twoerner@2764
|
89 |
sysroot in favour of your own.
|
twoerner@2764
|
90 |
|
twoerner@2764
|
91 |
Incidentally this is what buildroot does using a wrapper, when using an
|
twoerner@2764
|
92 |
external toolchain.
|
twoerner@2764
|
93 |
|
twoerner@2764
|
94 |
$ cp -a $(<host tuple>-gcc --your-cflags-except-sysroot -print-sysroot) \
|
twoerner@2764
|
95 |
/path/to/staging
|
twoerner@2764
|
96 |
$ ./configure --build=<build tuple> --host=<host tuple> \
|
twoerner@2764
|
97 |
--prefix=/usr --enable-foo-bar... \
|
twoerner@2764
|
98 |
CC="<host tuple>-gcc --syroot=/path/to/staging" \
|
twoerner@2764
|
99 |
CXX="<host tuple>-g++ --sysroot=/path/to/staging" \
|
twoerner@2764
|
100 |
LD="<host tuple>-ld --sysroot=/path/to/staging" \
|
twoerner@2764
|
101 |
AND_SO_ON="tuple-andsoon --sysroot=/path/to/staging"
|
twoerner@2764
|
102 |
$ make
|
twoerner@2764
|
103 |
$ make DESTDIR=/path/to/staging install
|
twoerner@2764
|
104 |
|
twoerner@2764
|
105 |
3) Use separate staging and sysroot directories.
|
twoerner@2764
|
106 |
|
twoerner@2764
|
107 |
In this scenario you use a staging area to install programs, but you do
|
twoerner@2764
|
108 |
not pre-fill that staging area with the toolchain's sysroot. In this case
|
twoerner@2764
|
109 |
the compiler will find the system includes and libraries in its sysroot
|
twoerner@2764
|
110 |
area but you have to pass appropriate CPPFLAGS and LDFLAGS to tell it
|
twoerner@2764
|
111 |
where to find your headers and libraries from your staging area (or use
|
twoerner@2764
|
112 |
a wrapper).
|
twoerner@2764
|
113 |
|
twoerner@2764
|
114 |
$ ./configure --build=<build tuple> --host=<host tuple> \
|
twoerner@2764
|
115 |
--prefix=/usr --enable-foo-bar... \
|
twoerner@2764
|
116 |
CPPFLAGS="-I/path/to/staging/usr/include" \
|
twoerner@2764
|
117 |
LDFLAGS="-L/path/to/staging/lib -L/path/to/staging/usr/lib"
|
twoerner@2764
|
118 |
$ make
|
twoerner@2764
|
119 |
$ make DESTDIR=/path/to/staging install
|
twoerner@2764
|
120 |
|
twoerner@2764
|
121 |
4) A mix of 2) and 3), using carefully crafted union mounts.
|
twoerner@2764
|
122 |
|
twoerner@2764
|
123 |
The staging area is a union mount of:
|
twoerner@2764
|
124 |
- the sysroot as a read-only branch
|
twoerner@2764
|
125 |
- the real staging area as a read-write branch
|
twoerner@2764
|
126 |
This also requires passing --sysroot to point to the union mount, but has
|
twoerner@2764
|
127 |
other advantages, such as allowing per-package staging, and a few more
|
twoerner@2764
|
128 |
obscure pros. It also has its disadvantages, as it potentially requires
|
twoerner@2764
|
129 |
non-root users to create union mounts. Additionally, union mounts are not
|
twoerner@2764
|
130 |
yet mainstream in the Linux kernel, so it requires patching. There is a
|
twoerner@2764
|
131 |
FUSE-based unionfs implementation, but development is almost stalled,
|
twoerner@2764
|
132 |
and there are a few gotchas...
|
twoerner@2764
|
133 |
|
twoerner@2764
|
134 |
$ (good luck!)
|
twoerner@2764
|
135 |
|
twoerner@2764
|
136 |
|
yann@2279
|
137 |
It is strongly advised not to use the toolchain sysroot directory as an
|
twoerner@2764
|
138 |
install directory (i.e. option 1) for your programs/packages. If you do so,
|
twoerner@2764
|
139 |
you will not be able to use your toolchain for another project. It is even
|
twoerner@2764
|
140 |
strongly advised that your toolchain is chmod-ed to read-only once
|
twoerner@2764
|
141 |
successfully install, so that you don't go polluting your toolchain with
|
twoerner@2764
|
142 |
your programs'/packages' files. This can be achieved by selecting the
|
twoerner@2764
|
143 |
"Render the toolchain read-only" from crosstool-NG's "Paths and misc options"
|
twoerner@2764
|
144 |
configuration page.
|
yann@2076
|
145 |
|
twoerner@2764
|
146 |
Thus, when you build a program/package, install it in a separate, staging,
|
twoerner@2764
|
147 |
directory and let the cross-toolchain continue to use its own, pristine,
|
twoerner@2764
|
148 |
sysroot directory.
|
twoerner@2764
|
149 |
|
twoerner@2764
|
150 |
When you are done building and want to assemble your rootfs you could simply
|
twoerner@2764
|
151 |
take the full contents of your staging directory and use the 'populate'
|
twoerner@2764
|
152 |
script to add in the necessary files from the sysroot. However, the staging
|
twoerner@2764
|
153 |
area you have created will include lots of build artifacts that you won't
|
twoerner@2764
|
154 |
necessarily want/need on your target. For example: static libraries, header
|
twoerner@2764
|
155 |
files, linking helper files, man/info pages. You'll also need to add various
|
twoerner@2764
|
156 |
configuration files, scripts, and directories to the rootfs so it will boot.
|
twoerner@2764
|
157 |
|
twoerner@2764
|
158 |
Therefore you'll probably end up creating a separate rootfs directory which
|
twoerner@2764
|
159 |
you will populate from the staging area, necessary extras, and then use
|
twoerner@2764
|
160 |
crosstool-NG's populate script to add the necessary sysroot libraries.
|
yann@2076
|
161 |
|
yann@2076
|
162 |
|
yann@2076
|
163 |
The 'populate' script |
|
yann@2076
|
164 |
----------------------+
|
yann@2076
|
165 |
|
yann@2076
|
166 |
When your root directory is ready, it is still missing some important bits: the
|
yann@2076
|
167 |
toolchain's libraries. To populate your root directory with those libs, just
|
yann@2076
|
168 |
run:
|
yann@2076
|
169 |
your-target-tuple-populate -s /your/root -d /your/root-populated
|
yann@2076
|
170 |
|
yann@2076
|
171 |
This will copy /your/root into /your/root-populated, and put the needed and only
|
antony@2564
|
172 |
the needed libraries there. Thus you don't pollute /your/root with any cruft that
|
yann@2076
|
173 |
would no longer be needed should you have to remove stuff. /your/root always
|
yann@2076
|
174 |
contains only those things you install in it.
|
yann@2076
|
175 |
|
yann@2076
|
176 |
You can then use /your/root-populated to build up your file system image, a
|
yann@2076
|
177 |
tarball, or to NFS-mount it from your target, or whatever you need.
|
yann@2076
|
178 |
|
yann@2076
|
179 |
The populate script accepts the following options:
|
yann@2076
|
180 |
|
yann@2076
|
181 |
-s src_dir
|
yann@2076
|
182 |
Use 'src_dir' as the un-populated root directory.
|
yann@2076
|
183 |
|
yann@2076
|
184 |
-d dst_dir
|
yann@2076
|
185 |
Put the populated root directory in 'dst_dir'.
|
yann@2076
|
186 |
|
yann@2076
|
187 |
-l lib1 [...]
|
yann@2076
|
188 |
Always add specified libraries.
|
yann@2076
|
189 |
|
yann@2076
|
190 |
-L file
|
yann@2076
|
191 |
Always add libraries listed in 'file'.
|
yann@2076
|
192 |
|
yann@2076
|
193 |
-f
|
yann@2076
|
194 |
Remove 'dst_dir' if it previously existed; continue even if any library
|
yann@2076
|
195 |
specified with -l or -L is missing.
|
yann@2076
|
196 |
|
yann@2076
|
197 |
-v
|
yann@2076
|
198 |
Be verbose, and tell what's going on (you can see exactly where libs are
|
yann@2076
|
199 |
coming from).
|
yann@2076
|
200 |
|
yann@2076
|
201 |
-h
|
yann@2076
|
202 |
Print the help.
|
yann@2076
|
203 |
|
yann@2076
|
204 |
See 'your-target-tuple-populate -h' for more information on the options.
|
yann@2076
|
205 |
|
yann@2076
|
206 |
Here is how populate works:
|
yann@2076
|
207 |
|
yann@2076
|
208 |
1) performs some sanity checks:
|
yann@2076
|
209 |
- src_dir and dst_dir are specified
|
yann@2076
|
210 |
- src_dir exists
|
yann@2076
|
211 |
- unless forced, dst_dir does not exist
|
yann@2076
|
212 |
- src_dir != dst_dir
|
yann@2076
|
213 |
|
yann@2076
|
214 |
2) copy src_dir to dst_dir
|
yann@2076
|
215 |
|
yann@2076
|
216 |
3) add forced libraries to dst_dir
|
yann@2076
|
217 |
- build the list from -l and -L options
|
yann@2076
|
218 |
- get forced libraries from the sysroot (see below for heuristics)
|
yann@2076
|
219 |
- abort on the first missing library, unless -f is specified
|
yann@2076
|
220 |
|
yann@2076
|
221 |
4) add all missing libraries to dst_dir
|
yann@2076
|
222 |
- scan dst_dir for every ELF files that are 'executable' or
|
yann@2076
|
223 |
'shared object'
|
yann@2076
|
224 |
- list the "NEEDED Shared library" fields
|
yann@2076
|
225 |
- check if the library is already in dst_dir/lib or dst_dir/usr/lib
|
yann@2076
|
226 |
- if not, get the library from the sysroot
|
yann@2076
|
227 |
- if it's in sysroot/lib, copy it to dst_dir/lib
|
yann@2076
|
228 |
- if it's in sysroot/usr/lib, copy it to dst_dir/usr/lib
|
yann@2076
|
229 |
- in both cases, use the SONAME of the library to create the file
|
yann@2076
|
230 |
in dst_dir
|
yann@2076
|
231 |
- if it was not found in the sysroot, this is an error.
|