hello.c:5: warning: implicit declaration of function 'printf'
This introduces some interesting questions:
• Where is the file stdio.h located, and how is it found?
• Where does the printf() function live, and how is this reference resolved in the binary executable?
Somehow it seems that the compiler just knows how to put together a proper binary file that is executable from the command line. To further complicate matters, the final executable contains startup and shutdown prologue code that we never see but that the linker automatically includes. This prologue deals with details such as the environment and arguments passed to your program, startup and shutdown housekeeping, exit handling, and more.
To build the "hello world" application, we can use a simple command line invocation of the compiler, similar to this:
$ gcc -o hello hello.c
This produces the binary executable file called hello, which we can execute directly from the command line. Defaults referenced by the compiler provide guidance on where include files will be found. In a similar fashion, the linker knows how to resolve the reference to the printf() function by including a reference to the library where it is defined. This, of course, is the standard C library.
We can query the toolchain to see some of the defaults that were used. Listing 12-2 is a partial listing of the output from cpp when passed the -v flag. You might already know that cpp is the C preprocessor component of the gcc toolchain. We have added some formatting (whitespace only) to improve the readability.
Listing 12-2. Default Native cpp Search Directories
$ cpp -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.3.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share
/info --enable-shared --enable-threads=posix --disable-checking
--disable-libunwind-exceptions --with-system-zlib --enable-__cxa_atexit
--host=i386-redhat-linux
Thread model: posix
gcc version 3.3.3 20040412 (Red Hat Linux 3.3.3-7)
/usr/lib/gcc-lib/i386-redhat-linux/3.3.3/cc1 -E -quiet -v -
ignoring nonexistent directory "/usr/i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc-lib/i386-redhat-linux/3.3.3/include
/usr/include
End of search list.
/usr/lib/
This simple query produces some very useful information. First, we can see how the compiler was configured using the familiar ./configure utility. The default thread model is posix, which determines the thread library your application gets linked against if you employ threading functions. Finally, you see the default search directories for #include directives.
But what if we want to build hello.c for a different architecture, such as PowerPC? When we compile an application program for a PowerPC target using a cross-compiler on our host machine, we must make sure that the compiler does not use the default host include directories or library paths. Using a properly configured cross-compiler is the first step, and having a well designed cross-development environment is the second.
Listing 12-3 is the output from a popular open-source cross-development toolchain known as the Embedded Linux Development Kit (ELDK), assembled and maintained by Denx Software Engineering. This particular installation was configured for the PowerPC 82xx toolchain. Again, we have added some whitespace to the output for readability.
Listing 12-3. Default Cross-Search Directories
$ ppc_82xx-cpp -v
Reading specs from /opt/eldk/usr/bin/.. /lib/gcc-lib/ppc-linux/3.3.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share
/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib
--enable-__cxa_atexit --with-newlib --enable-languages=c,c++ --disable-libgcj
--host=i386-redhat-linux -target=ppc-linux
Thread model: posix
gcc version 3.3.3 (DENX ELDK 3.1.1 3.3.3-10)
/opt/eldk/usr/bin/../lib/gcc-lib/ppc-linux/3.3.3/cc1 -E -quiet -v -iprefix /opt/eldk/usr/bin/.. /lib/gcc-lib/ppc-linux/3.3.3/ -D__unix__ -D__gnu_linux__ -D__linux__ -Dunix -D__unix -Dlinux -D__linux -Asystem=unix -Asystem=posix --mcpu=603
ignoring nonexistent directory "/opt/eldk/usr/ppc-linux/sys-include"
ignoring nonexistent directory "/opt/eldk/usr/ppc-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/opt/eldk/usr/lib/gcc-lib/ppc-linux/3.3.3/include
/opt/eldk/ppc_82xx/usr/include
End of search list.
Here you can see that the default search paths for include directories are now adjusted to point to your cross versions instead of the native include directories. This seemingly obscure detail is critical to being able to develop applications and compile open-source packages for your embedded system. It is one of the most confusing topics to even experienced application developers who are new to embedded systems.
12.2. Host System Requirements
Your development workstation must include several important components and systems. Of course, you need a properly configured cross toolchain. You can download and compile one yourself or obtain one of the many commercial toolchains available. Building one yourself is beyond the scope of this book, although there are several good references available. See Section 12.4.1, "Suggestions for Additional Reading," at the end of this chapter for recommendations.
The next major item you need is a Linux distribution targeted for your embedded system architecture. This includes hundreds to potentially thousands of files that will populate your embedded system's file systems. Again, the choices are to build your own or to obtain one of the commercial ones. One of the more popular embedded system distributions available on the Internet is the aforementioned ELDK. The ELDK is available for some PowerPC and other embedded targets. Building an embedded Linux distribution from scratch would require a book of this size in itself and, therefore, is beyond the scope of our discussions here.
In summary, your development host requires four separate and distinct capabilities:
• Cross toolchain and libraries
• Target system packages, including programs, utilities, and libraries
• Host tools such as editors, debuggers, and utilities
• Servers for hosting your target board, covered in the next section
If you install a ready-built embedded Linux development environment on your workstation, either a commercial variety or one freely available in the open source community, the toolchain and components have already been preconfigured to work together. For example, the toolchain has been configured with default directory search paths that match the location of the target header files and system libraries on your development workstation. The situation becomes much more complex if your requirements include having support for multiple architectures and processors on your development workstation. This is the reason that embedded Linux distributions exist.
12.2.1. Hardware Debug Probe
In addition to the components listed previously, you should consider some type of hardware-assisted debugging. This consists of a hardware probe connected to your host (often via Ethernet) and connected to your target via a debug connector on the board. Many solutions are on the market today. We cover this topic in detail in Chapter 14, "Kernel Debugging Techniques."
Читать дальше