| <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" |
| "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> |
| |
| <appendix id='hello-world-example'> |
| <title>Hello World Example</title> |
| |
| <section id='bitbake-hello-world'> |
| <title>BitBake Hello World</title> |
| |
| <para> |
| The simplest example commonly used to demonstrate any new |
| programming language or tool is the |
| "<ulink url="http://en.wikipedia.org/wiki/Hello_world_program">Hello World</ulink>" |
| example. |
| This appendix demonstrates, in tutorial form, Hello |
| World within the context of BitBake. |
| The tutorial describes how to create a new project |
| and the applicable metadata files necessary to allow |
| BitBake to build it. |
| </para> |
| </section> |
| |
| <section id='example-obtaining-bitbake'> |
| <title>Obtaining BitBake</title> |
| |
| <para> |
| See the |
| "<link linkend='obtaining-bitbake'>Obtaining BitBake</link>" |
| section for information on how to obtain BitBake. |
| Once you have the source code on your machine, the BitBake directory |
| appears as follows: |
| <literallayout class='monospaced'> |
| $ ls -al |
| total 100 |
| drwxrwxr-x. 9 wmat wmat 4096 Jan 31 13:44 . |
| drwxrwxr-x. 3 wmat wmat 4096 Feb 4 10:45 .. |
| -rw-rw-r--. 1 wmat wmat 365 Nov 26 04:55 AUTHORS |
| drwxrwxr-x. 2 wmat wmat 4096 Nov 26 04:55 bin |
| drwxrwxr-x. 4 wmat wmat 4096 Jan 31 13:44 build |
| -rw-rw-r--. 1 wmat wmat 16501 Nov 26 04:55 ChangeLog |
| drwxrwxr-x. 2 wmat wmat 4096 Nov 26 04:55 classes |
| drwxrwxr-x. 2 wmat wmat 4096 Nov 26 04:55 conf |
| drwxrwxr-x. 3 wmat wmat 4096 Nov 26 04:55 contrib |
| -rw-rw-r--. 1 wmat wmat 17987 Nov 26 04:55 COPYING |
| drwxrwxr-x. 3 wmat wmat 4096 Nov 26 04:55 doc |
| -rw-rw-r--. 1 wmat wmat 69 Nov 26 04:55 .gitignore |
| -rw-rw-r--. 1 wmat wmat 849 Nov 26 04:55 HEADER |
| drwxrwxr-x. 5 wmat wmat 4096 Jan 31 13:44 lib |
| -rw-rw-r--. 1 wmat wmat 195 Nov 26 04:55 MANIFEST.in |
| -rw-rw-r--. 1 wmat wmat 2887 Nov 26 04:55 TODO |
| </literallayout> |
| </para> |
| |
| <para> |
| At this point, you should have BitBake cloned to |
| a directory that matches the previous listing except for |
| dates and user names. |
| </para> |
| </section> |
| |
| <section id='setting-up-the-bitbake-environment'> |
| <title>Setting Up the BitBake Environment</title> |
| |
| <para> |
| First, you need to be sure that you can run BitBake. |
| Set your working directory to where your local BitBake |
| files are and run the following command: |
| <literallayout class='monospaced'> |
| $ ./bin/bitbake --version |
| BitBake Build Tool Core version 1.23.0, bitbake version 1.23.0 |
| </literallayout> |
| The console output tells you what version you are running. |
| </para> |
| |
| <para> |
| The recommended method to run BitBake is from a directory of your |
| choice. |
| To be able to run BitBake from any directory, you need to add the |
| executable binary to your binary to your shell's environment |
| <filename>PATH</filename> variable. |
| First, look at your current <filename>PATH</filename> variable |
| by entering the following: |
| <literallayout class='monospaced'> |
| $ echo $PATH |
| </literallayout> |
| Next, add the directory location for the BitBake binary to the |
| <filename>PATH</filename>. |
| Here is an example that adds the |
| <filename>/home/scott-lenovo/bitbake/bin</filename> directory |
| to the front of the <filename>PATH</filename> variable: |
| <literallayout class='monospaced'> |
| $ export PATH=/home/scott-lenovo/bitbake/bin:$PATH |
| </literallayout> |
| You should now be able to enter the <filename>bitbake</filename> |
| command from the command line while working from any directory. |
| </para> |
| </section> |
| |
| <section id='the-hello-world-example'> |
| <title>The Hello World Example</title> |
| |
| <para> |
| The overall goal of this exercise is to build a |
| complete "Hello World" example utilizing task and layer |
| concepts. |
| Because this is how modern projects such as OpenEmbedded and |
| the Yocto Project utilize BitBake, the example |
| provides an excellent starting point for understanding |
| BitBake. |
| </para> |
| |
| <para> |
| To help you understand how to use BitBake to build targets, |
| the example starts with nothing but the <filename>bitbake</filename> |
| command, which causes BitBake to fail and report problems. |
| The example progresses by adding pieces to the build to |
| eventually conclude with a working, minimal "Hello World" |
| example. |
| </para> |
| |
| <para> |
| While every attempt is made to explain what is happening during |
| the example, the descriptions cannot cover everything. |
| You can find further information throughout this manual. |
| Also, you can actively participate in the |
| <ulink url='http://lists.openembedded.org/mailman/listinfo/bitbake-devel'></ulink> |
| discussion mailing list about the BitBake build tool. |
| </para> |
| |
| <note> |
| This example was inspired by and drew heavily from these sources: |
| <itemizedlist> |
| <listitem><para> |
| <ulink url="http://www.mail-archive.com/yocto@yoctoproject.org/msg09379.html">Mailing List post - The BitBake equivalent of "Hello, World!"</ulink> |
| </para></listitem> |
| <listitem><para> |
| <ulink url="http://hambedded.org/blog/2012/11/24/from-bitbake-hello-world-to-an-image/">Hambedded Linux blog post - From Bitbake Hello World to an Image</ulink> |
| </para></listitem> |
| </itemizedlist> |
| </note> |
| |
| <para> |
| As stated earlier, the goal of this example |
| is to eventually compile "Hello World". |
| However, it is unknown what BitBake needs and what you have |
| to provide in order to achieve that goal. |
| Recall that BitBake utilizes three types of metadata files: |
| <link linkend='configuration-files'>Configuration Files</link>, |
| <link linkend='classes'>Classes</link>, and |
| <link linkend='recipes'>Recipes</link>. |
| But where do they go? |
| How does BitBake find them? |
| BitBake's error messaging helps you answer these types of questions |
| and helps you better understand exactly what is going on. |
| </para> |
| |
| <para> |
| Following is the complete "Hello World" example. |
| </para> |
| |
| <orderedlist> |
| <listitem><para><emphasis>Create a Project Directory:</emphasis> |
| First, set up a directory for the "Hello World" project. |
| Here is how you can do so in your home directory: |
| <literallayout class='monospaced'> |
| $ mkdir ~/hello |
| $ cd ~/hello |
| </literallayout> |
| This is the directory that BitBake will use to do all of |
| its work. |
| You can use this directory to keep all the metafiles needed |
| by BitBake. |
| Having a project directory is a good way to isolate your |
| project. |
| </para></listitem> |
| <listitem><para><emphasis>Run Bitbake:</emphasis> |
| At this point, you have nothing but a project directory. |
| Run the <filename>bitbake</filename> command and see what |
| it does: |
| <literallayout class='monospaced'> |
| $ bitbake |
| The BBPATH variable is not set and bitbake did not |
| find a conf/bblayers.conf file in the expected location. |
| Maybe you accidentally invoked bitbake from the wrong directory? |
| DEBUG: Removed the following variables from the environment: |
| GNOME_DESKTOP_SESSION_ID, XDG_CURRENT_DESKTOP, |
| GNOME_KEYRING_CONTROL, DISPLAY, SSH_AGENT_PID, LANG, no_proxy, |
| XDG_SESSION_PATH, XAUTHORITY, SESSION_MANAGER, SHLVL, |
| MANDATORY_PATH, COMPIZ_CONFIG_PROFILE, WINDOWID, EDITOR, |
| GPG_AGENT_INFO, SSH_AUTH_SOCK, GDMSESSION, GNOME_KEYRING_PID, |
| XDG_SEAT_PATH, XDG_CONFIG_DIRS, LESSOPEN, DBUS_SESSION_BUS_ADDRESS, |
| _, XDG_SESSION_COOKIE, DESKTOP_SESSION, LESSCLOSE, DEFAULTS_PATH, |
| UBUNTU_MENUPROXY, OLDPWD, XDG_DATA_DIRS, COLORTERM, LS_COLORS |
| </literallayout> |
| The majority of this output is specific to environment variables |
| that are not directly relevant to BitBake. |
| However, the very first message regarding the |
| <filename>BBPATH</filename> variable and the |
| <filename>conf/bblayers.conf</filename> file |
| is relevant.</para> |
| <para> |
| When you run BitBake, it begins looking for metadata files. |
| The |
| <link linkend='var-BBPATH'><filename>BBPATH</filename></link> |
| variable is what tells BitBake where to look for those files. |
| <filename>BBPATH</filename> is not set and you need to set it. |
| Without <filename>BBPATH</filename>, Bitbake cannot |
| find any configuration files (<filename>.conf</filename>) |
| or recipe files (<filename>.bb</filename>) at all. |
| BitBake also cannot find the <filename>bitbake.conf</filename> |
| file. |
| </para></listitem> |
| <listitem><para><emphasis>Setting <filename>BBPATH</filename>:</emphasis> |
| For this example, you can set <filename>BBPATH</filename> |
| in the same manner that you set <filename>PATH</filename> |
| earlier in the appendix. |
| You should realize, though, that it is much more flexible to set the |
| <filename>BBPATH</filename> variable up in a configuration |
| file for each project.</para> |
| <para>From your shell, enter the following commands to set and |
| export the <filename>BBPATH</filename> variable: |
| <literallayout class='monospaced'> |
| $ BBPATH="<replaceable>projectdirectory</replaceable>" |
| $ export BBPATH |
| </literallayout> |
| Use your actual project directory in the command. |
| BitBake uses that directory to find the metadata it needs for |
| your project. |
| <note> |
| When specifying your project directory, do not use the |
| tilde ("~") character as BitBake does not expand that character |
| as the shell would. |
| </note> |
| </para></listitem> |
| <listitem><para><emphasis>Run Bitbake:</emphasis> |
| Now that you have <filename>BBPATH</filename> defined, run |
| the <filename>bitbake</filename> command again: |
| <literallayout class='monospaced'> |
| $ bitbake |
| ERROR: Traceback (most recent call last): |
| File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 163, in wrapped |
| return func(fn, *args) |
| File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 173, in parse_config_file |
| return bb.parse.handle(fn, data, include) |
| File "/home/scott-lenovo/bitbake/lib/bb/parse/__init__.py", line 99, in handle |
| return h['handle'](fn, data, include) |
| File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 120, in handle |
| abs_fn = resolve_file(fn, data) |
| File "/home/scott-lenovo/bitbake/lib/bb/parse/__init__.py", line 117, in resolve_file |
| raise IOError("file %s not found in %s" % (fn, bbpath)) |
| IOError: file conf/bitbake.conf not found in /home/scott-lenovo/hello |
| |
| ERROR: Unable to parse conf/bitbake.conf: file conf/bitbake.conf not found in /home/scott-lenovo/hello |
| </literallayout> |
| This sample output shows that BitBake could not find the |
| <filename>conf/bitbake.conf</filename> file in the project |
| directory. |
| This file is the first thing BitBake must find in order |
| to build a target. |
| And, since the project directory for this example is |
| empty, you need to provide a <filename>conf/bitbake.conf</filename> |
| file. |
| </para></listitem> |
| <listitem><para><emphasis>Creating <filename>conf/bitbake.conf</filename>:</emphasis> |
| The <filename>conf/bitbake.conf</filename> includes a number of |
| configuration variables BitBake uses for metadata and recipe |
| files. |
| For this example, you need to create the file in your project directory |
| and define some key BitBake variables. |
| For more information on the <filename>bitbake.conf</filename>, |
| see |
| <ulink url='http://hambedded.org/blog/2012/11/24/from-bitbake-hello-world-to-an-image/#an-overview-of-bitbakeconf'></ulink> |
| </para> |
| <para>Use the following commands to create the <filename>conf</filename> |
| directory in the project directory: |
| <literallayout class='monospaced'> |
| $ mkdir conf |
| </literallayout> |
| From within the <filename>conf</filename> directory, use |
| some editor to create the <filename>bitbake.conf</filename> |
| so that it contains the following: |
| <literallayout class='monospaced'> |
| TMPDIR = "${<link linkend='var-TOPDIR'>TOPDIR</link>}/tmp" |
| <link linkend='var-CACHE'>CACHE</link> = "${TMPDIR}/cache" |
| <link linkend='var-STAMP'>STAMP</link> = "${TMPDIR}/stamps" |
| <link linkend='var-T'>T</link> = "${TMPDIR}/work" |
| <link linkend='var-B'>B</link> = "${TMPDIR}" |
| </literallayout> |
| The <filename>TMPDIR</filename> variable establishes a directory |
| that BitBake uses for build output and intermediate files (other |
| than the cached information used by the |
| <link linkend='setscene'>Setscene</link> process. |
| Here, the <filename>TMPDIR</filename> directory is set to |
| <filename>hello/tmp</filename>. |
| <note><title>Tip</title> |
| You can always safely delete the <filename>tmp</filename> |
| directory in order to rebuild a BitBake target. |
| The build process creates the directory for you |
| when you run BitBake. |
| </note></para> |
| <para>For information about each of the other variables defined in this |
| example, click on the links to take you to the definitions in |
| the glossary. |
| </para></listitem> |
| <listitem><para><emphasis>Run Bitbake:</emphasis> |
| After making sure that the <filename>conf/bitbake.conf</filename> |
| file exists, you can run the <filename>bitbake</filename> |
| command again: |
| <literallayout class='monospaced'> |
| $ bitbake |
| ERROR: Traceback (most recent call last): |
| File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 163, in wrapped |
| return func(fn, *args) |
| File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 177, in _inherit |
| bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data) |
| File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/BBHandler.py", line 92, in inherit |
| include(fn, file, lineno, d, "inherit") |
| File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 100, in include |
| raise ParseError("Could not %(error_out)s file %(fn)s" % vars(), oldfn, lineno) |
| ParseError: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass |
| |
| ERROR: Unable to parse base: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass |
| </literallayout> |
| In the sample output, BitBake could not find the |
| <filename>classes/base.bbclass</filename> file. |
| You need to create that file next. |
| </para></listitem> |
| <listitem><para><emphasis>Creating <filename>classes/base.bbclass</filename>:</emphasis> |
| BitBake uses class files to provide common code and functionality. |
| The minimally required class for BitBake is the |
| <filename>classes/base.bbclass</filename> file. |
| The <filename>base</filename> class is implicitly inherited by |
| every recipe. |
| BitBake looks for the class in the <filename>classes</filename> |
| directory of the project (i.e <filename>hello/classes</filename> |
| in this example). |
| </para> |
| <para>Create the <filename>classes</filename> directory as follows: |
| <literallayout class='monospaced'> |
| $ cd $HOME/hello |
| $ mkdir classes |
| </literallayout> |
| Move to the <filename>classes</filename> directory and then |
| create the <filename>base.bbclass</filename> file by inserting |
| this single line: |
| <literallayout class='monospaced'> |
| addtask build |
| </literallayout> |
| The minimal task that BitBake runs is the |
| <filename>do_build</filename> task. |
| This is all the example needs in order to build the project. |
| Of course, the <filename>base.bbclass</filename> can have much |
| more depending on which build environments BitBake is |
| supporting. |
| For more information on the <filename>base.bbclass</filename> file, |
| you can look at |
| <ulink url='http://hambedded.org/blog/2012/11/24/from-bitbake-hello-world-to-an-image/#tasks'></ulink>. |
| </para></listitem> |
| <listitem><para><emphasis>Run Bitbake:</emphasis> |
| After making sure that the <filename>classes/base.bbclass</filename> |
| file exists, you can run the <filename>bitbake</filename> |
| command again: |
| <literallayout class='monospaced'> |
| $ bitbake |
| Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information. |
| </literallayout> |
| BitBake is finally reporting no errors. |
| However, you can see that it really does not have anything |
| to do. |
| You need to create a recipe that gives BitBake something to do. |
| </para></listitem> |
| <listitem><para><emphasis>Creating a Layer:</emphasis> |
| While it is not really necessary for such a small example, |
| it is good practice to create a layer in which to keep your |
| code separate from the general metadata used by BitBake. |
| Thus, this example creates and uses a layer called "mylayer". |
| <note> |
| You can find additional information on adding a layer at |
| <ulink url='http://hambedded.org/blog/2012/11/24/from-bitbake-hello-world-to-an-image/#adding-an-example-layer'></ulink>. |
| </note> |
| </para> |
| <para>Minimally, you need a recipe file and a layer configuration |
| file in your layer. |
| The configuration file needs to be in the <filename>conf</filename> |
| directory inside the layer. |
| Use these commands to set up the layer and the <filename>conf</filename> |
| directory: |
| <literallayout class='monospaced'> |
| $ cd $HOME |
| $ mkdir mylayer |
| $ cd mylayer |
| $ mkdir conf |
| </literallayout> |
| Move to the <filename>conf</filename> directory and create a |
| <filename>layer.conf</filename> file that has the following: |
| <literallayout class='monospaced'> |
| BBPATH .= ":${<link linkend='var-LAYERDIR'>LAYERDIR</link>}" |
| |
| <link linkend='var-BBFILES'>BBFILES</link> += "${LAYERDIR}/*.bb" |
| |
| <link linkend='var-BBFILE_COLLECTIONS'>BBFILE_COLLECTIONS</link> += "mylayer" |
| <link linkend='var-BBFILE_PATTERN'>BBFILE_PATTERN_mylayer</link> := "^${LAYERDIR_RE}/" |
| </literallayout> |
| For information on these variables, click the links |
| to go to the definitions in the glossary.</para> |
| <para>You need to create the recipe file next. |
| Inside your layer at the top-level, use an editor and create |
| a recipe file named <filename>printhello.bb</filename> that |
| has the following: |
| <literallayout class='monospaced'> |
| <link linkend='var-DESCRIPTION'>DESCRIPTION</link> = "Prints Hello World" |
| <link linkend='var-PN'>PN</link> = 'printhello' |
| <link linkend='var-PV'>PV</link> = '1' |
| |
| python do_build() { |
| bb.plain("********************"); |
| bb.plain("* *"); |
| bb.plain("* Hello, World! *"); |
| bb.plain("* *"); |
| bb.plain("********************"); |
| } |
| </literallayout> |
| The recipe file simply provides a description of the |
| recipe, the name, version, and the <filename>do_build</filename> |
| task, which prints out "Hello World" to the console. |
| For more information on these variables, follow the links |
| to the glossary. |
| </para></listitem> |
| <listitem><para><emphasis>Run Bitbake With a Target:</emphasis> |
| Now that a BitBake target exists, run the command and provide |
| that target: |
| <literallayout class='monospaced'> |
| $ cd $HOME/hello |
| $ bitbake printhello |
| ERROR: no recipe files to build, check your BBPATH and BBFILES? |
| |
| Summary: There was 1 ERROR message shown, returning a non-zero exit code. |
| </literallayout> |
| We have created the layer with the recipe and the layer |
| configuration file but it still seems that BitBake cannot |
| find the recipe. |
| BitBake needs a <filename>conf/bblayers.conf</filename> that |
| lists the layers for the project. |
| Without this file, BitBake cannot find the recipe. |
| </para></listitem> |
| <listitem><para><emphasis>Creating <filename>conf/bblayers.conf</filename>:</emphasis> |
| BitBake uses the <filename>conf/bblayers.conf</filename> file |
| to locate layers needed for the project. |
| This file must reside in the <filename>conf</filename> directory |
| of the project (i.e. <filename>hello/conf</filename> for this |
| example).</para> |
| <para>Set your working directory to the <filename>hello/conf</filename> |
| directory and then create the <filename>bblayers.conf</filename> |
| file so that it contains the following: |
| <literallayout class='monospaced'> |
| BBLAYERS ?= " \ |
| /home/<you>/mylayer \ |
| " |
| </literallayout> |
| You need to provide your own information for |
| <filename>you</filename> in the file. |
| </para></listitem> |
| <listitem><para><emphasis>Run Bitbake With a Target:</emphasis> |
| Now that you have supplied the <filename>bblayers.conf</filename> |
| file, run the <filename>bitbake</filename> command and provide |
| the target: |
| <literallayout class='monospaced'> |
| $ bitbake printhello |
| Parsing recipes: 100% |##################################################################################| |
| Time: 00:00:00 |
| Parsing of 1 .bb files complete (0 cached, 1 parsed). 1 targets, 0 skipped, 0 masked, 0 errors. |
| NOTE: Resolving any missing task queue dependencies |
| NOTE: Preparing RunQueue |
| NOTE: Executing RunQueue Tasks |
| ******************** |
| * * |
| * Hello, World! * |
| * * |
| ******************** |
| NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded. |
| </literallayout> |
| BitBake finds the <filename>printhello</filename> recipe and |
| successfully runs the task. |
| <note> |
| After the first execution, re-running |
| <filename>bitbake printhello</filename> again will not |
| result in a BitBake run that prints the same console |
| output. |
| The reason for this is that the first time the |
| <filename>printhello.bb</filename> recipe's |
| <filename>do_build</filename> task executes |
| successfully, BitBake writes a stamp file for the task. |
| Thus, the next time you attempt to run the task |
| using that same <filename>bitbake</filename> command, |
| BitBake notices the stamp and therefore determines |
| that the task does not need to be re-run. |
| If you delete the <filename>tmp</filename> directory |
| or run <filename>bitbake -c clean printhello</filename> |
| and then re-run the build, the "Hello, World!" message will |
| be printed again. |
| </note> |
| </para></listitem> |
| </orderedlist> |
| </section> |
| </appendix> |