Checksums and dependencies, as discussed in the previous section, solve half the problem. The other part of the problem is being able to use checksum information during the build and being able to reuse or rebuild specific components.
The shared state class (sstate.bbclass
)
is a relatively generic implementation of how to "capture" a snapshot of a given task.
The idea is that the build process does not care about the source of a task's output.
Output could be freshly built or it could be downloaded and unpacked from
somewhere - the build process doesn't need to worry about its source.
There are two types of output, one is just about creating a directory
in WORKDIR
.
A good example is the output of either do_install
or
do_package
.
The other type of output occurs when a set of data is merged into a shared directory
tree such as the sysroot.
The Yocto Project team has tried to keep the details of the implementation hidden in
sstate.bbclass
.
From a user's perspective, adding shared state wrapping to a task
is as simple as this do_deploy
example taken from
do_deploy.bbclass
:
DEPLOYDIR = "${WORKDIR}/deploy-${PN}" SSTATETASKS += "do_deploy" do_deploy[sstate-name] = "deploy" do_deploy[sstate-inputdirs] = "${DEPLOYDIR}" do_deploy[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}" python do_deploy_setscene () { sstate_setscene(d) } addtask do_deploy_setscene
In the example, we add some extra flags to the task, a name field ("deploy"), an
input directory where the task sends data, and the output
directory where the data from the task should eventually be copied.
We also add a _setscene
variant of the task and add the task
name to the SSTATETASKS
list.
If you have a directory whose contents you need to preserve, you can do this with a line like the following:
do_package[sstate-plaindirs] = "${PKGD} ${PKGDEST}"
This method, as well as the following example, also works for multiple directories.
do_package[sstate-inputdirs] = "${PKGDESTWORK} ${SHLIBSWORKDIR}" do_package[sstate-outputdirs] = "${PKGDATA_DIR} ${SHLIBSDIR}" do_package[sstate-lockfile] = "${PACKAGELOCK}"
These methods also include the ability to take a lockfile when manipulating shared state directory structures since some cases are sensitive to file additions or removals.
Behind the scenes, the shared state code works by looking in
SSTATE_DIR
and
SSTATE_MIRRORS
for shared state files.
Here is an example:
SSTATE_MIRRORS ?= "\ file://.* http://someserver.tld/share/sstate/PATH \n \ file://.* file:///some/local/dir/sstate/PATH"
SSTATE_DIR
) is
organized into two-character subdirectories, where the subdirectory
names are based on the first two characters of the hash.
If the shared state directory structure for a mirror has the
same structure as SSTATE_DIR
, you must
specify "PATH" as part of the URI to enable the build system
to map to the appropriate subdirectory.
The shared state package validity can be detected just by looking at the filename since the filename contains the task checksum (or signature) as described earlier in this section. If a valid shared state package is found, the build process downloads it and uses it to accelerate the task.
The build processes uses the *_setscene
tasks
for the task acceleration phase.
BitBake goes through this phase before the main execution code and tries
to accelerate any tasks for which it can find shared state packages.
If a shared state package for a task is available, the shared state
package is used.
This means the task and any tasks on which it is dependent are not
executed.
As a real world example, the aim is when building an IPK-based image,
only the do_package_write_ipk
tasks would have their
shared state packages fetched and extracted.
Since the sysroot is not used, it would never get extracted.
This is another reason why a task-based approach is preferred over a
recipe-based approach, which would have to install the output from every task.