Factory Best Practices
Table of Contents
- Table of contents
- Factory Best Practices
- Setup
- Configuring
- I want to change my RFS software selection.
- I want to change the Packaging output Format.
- I want to build an initramfs for my system
- I want a JFFS2 image of my RFS
- I want an UBI or UBIFS image of my RFS
- How do I add my custom patch to a package?
- How do I add a library to the toolchain if it is not required by one of my selected packages?
- How do I customize the Linux kernel configuration?
- How do I customize busybox's configuration?
- How do I customize uClibc's configuration?
- How do I build Factory packages without an internet connection?
- How do I keep a local repository for my previously-chosen packages while still using the Timesys repository for new packages?
- How do I use my existing kernel source without having to create a tarball and a set of patches?
- How do I add a custom kernel module to my Factory builds?
- How do I fetch the source for a package from git?
- Building
- Incremental build
- When to rebuild from scratch
- Logging
- I do not want to compile a toolchain, I want to use an existing binary toolchain.
- Building a new Timesys provided package without building the entire Factory workorder (Application Guy)
- Building a non-Timesys provided package (Application Guy)
- I want to include various custom files in my RFS
- I want to execute a custom script on my staged root filesystem prior to building the filesystem images
- I want to add my application to the build process.
- I want to develop a package in the middle of the build process
- How do I rebuild the Linux kernel after making a change in the kernel build working directory?
- How do I add user defined make targets?
- Using the Output
- Upgrading the Factory Build Engine
- Using Factory in SCM
This page documents the best practices for use with the Timesys Factory build system.
Setup
Setup involves first obtaining the Factory build system. The Factory can be obtained from the Timesys Git repository or from the output of a Timesys Web Factory build. Refer to the Factory Getting Started Guide and HOWTO Clone a Timesys Git Repository for more information.
Configuring
The basic configuration of the build system is performed by starting one of the following configuration interfaces:
make menuconfig make webui make gconfig make xconfig make config
The menuconfig interface is the most commonly used front-end to the build system configuration.
I want to change my RFS software selection.
Changing the package selection involves adding an application, removing an application, or modifying the configuration of an existing application.
Adding an application is easy. Open the configuration and select the new application you would like to add. The next invocation of make will fetch, configure, build, and install that application into your RFS staging directory. Or, you can invoke the select target for that application:
make application-select
You can also build this application as a package by invoking the application's '-package' target.
make application-package
Removing an application requires the RFS staging directory to be reset as there is no application "uninstall" within the build system. This does not recompile all of the previously selected applications. It simply re-installs the selected applications to a pristine RFS staging directory.
make rfs-distclean make rfs
Modifying an application configuration requires resetting the application in the build system in order for the new configuration to be fetched and applied.
make application-distclean
Running make without additional targets will perform the following steps as required (if RFS generation and package generation is selected):
make application-rfs-install make application-package make rfs
I want to change the Packaging output Format.
Changing the packaging output format requires the following steps:
make packages-distclean make packages
This does not result in a recompile. It simply deletes the generated packages and forces the invocation of the "-package" target for each selected application.
I want to build an initramfs for my system
An initramfs is a filesystem image that runs directly from RAM. It is packaged as an archive using the cpio tool and typically stored within the kernel image. The Factory allows you to automate this process and output your RFS as a cpio-archived initramfs with the selection of a few options. You can choose to either build it as a separate image, or even build it in to the kernel image itself. The former choice makes it easier to modify your initramfs image without having to modify the kernel, while the latter method simplifies the boot process and possibly saves space. To build an initramfs image of your RFS using the Factory:
- In the root of your Factory directory, run make menuconfig.
- In the menu, set Target Configuration->Build RFS->cpio to y.
- If you wish to build the initramfs image into the kernel, set the option Target Configuration->Build RFS->cpio->Build cpio into kernel as initramfs to y.
- The gzip-compressed initramfs image is located at build_<architecture>-timesys-linux-<libc>/images/rfs/rootfs.cpio.gz.
I want a JFFS2 image of my RFS
JFFS2 is a flash-friendly filesystem that automatically handles wear-leveling and bad blocks on Linux MTDs. More information about JFFS2 can be found in the following document: HOWTO Create JFFS2 Images. The Factory can automatically produce JFFS2 images of your RFS, which can be burned directly to flash using a number of methods. To configure your .config work order to produce a JFFS2 image:
- In the root of your Factory directory, run make menuconfig.
- In the menu, set Target Configuration->Build RFS->jffs2 to y.
- In the Target Configuration->Build RFS->jffs2 menu, set the parameters to match the geometry of your flash chip. See the documents HOWTO Find NAND Parameters and HOWTO Find NOR Parameters for more information. The default values may be sufficient if you are using the supported development board.
- Also in the jffs2 menu, select whether or not to add summary information to your image. Your kernel must have JFFS2 Summary Support enabled for this option to work.
- The JFFS2 image is located at build_<architecture>-timesys-linux-<libc>/images/rfs/rootfs.jffs2.
I want an UBI or UBIFS image of my RFS
UBI is a flash abstraction layer, similar to LVM on hard disks, that allows you to divide a single flash chip into multiple logical partitions. The UBI layer takes care of wear-leveling and bad blocks, much like JFFS2. For more information about UBI, see the document HOWTO Use UBIFS. The Factory can automatically produce UBI and UBIFS images of your RFS, the former of which can be burned directly to flash, while the latter can be added to a preexisting UBI device. To enable UBI/UBIFS support in Factory:
- In the root of your Factory directory, run make menuconfig
- In the menu, set Target Configuration->Build RFS->ubifs to y
- In the Target Configuration->Build RFS->ubifs menu, set the parameters to match the geometry of your flash chip. See the documents HOWTO Find NAND Parameters and HOWTO Find NOR Parameters for more information. The default values may be sufficient if you are using the supported development board.
- Also in the ubifs menu, select whether or not to wrap your UBIFS image in an UBI layer. If you select y, you can write the resulting image directly to a flash partition. Otherwise, you will need to add the image to an UBI-formatted device.
- The UBI/UBIFS images are located at build_<architecture>-timesys-linux-<libc>/images/rfs/rootfs.ubi[fs]
How do I add my custom patch to a package?
Adding a custom patch to an existing package in the Factory is accomplished by either:
- Adding the patch to the package's LOCAL_PATCHES list within the platform configuration (.config)
- Storing your custom patch and the Timesys provided package source archive, patches, and files locally
Adding the patch to the LOCAL_PATCHES list is the easiest approach. It allows local customizations to live outside of the Timesys provided source and patches, keeping the configuration clean when tracking updates from Timesys. Storing your custom patches along with the Timesys provided sources and patches locally would be preferred for large scale changes, when future changes from the Timesys provided sources and patches are not desired as they will create unnecessary integration and testing costs.
Note that the patch format assumes a top level prefix that is the name of the uncompressed source directory (-p1). For example, using diff with a pristine copy and a modified copy of the source tree:
diff -Naur openssl-x.x.x.orig openssl-x.x.x > openssl-0.9.12f-mychanges.patch
Also note that modifying the configuration of a previously built package will require resetting that package and the source files fetched for it. This is easily done with
$ make openssl-distclean
Adding a custom patch to LOCAL_PATCHES
This is the easiest and preferred method of adding a custom patch to any package provided by Timesys. Below is an example of creating a custom source directory in which to store custom application patches. The custom patch is then named in the platform configuration within the packages LOCAL_PATCHES list. This patch is copied into the src/dl along with any remote sources at fetch time.
Create a directory to store package customizations:
$ mkdir -p src/local/o/openssl/openssl-<openssl version>/
Copy the custom patch to the local custom directory:
$ cp custom.patch src/local/o/openssl/openssl-<package version>/
Add custom.patch to the package LOCAL_PATCHES list in the platform configuration (.config file located in your top-level Factory directory):
TSWO_openssl_LOCAL_PATCHES="custom.patch"
Storing your custom patch along with the Timesys sources locally
You can locally store the Timesys sources for the application along with your custom patches. This is equivalent to using LOCAL_PATCHES except all sources are also stored locally.
Create a directory to store package customizations:
$ mkdir -p src/local/o/openssl/openssl-<openssl version>/
Copy the previously fetched Timesys patches, tarball and the custom patch to the local custom directory:
$ cp src/dl/o/openssl/openssl-<openssl version>/* src/local/openssl/openssl-<openssl version>/
$ cp custom.patch src/local/o/openssl/openssl-<openssl version>/
Modify the package URL in the platform configuration to point to the local path, relative to the base directory of the build system:
TSWO_openssl_URL="file://$(BASE_DIR)/src/local/o/openssl/openssl-$(TSWO_openssl_VERSION)/"
Add the custom patch to the work order patch list:
TSWO_openssl_PATCHES="existing_a.patch existing_b.patch custom.patch"
How do I add a library to the toolchain if it is not required by one of my selected packages?
Libraries are added to the toolchain as required, so if a selected application requires openssl, then openssl is added to the toolchain. However, if you select openssl but do not select any packages that use openssl, you will end up with a toolchain that does not contain the openssl library. This can be bad if you are going to build a custom application against a cross-openssl library.
To get our example, openssl, automatically added to your toolchain, select the "Install openssl to Toolchain" option within the openssl configuration menu. The next invocation of "make" will update your toolchain.
You can also manually update your toolchain to include openssl using:
make openssl-host-install
and then regenerate the toolchain with:
make toolchain-final-package
The toolchain can now be shared with an application developer who requires openssl.
How do I customize the Linux kernel configuration?
You can customize the configuration several ways. The most basic way is to point the kernel configuration location to your customized .config. By default the kernel configuration option points to the kernel configuration within the Factory builder:
TSWO_KERNEL_CONFIG="file://$(BASE_DIR)/target/configs/kernel/sh7785lcr/config-$(TSWO_kernel_VERSION)"
Notice the file:// URL and the use of $(BASE_DIR) to point to the top level Factory builder directory.
You may also invoke the Linux kernel menu configuration by using the kernel-menuconfig target.
make kernel-menuconfig
This target makes sure the default configuration from TSWO_KERNEL_CONFIG has been fetched and copied into an uncompressed kernel source before invoking the Linux kernel's menuconfig target. If the Linux kernel's menuconfig target returns successful, the resulting .config in the kernel working directory is copied back to the src/dl/kernel/ cache location. Note that if this modified configuration is desired for future uses, it should be copied from the source download cache or from the Linux kernel's working directory into a persistent location. This location could then be used as the value for TSWO_KERNEL_CONFIG.
Modifying the kernel configuration will cause the kernel to be rebuilt when make is next invoked. The kernel can always be forced to rebuild using the 'kernel-restage' make target.
If you have already built a kernel using another kernel configuration file, including the default, make sure to execute the following before building the kernel with the new kernel configuration file:
make kernel-distclean
Please refer to HOWTO Rebuild and customize your kernel in Desktop Factory for additional information on rebuilding your Linux kernel.
How do I customize busybox's configuration?
Much like the Linux kernel configuration previously described, you can run the busybox-menuconfig make target.
How do I customize uClibc's configuration?
Much like the Linux kernel configuration previously described, you can run the uclibc-menuconfig make target.
How do I build Factory packages without an internet connection?
If your build machine does not have an internet connection and/or is not able to reach repository.timesys.com, you will need to download all of the required source packages from another machine with an internet connection and transfer them to the respective directory in src/dl found in your Factory base directory. Then disable the source file fetch command by doing the following:
# make menuconfig
Go to Advanced Build Configuration, and enable the Work Offline option.
At this point, your local Factory build environment is ready to perform offline builds.
How do I keep a local repository for my previously-chosen packages while still using the Timesys repository for new packages?
It is often desirable to build a local cache of packages while still relying on the Timesys repository for newly-added packages. This is also the recommended method for sharing the same sources and patches between multiple Factories.
Factory includes a script called awget, which is a wrapper for wget (the tool used for fetching sources). awget downloads archives and other compressed files to a well-known location for use by all Factories on a system (or at least all Factories configured to use the script) and then creates a symlink in the Factory download directory to a global file location. Symlinking protects the archive against distcleaning. If a file is found to have already been archived, then just the symlink is created. The local repository location is /home/user/timesys/repository.
To use awget, set the Factory config option, Advanced Build Configuration -> URL command (TSWO_URL_CMD), to use the script instead of the default wget executable:
awget -nv -c
If you would prefer to keep only certain packages locally rather than building up a repository of all packages used by your Factories, you can do so by setting the package's URL in the .config work order. The location of your choice can then be populated by copying the sources from an existing local src/dl directory, or by manually downloading individual files from the Timesys repository. Below is an example of a custom repository entry:
TSWO_openssl_URL="http://repository.somecompany.internal/o/openssl-$(TSWO_openssl_VERSION)/"
How do I use my existing kernel source without having to create a tarball and a set of patches?
Often significant work is done on the kernel as part of embedded projects. In these cases it may be more convenient to work with a source tree, rather than tar files and patches. The Factory supports this work flow through the "external" kernel source option.
In Factory menuconfig, under Target Software -> Kernel, set the Build an internal kernel or use an external kernel? to external. The Kernel Source Path should now be available. This option specifies the location to the unpacked kernel source directory from which the kernel will be built. This is the literal directory path to the location of your kernel source tree. Optionally you can also provide the location for a kernel configuration file or accept the default that assumes an existing, working .config is present in the kernel source location.
Much like other packages, the kernel can also be fetched from a git repository. Refer to How do I fetch the source for a package from git? for more information.
How do I add a custom kernel module to my Factory builds?
You can create a Factory make recipe for a custom kernel module so that it is built by the Factory. The Factory automatically sources all .mk files included within the target/software/Custom directory.
First, create the target/software/Custom directory. Add a customized version of following make recipe to target/software/Custom/ with a .mk file extension. Replace all occurrences of mymodule with the name of your module. All expansions are based on the name passed to COMMON_SETUP.
NOTE: Copy and pasting the following example may not preserve the formatting required by the make utility.
# specify the *_EXTERNAL_SRC path # this can be any path, including within the factory # directory itself (using $(BASE_DIR) as the starting point) TSWO_mymodule_EXTERNAL_SRC=$(BASE_DIR)/src/mymodule/ # if no real version, 0 will do TSWO_mymodule_VERSION=0 TSWO_mymodule_DEPENDS="" TSWO_mymodule_RUNTIME_DEPENDS="" $(eval $(call COMMON_SETUP,mymodule)) # kernel build needs to happen first mymodule-configure: kernel-build # empty, or add commands as necessary $(BUILD_DIR)/mymodule-$(mymodule_VERSION)/.stamp_configured: @touch $@ # call the default target, or change to call a specific target $(BUILD_DIR)/mymodule-$(mymodule_VERSION)/.stamp_built: PATH=$(BUILD_PATH) \ $(MAKE) -C $(mymodule_EXTERNAL_SRC) \ KERNELDIR=$(BUILD_DIR)/linux-$(TSWO_kernel_VERSION)/ \ CROSS_COMPILE=$(TSWO_FULL_TARGET_NAME)- \ ARCH=$(TSWO_KERNEL_ARCH) @touch $@ # assuming a modules_install target is present, which could look like # modules_install: # $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install $(BUILD_DIR)/mymodule-$(mymodule_VERSION)/.stamp_rfs_installed: PATH=$(BUILD_PATH) \ $(MAKE) -C $(mymodule_EXTERNAL_SRC) \ KERNELDIR=$(BUILD_DIR)/linux-$(TSWO_kernel_VERSION)/ \ CROSS_COMPILE=$(TSWO_FULL_TARGET_NAME)- \ ARCH=$(TSWO_KERNEL_ARCH) \ INSTALL_MOD_PATH=$(TSWO_RFS_INSTALL_DIR) \ modules_install @touch $@ # empty $(BUILD_DIR)/mymodule-$(mymodule_VERSION)/.stamp_host_installed: @touch $@ # optional, remove commands if you do not want a package $(BUILD_DIR)/mymodule-$(mymodule_VERSION)/.stamp_packaged: PATH=$(BUILD_PATH) \ $(MAKE) -C $(mymodule_EXTERNAL_SRC) \ KERNELDIR=$(BUILD_DIR)/linux-$(TSWO_kernel_VERSION)/ \ CROSS_COMPILE=$(TSWO_FULL_TARGET_NAME)- \ ARCH=$(TSWO_KERNEL_ARCH) \ INSTALL_MOD_PATH=$(mymodule_PKG_INSTALL_DIR) \ modules_install @touch $@ # add mymodule to the software build SOFTWARE+=mymodule
Your custom kernel module will need a Makefile that the Factory builder can invoke with the above recipe. If you do not have a Makefile for your custom kernel module, the following template may be helpful:
NOTE: Copy and pasting the following example may not preserve the formatting required by the make utility.
# customize as needed CFLAGS_MODULE+= ARFLAGS_MODULE+= LDFLAGS_MODULE+= MODULE_NAME=mymodule SOURCE_FILES=mymodule_file1.c mymodule_file2.c ifneq ($(KERNELRELEASE),) obj-m := $(MODULE_NAME).o $(MODULE_NAME)-objs := $(SOURCE_FILES:.c=.o) else KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install endif clean: -rm -f *.o *.ko Module.* *.mod.c modules.order
How do I fetch the source for a package from git?
You can change the applications URL value to point to a git repository. The build system looks for either a URI that begins with git:// or ends with .git. So either of the following will use the globally configured git command to fetch the sources:
- git://git.collabora.co.uk/git/libnice
- http://cgit.collabora.com/git/libnice.git
The version field can be used to specify the git refspec to checkout. If the given version is not a valid tag, branch, or other refspec, then HEAD will be used instead.
The checked out sources are then archived into the value of the source file name field. In our example, we are left with a libnice-$(libnice_VERSION).tar.gz tarball in the source download directory. This is then unpacked and built as any other source archive.
Building
Incremental build
Adding a new package does not require a full rebuild. Adding the selection and reissuing a generic "make" will build, package, and install into the RFS only the new selections made since the previous build. The RFS staging directory is populated with all current selections. Any time a selection is removed a 'make rfs-distclean' should be run to reset the RFS staging directory, thereby removing the prior selections.
See I want to change my RFS software selection below.
When to rebuild from scratch
Rebuilding from scratch is sometimes ideal. The following situations may call for a clean, from scratch build:
- nightly builds
- whenever the auditing requirements are high and any change causes the entire platform to be retested
- whenever a newly added application can provide additional functionality to the other application selections (this requires compile time detection)
- for Q/A purposes
Rebuilding from scratch involves building the entire platform again and is more time costly than an incremental build. To purge all staged and built software use the following:
make clean
This removes the build directory, but leaves the downloaded sources and the current .config. To remove the sources and platform configuration use
make distclean
See make help for more options and their descriptions.
Logging
Build logs should capture both stdout and stderr. Use tee utility to capture all output from the build:
make 2>&1 | tee log
The '-a' option to tee will append to a previously created file. This is useful for subsequent runs after any platform configuration changes.
The log can be inspected for a shorter summary of the steps performed by the build system. An entry in the output for each step takes the following form:
-- action name version -- posix time [human readable time]
Using this format, a shorter summary from the log would be generated by a command similar to:
grep '^-- ' log | less
I do not want to compile a toolchain, I want to use an existing binary toolchain.
Configure the build system to fetch your existing toolchain by providing the URI to the binary toolchain archive.
In Factory menuconfig, open the Toolchain Configuration menu, and change the Toolchain (build) option to fetch. You can then provide the location for an existing binary toolchain. For support and compatibility concerns, this should be a toolchain archive generated by a previous build either locally or from the Timesys Factory web system.
In addition to the above option, you will have to specify the vendor and architecture identifiers along with the location. The architecture and vendor identifiers come from the toolchain quad/triplet of arch-vendor-os-libc.
Examples of toolchain location values include:
- svn://src.timesys.com/svn/team/project/toolchain/toolchain.tgz
- http://src.timesys.com/svn/team/project/toolchain/toolchain.tgz
- ftp://vendor/path/toolchain/toolchain.tgz
- file:///opt/timesys/packages/ppc4xx/toolchain.tgz
Building a new Timesys provided package without building the entire Factory workorder (Application Guy)
You can use the binary toolchain and the Factory to build a specific package, such as a library, that is provided by Timesys without having to rebuild the entire project locally. Setup the Factory to use a binary toolchain as previously described. Then you issue the package build target to create a binary package of the new library you can then unpack into your working area.
make libpng-package
Building a non-Timesys provided package (Application Guy)
You can use the binary toolchain to cross compile any autotools enabled application easily:
PATH=/path/to/toolchain/bin:/usr/bin:/bin \ ./configure \ --prefix=/usr \ --target=$TARGET \ --host=$TARGET \ --build=`gcc -dumpmachine` && \ make
Typically this is all that is needed to install the package into your RFS:
make install DESTDIR=/path/to/rfs
The toolchains provided by the Factory come bundled with several utilities to help build and work with autotools based software that it outside of the Factory tree. These utilities are within the same directory as your cross toolchain and should be in your PATH.
- cross_configure performs the same steps as the above ./configure step automatically. Any arguments you pass will be passed through to the ./configure invocation.
- cross_make is a similar helper, invoking make along with any provided arguments.
- cross_install_to_toolchain invokes make passing along the correct DESTDIR to add the library to your toolchain location.
- cross_cmake invokes cmake on your behalf specifying the toolchain configuration.
- cross_qmake invokes qmake on your behalf specifying the toolchain configuration.
I want to include various custom files in my RFS
You can use the RFS Overlay facility in Desktop Factory to overlay an archive on top of your RFS.
I want to execute a custom script on my staged root filesystem prior to building the filesystem images
You can use the RFS customization script facility in Desktop Factory that allows for more advanced, scripted customizations prior to generating the BSP RFS image(s).
I want to add my application to the build process.
You have several options. The first option is to add a proper Factory package that defines a Kconfig (Config.in) file and a make rules ([app_name].mk) file. The second option is to include your application in the RFS content tarball as previously described. Also refer to How do I add user defined make targets? for a much simpler mechanism but does not integrate into the Factory's configuration system.
The "new package" script will create the app directory as target/software/[Category]/[app_name] and setup the Config.in and app_name.mk files using the templates target/software/.template_in and target/software/.template_mk:
Usage: ./bin/new_pkg [app_name] [Category]
The script will then open the two generated files using $EDITOR or vim. You will need to specify the location to fetch the source and patches, the version, the source tarball name, the directory created when uncompressing the tarball (working directory), a list of patches, configure and build options, and a description. The default make rule file is generated to replicate all of the default build commands for the standard make targets that the Factory will issue on behalf of the package. Each make target can be edited if necessary to override the steps performed. All commented lines represent the default actions that are executed for each step in a packages build and can be removed if no customization is required.
The Factory defines a series of default actions that each package should support:
- fetch
- unpack
- patch
- configure
- build
- check
- host-install
- rfs-install
- package
- clean
- distclean
Most of these targets have pre and post hooks so that setup and tear down actions can be performed.
Any actions that are not necessary should be represented as an empty target. For example, packages that are not autoconf enabled do no need the configure step and should define the configure target as empty.
The Factory exposes the configuration values that are passed to all of these steps. They are defined in the Config.in file for inclusion within the top level .config work order. The two most important are CONFIGURE_OPTIONS and BUILD_OPTIONS. Configure options are passed to the configure script during the configure action. Build options are passed to each make invocation and typically are used to pass environment variables that can be used by make.
Examples can be found within the Factory target/software/* sub-directories. Most packages do not need to specify anything custom to the make rules and can use only the values provided in the packages Config.in.
I want to develop a package in the middle of the build process
You can edit a package in the middle of the build process by manually intervening in the build at a certain point, make your changes, and then set and/or unset target stamp files.
For example, you are interested in customizing openssl for your board. The following work flow may be appropriate:
make openssl-package
You take the package, uncompress it to your RFS and begin testing. You find you would like to tweak a source file or a static configuration file included in the package.
Reset the build status of the package:
make openssl-restage
Change directory to the openssl build directory and make your changes:
cd build_*/openssl*/openssl*/
Change directory back to the top level build directory and reissue the make command:
cd ../../.. && make openssl-package
Repeat as necessary. The final changes can then be expressed as a patch that can then be integrated into the normal build flow.
For faster iterations you can use the cross_configure and cross_make utilities described above to make source level edits and re-invoke the configuration and build steps.
export PATH=$PWD/build_*/toolchain/bin:$PATH cd build_*/openssl*/openssl* # edit various source files cross_make # repeat cross_make
How do I rebuild the Linux kernel after making a change in the kernel build working directory?
If you modify the Linux kernel sources directly within the build_*/linux-[version] working directory, you will need to run the following make target:
$ make kernel-restage
How do I add user defined make targets?
The Factory automatically sources all .mk files included within the target/software/Custom directory. Create the directory and add a .mk file for your custom targets. Here is an example of adding defconfig like make targets to the Factory:
$ mkdir -p target/software/Custom $ vi target/software/Custom/defconfigs.mk # NOTE THIS MUST BE TABBED CORRECTLY FOR MAKE, BEWARE COPY AND PASTE # begin custom defconfig rules foo_defconfig: cp -f $(BASE_DIR)/foo_config .config bar_defconfig: cp -f $(BASE_DIR)/bar_config .config .PHONY: foo_defconfig bar_defconfig # end custom defconfig rules
Then you can issue make foo_defconfig and it will copy foo_config to .config in the base Factory directory.
Using the Output
Toolchain
The working toolchain is found within the build_*/toolchain directory. There are also two toolchain archives within build_/. The toolchain-initial*tgz file is a bare bones toolchain that does not contain any of the libraries selected during the build. This is useful for seeding other build environments or resetting the current build environment back to a bare toolchain without any customizations. The toolchain-final*tgz contains the bare toolchain along with the header and library files installed by all of the package selections.
Any additional selections will be added to the toolchain when a generic make is invoked. If you would like to make manual changes to the toolchain, you can regenerate the toolchain packages with either the 'toolchain-final-package' or 'toolchain-initial-package' depending on which toolchain you are interested in.
Kernel
The kernel image is found within the build_*/images/ directory. It is ready to deploy as is. It may optionally be included within the RFS.
RFS
The RFS working area is in the build_*/rfs directory. This is NOT ready to be immediately exported due to missing device files and permissions. Device files are created during the RFS image creation process (invoked with the rfs-images target). File permissions are set to root:root as well during the image creation process. Any changes made manually to the filesystem staging directory (build_*/rfs) will be reflected in the generated RFS images only when rfs-images is rerun.
The RFS image(s) located in build_*/images/rfs are ready to be deployed. It may be a tarball, flash image, or other filesystem image that is meant to be burned to the board or served via NFS. When exporting a tarball via NFS the tarball must be uncompressed with root permissions so that the file permissions and device files are correctly created and set.
Determining the RFS size requirements
Within the Factory bin/ directory, the rfs-report.sh script reports size information relating to your target's built RFS. This is particularly helpful while making adjustments to your build to meet RFS size limitations. Invoking this script (from the top-level Factory directory), along with one of the following options, will provide the corresponding data as it pertains to the target's RFS:
NOTE: the build must be completed prior to running the rfs-report.sh script
$ bin/rfs-report.sh total
The 'total' option provides the overall size requirement for your target's RFS.
$ bin/rfs-report.sh by-package
The 'by-package' option provides size requirements (in bytes) for each package added to your target's RFS, as well as a perctage of the overall RFS size.
$ bin/rfs-report.sh by-file
The 'by-file' option provides very similar size information as 'by-package' though on a per-file basis. The size of each file in your target's RFS is reported in both bytes and as a percentage of the overall RFS size. Due to the large number of files typically included in the target RFS of a built, it is recommended to direct output of the by-file rfs-report to a temporary file for review i.e.
$ bin/rfs-report.sh by-file > ByFileReport.txt
Passing binary tools to the Application Guy
An installer containing the cross toolchain, RFS, and kernel sources are built by default with the rest of the platform build. The configuration is found within the Toolchain Configuration -> Generate target SDK installer settings. The installer can be rebuilt anytime by issuing 'make installer' directly, or just 'make' if enabled. For more information on the installer and other Factory outputs, see FactoryOutput.
The self-extracting installer that places its contents into a location specified at install time. The default location is $HOME/timesys/[target name]. This location can be customized at build time and installation time. The target name can be replaced in the platform configuration by a more descriptive project or milestone name. At installation time, the ~/timesys prefix can be changed to another preferred location. Command line developers need only setup the $PATH environment variable to use the cross toolchain and the built in ccache utility (which makes rebuilding much faster during development).
Here is an example installer being run:
Timesys raspberrypi distribution installer (Sun Jan 22 20:57:34 2012) Please enter the destination directory [/home/user/timesys]: /home/user/development_targets Installing toolchain to /home/user/development_targets/raspberrypi/toolchain...Done. Installing kernel image to /home/user/development_targets/raspberrypi/zImage-3.1-ts-armv6l...Done. Installing kernel source to /home/user/development_targets/raspberrypi/kernel-source/...Done. Copying the root filesystem archive to /home/user/development_targets/raspberrypi/rfs/rootfs.tar.gz...Done. When extracting the root filesystem, remember to use a privileged account so that the device files are correctly created. Using the toolchain requires updating your PATH environment variable: export PATH=/home/user/development_targets/raspberrypi/toolchain/ccache:/home/user/development_targets/raspberrypi/toolchain/bin:$PATH
NOTE: If tools built on a 32-bit machine are passed to a developer on a 64-bit machine, that developer must install 32-bit compatibility libraries for the toolchain to function. Without these libraries using the toolchain will report:
No such file or directory
Creating an RPM database from my Factory packages.
An RPM database can be created after the platform build is complete by using the host RPM with commands similar to the following:
mkdir -p root/var/lib/rpm rpm --initdb --dbpath $PWD/root/var/lib/rpm rpm --dbpath $PWD/root/var/lib/rpm -i /path/to/packages/*.rpm --force rpm --dbpath $PWD/root/var/lib/rpm -qa
The RPM run time files can then be placed in the target RFS.
Using ccache with the cross toolchain
The binary toolchain from the Factory build includes ccache by default. To use with the binary toolchain, set the PATH environment variable to include the ccache sub-directory of the toolchain location. If your toolchain is located in /home/user/timesys/board/toolchain:
export PATH=/home/user/timesys/board/toolchain/ccache:/home/user/timesys/board/toolchain/bin:$PATH
You can create additional links within the toolchain/ccache directory to other compilers you may have on your system.
Using distcc along with ccache with the cross toolchain
In order to use distcc with the binary toolchain, export the CCACHE_PREFIX and DISTCC_HOSTS environment variables. CCACHE_PREFIX should be set to distcc which will cause ccache to prefix the compiler command with distcc. DISTCC_HOSTS is a space delimited list of hosts which are running distcc. Each distcc host must have the cross toolchain available locally in its path.
$ export CCACHE_PREFIX=distcc $ export DISTCC_HOSTS="foo bar"
Customizing and using the target init system
The init system in each Factory build is provided by either the busybox or the sysvinit package. Both packages provide a similar framework for booting the system, providing the /etc/inittab configuration file along with the startup scripts in /etc/init.d. Busybox is self contained and has everything required for a fully functional init. Sysvinit requires bash, coreutils, mingetty, and shadow.
For busybox, application startup scripts are placed in /etc/init.d following a S[0-9] format for the startup scripts and K[0-9] for the shutdown (or kill) scripts. Each is called in numerical order passing either "start" or "stop" as the first argument. Each script must have executable permissions otherwise they will not be called. If /etc/init.d/rc.local is present, it is called last in the startup process or first in the shutdown process.
For sysvinit, application start scripts are placed in /etc/init.d with symlinks to the /etc/rcX.d run level directories following a S[0-9] format for the startup scripts and K[0-9] for the shutdown (or kill) scripts. Each is called in numerical order passing either "start" or "stop" as the first argument. Each script must have executable permissions otherwise they will not be called. If /etc/init.d/rc.local is present, it is called last in the startup process or first in the shutdown process.
Sysvinit is configured by default to spawn mingetty and provide a login prompt. Busybox spawns a shell by default. Both can support either option and examples are provided within the inittab file to change the default behavior. A valid device file for the console must be present when the init system starts, otherwise Freeing init memory: will be the last line printed.
Upgrading the Factory Build Engine
Uncompress the new version of the Factory build system. Newer versions are available from the Timesys Git repository or from a Factory web build. Copy your existing .config file into the new directory and run: make olddefconfig
This will keep your existing selections and settings while updating the core Factory settings that do not have an impact on your platform configuration.
Next you can run make checkupdates. This will identify any patches or configuration options missing from your existing configuration that you may be interested in adding.
If you see updates you are interested in applying to your configuration, you can run make menuupdate to launch a menuconfig interface for accepting updates. Alternatively, you can step through each available update and choose whether or not to incorporate it into your platform definition by using the make update.
While reviewing updates, higher level updates which will override other software options, such as new gcc or the Kernel versions are called 'base' updates. When you accept a base update, menuupdate should run again to find new defaults for any affected software selections. For example, a newer kernel choice will impact the kernel patch list. Conversely, if a new patch was released for an older kernel used by your configuration, that is shown separately as a Software Updates.
In addition to the configuration changes outlined above, you can also move your previous ./src directory into the new Factory build directory to prevent having to re-download any identical sources and patches.
Upgrading the Factory Build Engine using GIT
Using the Timesys Git repository to update the build system is the simplest way of getting the latest updates from Timesys. Any customizations that are made can be stored in a local branch, and then git can "rebase" your changes over the newer Timesys commits.
git clone http://git.timesys.com/factory.git cd factory git checkout -b mycompany_branch ... # later, use git to download all changes in the newer releases git fetch origin ... # review log of changes in the Timesys master branch git log origin # to rebase your branch on top of newer Timesys changes git rebase origin # or cherry pick the change that you are interested in (repeat as necessary) git cherry-pick [sha1 of commit] # check for new default settings and configuration for your current configuration make checkupdates
Kernel configuration files
The Factory build system provides configuration files for the kernel as well as some other software packages. In general, it is best to accept this new configuration file when you are updating to a newer kernel. For some kernels, configuration flags are not portable between versions due to the way the upstream BSP is implemented. Also, the Factory kernel configuration is tested by Timesys and known to work. If you have difficulty using the Timesys default, please contact support@timesys.com.
Using Factory in SCM
The Factory build system itself is perfectly suited to be stored within a source control management system. The source and patch information may also be stored in an SCM but this is not required.
The build system (and accompanying work order) can be checked out of an SCM system and the build can be invoked. The source and patch information used by the Factory can be stored on site, off site, or locally on the build machine. The global location provides this location (as well as a per application override).