| 1 | \documentclass[12pt,a4paper,openany,smallheadings,
|
|---|
| 2 | headinclude,headsepline,final]{scrreprt}
|
|---|
| 3 | \usepackage[utf8]{inputenc}
|
|---|
| 4 | \usepackage{amsmath}
|
|---|
| 5 | \usepackage{amsfonts}
|
|---|
| 6 | \usepackage{amssymb}
|
|---|
| 7 | \usepackage{caption2}
|
|---|
| 8 | \usepackage[canadian]{babel}
|
|---|
| 9 | \usepackage{varioref}
|
|---|
| 10 | \usepackage{txfonts}
|
|---|
| 11 | \usepackage[pdftex]{graphicx}
|
|---|
| 12 | \usepackage{makeidx}
|
|---|
| 13 | \usepackage[T1]{fontenc}
|
|---|
| 14 |
|
|---|
| 15 | % fancy verbatim enables changing of font, fontsize, etc. in verbatim code
|
|---|
| 16 | % also set smaller font and a frame as default
|
|---|
| 17 | \usepackage{fancyvrb}
|
|---|
| 18 | \fvset{fontsize=\small, frame=single}
|
|---|
| 19 |
|
|---|
| 20 | % marvosym macht Pfeil kaputt, also sichern
|
|---|
| 21 | % line 28, /usr/share/texmf/tex/latex/marvosym/marvosym.sty
|
|---|
| 22 | \let\RescueRightarrow=\Rightarrow
|
|---|
| 23 | \usepackage{marvosym}
|
|---|
| 24 | \renewcommand{\Rightarrow}{\RescueRightarrow}
|
|---|
| 25 |
|
|---|
| 26 | \usepackage[pdftex]{color}
|
|---|
| 27 | \definecolor{skyblue}{rgb}{0,0.3323,0.5720}
|
|---|
| 28 | \usepackage[%
|
|---|
| 29 | colorlinks=true,anchorcolor=red,
|
|---|
| 30 | breaklinks=true,linkcolor=blue,urlcolor=red,
|
|---|
| 31 | citecolor=skyblue,
|
|---|
| 32 | pdfauthor={The FreeWRT Team},
|
|---|
| 33 | pdftitle={FreeWRT Developer Handbook},
|
|---|
| 34 | pdfcreator={tetex and VIM},
|
|---|
| 35 | pdfsubject={Open Source},
|
|---|
| 36 | pdfview=FitV,
|
|---|
| 37 | pdfstartview=FitV,
|
|---|
| 38 | pdfstartpage={1},
|
|---|
| 39 | pdfpagelayout=SinglePage,
|
|---|
| 40 | pdfpagemode=None,
|
|---|
| 41 | pdfkeywords={FreeWRT}]{hyperref}
|
|---|
| 42 | %\usepackage{thumbpdf}
|
|---|
| 43 | \usepackage{cancel}
|
|---|
| 44 | %\usepackage[final, activate, verbose=true]{microtype}
|
|---|
| 45 | \usepackage{ngerman}
|
|---|
| 46 | %\usepackage{bookman}
|
|---|
| 47 | %\usepackage[a4paper,twoside,rmargin=2cm,lmargin=2cm,tmargin=2.5cm]{geometry}
|
|---|
| 48 | \usepackage[a4paper,rmargin=2cm,lmargin=2cm,tmargin=2.5cm,bmargin=2.5cm]{geometry}
|
|---|
| 49 | %\usepackage{ncntrsbk}
|
|---|
| 50 | \usepackage{float}
|
|---|
| 51 | \restylefloat{figure}
|
|---|
| 52 | %\bibliographystyle{alphadin}
|
|---|
| 53 | \bibliographystyle{alpha}
|
|---|
| 54 |
|
|---|
| 55 | % Change Section, Chapter Layout
|
|---|
| 56 | % http://www.mackichan.com/index.html?techtalk/518.htm~mainFrame
|
|---|
| 57 | %\usepackage{sectsty}
|
|---|
| 58 | %\allsectionsfont{\raggedleft}
|
|---|
| 59 | %\chapterfont{\raggedleft}
|
|---|
| 60 |
|
|---|
| 61 | % BEGIN Fancy Header Extensions
|
|---|
| 62 | % Save Graphics in Latex box
|
|---|
| 63 | %\renewcommand{\headheight}{30pt} %Make height wider so picture is ok
|
|---|
| 64 | %\renewcommand{\footskip}{45pt} %Make height wider so picture is ok
|
|---|
| 65 |
|
|---|
| 66 | \usepackage{fixltx2e, mparhack}
|
|---|
| 67 |
|
|---|
| 68 | % Generate index in preamble
|
|---|
| 69 | \makeindex
|
|---|
| 70 | \begin{document}
|
|---|
| 71 | \setlength{\marginparwidth}{10mm}
|
|---|
| 72 | \include{cover}
|
|---|
| 73 | \renewcommand{\thepage}{\roman{page}}
|
|---|
| 74 | \tableofcontents
|
|---|
| 75 | %Set Arabic Numbering 1,2,3,...
|
|---|
| 76 | % Clear needed to renumber from the right position
|
|---|
| 77 | \cleardoublepage
|
|---|
| 78 | \renewcommand{\thepage}{\arabic{page}}
|
|---|
| 79 | %Reset Counter
|
|---|
| 80 | %\setcounter{page}{1}
|
|---|
| 81 |
|
|---|
| 82 | % Set marks where it should Change
|
|---|
| 83 | \renewcommand{\chaptermark}[1]{%
|
|---|
| 84 | \markboth{\large \thechapter.\ \normalsize \scshape #1}{}}
|
|---|
| 85 | \renewcommand{\sectionmark}[1]{\markright{\thesection.\ \scshape #1}}
|
|---|
| 86 |
|
|---|
| 87 | \newcommand{\blitz}{ \Lightning }
|
|---|
| 88 | \newcommand{\entspr}{\stackrel{\wedge}{=}}
|
|---|
| 89 |
|
|---|
| 90 | \chapter{Introduction}
|
|---|
| 91 |
|
|---|
| 92 | Welcome to FreeWRT! This handbook covers all aspects of the Appliance Development
|
|---|
| 93 | Kit from a view of an embedded system developer. FreeWRT is a portable, secure and
|
|---|
| 94 | functional Linux distribution for embedded systems. As FreeWRT is a source code
|
|---|
| 95 | distribution, it does not provide any pre-compiled firmware for embedded systems.
|
|---|
| 96 | The latest version of this document is always available at the FreeWRT website.
|
|---|
| 97 | This book describes the ADK for FreeWRT 1.1 and maybe later.
|
|---|
| 98 |
|
|---|
| 99 | If you have any comments, criticism or found some wrong description, please send
|
|---|
| 100 | us an e-mail to freewrt-handbook@freewrt.org, we are always happy about getting
|
|---|
| 101 | feedback and will try to update or correct the issues mentioned by you.
|
|---|
| 102 |
|
|---|
| 103 | The FreeWRT developer handbook is split into five distinct sections.
|
|---|
| 104 | % ADK Overview
|
|---|
| 105 | % SVN Grundlagen
|
|---|
| 106 | % Paket Portieren
|
|---|
| 107 | % Troubleshooting (uclibc limits, dns stuff, libnotimpl, fpu, asm, host mixup )
|
|---|
| 108 | % Strace, Debugging via GDBServer
|
|---|
| 109 | % ADK in detail, Kernel Buildsystem
|
|---|
| 110 | % New Embedded System (Etrax)
|
|---|
| 111 |
|
|---|
| 112 | The first chapter will give you an overview to the Appliance Development Kit.
|
|---|
| 113 | The second chapter, Using SVN, will describe some basics about subversion.
|
|---|
| 114 | Useful if you work with the ADK and want to send your improvements or new
|
|---|
| 115 | packages back to the FreeWRT project. After that we will port a application to
|
|---|
| 116 | show the simplicity of doing this with the FreeWRT ADK. The fourth chapter
|
|---|
| 117 | will contain information about troubleshooting compile time problems, the fifth
|
|---|
| 118 | chapter contains helpful information about debugging runtime problems. After
|
|---|
| 119 | that we will give detailed instructions about the inner structure of the ADK.
|
|---|
| 120 | In our last chapter we describe how to integrate a new embedded system into the
|
|---|
| 121 | ADK.
|
|---|
| 122 |
|
|---|
| 123 | The intended audience for this handbook are embedded systems developers with
|
|---|
| 124 | deep knowledge about Linux hacking. It is aimed for developers who would like
|
|---|
| 125 | to port software to FreeWRT, like to create an Linux-based appliance or need
|
|---|
| 126 | information about debugging compile or runtime problems on the FreeWRT Linux
|
|---|
| 127 | distribution.
|
|---|
| 128 |
|
|---|
| 129 | \section{Typographic Conventions}
|
|---|
| 130 |
|
|---|
| 131 | Examples starting with \# indicate a command that must be invoked as super
|
|---|
| 132 | user. You can use su to gain super user privileges.
|
|---|
| 133 |
|
|---|
| 134 | \begin{Verbatim}
|
|---|
| 135 | # gdbserver /usr/bin/vim
|
|---|
| 136 | \end{Verbatim}
|
|---|
| 137 |
|
|---|
| 138 | Examples starting with \$ indicate a command that should be invoked as a
|
|---|
| 139 | unprivileged user.
|
|---|
| 140 |
|
|---|
| 141 | \begin{Verbatim}
|
|---|
| 142 | $ make
|
|---|
| 143 | \end{Verbatim}
|
|---|
| 144 |
|
|---|
| 145 | \chapter{Appliance Development Kit (ADK) Overview}
|
|---|
| 146 |
|
|---|
| 147 | The ADK is the core of FreeWRT. It contains all the magic to create the FreeWRT
|
|---|
| 148 | firmware for your embedded system. It will download the needed software
|
|---|
| 149 | packages from the internet and will prepare, compile and combine all components
|
|---|
| 150 | into a ready-to-go firmware image. The ADK is a combination of Makefiles, the
|
|---|
| 151 | Kernel 2.6 configuration system, shell scripts and some other helper
|
|---|
| 152 | applications.
|
|---|
| 153 |
|
|---|
| 154 | \section{Prerequisites}
|
|---|
| 155 |
|
|---|
| 156 | Before you can start with the ADK you need to check if you have one of the
|
|---|
| 157 | supported Hostsystems and have installed the needed software for that. Here is
|
|---|
| 158 | a list of all supported and tested host systems. The host system is needed to
|
|---|
| 159 | create a firmware for your embedded system.
|
|---|
| 160 |
|
|---|
| 161 | The list of supported GNU/Linux build systems is not an exclusive one, these
|
|---|
| 162 | are just the ones tested and verified. The other millions of linux
|
|---|
| 163 | distributions are very likely to work, too.
|
|---|
| 164 |
|
|---|
| 165 | \begin{itemize}
|
|---|
| 166 | \item Debian GNU/Linux
|
|---|
| 167 | \item Gentoo Linux
|
|---|
| 168 | \item OpenSuSE
|
|---|
| 169 | \item Ubuntu GNU/Linux
|
|---|
| 170 | \item Fedora Core
|
|---|
| 171 | \item OpenBSD (partial support)\footnote{some addon packages does not compile}
|
|---|
| 172 | \item MirOS BSD (partial support)\footnote{some addon packages does not compile}
|
|---|
| 173 | \end{itemize}
|
|---|
| 174 |
|
|---|
| 175 | Please install the following software, which is needed to build a basic
|
|---|
| 176 | firmware image. If you choose more packages some more prerequisites might be
|
|---|
| 177 | needed. The ADK host checks will warn you about any software you need to install to
|
|---|
| 178 | compile a specific package. Here is a list of the required software:
|
|---|
| 179 |
|
|---|
| 180 | \begin{itemize}
|
|---|
| 181 | \item gcc3 or higher
|
|---|
| 182 | \item g++
|
|---|
| 183 | \item binutils
|
|---|
| 184 | \item patch
|
|---|
| 185 | \item gzip
|
|---|
| 186 | \item bzip2
|
|---|
| 187 | \item unzip
|
|---|
| 188 | \item flex
|
|---|
| 189 | \item bison
|
|---|
| 190 | \item zlib (+headers)
|
|---|
| 191 | \item ncurses (+headers)
|
|---|
| 192 | \item (g)libc headers
|
|---|
| 193 | \end{itemize}
|
|---|
| 194 |
|
|---|
| 195 | The ADK scripts will check for the required versions of these tools in advance.
|
|---|
| 196 |
|
|---|
| 197 | To build FreeWRT with the ADK it is recommended to have an unprivileged
|
|---|
| 198 | user. Please \underline{never} build FreeWRT as super user. Because all necessary source
|
|---|
| 199 | tarballs are downloaded from the internet automatically, your host system
|
|---|
| 200 | needs a working internet connection.
|
|---|
| 201 |
|
|---|
| 202 | \section{Details Of Cross-Compiling}
|
|---|
| 203 |
|
|---|
| 204 | A cross-compile toolchain exists of a set of tools: a compiler, linker, assembler,
|
|---|
| 205 | debugger and a c library. A cross-compile toolchain runs on your host system and
|
|---|
| 206 | creates native binaries for your target system. A cross-compile toolchain is
|
|---|
| 207 | basically created in six steps:
|
|---|
| 208 |
|
|---|
| 209 | \begin{enumerate}
|
|---|
| 210 | \item Get and prepare the Kernel and C Library headers of your target system
|
|---|
| 211 | \item Compile the binutils package for your target
|
|---|
| 212 | \item Compile a static C compiler for your target
|
|---|
| 213 | \item Compile and install a C library for your target
|
|---|
| 214 | \item Compile and install a full C/C++ compiler
|
|---|
| 215 | \item Compile and install the GNU debugger
|
|---|
| 216 | \end{enumerate}
|
|---|
| 217 |
|
|---|
| 218 | The cross-compile toolchain is created in
|
|---|
| 219 | ,,staging\_dir\_\$(cpu\_arch)''\footnote{f.e. mipsel, which stands for MIPS Little
|
|---|
| 220 | Endian)}. All the tools running on the host, but used to create, analyze or debug
|
|---|
| 221 | for the target are kept in this directory. All addon headers and libraries
|
|---|
| 222 | are installed to this directory.
|
|---|
| 223 |
|
|---|
| 224 | If you want to compile a simple application without using the ADK, just use the
|
|---|
| 225 | compiler directly (f.e. compiling a MIPS Little Endian application):
|
|---|
| 226 | \begin{verbatim}
|
|---|
| 227 | ./staging_dir_mipsel/bin/mipsel-linux-uclibc-gcc -o myapp myapp.c
|
|---|
| 228 | \end{verbatim}
|
|---|
| 229 |
|
|---|
| 230 | Check with ,,file'' if you got a MIPS binary:
|
|---|
| 231 | \begin{verbatim}
|
|---|
| 232 | $ file myapp
|
|---|
| 233 | myapp: ELF 32-bit LSB MIPS-I executable, MIPS, version 1 (SYSV), dynamically
|
|---|
| 234 | linked (uses shared libs), not stripped
|
|---|
| 235 | \end{verbatim}
|
|---|
| 236 |
|
|---|
| 237 | \section{Firmware Build Process}
|
|---|
| 238 |
|
|---|
| 239 | Just like when building the ADK's toolchain, the sources for the selected
|
|---|
| 240 | packages are downloaded from the internet first, then build using the
|
|---|
| 241 | cross-compiler and libraries of the ADK.
|
|---|
| 242 |
|
|---|
| 243 | The detailed order of firmware image building is:
|
|---|
| 244 |
|
|---|
| 245 | \begin{itemize}
|
|---|
| 246 | \item compile the Linux kernel and all supported kernel modules
|
|---|
| 247 | \item compile all selected packages
|
|---|
| 248 | \item clean the target root directory
|
|---|
| 249 | \item install all packages to the target root directory
|
|---|
| 250 | \item create the root filesystem image
|
|---|
| 251 | \item create the firmware image (bootloader, kernel and root filesystem)
|
|---|
| 252 | \end{itemize}
|
|---|
| 253 |
|
|---|
| 254 | The result of the build process is created in the ,,bin'' directory. You will
|
|---|
| 255 | find a firmware image in the top level directory. Furthermore there is a
|
|---|
| 256 | ,,package'' directory, which contains all base and addon packages.
|
|---|
| 257 |
|
|---|
| 258 |
|
|---|
| 259 | \chapter{Using Subversion}
|
|---|
| 260 |
|
|---|
| 261 | \section{Getting the source}
|
|---|
| 262 |
|
|---|
| 263 | Go to a directory where you want to checkout the ADK.
|
|---|
| 264 | To get the latest version of the FreeWRT ADK use one of these commands:
|
|---|
| 265 | \begin{Verbatim}
|
|---|
| 266 | $ svn co http://www.freewrt.org/svn/trunk freewrt
|
|---|
| 267 | $ svn co svn://www.freewrt.org/trunk freewrt
|
|---|
| 268 | \end{Verbatim}
|
|---|
| 269 |
|
|---|
| 270 | After successfully downloading, enter the directory:
|
|---|
| 271 |
|
|---|
| 272 | \begin{Verbatim}
|
|---|
| 273 | $ cd freewrt
|
|---|
| 274 | \end{Verbatim}
|
|---|
| 275 |
|
|---|
| 276 | This directory will be referred to as the ADK root directory later on.
|
|---|
| 277 |
|
|---|
| 278 | \chapter{Porting an application}
|
|---|
| 279 |
|
|---|
| 280 | % strongswan?
|
|---|
| 281 |
|
|---|
| 282 | \section{Using a package template}
|
|---|
| 283 |
|
|---|
| 284 | \chapter{Troubleshooting compile time problems}
|
|---|
| 285 |
|
|---|
| 286 | % other projects (Gentoo, OpenWrt, OpenEmbedded, *BSD ports)
|
|---|
| 287 |
|
|---|
| 288 | \chapter{Troubleshooting runtime problems}
|
|---|
| 289 |
|
|---|
| 290 | % other projects (Gentoo, OpenWrt, OpenEmbedded, *BSD ports)
|
|---|
| 291 | % Upstream Bugtracking and Mailinglist archives
|
|---|
| 292 |
|
|---|
| 293 | % gdbserver
|
|---|
| 294 | % strace
|
|---|
| 295 | % logging (logread, ...), verbose mode, non-fork
|
|---|
| 296 |
|
|---|
| 297 | % compile the application with -g
|
|---|
| 298 | % disable -O flags
|
|---|
| 299 | % disable -fomit-frame-pointer
|
|---|
| 300 |
|
|---|
| 301 | % install gdbserver package
|
|---|
| 302 | % gdbserver /usr/bin/vim
|
|---|
| 303 |
|
|---|
| 304 |
|
|---|
| 305 | \begin{verbatim}
|
|---|
| 306 | Target system:
|
|---|
| 307 | admin@FreeWRT:~$ /usr/bin/gdbserver 192.168.42.1:10000 /usr/bin/vim
|
|---|
| 308 | Process /usr/bin/vim created; pid = 440
|
|---|
| 309 | Listening on port 10000
|
|---|
| 310 |
|
|---|
| 311 |
|
|---|
| 312 | Host system:
|
|---|
| 313 | cd build_mipsel/w-vim-5.8/vim-5.8
|
|---|
| 314 | ~/freewrt/staging_dir_mipsel/bin/mipsel-linux-gdb vim
|
|---|
| 315 | (gdb) target extended-remote 192.168.42.1:10000
|
|---|
| 316 | Remote debugging using 192.168.42.1:10000
|
|---|
| 317 | 0x2aaa8ac0 in ?? ()
|
|---|
| 318 | warning: Unable to find dynamic linker breakpoint function.
|
|---|
| 319 | GDB will be unable to debug shared library initializers
|
|---|
| 320 | and track explicitly loaded dynamic code.
|
|---|
| 321 |
|
|---|
| 322 | (gdb) dir .
|
|---|
| 323 | (gdb) set solib-absolute-prefix ~/staging_dir_mipsel
|
|---|
| 324 | (gdb) continue
|
|---|
| 325 | Continuing.
|
|---|
| 326 |
|
|---|
| 327 | Program received signal SIGSEGV, Segmentation fault.
|
|---|
| 328 | 0x0044efa0 in op_yank (oap=0x7fff7d18, deleting=7, mess=1) at ops.c:2388
|
|---|
| 329 | 2388 curbuf->b_op_start = oap->start;
|
|---|
| 330 | (gdb) bt
|
|---|
| 331 | #0 0x0044efa0 in op_yank (oap=0x7fff7d18, deleting=7, mess=1) at ops.c:2388
|
|---|
| 332 | #1 0x004452bc in do_pending_operator (cap=0x7fff7c40, searchbuff=0x10006010 "",
|
|---|
| 333 | command_busy=0x7fff7c90, old_col=0, gui_yank=0, dont_adjust_op_end=646447176)
|
|---|
| 334 | at normal.c:1789
|
|---|
| 335 | #2 0x0044c780 in normal_cmd (oap=0x7fff7d18, toplevel=1) at normal.c:1277
|
|---|
| 336 | #3 0x00431490 in main (argc=2147450136, argv=0x10005ff0) at main.c:1573
|
|---|
| 337 |
|
|---|
| 338 |
|
|---|
| 339 | \end{verbatim}
|
|---|
| 340 |
|
|---|
| 341 | \chapter{Appliance Development Kit (ADK) Reference}
|
|---|
| 342 |
|
|---|
| 343 | \section{Filesystem structure}
|
|---|
| 344 |
|
|---|
| 345 | After a fresh checkout you get following file and directory structure in your
|
|---|
| 346 | working directory:
|
|---|
| 347 | \begin{verbatim}
|
|---|
| 348 | docs
|
|---|
| 349 | mk
|
|---|
| 350 | target
|
|---|
| 351 | tools
|
|---|
| 352 | toolchain
|
|---|
| 353 | package
|
|---|
| 354 | scripts
|
|---|
| 355 | Config.in
|
|---|
| 356 | Makefile
|
|---|
| 357 | \end{verbatim}
|
|---|
| 358 |
|
|---|
| 359 | You will see some more files there, containing license information, portability
|
|---|
| 360 | code for different make implementations or some special files for automatic
|
|---|
| 361 | builds. We will concentrate on the above list for now.
|
|---|
| 362 |
|
|---|
| 363 | The docs/ directory contains a package template and the FreeWRT handbook's
|
|---|
| 364 | as LaTeX source code.
|
|---|
| 365 |
|
|---|
| 366 | \section{NFO system}
|
|---|
| 367 |
|
|---|
| 368 |
|
|---|
| 369 | \section{Kernel buildsystem}
|
|---|
| 370 |
|
|---|
| 371 |
|
|---|
| 372 |
|
|---|
| 373 |
|
|---|
| 374 | \chapter{Integration of a new embedded system into ADK}
|
|---|
| 375 |
|
|---|
| 376 | This is a chapter with many practical advices and code. We will describe in detail
|
|---|
| 377 | how the Foxboard was added to the FreeWRT ADK. The Foxboard is choosen, because
|
|---|
| 378 | it is not yet ported in other embedded projects and has many differences to
|
|---|
| 379 | existing supported systems. Therefore we need to go through all aspects needed
|
|---|
| 380 | to support the Foxboard in the FreeWRT ADK.
|
|---|
| 381 |
|
|---|
| 382 | \section{Information Gathering}
|
|---|
| 383 |
|
|---|
| 384 | % CPU, ARCH, RAM, Flash, Filesystems
|
|---|
| 385 |
|
|---|
| 386 | \section{ADK variables}
|
|---|
| 387 |
|
|---|
| 388 | % CPU, Endianess, Kernel version, Boardshortname
|
|---|
| 389 |
|
|---|
| 390 |
|
|---|
| 391 | \section{Toolchain}
|
|---|
| 392 |
|
|---|
| 393 | \section{Bootloader}
|
|---|
| 394 |
|
|---|
| 395 | \section{Kernel}
|
|---|
| 396 |
|
|---|
| 397 | % versions supported? 2.4 / 2.6
|
|---|
| 398 | % patches from vendors?
|
|---|
| 399 |
|
|---|
| 400 | \section{Filesystems}
|
|---|
| 401 |
|
|---|
| 402 | % different kinds of possibilities
|
|---|
| 403 | % squashfs, lzma, jffs2, yaffs2, ext2, nfs
|
|---|
| 404 |
|
|---|
| 405 | \section{Firmware Images}
|
|---|
| 406 |
|
|---|
| 407 | \section{Drivers}
|
|---|
| 408 |
|
|---|
| 409 | % always builtin all essential drivers
|
|---|
| 410 | % make packages for all non-essential drivers
|
|---|
| 411 |
|
|---|
| 412 | \section{Boardspecific Packages}
|
|---|
| 413 |
|
|---|
| 414 | % external packages for drivers
|
|---|
| 415 | % binary only drivers
|
|---|
| 416 |
|
|---|
| 417 | \chapter{FreeWRT policy for submissions}
|
|---|
| 418 |
|
|---|
| 419 | - runtime tests
|
|---|
| 420 | - package quality, add startup scripts, provide subpackages if useful
|
|---|
| 421 | - clean patches, why you have changed sth, not how
|
|---|
| 422 |
|
|---|
| 423 | \end{document}
|
|---|