Overview of porting C/C++ software with SBuild
|This page gives an overview of the process of porting of C/C++ software using SBuild. It supposes no previous knowledge of SBuild (it explains from scratch the concepts involved).|
|Table of content|
Porting a piece of C/C++ software has several aspects, one of them being the adaptation of the build description of that software. In the following, when we say "porting with SBuild", we refer to these changes in the build tool and the build description of your product that makes up the build-related part of the porting effort (we ignore the rest of the porting effort).
The goal of the operation is to have your software to be built for and to run on a new target platform. We stress that you are interested in a new target platform and not a new build platform (a.k.a. host platform). The new build platform, if any, it is a side effect of the desired goal. Therefore, when you see in SBuild documentation "platform", without any specification, it will mean target platform, not build platform .
|How it will look like in
Let's assume your software already works fine for some target platform called old_plat which also happens to be the development platform. And your SBuild project for that software the directory my_dir. That means that you build and run your software like that:
cd my_dir python build_mysoftware.py tgtplatform=old_plat -b python build_mysoftware.py tgtplatform=old_plat -r
May be you don't even provide tgtplatform= keyword argument because you configured your SBuild project for that to be the default target platform. Now assume that you also want your software to work on some embedded device. Let's call this new target platform new_plat. Once your porting work is done, you will build your software like that:
python build_mysoftware.py tgtplatform=new_plat -b
Since it is an embedded device, it is likely that smoke testing the build is not trivial. But that you can write code in the build scripts so that the following command line
python build_mysoftware.py tgtplatform=new_plat -r
actually downloads the just-built software to the target device, making it ready for (manual) testing. It may also be the case that your device has an simulator running on the build machine. In that case you will define another target platform, say new_plat_sim, and then use the same build and smoke test style as before:
python build_mysoftware.py tgtplatform=new_plat_sim -b python build_mysoftware.py tgtplatform=new_plat_sim -r
where the last line starts the simulator with the just-built software on it.
|Defining the task in
When you extend SBuild to support, let's say, a new C compiler, you are busy changing a part of SBuild that is named the C/C++ SBuild toolkit. You don't need to know what is a SBuild toolkit in general but you need to locate the C/C++ toolkit because you will likely make additions in its files.
Now when you compile for a new target platform, you start from the same source files. You compile and link the same C/C++ source files but is some different way. Meaning you build a different flavor of the same thing. The "thing" that you build is called a target and the typical way to describe flavors of targets in SBuild is called a variant. A variant is basically named enumeration, in other words a variant id plus a closed set of values. The values are also called flavors, because to each allowed value corresponds a different flavor of the target built.
The C/C++ toolkit of SBuild stores the target platform as a variant. This variant identifier is tgtplatform and the variant has a bunch of allowed values, for example:
and many others. Know that you don't have to dig files of the C/C++ toolkit to know what is available in your installation. See the instructions on using the command line to learn how to make a build script tell you allowed values of variants (for ex. explain=sum) along with their descriptions. The example above illustrate how to build for one target platform or another.
The point to take away is that introducing to SBuild support for a new target platform actually means introducing a new allowed value for the variant tgtplatform. How to do that is explained in more detail elsewhere.
What is a compilation tool chain? It is that set of command line tools that allow to make an executable binary file from source files. In most cases, the C/C++ compilation tool chain contains three main individual tools: a C or a C++ compiler, a linker and an archiver. Typically, these tools are not called directly but through a wrapper called "compiler front end", like the well-known "gcc" in the case of the GNU C/C++ compilation tool chain. This wrapper calls underneath the preprocessor, the compiler, the assembler, the linker, etc.
What is the relationship between a tool chain and a target platform? Typically you use a different tool chain to compile for each different target platform. But one-to-many and many-to-one are also frequently encountered. For example, one tool chain may compile for several platforms, named cross-compilation development (ex. the -m option of gcc). Also, several tool chains may compile for the same platform (ex. Intel x86 Microsoft Windows saw a long list of competing compilers: Microsoft, Borland, Intel, Watcom, Zortech/Symantec, etc.)
SBuild C/C++ toolkit stores the information about the tool chain into a variant named toolchain. The information in toolchain is, generally speaking, information about the build platform that you use.
We say that every tgtplatform has one or more tool chains. More technically, it means that to each allowed value for the variant tgtplatform corresponds one or several allowed values of the variant toolchain. For example, with tgtplatform=i86_win32 you can use toolchain=msvc6, toolchain=msvc80, toolchain=msvc80compat (among others) to change on the command line what version of the Microsoft Visual studio is used for that compilation. You can also say nothing at all about the toolchain on the command line because each value of tgtplatform has one preferred value for toolchain.
The point to take away is that you will need to provide also a new allowed value for the toolchain variant. Since you have to touch variants, it's useful to know that SBuild allows you to "clone" one allowed value of a variant in order to save typing when introducing things that are similar.
Porting C/C++ software with SBuild works in three big steps. Each of these steps will be described briefly below and in much more detail on this page:
Before the real steps listed above, let's not forget the common sense Step 0:
The first and the second step is where you give to SBuild the product independent information. This is the information that is valid for all the compilations that will be performed for this device with this compiler and linker. That includes: which are all executables of the new tool chain, what are their command line options, what is their location and how to call them in order to build something.
The first step consists of adding a new allowed value to several variants: tgtplatform, toolchain and bldopt. This work happens all in the file ccpp_vars.py. The name comes from "C/C++ variants". More information on the Step 1 here.
The second step is a consequence of the fact that SBuild is (transparently) using SCons underneath for most important actions. It is SCons that makes up, among other things, the compilation command lines for SBuild. It means that SCons has to be aware of the executables that you need to run in order to perform a build. SCons way to get informed is through your implementation of a Python wrapper to the executable. This is called an SCons Tool.
An SCons Tool is usually a one-screen-page Python script with the same name as the wrapped executable, for example cc.py, zip.py, yacc.py, latex.py, etc. They live all in the same directory. SCons provides a lot of tools (mostly not used yet by SBuild). Your chance to find an SCons tool to reuse without changes are low but chances to find one that is close to what you need are fair.
The point to take away is that you will most likely have to implement several SCons Tools based on the existing examples. They will know about the installation of the needed executables on your build machine. More information on the Step 2 here.
The third step is where you put the information that is specific both to the product that you build and to the new target platform. Typically, one executable will link with some "system libraries" that are different from one executable to another executable and from one target platform to another one. This information will be kept in the build description of that executable. This means that Step 3 happens in the SBuild project of the product that you port, unlike Step 1 and Step 2 that happen in the SBuid tool itself. More information on the Step 3 here.
For the porting engineer, it is useful to know that tgtplatform, toolchain and bldopt are global variants that are used by SBuild to make the path of the destination of your build on disk (including for the so called copy directory). You will see as part of the copy directory path: toolchain_value\tgtplatform_value\blodopt_value, for example msvc6\i86_win32\dbg for a debug build using MS Visual Studio 6 compilers.
It will depend a lot on your previous experience with SBuild porting. It will depend a lot on how close your new platform is to one already available. It depends on your experience with the product that you need to port. Any time between a few hours and a few days is possible.
Now, assuming that you have to pass through all steps and that you are not at your first port with SBuild, then the Step 3 is probably the longest, even if you are not new to the product to port. That is because all the builds and rebuilds that you have to do to get the product right (this step tails into the actual porting of the C/C++ code). If you touch the code in significant ways you may want to build also for other platforms to check that you didn't break anything.
The next in length is Step 2. It contains a small exercise in Python development (may get large if you want, for example, to provide code to scan the registry to find locations on disk). But more important and more challenging, it contains some effort of reverse engineering. Very few manuals of compilers are really complete, so you have to experiment by yourself (what shell environment variables are used and how, how to indirect the command line, etc.).
The next in length is Step 0. It involves some reading (looking for something similar to what you want). Finally, Step 1 is usually the shortest. It does require good understanding of options of executables but those are usually well documented.
The point to take away is that, like always in software development, taking shortcuts does not really pay off in the long run. It is possible (on purpose) to write SCons Tools in a quick&dirty way, resulting in a build for some device that is tight to a particular PC of a particular developer. That may save a little time on this customer project and then hurt the next one. Like always, small efforts small gains, bigger effort bigger gain.