Getting started with Embedded Linux -- Part Three
We're continuing our series on how to get started with Embedded Linux if you have experience with embedded systems, but no Linux experience. You can find the previous article here and Part 1 here.
Just about every project is going to require using the GNU Compiler Collection (GCC), the GNU binary utilities (Binutils), and make, used to build programs and handle dependencies. Linux does have several IDEs (integrated development environments) like Eclipse, but they're all built around these command line tools. Unlike development on Windows, where using Visual Studio is the rule, many Linux developers do not use an IDE.
To compile a C program using gcc, write your program using your favorite text editor (vi, emacs, gedit, kwrite, etc.) and save it with a suffix of .c (in the following example, we use the standard first C program from K&R and saved it as hello.c). Then enter the following commands:
$ gcc -o hello -g -O1 hello.c
This will invoke the C compiler to translate your program, and, if this succeeds without errors, it will go on to invoke the linker with the correct system libraries to create an executable named hello. (Other operating systems identify executables by a suffix, like .exe. Linux executables generally do not have a suffix. Instead a file system flag indicates that a file can be executed.) The name of the executable follows the -o option, the -g options says to generate debugging information, and the -O1 (that's letter O followed by digit 1) indicates to generate optimized code. GCC has a large number of different options, but these are the basics. For easier debugging, you may want to specify -O0 (letter O followed by digit 0) or omit the -O option to compile without optimization. If you have more than one file which you want to compile and link together, just list the source file names one after the other.
You might find that your Linux installation is missing some components, like GCC or the headers for the C library, which are not installed by default. If this is the case, you can use your system's package manager to add these component. On a Fedora system, this means using yum or perhaps the packagekit GUI; on an Ubuntu system, you would use apt-get or the synaptic GUI. These package managers will handle downloading and installing the component you request, as well as any dependencies that may be required.
You can execute programs from the command line by entering the name of the program, if it is in a directory in your path list, or by giving the path to the file. For our example, we can do the following:
In this case, since our current directory is not listed in the $PATH environment variable, we use the dot (.) to indicate the current directory and then the file name, separated by a slash from the directory specification.
This might be a good time to use GDB debugger to run your program. Whether you are doing kernel, driver, or application development, it's likely that you will need to debug your program using GDB. GDB has a command line interface and it is a good idea to learn the commands to do basic operations like printing variable values, setting breakpoints, and stepping through your program. There are several GUI's available for GDB. I use DDD, which now has a new maintainer after being dormant for a while. Other GUI's include the Eclipse CDT IDE, Insight, and even extensions to the Emacs text editor.
You can invoke gdb as follows:
$ gdb hello [ start up messages from gdb ] (gdb) break main Breakpoint 1 at 0x400530: file hello.c, line 5. (gdb) run Starting program: /tmp/hello Breakpoint 1, main () at hello.c:5 5 printf ("Hello world!\n"); (gdb) cont Continuing. Hello world! (gdb) quit
In the above example, the output from gdb is in bold; our commands are in normal type. In addition to the initial startup messages from gdb, there may be some other messages about missing debugging information for system libraries or a message about the program exiting.
In an Embedded Linux environment, you will be using GCC, GDB, and make in ways which are similar to native Linux development. In most cases, you will use a different build of GCC and GDB which are targeted for the processor you are using. The program names may be different, for example, arm-none-eabi-gcc, which generates code for ARM using the EABI (Embedded ABI). Another difference is that you most likely will be working in a cross-development environment, where you compile on a host system and download your programs to a target system. If you have experience with embedded programming, working in a cross-development environment should be familiar to you. We'll talk about how this works with Embedded Linux in a future installment.
In the next installment, we'll talk about Linux applications, libraries, and the wide range of freely available software packages.
Michael Eager is principal consultant at Eager Consulting in Palo Alto, Calif. He has over four decades experience developing compilers, debuggers, and simulators for a wide range of processor architectures used in embedded systems. His current and former clients include major semiconductor companies and systems developers. Michael has been a member of the ISO C++ Standard Committee and ABI Committees for several processor architectures. He is chair of the Debugging Standards Committee for DWARF, a widely used debug data format. He is active in the open-source and Linux communities.