cookutils view cross @ rev 420

cross: improve prebuitl toolchain creation
author Christophe Lincoln <pankso@slitaz.org>
date Wed May 16 11:55:25 2012 +0200 (2012-05-16)
parents 97a80eb3cf19
children 71450d322f7b
line source
1 #!/bin/sh
2 #
3 # Cross - Help build a cross toolchain on SliTaz.
4 #
5 # Copyright 2012 (C) SliTaz GNU/Linux - BSD License
6 # Author: Christophe Lincoln <pankso@slitaz.org>
7 #
8 . /lib/libtaz.sh
10 [ -f "/etc/slitaz/cross.conf" ] && . /etc/slitaz/cross.conf
11 [ -f "cross.conf" ] && . ./cross.conf
13 # Handle --config=/path/to/cross.conf
14 [ "$config" ] && . $config
15 source=$WORK/source
16 logdir=$WORK/log
17 install=$WORK/install
19 # Help and usage.
20 usage() {
21 cat << EOT
23 Usage: $(basename $0) command --option
25 Commands:
26 howto Man alike and howto
27 info Display cross-tools info
28 testsuite Execute a small testsuite
29 check-env Check build host tools
30 download Download necessary sources
31 show-log Show a compile log
32 binutils Compile Binutils
33 gcc-static Compile GCC static
34 linux-headers Install Kernel headers
35 glibc Compile GNU Glibc
36 gcc-final Compile final GCC
37 busybox Cross compile Busybox
38 compile Compile everything at once
39 clean Clean-up build environment
40 clean-tools Clean: $PREFIX
41 gen-prebuilt Create an prebuilt toolchain archive
43 EOT
44 }
46 # Prebuilt README
47 prebuilt_readme() {
48 echo -n "Creating toolchain README..."
49 cat >> $package/README << EOT
51 SliTaz Prebuilt $ARCH cross toolchain
52 ================================================================================
53 Move this $ARCH cross compilation toolchain to /usr/cross then add tools
54 to your PATH environment and test the toolchain:
56 # mv $ARCH /usr/cross
57 # export PATH=\$PATH:/usr/cross/$ARCH/bin
59 # echo 'int main() { return 0; }' > test.c
60 # $TARGET-gcc -v -o test.out test.c
61 # readelf -h test.out
63 ================================================================================
65 EOT
66 status
67 }
69 # Make sure we have all directories.
70 init_compile() {
71 export LC_ALL=POSIX LANG=POSIX
72 [ "$SYSROOT" ] || export PATH=$PATH:$PREFIX/bin
73 export CROSS_COMPILE=${TARGET}-
74 mkdir -p $source $logdir $install
75 cd $source
76 }
78 # Get source if not yet in $SRC.
79 download_src() {
80 mkdir -p $SRC && cd $SRC
81 [ -f "binutils-$BINUTILS_VERSION.tar.bz2" ] || wget $BINUTILS_WGET
82 [ -f "linux-$LINUX_VERSION.tar.bz2" ] || wget $LINUX_WGET
83 [ -f "glibc-$GLIBC_VERSION.tar.bz2" ] || wget $GLIBC_WGET
84 [ -f "gcc-$GCC_VERSION.tar.bz2" ] || wget $GCC_WGET
85 [ -f "busybox-$BUSYBOX_VERSION.tar.bz2" ] || wget $BUSYBOX_WGET
86 }
88 # Use sysroot or not ?
89 check_sysroot() {
90 if [ "$SYSROOT" ]; then
91 PREFIX=/usr
92 HDR_PATH=$SYSROOT/usr
93 sysroot="--with-sysroot=$SYSROOT"
94 echo "Configure : $sysroot"
95 else
96 HDR_PATH=$PREFIX
97 fi
98 }
100 # 1. Binutils
101 binutils() {
102 init_compile
103 rm -rf binutils-$BINUTILS_VERSION
104 echo "Extracting: binutils-$BINUTILS_VERSION.tar.bz2"
105 tar xjf $SRC/binutils-$BINUTILS_VERSION.tar.bz2
106 : ${BINUTILS_ARGS=--enable-shared}
107 echo "Configure : $BINUTILS_ARGS"
108 check_sysroot
109 cd binutils-$BINUTILS_VERSION
110 ./configure \
111 --prefix=$PREFIX \
112 --target=$TARGET \
113 --enable-targets=$BUILD_SYSTEM \
114 $BINUTILS_ARGS $sysroot
115 make || exit 1
116 make install
117 #echo "cross: binutils compiled on: $(date)"
118 }
120 # 2. GCC static (first pass)
121 gcc_static() {
122 init_compile
123 echo "Extracting: gcc-$GCC_VERSION.tar.bz2"
124 tar xjf $SRC/gcc-$GCC_VERSION.tar.bz2
125 echo "Configure : $GCC_STATIC_ARGS"
126 check_sysroot
127 # Arch fixes and work around
128 case "$ARCH" in
129 x86_64)
130 # GCC wants Glib headers in cross environment (not tested
131 # with sysroot) Should we install glibc-headers before ?
132 [ "$SYSROOT" ] || \
133 ln -s /usr/include $PREFIX/$TARGET/include ;;
134 esac
135 rm -rf gcc-static
136 mkdir gcc-static && cd gcc-static
137 ../gcc-$GCC_VERSION/configure \
138 --prefix=$PREFIX \
139 --libexec=$PREFIX/lib \
140 --target=$TARGET \
141 --disable-shared \
142 --disable-threads \
143 --without-headers \
144 --with-newlib \
145 $GCC_STATIC_ARGS $sysroot
146 make all-gcc all-target-libgcc || exit 1
147 make install-gcc install-target-libgcc
148 cd $PREFIX/lib/gcc/$TARGET/$GCC_VERSION
149 echo "Creating symlink for static libgcc: libgcc_eh.a"
150 rm -f libgcc_eh.a && ln -s libgcc.a libgcc_eh.a
151 }
153 # 3. Kernel headers use static GCC
154 linux_headers() {
155 init_compile
156 echo "Extracting: linux-$LINUX_VERSION.tar.bz2"
157 tar xjf $SRC/linux-$LINUX_VERSION.tar.bz2
158 check_sysroot
159 cd linux-$LINUX_VERSION
160 make mrproper
161 make ARCH=$ARCH headers_check
162 make ARCH=$ARCH headers_install \
163 INSTALL_HDR_PATH=$HDR_PATH
164 }
166 # 4. GNU Glibc
167 glibc() {
168 init_compile
169 echo "Extracting: glibc-$GLIBC_VERSION.tar.bz2"
170 tar xjf $SRC/glibc-$GLIBC_VERSION.tar.bz2
171 echo "Configure : $GLIBC_ARGS"
172 [ "$continue" ] || rm -rf glibc-build
173 # Some arch may need glibc-ports and custom CFLAGS
174 case "$ARCH" in
175 arm)
176 #export CFLAGS="-march=armv6 -mtune=generic -g -O2"
177 [ -f "$SRC/glibc-ports-$GLIBC_VERSION.tar.bz2" ] || wget \
178 http://ftp.gnu.org/gnu/libc/glibc-ports-$GLIBC_VERSION.tar.bz2 \
179 -O $SRC/glibc-ports-$GLIBC_VERSION.tar.bz2 || exit 1
180 echo "Extracting: glibc-ports-$GLIBC_VERSION.tar.bz2"
181 rm -rf glibc-$GLIBC_VERSION/ports
182 tar xjf $SRC/glibc-ports-$GLIBC_VERSION.tar.bz2
183 mv glibc-ports-$GLIBC_VERSION glibc-$GLIBC_VERSION/ports ;;
184 x86_64)
185 ccflags="-m64" ;;
186 esac
187 #echo "CFLAGS: $CFLAGS"
188 mkdir -p glibc-build && cd glibc-build
189 BUILD_CC="gcc" \
190 CC="${TARGET}-gcc $ccflags" \
191 libc_cv_forced_unwind=yes \
192 libc_cv_c_cleanup=yes \
193 ../glibc-$GLIBC_VERSION/configure \
194 --prefix=$PREFIX \
195 --libexec=$PREFIX/lib/glibc \
196 --host=$TARGET \
197 --with-headers=$PREFIX/include \
198 --with-binutils=$PREFIX/bin \
199 $GLIBC_ARGS
200 make || exit 1
201 make install
202 # Work around to let GCC find Glibc headers.
203 if [ "$SYSROOT" ]; then
204 cd $SYSROOT
205 ln -s usr/include sys-include
206 else
207 cd $PREFIX/$TARGET
208 rm -rf lib include
209 ln -s ../lib lib
210 ln -s ../include include
211 fi
212 #unset CFLAGS
213 }
215 # 5. GCC final
216 gcc_final() {
217 init_compile
218 if [ ! -d "gcc-$GCC_VERSION" ]; then
219 echo "Extracting: gcc-$GCC_VERSION.tar.bz2"
220 tar xjf $SRC/gcc-$GCC_VERSION.tar.bz2
221 fi
222 echo "Configure : $GCC_FINAL_ARGS"
223 check_sysroot
224 rm -rf gcc-build
225 mkdir gcc-build && cd gcc-build
226 ../gcc-$GCC_VERSION/configure \
227 --prefix=$PREFIX \
228 --libexec=$PREFIX/lib \
229 --target=$TARGET \
230 --enable-shared \
231 --enable-c99 \
232 --enable-long-long \
233 --enable-__cxa_atexit \
234 --with-pkgversion="SliTaz" \
235 $GCC_FINAL_ARGS $sysroot
236 make || exit 1
237 make install
238 }
240 # Build Busybox to we can create prebuilt tiny rootfs image and boot
241 # from NFS ?
242 cross_busybox() {
243 init_compile
244 echo "Extracting: busybox-$BUSYBOX_VERSION.tar.bz2"
245 tar xjf $SRC/busybox-$BUSYBOX_VERSION.tar.bz2
246 cd busybox-$BUSYBOX_VERSION
247 # CROSS_COMPILE is exported via init_compile.
248 make defconfig
249 make || exit 1
250 make install
251 chmod 4755 _install/bin/busybox
252 readelf -h _install/bin/busybox
253 echo "Busybox install path: $(pwd)/_install"
254 }
256 #
257 # Commands
258 #
260 case "$1" in
261 howto|man)
262 doc=/usr/share/doc/cookutils/cross.txt
263 [ -f "$doc" ] && less -E $doc ;;
264 info)
265 init_compile
266 CC=${TARGET}-gcc
267 echo -e "\nCross Toolchain information" && separator
268 [ "$config" ] && echo "Config file : $config"
269 cat << EOT
270 Target arch : $ARCH
271 C Compiler : $CC
272 Build directory : $WORK
273 EOT
274 if [ "$SYSROOT" ]; then
275 PREFIX=/usr
276 echo "Arch sysroot : $SYSROOT"
277 else
278 echo "Additional path : $PREFIX/bin"
279 fi
280 separator && echo ""
281 echo "GCC version" && separator
282 if [ -x "$PREFIX/bin/$CC" ]; then
283 $CC -v
284 else
285 echo "No C compiler. To build a toolchain run: cross compile"
286 fi
287 separator && echo "" ;;
288 testsuite)
289 init_compile
290 echo "[COMPILING] $TARGET-gcc -v -Wall -o test.out test.c" \
291 | tee $logdir/testsuite.log
292 echo 'int main() { return 0; }' > test.c
293 $TARGET-gcc -v -Wall -o test.out test.c 2>&1 | tee -a $logdir/testsuite.log
294 if [ -x /usr/bin/file ]; then
295 echo -e "\n[CHECKING] file test.out" | tee -a $logdir/testsuite.log
296 file test.out | tee -a $logdir/testsuite.log
297 fi
298 echo -e "\n[CHECKING] readelf -h test.out" | tee -a $logdir/testsuite.log
299 readelf -h test.out | tee -a $logdir/testsuite.log ;;
300 check-env)
301 for pkg in mpfr mpfr-dev gmp gmp-dev mpc-library gawk autoconf
302 do
303 if [ ! -d "/var/lib/tazpkg/installed/$pkg" ]; then
304 echo "Missing packages: $pkg"
305 [ "$install" ] && tazpkg -gi $pkg
306 fi
307 done ;;
308 download)
309 download_src ;;
310 show-log)
311 pkg=$2
312 log=$logdir/$pkg.log
313 if [ ! -f "$log" ]; then
314 echo "No log file found for: $pkg" && exit 1
315 fi
316 less -E $log ;;
317 binutils)
318 rm -f $logdir/binutils.log
319 binutils 2>&1 | tee $logdir/binutils.log ;;
320 gcc-static)
321 gcc_static 2>&1 | tee $logdir/gcc-static.log ;;
322 linux-headers)
323 linux_headers 2>&1 | tee $logdir/linux-headers.log ;;
324 glibc)
325 glibc 2>&1 | tee $logdir/glibc.log ;;
326 gcc-final)
327 gcc_final 2>&1 | tee $logdir/gcc-final.log ;;
328 busybox)
329 cross_busybox 2>&1 | tee $logdir/busybox.log ;;
330 compile)
331 # Compile the full toolchain.
332 time=$(date +%s)
333 init_compile
334 echo "Compile start: $(date)" | tee $logdir/compile.log
335 download_src
336 binutils 2>&1 | tee $logdir/binutils.log
337 gcc_static 2>&1 | tee $logdir/gcc-static.log
338 linux_headers 2>&1 | tee $logdir/linux-headers.log
339 glibc 2>&1 | tee $logdir/glibc.log
340 gcc_final 2>&1 | tee $logdir/gcc-final.log
341 echo ""
342 echo "Compile end : $(date)" | tee -a $logdir/compile.log
343 time=$(($(date +%s) - $time))
344 sec=$time
345 div=$(( ($time + 30) / 60))
346 [ "$div" != 0 ] && min="~ ${div}m"
347 echo "Build time : ${sec}s $min" | tee -a $logdir/compile.log
348 echo "" ;;
349 clean)
350 echo -n "Removing all source files..."
351 rm -rf $WORK/source/* && status
352 [ "$log" ] && rm -f $WORK/log/*.log
353 echo "To clean chroot: rm -rf $PREFIX" ;;
354 clean-tools)
355 # Remove crap :-)
356 init_compile
357 echo "Cleaning : $PREFIX ($(du -sh $PREFIX | awk '{print $1}'))"
358 for dir in info man locale
359 do
360 echo -n "Removing : $dir"
361 rm -rf $PREFIX/share/$dir && status
362 done
363 rm -f $PREFIX/lib/*-gdb.py
364 echo -n "Stripping : shared libs and binaries"
365 ${TARGET}-strip -s $PREFIX/lib/*.so* 2>/dev/null
366 ${TARGET}-strip -s $PREFIX/bin/* 2>/dev/null
367 ${TARGET}-strip -s $PREFIX/${TARGET}/bin/* 2>/dev/null
368 ${TARGET}-strip -s $PREFIX/$TARGET/lib/gcc/$TARGET/*/cc1*
369 ${TARGET}-strip -s $PREFIX/$TARGET/lib/gcc/$TARGET/*/lto*
370 sleep 1 && status
371 echo -n "Tools size : " && du -sh $PREFIX | awk '{print $1}' ;;
372 gen-rootfs)
373 echo "Use arm packages: basefile, boot-scripts, busybox and glibc-base"
374 echo "Install them in a rootfs: tazpkg *-arm.tazpkg --root=/my/rootfs" ;;
375 gen-prebuilt)
376 # Create a prebuilt cross toolchain tarball.
377 init_compile
378 date=$(date "+%Y%m%d")
379 package="slitaz-cross-$ARCH-toolchain-$date"
380 tarball="$package.tar.bz2"
381 cd /usr/cross
382 mkdir $package || exit 1
383 echo ""
384 echo -n "Copying $ARCH to: $package"
385 cp -a $ARCH $package
386 rm -rf $package/share $package/etc
387 status
388 prebuilt_readme
389 echo -n "Creating prebuilt $ARCH toolchain tarball..."
390 tar cjf $tarball $package
391 status
392 mv -f $tarball $WORK
393 rm -rf $package
394 size=$(du -sh $WORK/$tarball | awk '{print $1}')
395 echo "Tarball path: $WORK/$tarball"
396 echo "Tarball size: $size"
397 echo "" ;;
398 *)
399 usage ;;
400 esac