Modifying and Building the Packages
Workflow Overview
A typical development scenario is one in which you want to modify the source files in a given platform package to customize functionality or look and behavior of an interface. In such a scenario, you will need to do the following:
- Extract the source code from a source RPM (SRPM).
- Modify the source files using your favorite tools and editors.
- Add your modifications as a patch to the SRPM, rebuild the package, and add the binary package to the root file system (RFS) image (with command line tools).
- Recreate the RFS image to include the customized package.
Figure 1 Workflow for Modifying a Package
The following sections explain how to accomplish these tasks using the platform command line tools.
(As a final step, you will probably want to load the RFS image and kernel images onto the target device for testing purposes on a live network. For this last step, you can follow the instructions on booting and loading the kernel in the Getting Started guide for your board.)
Using Command Line Tools to Modify and Build Packages (tsrpm)
tsrpm is a wrapper for rpmbuild that supports cross-compilation of SRPMs, in most cases without any need to modify the original package. The following sections describe how to build packages from the command line using tsrpm:
Building a Userspace Package from the Command Line
The Devicescape Wireless Infrastructure Platform provides source code for most core packages with the assumption that you might want to modify some of the target functionality provided per your end product requirements. Source code for target functionality for each binary packages is provided as single file called a source RPM (SRPM). In order to get access to all the files that make up the source code for a particular set of functionality, you must extract the SRPM.
To build a target package, obtain the source RPM for the package you want to build. Devicescape source RPMs are in installed in the following directories:
/opt/devicescape/linux/2.0/<Architecture>-bbdyn-uclibc/packages/core/SRPMS/
Devicescape source RPMs are known to build using tsrpm. Other source RPM sources such as Fedora (http://download.fedora.redhat.com/pub/fedora/linux/core/) can give you a starting point if you need a package not supported by Devicescape. Source RPMs from an external source such as Fedora may require patches before they can be cross-compiled by tsrpm.
For example to build the hello package distributed by Devicescape for an arm target:
- Create and enter a build directory then extract the source package.
$ tsrpm --extract hello-1.0-1.src.rpm
- Then invoke tsrpm again to build the package.
$ tsrpm --target=armv5bf-uclibc \
--build rpm-sources/hello-1.0-1/hello.spec
The --target flag indicates the target hardware for which the binary should be built. The following table shows the mapping between the tsrpm target and Devicescape supported platforms.
|
Model
|
Board String
|
tsrpm Target
|
|
D-Link dwl-2210ap
|
ar531x
|
mipsf-uclibc
|
|
Linksys wrt54g
|
bcm947xx
|
mipself-uclibc
|
|
Monte Jade
|
ixdpg425
|
armv5bf-uclibc
|
|
Intel PC
|
x86pc
|
i686-uclibc
|
- When the build is complete, tsrpm writes the RPM and source RPM to a target subdirectory. You can check this by doing an
ls of the target subdirectories:
$ ls armv5bf-uclibc/RPMS/ armv5bf-uclibc/SRPMS/
hello-1.0-1.armv5bf-uclibc.rpm
- To convert to ipkg invoke tsrpm again.
$ tsrpm --repackage=targetipkg --target=armv5bf-uclibc \
armv5bf-uclibc/RPMS/hello-1.0-1.armv5bf-uclibc.rpm
Building a Target Library
If you are building a library for target use only, you need only extract and build the source package. If you need to use target library in your development work, you will take the output of the build and install the target library into the development host's toolchain. The follow example illustrates the build process using the zlib library:
- Extract the library source.
$ tsrpm --extract zlib-1.2.1.1-2.1.src.rpm
- Build the library source package from the .spec file.
$ tsrpm --target=armv5bf-uclibc \
--build rpm-sources/zlib-1.2.1.1-2.1/zlib.spec
Wrote: /usr/src/armv5bf-uclibc/RPMS/zlib-1.2.1.1-2.1.armv5bf-uclibc.rpm
Wrote: /usr/src/armv5bf-uclibc/RPMS/zlib-devel-1.2.1.1-2.1.armv5bf-uclibc.rpm
The build produces two packages. The first package, zlib-1.2.1.1-2.1.armv5bf-uclibc.rpm, contains the shared library and can be installed directly on the target. The second, zlib-devel-1.2.1.1-2.1.armv5bf-uclibc.rpm, contains library header files and is intended for installation into the host machine's toolchain; it is not installed on the target.
Installing a Target Library into the Host's Toolchain
To install a target library into the host machine's toolchain, you must convert the built target libraries into the host format as illustrated in the following example.
- Convert the built libraries into host format using tsrpm with the --convert-to-host option:
$ tsrpm --target=armv5bf-uclibc --convert-to-host \
armv5bf-uclibc/RPMS/zlib-1.2.1.1-2.1.armv5bf-uclibc.rpm
Wrote: /usr/src/i386-x-armv5bf-uclibc/RPMS/zlib-armv5bf-uclibc-1.2.1.1-2.1.i386.rpm
$ tsrpm --target=armv5bf-uclibc --convert-to-host \
armv5bf-uclibc/RPMS/zlib-devel-1.2.1.1-2.1.armv5bf-uclibc.rpm
/usr/src/i386-x-armv5bf-uclibc/RPMS/zlib-devel-armv5bf-uclibc-1.2.1.1-2.1.i386.rpm
- Install the converted target libraries into the host's toolchain.
$ sudo rpm -i --nodeps --force \
i386-x-armv5bf-uclibc/RPMS/zlib-devel-armv5bf-uclibc-1.2.1.1-2.1.i386.rpm \
i386-x-armv5bf-uclibc/RPMS/zlib-armv5bf-uclibc-1.2.1.1-2.1.i386.rpm
At this point the zlib headers and libraries are in the toolchain's search path. Applications that use zlib can now be built.
Building Driver Packages
Many Linux driver packages require a built kernel tree for part of the build process. The driver packages expect the kernel tree in a known location. The following steps outline how to build a kernel tree in the location the modules packages expect. The kernel build starts like all the other builds that use tsrpm:
- Extract the source RPM.
$ tsrpm --extract kernel-arm-ixdpg425-2.4-devicescape.1.src.rpm
To prevent the package build from cleaning the kernel tree after the build, you can specify the '-bc' option be passed to tsrpm.
$ tsrpm --target=armv5bf-uclibc -bc \
rpm-sources/kernel-arm-ixdpg425-2.4-devicescape.1/kernel-arm-ixdpg425.spec
- Create a link so the drivers build can find the kernel.
$ ln -s `pwd`/armv5bf-uclibc/BUILD/kernel-arm-ixdpg425-2.4/linux-2.4.27-uc1/ \
After the built kernel tree is setup as described above driver packages can be built just like any other package.
$ tsrpm --extract ieee80211-0.1-1.src.rpm
$ tsrpm --target=armv5bf-uclibc --build rpm-sources/ieee80211-0.1-1/ieee80211.spec
Making Changes to a Package
|
Note
|
This procedure allows you to make textual changes to source files by extracting a source RPM into an editable format, and then generating a patch with your modifications. If you want to update images (for example, for rebranding a Web UI), you must create and run a post-install script during the root file system (RFS) image build procedure to drop in the new binary images. For more information, see Creating an RFS Image for the Reference AP (with ipkg and mkfs.jffs2 commands)
|
To modify an existing source package using command line tools, do the following.
- Extract the source RPM.
$ tsrpm --extract hello-1.0-1.src.rpm
- To make changes to the source of a package first run only the prep stage of build. This typically involves extracting the tarball and applying any patches. This gives you the source files in an editable form:
$ tsrpm --target=i686-uclibc -bp rpm-sources/hello-1.0-1/hello.spec
- Now make a copy of the original build directory. You will use the copy later to generate a patch that includes your changes:
$ cp -a i686-uclibc/BUILD/hello-1.0 i686-uclibc/BUILD/hello-1.0.orig
- When developing, debugging and testing it can be helpful to interact with the package in the tsrpm cross environment. To do this, execute a shell and enter the build directory. Execute build commands via this shell while testing the changes you made to the package.
For example:
$ tsrpm --target=i686-uclibc --run-tool /bin/sh
$ cd i686-uclibc/BUILD/hello-1.0
i686-uclibc-gcc -g -Wall -o hello hello.c
i686-uclibc-gcc -O2 -o hello hello.c
|
Note
|
The tsrpm cross environment above has a set of environment variables specifically for cross building so some tools may not work as expected. Specifically, you may find that your editor does not work when invoked from this shell. Only execute build commands (commands that typically appear in a spec file such as configure or make) within the cross shell described above. Make your source changes (run your editor) outside of the tsrpm cross environment.
|
- Once your source changes are complete generate a patch:
$ mkdir rpm-sources/hello-1.0-1/devicescape
$ (cd i686-uclibc/BUILD && diff -urN hello-1.0.orig hello-1.0 > \
../../rpm-sources/hello-1.0-1/devicescape/hello-1.0-compact.patch)
|
Note
|
The diff as written above handles changes to text files. If you have modified binary files (such as images) within a package, then pass --text to the diff command. You might want to remove the -N option for this case to make it easier to remove machine-generated files from the diff per the next step ( step 6). So if you have modified binary files, we suggest that you generate the patch like this instead:
$ mkdir rpm-sources/hello-1.0-1/devicescape
$ (cd i686-uclibc/BUILD && diff --text -ur hello-1.0.orig hello-1.0 > \
../../rpm-sources/hello-1.0-1/devicescape/hello-1.0-compact.patch)
|
- Look through the diff and delete any changes you did not want to make, any generated files, and so on. Your patch might then look something like the following:
diff -urN hello-1.0.orig/hello.c hello-1.0/hello.c
--- hello-1.0.orig/hello.c
main (int argc, char *argv[])
diff -urN hello-1.0.orig/Makefile hello-1.0/Makefile
--- hello-1.0.orig/Makefile
- Then build the new package as shown earlier:
$ tsrpm --target=i686-uclibc --build rpm-sources/hello-1.0-1/hello.spec
The updated source rpm is available under the target subdir:
Summary of tsrpm Command Syntax and Options
tsrpm is a wrapper for rpmbuild that supports cross-compilation of SRPMs, in most cases without any need to modify the original package. It allows you to manipulate source and binary RPMs and specification files.
Syntax
tsrpm --<option> [--<option>...] <args>
Options
This section describes a subset of tsrpm command options that are particularly relevant for use with the Devicescape Wireless Infrastructure Platform, as described in the previous modify/build tasks. You can get the full list of tsrpm command options by entering tsrpm --help at the command line on a platform development host.
|
Option
|
Description and Example
|
|
--extract
|
Extract source RPM to current directory.
tsrpm --extract hello-1.0-1.src.rpm
|
|
--target=<target>
|
Indicates the target hardware for which the binary should be built. You must specify a target platform when building a package (--build ) or installing a package (--install).
tsrpm --target=armv5bf-uclibc --build rpm-sources/hello-1.0-1/hello.spec
For the mapping between the tsrpm target and Devicescape supported platforms, see the table in step 2 of Building a Userspace Package from the Command Line.
|
|
--repackage=<type>
|
Repackage target RPMs in another format. For Devicescape Wireless Infrastructure Platform, we use this option to repackage binary RPMs as IPKGs:
tsrpm --repackage=targetipkg --target=armv5bf-uclibc \ armv5bf-uclibc/RPMS/hello-1.0-1.armv5bf-uclibc.rpm
|
|
--run-tool <args>
|
Run the specified arguments as commands in the tsrpm environment. For Devicescape Wireless Infrastructure Platform, we use this for developing, debugging and testing:
tsrpm --target=i686-uclibc --run-tool /bin/sh
|
|
--convert-to-host
|
Convert the given target RPM for use as Host RPM cross library:
tsrpm --target=armv5bf-uclibc --convert-to-host \ armv5bf-uclibc/RPMS/zlib-1.2.1.1-2.1.armv5bf-uclibc.rpm
|
Debugging a Program Running on the Target
To debug a program running on the target, you can use the cross GNU debugger, gdb (for example armv5bf-uclibc-gdb). To do this, you run gdb on the development host and run the program to be debugged under gdbserver on the target. For this example, we will use the buggy program showargs.c:
5 main (int argc, char *argv[])
8 for (i = 0; i < argc + 1; i++)
10 printf ("arg %d is %d character(s) '%s'\n", i, strlen (argv[i]),
To use gdb to debug a program, you must compile the program with the -g flag. The -g flag tells the compiler to include debug symbols. Debug symbols provide information that gdb uses to determine, for example, the current source file line given the current program counter. To compile showargs.c with debug symbols for an arm target:
armv5bf-uclibc-gcc -g showargs.c -o showargs
After showargs is compiled, you must transfer it to the target. For this, you can, for example, run the ftpd daemon included in the simple-ftpd package and ftp the program to the target. Assuming a target IP address of 10.10.63.244, the following ftp session illustrates the transfer:
Connected to 10.10.63.244 (10.10.63.244).
220 Welcome to Simple-FTPd server.
6566 bytes sent in 7.7e-05 secs (8.3e+04 Kbytes/sec)
After you have placed the program on the server, you can open a telnet session on your target device and execute showargs.
arg 0 is 10 character(s) './showargs'
arg 1 is 6 character(s) '--help'
As showargs is a buggy program, an error results. To debug showargs on the target, you must connect from the target device to the gdb on the remote development host. To do this you use the gdbserver command. You must tell the gdbserver how to communicate with gdb, to do this you can provide a serial <devicename> such as /dev/com1 or a <hostname:port> combination. Assuming a host IP address of 192.168.3.232 and a port number of 2000, you would connect to gdb by entering the following into your target telnet session:
# gdbserver 192.168.3.232:2000 showargs --help
Process showargs created; pid = 8935
Finally, you run the cross gdb on the remote development host. You must identify both the name of the file to debug and a remote target as follows:
(gdb) target remote 10.10.63.244:2000
Breakpoint 1, main (argc=2, argv=0xbffffeb4) at showargs.c:8
8 for (i = 0; i < argc + 1; i++)
From this point you can debug the program on the target in a similar manner to debugging local programs using a native gdb. For more information on how to use gdb and gdbserver please refer to the following:
The fix to the showargs program above is left as an exercise for the reader.