Building and running embedded Linux .NET applications from first principles: Difference between revisions

From Yocto Project
Jump to navigationJump to search
(Created page with " [Work in progress] == Overview == This walk-through has the aim of taking you from a clean system through to including Mono in a build image with the meta-mono layer, then bui...")
 
(Update to Jethro)
 
(28 intermediate revisions by the same user not shown)
Line 1: Line 1:
[Work in progress]
== Overview ==
== Overview ==


This walk-through has the aim of taking you from a clean system through to including Mono in a build image with the meta-mono layer, then building and packaging an example .NET project for inclusion in that image.
This walk-through has the aim of taking you from a clean system through to including Mono in a build image using the meta-mono layer, then building and packaging an example .NET project for inclusion in that image.


You may already have Yocto installed and just be looking to work with recipes for the first time, in which case you can jump forward to the section you find most relevant, <br/>
You may already have Yocto installed and just be looking to work with Mono for the first time, in which case you can jump forward to the section you find most relevant, <br/>
such as [[#Build an example project on the host for testing (optional)|building an example package on the host to test]] or [[#Build an example package based on a git repository commit|building an example package from a git commit]].
such as [[#Build an example project on the host for testing (optional)|building an example package on the host to test]] or [[#Adding the meta-mono layer to the Yocto build system|adding the meta-mono layer to the Yocto build system]].


The following assumptions are made. You are:
The following assumptions are made. You are:
Line 13: Line 10:
* familiar with basic Linux admin tasks
* familiar with basic Linux admin tasks
* aware of the Yocto Project Reference Manual [http://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html here].
* aware of the Yocto Project Reference Manual [http://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html here].
* using Ubuntu 12.04 LTS as your host build system
* using Ubuntu [http://releases.ubuntu.com/14.04.4 14.04.4 LTS] as your host build system
* working with Yocto 1.6 (daisy) release
* working with Yocto 2.0 (Jethro) release


== Obtain the required packages for your host system to support Yocto ==
== Obtain the required packages for your host system to support Yocto ==
Line 20: Line 17:
First we will install the required host packages for Ubuntu as detailed in the quickstart, i.e.
First we will install the required host packages for Ubuntu as detailed in the quickstart, i.e.


   $ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath libsdl1.2-dev xterm nano
   $ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat libsdl1.2-dev xterm nano


Full details of system requirements and installation can be found in the Yocto Quickstart [http://www.yoctoproject.org/docs/1.6/yocto-project-qs/yocto-project-qs.html here]
Full details of system requirements and installation can be found in the Yocto Quickstart [http://www.yoctoproject.org/docs/1.6/yocto-project-qs/yocto-project-qs.html here]
In addition, if you wish to build the example on the host, outside Yocto, you will need autoconf installed
  $ sudo apt-get install autoconf
=== Install Mono ===


Also install Mono on your host system as we'll use it to build and run some examples for test later
Also install Mono on your host system as we'll use it to build and run some examples for test later
Line 29: Line 32:
   $ mono --version
   $ mono --version


With Ubuntu 12.04 LTS this will install Mono version 2.10 which is now quite old (December 2011).
With Ubuntu 14.04.4 LTS this will install Mono version 3.2.8 which is now quite old


If you wish to install a newer build of Mono to your host system you can follow the instructions [http://stackoverflow.com/questions/13365158/installing-mono-3-x-3-0-x-and-or-3-2-x here].
If you wish to install a newer build of Mono to your host system you can follow the instructions [http://stackoverflow.com/questions/13365158/installing-mono-3-x-3-0-x-and-or-3-2-x here].
Line 38: Line 41:
   $ mono --version
   $ mono --version


This will install Mono 3.2.1 (August 2013)
Currently this will also install Mono 3.2.8 but may in future provide newer builds.


If you wish to use the absolute latest Mono then there are instructions you can follow to build a release tarball [http://www.mono-project.com/Compiling_Mono_From_Tarball here] and from git [http://mono-project.com/Compiling_Mono_From_GIT here]. Be aware this may not be straightforward and that there can be issues, such as with missing files, if you follow this process.  
If you wish to use the absolute latest Mono then there are instructions you can follow to build a release tarball [http://www.mono-project.com/Compiling_Mono_From_Tarball here] and from git [http://mono-project.com/Compiling_Mono_From_GIT here]. Be aware this may not be straightforward and that there can be issues, such as with missing files, if you follow this process.


== Download and extract the Yocto 1.6 release ==
== Download and extract the Yocto 2.0 release ==


At the time of writing, the current release of Yocto (1.6) can be found [https://www.yoctoproject.org/download/yocto-project-16 here]
At the time of writing, the current release of Yocto (2.0) can be found [https://www.yoctoproject.org/downloads/core/jethro20 here]
   
   
   $ cd ~
   $ cd ~
   $ mkdir yocto
   $ mkdir yocto
   $ wget http://downloads.yoctoproject.org/releases/yocto/yocto-1.6/poky-daisy-11.0.0.tar.bz2
  $ cd yocto
   $ tar xjvf poky-daisy-11.0.0.tar.bz2
   $ wget http://downloads.yoctoproject.org/releases/yocto/yocto-2.0/poky-jethro-14.0.0.tar.bz2
   $ tar xjvf poky-jethro-14.0.0.tar.bz2


This will get you the Yocto 1.6 base meta-data and the bitbake tool. You can also add in extra layers, usually of the form "meta-foo" to provide machine support and additional functionality.
This will get you the Yocto 2.0 base meta-data and the bitbake tool. You can also add in extra layers, usually of the form "meta-foo" to provide machine support and additional functionality.


== Configure the build environment to build an emulator image ==
== Configure the build environment to build an emulator image ==


   $ cd ~/yocto/poky-daisy-11.0.0
   $ cd ~/yocto/poky-jethro-14.0.0
   $ source oe-init-build-env build_qemux86
   $ source oe-init-build-env build_qemux86


Line 74: Line 78:
== Build an example project on the host for testing (optional) ==
== Build an example project on the host for testing (optional) ==


The most straightforward way to cross-compile projects for different targets within Yocto is to make use of [http://www.gnu.org/savannah-checkouts/gnu/automake/manual/html_node/index.html autotools]
=== Building with autotools ===
 
The most straightforward way to compile non-.NET projects for different targets within Yocto is to make use of [http://www.gnu.org/savannah-checkouts/gnu/automake/manual/html_node/index.html autotools]


Projects which support <code>autotools</code> provide a set of template files which are then used by the <code>autotools</code> to generate <code>Makefiles</code> and associated configuration files which are appropriate to build for the target environment.
Projects which support <code>autotools</code> provide a set of template files which are then used by the <code>autotools</code> to generate <code>Makefiles</code> and associated configuration files which are appropriate to build for the target environment.


A very basic example 'Hello World' style project called <code>bbexample</code> has been committed to GitHub [https://github.com/DynamicDevices/bbexample here]
Similarly it is possible to compile Mono/.NET projects using <code>autotools</code>


If you take a look at the two source files [https://github.com/DynamicDevices/bbexample/blob/master/bbexample.c bbexample.c] and [https://github.com/DynamicDevices/bbexample/blob/master/bbexamplelib.c bbexamplelib.c] you can see the main entry point prints a Hello World message, then calls a function exported by the shared library which also prints a message.
A very basic example 'Hello World' style project called <code>mono-helloworld</code> has been committed to GitHub [https://github.com/DynamicDevices/mono-helloworld here]


Discussion of <code>autotools</code> template configuration is outside the scope of this guide, but the <code>bbexample</code> project is based on the 'Quick and Dirty' example which can be found [http://www.niksula.cs.hut.fi/~mkomu/docs/autohowto.html here]
If you take a look at the two source files [https://github.com/DynamicDevices/mono-helloworld/blob/master/src/helloworld.cs helloworld.cs] and [https://github.com/DynamicDevices/mono-helloworld/blob/master/src/helloworldform.cs  helloworldform.cs] you can see the first outputs a 'Hello World' message to the console, and the second creates a Windows Form titled 'Hello World'.


The project itself builds an executable, <code>bbexample</code> which has a dependency on a shared library <code>libbbexample.so</code>.
Discussion of <code>autotools</code> template configuration for Mono is outside the scope of this guide, but the <code>mono-helloworld</code> project is based on the <code>mono-skel</code> example which can be found in the Autotools section of the Mono Application Deployment guidelines [http://mono-project.com/Guidelines:Application_Deployment here]
 
The project itself builds two .NET executables, <code>helloworld</code> and <code>helloworldform</code> respectively, the first of which is a console application and the second of which is a simple Windows Forms application.


To build the project on the host independently of Yocto first clone the example repository  
To build the project on the host independently of Yocto first clone the example repository  
Line 90: Line 98:
   $ mkdir ~/host
   $ mkdir ~/host
   $ cd ~/host
   $ cd ~/host
   $ git clone https://github.com/DynamicDevices/bbexample
   $ git clone https://github.com/DynamicDevices/mono-helloworld


Then run the autotools, configure the build, and make the project
Then run the autotools, configure the build, and make the project


   $ cd bbexample
   $ cd mono-helloworld
   $ ./autogen.sh
   $ ./autogen.sh
   $ ./configure
   $ ./configure --enable-winformdemo
   $ make
   $ make


Following a successful compilation you will have a number of new files in the root of the build folder.  
Following a successful compilation you will have a number of new files in the root of the build folder.  


There is a new executable <code>bbexample</code> which depends upon a shared library <code>.libs/libbbexample.so</code>
There are two new .NET executables <code>src/helloworld.exe</code> and <code>src/helloworldform.exe</code>.


As this project has been built to run on the host you can
You can run the first with


   ./bbexample
   $ mono src/helloworld.exe


It will output  
It will output  


   Hello Yocto World...
HelloWorld
   Hello World (from a shared library!)
 
You can run the second with
 
   $ mono src/helloworldform.exe
 
Depending on your host environment (e.g. using SSH) you may need to explicitly set the <code>DISPLAY</code> variable for this to work, with
 
   $ export DISPLAY=:0
  $ mono src/helloworldform.exe
 
This will give you a basic Windows Forms window title
 
[[File:Monohelloworld.png|800px]]


So you have now shown that you can successfully fetch configure and build the project on the host.  
So you have now shown that you can successfully fetch configure and build the project on the host.  
Line 116: Line 136:
Next we will look at how Yocto automates the this process of fetching, configuring and building, then also installs and packages the output files.
Next we will look at how Yocto automates the this process of fetching, configuring and building, then also installs and packages the output files.


== Adding new recipes to the build system ==
=== Building with xbuild ===
 
Many individuals develop with Visual Studio, Mono Develop, Xamarin Studio or other similar integrated development environments (IDEs).
 
Mono provides <code>xbuild</code> which is the Mono implementation of Microsoft's <code>msbuild</code>, discussed [http://mono-project.com/Microsoft.Build here].


There are different ways to add new recipes to Yocto.  
In essence this enables a developer to create a solution of projects within their IDE of choice, then use xbuild to build within the Mono environment.


One way is to simply create a new recipe_version.bb file in a recipe-foo/recipe folder within one of the existing layers used by Yocto.
A useful workflow to follow may be to develop locally with an IDE of choice, commit to a git repository upon release, then use a Yocto recipe to build and package that release into an existing image, or for provision to a package feed for update to existing targets in the field.


=== Placing a recipe in an existing layer (example only) ===
The <code>mono-helloworld</code> project discussed [[#Building with autotools|above]] also provides a solution and project files to support build with <code>xbuild</code>, or indeed with an IDE such as Visual Studio.


For example you could
If you have already built the examples using <code>autotools</code> remove the folder and start again.


   $ cd ~/yocto/poky-daisy-11.0.0/meta-yocto
   $ cd ~/host
  $ mkdir recipes-example
   $ rm -Rf mono-helloworld
  $ mkdir bbexample
  $ cd bbexample
   $ wget https://raw.githubusercontent.com/DynamicDevices/meta-example/master/recipes-example/bbexample/bbexample_1.0.bb


The recipe will then be picked up by bitbake and you can build the recipe with
Check out the mono-helloworld project again


   $ cd ~/yocto/poky-daisy-11.0.0/build-qemux86
   $ git clone https://github.com/DynamicDevices/mono-helloworld
  $ bitbake bbexample


=== Using a new layer for recipes ===
Run xbuild. (As you might guess from the name of the .sln file you could clone this example project to a Windows host and open it up with Visual Studio, and in fact that is how it was created)


A preferred method for adding recipes to the build environment, and the method you should use with this guide, is to place them within a new layer.  
  $ xbuild /p:Configuration=Debug mono-helloworld_vs2010.sln
 
This results in a number of new files, including two new Mono/.NET executables in <code>bin/Debug</code> <code>helloworld.exe</code> and <code>helloworldform.exe</code>
 
You can run the first with
 
  $ mono bin/Debug/helloworld.exe
 
It will output
 
HelloWorld
 
You can run the second with
 
  $ mono bin/Debug/helloworldform.exe
 
Depending on your host environment (e.g. using SSH) you may need to explicitly set the <code>DISPLAY</code> variable for this to work, with
 
  $ export DISPLAY=:0
  $ mono bin/Debug/helloworldform.exe
 
This will give you a basic Windows Forms window title
 
[[File:Monohelloworld.png|800px]]
 
So you have now shown that you can successfully fetch configure and build the project on the host.
 
Next we will look at how Yocto automates the this process of fetching, configuring and building, then also installs and packages the output files.
 
== Adding the <code>meta-mono</code> layer to the Yocto build system ==
 
A preferred method for adding recipes to the build environment, and the method shown with this guide, is to place them within a new layer.  


Layers isolate particular sets of build meta-data based on machine, functionality or similar, and help to keep the environment clean.
Layers isolate particular sets of build meta-data based on machine, functionality or similar, and help to keep the environment clean.


An example layer, meta-example, has been created using the <code>yocto-layer</code> command and committed into a GitHub repository [https://github.com/DynamicDevices/meta-example here].
The <code>meta-mono</code> layer contains Mono specific recipes to support execution of .NET applications on target boards. The layer can be found [http://git.yoctoproject.org/cgit/cgit.cgi/meta-mono here].


To use a new layer such as this you first clone the git repository and then add the layer to your bitbake configuration in <code>conf/bblayers.conf</code>
To use a new layer such as this you first clone the layer from its git repository and then add the layer to your <code>bitbake</code> configuration by editing <code>conf/bblayers.conf</code>


   $ cd ~/yocto/poky-daisy-11.0.0
   $ cd ~/yocto/poky-daisy-11.0.0
   $ git clone https://github.com/DynamicDevices/meta-example
   $ git clone git://git.yoctoproject.org/meta-mono
   $ cd ~/yocto/poky-daisy-11.0.0/build_qemux86
   $ cd ~/yocto/poky-daisy-11.0.0/build_qemux86
   $ nano conf/bblayers.conf
   $ nano conf/bblayers.conf
Line 177: Line 228:
     /home/user/yocto/poky-daisy-11.0.0/meta-yocto \
     /home/user/yocto/poky-daisy-11.0.0/meta-yocto \
     /home/user/yocto/poky-daisy-11.0.0/meta-yocto-bsp \
     /home/user/yocto/poky-daisy-11.0.0/meta-yocto-bsp \
     /home/user/yocto/poky-daisy-11.0.0/meta-example \
     /home/user/yocto/poky-daisy-11.0.0/meta-mono \
     "
     "


Line 197: Line 248:
   meta-yocto
   meta-yocto
   meta-yocto-bsp    = "<unknown>:<unknown>"
   meta-yocto-bsp    = "<unknown>:<unknown>"
   meta-example      = "master:da011ba5dda914dc8bc3768356e2a9fd726383bc"
   meta-mono        = "master:88c6d5f1961d58b3ec203ff19594f954c3e49cd9"
 
== Build an example package based on a git repository commit ==


==== The bbexample recipe ====
== Build an image including Mono/.NET support ==
The recipe we are going to build is [https://github.com/DynamicDevices/meta-example/blob/master/recipes-example/bbexample/bbexample_1.0.bb /home/user/yocto/poky-daisy-11.0.0/meta-example/recipes-example/bbexample/bbexample_1.0.bb].


The main points to note are that
The <code>meta-mono</code> layer includes a recipe to build an image <code>core-image-mono</code> based on the Yocto standard image <code>core-image-sato</code>


* <code>SRC_URI</code> is set to point to the git repository
To build this image
* <code>SRC_REV</code> corresponds to a particular commit into that repository (it is also possible to specify a branch)
* There is a <code>LICENSE</code> variable defined to indicate the type of license to the build environment (MIT) and another variable,
* <code>LIC_FILES_CHKSUM</code>, points to a file within the source tree that will be retrieved, with a corresponding md5 check-sum to ensure that somebody has actually verified the source license file corresponds to that given to the build environment. Also that this file, and thus potentially the license, has not changed over time.
* The source directory for the recipe build, <code>${S}</code> is set to <code>"${WORKDIR}/git"</code> which is the default location to which the retrieved git repository will be checked out and unpacked.
* We inherit a class called <code>autotools</code> which provides the functionality to enable <code>bitbake</code> to automatically build projects with <code>autotools</code> support.
* There is a marked absence of a <code>do_install</code> function, which you may have seen elsewhere, as this is dealt with by the <code>autotools</code> support


To start the build
  $ bitbake core-image-mono


  $ bitbake bbexample
This may take a while, even if you have already built <code>core-image-minimal</code> as additional GUI support packages need to be built.


Bitbake will work through a number of tasks, including fetching the source from the git repository, unpacking, configuring, compiling, installing and packaging the output.
The <code>core-image-mono</code> recipe can be found [http://git.yoctoproject.org/cgit/cgit.cgi/meta-mono/tree/recipes-mono/images/core-image-mono.bb here] and pulls in an include file from [http://git.yoctoproject.org/cgit/cgit.cgi/meta-mono/tree/recipes-mono/images/core-image-mono.inc here].


As we are building for the emulator, <code>qemux86</code>, and are building RPM packages (the default), output packages will be in
You can see in the include file that extra packages are added to the standard <code>core-image-sato</code> image.


   ~/yocto/poky-daisy-11.0.0/build_qemux86/tmp/deploy/rpm/i586/bbexample-1.0-r0.0.i586.rpm
   IMAGE_INSTALL += "mono mono-helloworld"
 
This is how you would add Mono support to your image within a recipe, or within a .bbappend file. In fact it should only be necessary to add the <code>mono</code> package as it is not necessary to have the examples unless you wish to for testing purposes.


For other machine targets the folder and suffix <code>i586</code> will be replaced by a different machine-specific name. To find the location of the package you can use
The <code>mono-helloworld</code> recipe included here shows how to build the example project using <code>autotools</code>. For details see the recipe itself [http://git.yoctoproject.org/cgit/cgit.cgi/meta-mono/tree/recipes-mono/mono-helloworld/mono-helloworld_1.1.bb here], and more importantly the include file it pulls in [http://git.yoctoproject.org/cgit/cgit.cgi/meta-mono/tree/recipes-mono/mono-helloworld/mono-helloworld.inc here].


  $ cd ~/yocto/poky-daisy-11.0.0/build_qemux86/tmp/deploy/rpm
You could choose to replace <code>mono-helloworld</code> with <code>mono-helloworld-xbuild</code> which as the name suggests shows how to build the eaxmple project with <code>xbuild</code>.
  $ find -name bbexample*


(Or instead of <code>bbexample</code> use a prefix of the name of the recipe you are building)
== Testing the .NET executable on an emulated target==


This will show you both the main package and the subsidiary packages which <code>bitbake</code> builds for each recipe such as -dev, -debug, -staticdev and so forth. For more on this see [http://www.embeddedlinux.org.cn/OEManual/recipes_packages.html here]
Having built <code>core-image-mono</code> you can then run it up under <code>qemu</code>


Having found the package you can check that the contents are as expected with
To run up the image, simply use
$ runqemu qemux86


  $ cd ~/yocto/poky-daisy-11.0.0/build_qemux86/tmp/deploy/rpm
This will boot the emulator, load up the image, you'll see a kernel loading and then a basic user interface.
  $ rpm -qlp i586/bbexample-1.0-r0.0.i586.rpm


For the <code>bbexample</code> recipe we expect to see the cross-compiled executable <code>bbexample</code> and the shared library it needs <code>libbbexample.so.1</code>
If you find that your keymap is incorrect you might wish to set this explicitly, for example


  /usr
$ runqemu qemux86 qemuparams='-k en-gb'
  /usr/bin
  /usr/bin/bbexample
  /usr/lib
  /usr/lib/libbbexample.so.1
  /usr/lib/libbbexample.so.1.0.0


You could then add the output of this recipe to your output image by adding something like this to your <code>conf/local.conf</code>
or


  IMAGE_INSTALL_append = " bbexample"
$ runqemu qemux86 qemuparams='-k en-us'


Alternatively you could make the new packages available to existing target systems using the Yocto <code>package-management</code> tools such as <code>smart</code>.
Open up a terminal window using the appropriate icon, Log into the emulator as 'root', no password and run the examples.


== Build an example package based on a remote source archive ==
You can run the first with


The recipe we are going to build is [https://github.com/DynamicDevices/meta-example/blob/master/recipes-example/bbexample/bbexample-rt_1.0.bb /home/user/yocto/poky-daisy-11.0.0/meta-example/recipes-example/bbexample/bbexample-rt_1.0.bb].  
  $ mono helloworld.exe


This is based on the previous recipe that builds from a git checkout, with the major difference being we are building from a remote tarball.
Or alternatively the recipe installs a script to wrap use of Mono, so you can use the form


This tarball may, in theory, contain any sources we wish to build, although sometimes build failures may require patching of the sources, and if <code>autotools</code> is not provided then the recipe may well have to be extended with a <code>do_install</code> function to ensure appropriate files are installed, and the FILES_${PN} variable modified to ensure installed files are correctly packaged.
  $ helloworld


For this simple example the git commit used above has been tagged 'bbexample-v1.0' in the GitHub repository, which causes GitHub to provide a release source archive.
This will output


This tagged archive is what we set in the recipe <code>SRC_URI</code> to retrieve and build.
HelloWorld


The main points to note are that
[[File:Monoemulatedhelloworld.png|800px]]


* <code>SRC_URI</code> is set to point to the remote source archive
You can run the second with


   SRC_URI = "https://github.com/DynamicDevices/bbexample/archive/bbexample-v${PV}.tar.gz"
   $ mono /usr/lib/helloworldform.exe


Ideally we would use both of the variables ${PN} and ${PV} which would be replaced by the recipe name and recipe version, and could usually be expected to map to the naming convention employed for the source archive file. This makes the recipe more generic and easier to update to a new version of the source code by renaming the recipe .bb file. However as I am using a slightly different recipe name, 'bbexample-rt' I have hard-coded the names here.
or


* There is no <code>SRC_REV</code> here but instead we have <code>SRC_URI</code> values for md5sum and an sha256sum check-sums
  $ helloworldform


As you would expect, these correspond to the particular check-sums generated by those algorithms when run over the entire archive.
Depending on your host environment (e.g. using SSH) you may need to explicitly set the <code>DISPLAY</code> variable for this to work, with


You can generate these by hand by retrieving the file yourself, running <code>md5sum archivename</code> and <code>sha256sum archivename</code> but it is easier to set these incorrectly and let <code>bitbake</code> retrieve the archive and error on incorrect checksums and which point it will tell you what the lines should be.
  $ export DISPLAY=:0
  $ mono /usr/lib/helloworld/helloworldform.exe


  SRC_URI[md5sum] = "a040115592f4200188a805368d9456ff"
This will show a test Windows Forms form titled 'Hello World'
  SRC_URI[sha256sum] = "589b22fc6c2c0b266223c5988f0e33f5c2f03a114da9145e722e3552a0edd308"


You should be aware that sometimes maintainers re-release archives under the same name but with updated contents. Should this happen the check-sum check will fail and you will have to look into whether this is because of a corrupted download (check the downloaded archive in ~/yocto/poky-daisy-11.0.0/build_qemux86/downloads) or because the archive has actually been changed.
[[File:Monoemulatedhelloworldform.png|800px]]


* There is a <code>LICENSE</code> variable defined to indicate the type of license to the build environment (MIT) and another variable,
Lastly you can run a test GTK# application with
* <code>LIC_FILES_CHKSUM</code>, points to a file within the source tree that will be retrieved, with a corresponding md5 check-sum to ensure that somebody has actually verified the source license file corresponds to that given to the build environment. Also that this file, and thus potentially the license, has not changed over time.


* The source directory for the recipe build, <code>${S}</code> is set to <code>"bbexample-bbexample-v${PV}"</code> which corresponds to the path to the source-code when extracted from the archive generated by GitHub. This looks slightly strange but is due to the vagaries of the way the git repository tag was added, as this is embedded by GitHub within the archive.
You can run the second with


   # Make sure our source directory (for the build) matches the directory structure in the tarball
   $ mono /usr/lib/helloworldgtk.exe
  # A tagged tarball from github contains a folder which includes the github tag, so deal with it here
  S = "${WORKDIR}/bbexample-bbexample-v${PV}"


* We inherit a class called <code>autotools</code> which provides the functionality to enable <code>bitbake</code> to automatically build projects with <code>autotools</code> support.
or
* There is a marked absence of a <code>do_install</code> function, which you may have seen elsewhere, as this is dealt with by the <code>autotools</code> support


To start the build
  $ helloworldgtk


  $ bitbake bbexample
== Breakdown of an autotools recipe ==


Bitbake will work through a number of tasks, including fetching the source archive, unpacking, configuring, compiling, installing and packaging the output.
This is the contents of the mono-helloworld_1.1.bb recipe [http://git.yoctoproject.org/cgit/cgit.cgi/meta-mono/tree/recipes-mono/mono-helloworld/mono-helloworld_1.1.bb here]


There may be some warnings shown as all three recipes <code>bbexample</code>, <code>bbexample-rt</code> and <code>bbexample-lt</code> are generating the same output and thus there is some collision of shared files. These warnings may be ignored.
require mono-helloworld.inc
SRC_URI[md5sum] = "79b0ba0044689789a54e3d55ec400fc0"
SRC_URI[sha256sum] = "56388435f29ce94007155acc39593c900b6d3248a7f281e83ed2101a6da455f0"


As we are building for the emulator, <code>qemux86</code>, and are building RPM packages (the default), output packages will be in
It can be seen that we provide a couple of checksums which relate to the release tarball that will be downloaded


  ~/yocto/poky-daisy-11.0.0/build_qemux86/tmp/deploy/rpm/i586/bbexample-1.0-r0.0.i586.rpm
Similarly the is the included mono-helloworld.inc file can be found [http://git.yoctoproject.org/cgit/cgit.cgi/meta-mono/tree/recipes-mono/mono-helloworld/mono-helloworld.inc here]


For other machine targets the folder and suffix <code>i586</code> will be replaced by a different machine-specific name. To find the location of the package you can use
  SUMMARY = "Mono Hello World"
  DESCRIPTION = "Test applications for Mono console and windows forms"
  AUTHOR = "Alex J Lennon <ajlennon@dynamicdevices.co.uk>"
  HOMEPAGE = "http://www.dynamicdevices.co.uk"
  SECTION = "mono/applications"
  PRIORITY = "optional"
  LICENSE = "GPLv3"
  LIC_FILES_CHKSUM = "file://LICENSE;md5=783b7e40cdfb4a1344d15b1f7081af66"
  DEPENDS = "mono"
  SRC_URI = "https://github.com/DynamicDevices/mono-helloworld/archive/v${PV}.tar.gz"
  inherit autotools
  FILES_${PN} = "${libdir}/helloworld/helloworld.exe \
  ${bindir}/helloworld \
        ${libdir}/helloworld/helloworldform.exe \
                ${bindir}/helloworldform \
  "


  $ cd ~/yocto/poky-daisy-11.0.0/build_qemux86/tmp/deploy/rpm
For more details on check-sums, licenses and so forth, see [https://wiki.yoctoproject.org/wiki/Building_your_own_recipes_from_first_principles#Build_an_example_package_based_on_a_remote_source_archive Building your own recipes from first principles] and the [https://wiki.yoctoproject.org/wiki/Recipe_%26_Patch_Style_Guide Recipe & Style Patch Guide].
  $ find -name bbexample*


(Or instead of <code>bbexample</code> use a prefix of the name of the recipe you are building)
We have a dependency on the <code>mono</code> package, and again we inherit the <code>autotools</code> class to make use of the <code>bitbake</code> <code>autotools</code> functionality.


This will show you both the main package and the subsidiary packages which <code>bitbake</code> builds for each recipe such as -dev, -debug, -staticdev and so forth. For more on this see [http://www.embeddedlinux.org.cn/OEManual/recipes_packages.html here]
Lastly we override <code>FILES_${PN}</code> which controls the installed files which are added to the main output package. <code>${libdir}</code> <code>${bindir}</code> are standard GNU variable naming conventions for installation paths. For details see [http://www.gnu.org/prep/standards/html_node/Directory-Variables.html here] and [https://www.sourceware.org/autobook/autobook/autobook_106.html here].


Having found the package you can check that the contents are as expected with
In this case we have made sure that the <code>helloworld</code> executable goes to <code>/usr/lib/helloworld/helloworld.exe</code> as does the <code>helloworldform.exe</code>.


  $ cd ~/yocto/poky-daisy-11.0.0/build_qemux86/tmp/deploy/rpm
It might seem quite strange to be installing the executable assemblies to the <code>/usr/lib</code> location, but this is in line with Mono application deployment recommendations [http://mono-project.com/Guidelines:Application_Deployment here].
  $ rpm -qlp i586/bbexample-1.0-r0.0.i586.rpm


For the <code>bbexample</code> recipe we expect to see the cross-compiled executable <code>bbexample</code> and the shared library it needs <code>libbbexample.so.1</code>
We then install wrapper scripts to <code>/usr/bin</code> which can be called directly to run the respective examples. These scripts take the form


   /usr
   #!/bin/sh
  /usr/bin
   exec @MONO@ @prefix@/lib/helloworld/@APP@.exe $MONO_EXTRA_ARGS "$@"
  /usr/bin/bbexample
   /usr/lib
  /usr/lib/libbbexample.so.1
  /usr/lib/libbbexample.so.1.0.0


You could then add the output of this recipe to your output image by adding something like this to your <code>conf/local.conf</code>
== Breakdown of an xbuild recipe ==


  IMAGE_INSTALL_append = " bbexample"
The <code>xbuild</code> recipe is similar to the <code>autotools</code> recipe above, excepting that we override a couple of methods to ensure <code>xbuild</code> runs as we wish it too


Alternatively you could make the new packages available to existing target systems using the Yocto <code>package-management</code> tools such as <code>smart</code>.
This recipe can be found [http://git.yoctoproject.org/cgit/cgit.cgi/meta-mono/tree/recipes-mono/mono-helloworld/mono-helloworld-xbuild_1.1.bb here].


== Build an example package based on a local source archive ==
First we include the definitions in the include file, and set the version specific checksums for the archive to be retrieved


The recipe we are going to build is [https://github.com/DynamicDevices/meta-example/blob/master/recipes-example/bbexample/bbexample-lt_1.0.bb /home/user/yocto/poky-daisy-11.0.0/meta-example/recipes-example/bbexample/bbexample-lt_1.0.bb].
require mono-helloworld.inc
SRC_URI[md5sum] = "79b0ba0044689789a54e3d55ec400fc0"
SRC_URI[sha256sum] = "56388435f29ce94007155acc39593c900b6d3248a7f281e83ed2101a6da455f0"


This is based on the previous recipe that builds from a remote source release, with the major difference being we are building from a local source tarball.
Then we set our source directory which must be correct for <code>bitbake</code> to find extracted files from the retrieved archive


This tarball may, in theory, contain any sources we wish to build, although sometimes build failures may require patching of the sources, and if <code>autotools</code> is not provided then the recipe may well have to be extended with a <code>do_install</code> function to ensure appropriate files are installed, and the FILES_${PN} variable modified to ensure installed files are correctly packaged.
REALPN = "mono-helloworld"
S = "${WORKDIR}/${REALPN}-${PV}"


For this simple example the release source archive available from GitHub has been copied locally into the <code>meta-example</code> layer folder tree,
Now we override the compilation method to call <code>xbuild</code> to build a particular .NET configuration against the a .SLN file in the archive


  yocto/poky-daisy-11.0.0/meta-example/recipes-example/bbexample/bbexample-lt-1.0/bbexample-v1.0.tar.gz
CONFIGURATION = "Debug"
do_compile() {
        xbuild /p:Configuration=${CONFIGURATION} ${REALPN}_vs2010.sln
}


This local file is what we set in the recipe <code>SRC_URI</code> to copy across, unpack, patch (if necessary) and build.
Next we modify the installation method to make sure that the correct output files are installed and the executable scripts are modified to run the output assemblies


The main points to note are that
  do_install() {
 
          install -d "${D}${bindir}"
* <code>SRC_URI</code> is set to point to a local file archive
          install -d "${D}${libdir}/helloworld/.debug"
 
          install -m 0755 ${S}/bin/${CONFIGURATION}/*.mdb ${D}${libdir}/helloworld/.debug
  SRC_URI = "file://bbexample-v${PV}.tar.gz"
          install -m 0755 ${S}/bin/${CONFIGURATION}/*.exe ${D}${libdir}/helloworld
 
    
Ideally we would use both of the variables ${PN} and ${PV} which would be replaced by the recipe name and recipe version, and could usually be expected to map to the naming convention employed for the source archive file. This makes the recipe more generic and easier to update to a new version of the source code by renaming the recipe .bb file. However as I am using a slightly different recipe name, 'bbexample-lt' I have hard-coded the names here.
          install -m 0755 ${S}/script.in ${D}${bindir}/helloworld
 
          sed -i "s|@MONO@|mono|g" ${D}${bindir}/helloworld
* We provide a search path to ensure <code>bitbake</code> can find the archive
          sed -i "s|@prefix@|/usr|g" ${D}${bindir}/helloworld
 
          sed -i "s|@APP@|helloworld|g" ${D}${bindir}/helloworld
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}-${PV}:"
          install -m 0755 ${S}/script.in ${D}${bindir}/helloworldform
 
          sed -i "s|@MONO@|mono|g" ${D}${bindir}/helloworldform
In this case the above will expand to the following folder, which is where we have placed <code>bbexample-v1.0.tar.gz</code>, and thus <code>bitbake</code> will find it to unpack.
          sed -i "s|@prefix@|/usr|g" ${D}${bindir}/helloworldform
 
          sed -i "s|@APP@|helloworld|g" ${D}${bindir}/helloworldform 
  ~/yocto/poky-daisy-11.0.0/meta-example/recipes-example/bbexample/bbexample-lt-1.0
   }
 
* There is no <code>SRC_REV</code> here but instead we have <code>SRC_URI</code> values for md5sum and an sha256sum check-sums
 
As you would expect, these correspond to the particular check-sums generated by those algorithms when run over the entire archive.
 
You can generate these by hand by retrieving the file yourself, running <code>md5sum archivename</code> and <code>sha256sum archivename</code> but it is easier to set these incorrectly and let <code>bitbake</code> retrieve the archive and error on incorrect checksums and which point it will tell you what the lines should be.
 
  SRC_URI[md5sum] = "a040115592f4200188a805368d9456ff"
  SRC_URI[sha256sum] = "589b22fc6c2c0b266223c5988f0e33f5c2f03a114da9145e722e3552a0edd308"
 
You should be aware that sometimes maintainers re-release archives under the same name but with updated contents. Should this happen the check-sum check will fail and you will have to look into whether this is because of a corrupted download (check the downloaded archive in ~/yocto/poky-daisy-11.0.0/build_qemux86/downloads) or because the archive has actually been changed.
 
* There is a <code>LICENSE</code> variable defined to indicate the type of license to the build environment (MIT) and another variable,
* <code>LIC_FILES_CHKSUM</code>, points to a file within the source tree that will be retrieved, with a corresponding md5 check-sum to ensure that somebody has actually verified the source license file corresponds to that given to the build environment. Also that this file, and thus potentially the license, has not changed over time.
 
* The source directory for the recipe build, <code>${S}</code> is set to <code>"bbexample-bbexample-v${PV}"</code> which corresponds to the path to the source-code when extracted from the local archive. This looks slightly strange but is due to the vagaries of the way the git repository tag was added, as this is embedded by GitHub within the archive. Alternatively we could have repacked the archive with a cleaner folder hierarchy.
 
  # Make sure our source directory (for the build) matches the directory structure in the tarball
  # A tagged tarball from github contains a folder which includes the github tag, so deal with it here
  S = "${WORKDIR}/bbexample-bbexample-v${PV}"
 
* We inherit a class called <code>autotools</code> which provides the functionality to enable <code>bitbake</code> to automatically build projects with <code>autotools</code> support.
* There is a marked absence of a <code>do_install</code> function, which you may have seen elsewhere, as this is dealt with by the <code>autotools</code> support
 
To start the build
 
   $ bitbake bbexample
 
Bitbake will work through a number of tasks, including fetching the source archive, unpacking, configuring, compiling, installing and packaging the output.
 
There may be some warnings shown as all three recipes <code>bbexample</code>, <code>bbexample-rt</code> and <code>bbexample-lt</code> are generating the same output and thus there is some collision of shared files. These warnings may be ignored.
 
As we are building for the emulator, <code>qemux86</code>, and are building RPM packages (the default), output packages will be in
 
  ~/yocto/poky-daisy-11.0.0/build_qemux86/tmp/deploy/rpm/i586/bbexample-1.0-r0.0.i586.rpm
 
For other machine targets the folder and suffix <code>i586</code> will be replaced by a different machine-specific name. To find the location of the package you can use
 
  $ cd ~/yocto/poky-daisy-11.0.0/build_qemux86/tmp/deploy/rpm
  $ find -name bbexample*
 
(Or instead of <code>bbexample</code> use a prefix of the name of the recipe you are building)
 
This will show you both the main package and the subsidiary packages which <code>bitbake</code> builds for each recipe such as -dev, -debug, -staticdev and so forth. For more on this see [http://www.embeddedlinux.org.cn/OEManual/recipes_packages.html here]
 
Having found the package you can check that the contents are as expected with
 
  $ cd ~/yocto/poky-daisy-11.0.0/build_qemux86/tmp/deploy/rpm
  $ rpm -qlp i586/bbexample-1.0-r0.0.i586.rpm
 
For the <code>bbexample</code> recipe we expect to see the cross-compiled executable <code>bbexample</code> and the shared library it needs <code>libbbexample.so.1</code>
 
  /usr
  /usr/bin
  /usr/bin/bbexample
  /usr/lib
  /usr/lib/libbbexample.so.1
  /usr/lib/libbbexample.so.1.0.0
 
You could then add the output of this recipe to your output image by adding something like this to your <code>conf/local.conf</code>
 
  IMAGE_INSTALL_append = " bbexample"
 
Alternatively you could make the new packages available to existing target systems using the Yocto <code>package-management</code> tools such as <code>smart</code>.
 
== Recipe gotchas ==
 
=== Incorrect source folder ${S} ===
 
It is extremely important to make sure that the source folder, the <code>${S}</code> variable is set correctly.
 
When retrieving files from git repositories, or when archives are unpacked, it is entirely possible that the source folder default will not be correct for the actual unpacked location of the sources.
 
If this happens the build will fail, often with a message that the <code>LICENSE</code> file cannot be found, as this is checked early on in the unpack.
 
To check through this one option is to drop into a development shell with
 
  $ bitbake -c devshell recipename
 
This will drop you into the configured location of <code>${S}</code>. If the sources defined in <code>SRC_URI</code> seemed to be retrieved correctly but you see nothing in your devshell, excepting perhaps a <code>patches</code> folder, this is a good indication that the code has been unpacked into a different folder.
 
  $ cd ..
  $ ls
 
You often will see another folder in the directory level about <code>${S}</code> which contains the source code.
 
This being the case you need to exit your devshell and edit your recipe to modify the source directory to point to the correct location. e.g.
 
  ${S} = "${WORKDIR}/correctfoldername"
 
 
Dropping back into the devshell should then show the correct files, and you should be able to make progress with the build
 
=== Incorrect license checksum ===
 
This can occur, particularly when upgrading a recipe to use a new repository commit or source archive version, as the licensing file may have changed.
 
If this does occur it is important to check through the new licensing file to ensure that the build environment is still being given correct information on the type of license for the source code.
 
It may also be that a minor textual change has been made to the file (e.g. new copyright date) which doesn't affect the type of the license itself.
 
Having satisfied yourself that the <code>LICENSE</code> variable in the recipe reports the correct license type you can update the license checksum to that reported by <code>bitbake</code> by modifying <code>LIC_FILES_CHKSUM</code>
 
=== Incorrect source archive checksum ===
 
You should be aware that sometimes maintainers re-release archives under the same name but with updated contents. Should this happen the check-sum check will fail and you will have to look into whether this is because of a corrupted download (check the downloaded archive in ~/yocto/poky-daisy-11.0.0/build_qemux86/downloads) or because the archive has actually been changed.
 
* You can try removing the archive from the downloads folder, and the corresponding .done file. The archive will then be downloaded again which may work if there was a corrupt/interrupted download (although in my experience this occurrence is unlikely).
 
* Alternatively the archive may have changed and you may wish to use the new archive, in which case you will need to update the check-sums in the recipe to those you calculate yourself on the archive with <code>md5sum</code> and <code>sha256sum</code>, or simply use what <code>bitbake</code> calculates and provides for you in the log.
 
  SRC_URI[md5sum] = "???"
   SRC_URI[sha256sum] = "???"
 
* Lastly you may be able to source the correct archive file from a mirror or through Googling, in which case you can drop it into the <code>downloads</code> folder for use by <code>bitbake</code>
 
In the latter two cases you may wish to feed the issue back to the Yocto mailing list (or other relevant mailing list for the layer in which the recipe resides) as this type of thing means mirrored copies of primary sources become out of sync, and the layer/mirror maintainers may wish to address the issue.
 
=== Missing source archive ===
 
This is less of an issue than it has been in the past as primary sources are now mirrored in one or more locations, not least by the Yocto project itself.
 
You can also set up your own mirror sources, which is dealt with [[How_do_I#Q:How do I create my own source download mirror? | here]]


However for a one-off missing archive it is often quickest and easiest to Google to find it, then drop it into the ~/yocto/poky-daisy-11.0.0/build_qemux86/downloads folder, creating an empty .done file with
Lastly we make sure that the .MDB debug files which are output are packaged correctly in the <code>-dbg</code> package. The other assemblies in <code>${libdir}</code> and <code>${bindir}</code> will be packaged correctly in the main output package by default


   $ touch archivename.done
   FILES_${PN}-dbg += "${libdir}/helloworld/.debug/*"


It should then be picked up and used by <code>bitbake</code>
For more details on check-sums, licenses and so forth, see [https://wiki.yoctoproject.org/wiki/Building_your_own_recipes_from_first_principles#Build_an_example_package_based_on_a_remote_source_archive Building your own recipes from first principles] and the [https://wiki.yoctoproject.org/wiki/Recipe_%26_Patch_Style_Guide Recipe & Style Patch Guide].


== Feedback ==
== Feedback ==


This is a living document. Please feel free to send comments, questions, corrections to Alex Lennon [mailto://ajlennon@dynamicdevices.co.uk here]
This is a living document. Please feel free to send comments, questions, corrections to Alex Lennon [mailto://ajlennon@dynamicdevices.co.uk here]

Latest revision as of 09:57, 23 February 2016

Overview

This walk-through has the aim of taking you from a clean system through to including Mono in a build image using the meta-mono layer, then building and packaging an example .NET project for inclusion in that image.

You may already have Yocto installed and just be looking to work with Mono for the first time, in which case you can jump forward to the section you find most relevant,
such as building an example package on the host to test or adding the meta-mono layer to the Yocto build system.

The following assumptions are made. You are:

  • familiar with basic Linux admin tasks
  • aware of the Yocto Project Reference Manual here.
  • using Ubuntu 14.04.4 LTS as your host build system
  • working with Yocto 2.0 (Jethro) release

Obtain the required packages for your host system to support Yocto

First we will install the required host packages for Ubuntu as detailed in the quickstart, i.e.

 $ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat libsdl1.2-dev xterm nano

Full details of system requirements and installation can be found in the Yocto Quickstart here

In addition, if you wish to build the example on the host, outside Yocto, you will need autoconf installed

 $ sudo apt-get install autoconf

Install Mono

Also install Mono on your host system as we'll use it to build and run some examples for test later

 $ sudo apt-get install mono-complete
 $ mono --version

With Ubuntu 14.04.4 LTS this will install Mono version 3.2.8 which is now quite old

If you wish to install a newer build of Mono to your host system you can follow the instructions here.

 $ sudo add-apt-repository ppa:directhex/monoxide
 $ sudo apt-get update
 $ sudo apt-get install mono-complete
 $ mono --version

Currently this will also install Mono 3.2.8 but may in future provide newer builds.

If you wish to use the absolute latest Mono then there are instructions you can follow to build a release tarball here and from git here. Be aware this may not be straightforward and that there can be issues, such as with missing files, if you follow this process.

Download and extract the Yocto 2.0 release

At the time of writing, the current release of Yocto (2.0) can be found here

 $ cd ~
 $ mkdir yocto
 $ cd yocto
 $ wget http://downloads.yoctoproject.org/releases/yocto/yocto-2.0/poky-jethro-14.0.0.tar.bz2
 $ tar xjvf poky-jethro-14.0.0.tar.bz2

This will get you the Yocto 2.0 base meta-data and the bitbake tool. You can also add in extra layers, usually of the form "meta-foo" to provide machine support and additional functionality.

Configure the build environment to build an emulator image

 $ cd ~/yocto/poky-jethro-14.0.0
 $ source oe-init-build-env build_qemux86

This will create a build tree in "build_qemux86" although you could use a different name if you so wish with no adverse effects.

It is entirely possible to have many build trees in parallel in different folders and to switch between them using oe-init-build-env.

oe-init-build-env will create a default configuration file in conf/local/conf which will build an emulator image suitable for execution with qemu

Build a baseline image

After configuring the environment you will be left in the build_qemux86 folder.

You should then build a baseline image, which will take some time (numbers of hours)

 $ bitbake core-image-minimal

Build an example project on the host for testing (optional)

Building with autotools

The most straightforward way to compile non-.NET projects for different targets within Yocto is to make use of autotools

Projects which support autotools provide a set of template files which are then used by the autotools to generate Makefiles and associated configuration files which are appropriate to build for the target environment.

Similarly it is possible to compile Mono/.NET projects using autotools

A very basic example 'Hello World' style project called mono-helloworld has been committed to GitHub here

If you take a look at the two source files helloworld.cs and helloworldform.cs you can see the first outputs a 'Hello World' message to the console, and the second creates a Windows Form titled 'Hello World'.

Discussion of autotools template configuration for Mono is outside the scope of this guide, but the mono-helloworld project is based on the mono-skel example which can be found in the Autotools section of the Mono Application Deployment guidelines here

The project itself builds two .NET executables, helloworld and helloworldform respectively, the first of which is a console application and the second of which is a simple Windows Forms application.

To build the project on the host independently of Yocto first clone the example repository

 $ mkdir ~/host
 $ cd ~/host
 $ git clone https://github.com/DynamicDevices/mono-helloworld

Then run the autotools, configure the build, and make the project

 $ cd mono-helloworld
 $ ./autogen.sh
 $ ./configure --enable-winformdemo
 $ make

Following a successful compilation you will have a number of new files in the root of the build folder.

There are two new .NET executables src/helloworld.exe and src/helloworldform.exe.

You can run the first with

 $ mono src/helloworld.exe

It will output

HelloWorld

You can run the second with

 $ mono src/helloworldform.exe

Depending on your host environment (e.g. using SSH) you may need to explicitly set the DISPLAY variable for this to work, with

 $ export DISPLAY=:0
 $ mono src/helloworldform.exe

This will give you a basic Windows Forms window title

Monohelloworld.png

So you have now shown that you can successfully fetch configure and build the project on the host.

Next we will look at how Yocto automates the this process of fetching, configuring and building, then also installs and packages the output files.

Building with xbuild

Many individuals develop with Visual Studio, Mono Develop, Xamarin Studio or other similar integrated development environments (IDEs).

Mono provides xbuild which is the Mono implementation of Microsoft's msbuild, discussed here.

In essence this enables a developer to create a solution of projects within their IDE of choice, then use xbuild to build within the Mono environment.

A useful workflow to follow may be to develop locally with an IDE of choice, commit to a git repository upon release, then use a Yocto recipe to build and package that release into an existing image, or for provision to a package feed for update to existing targets in the field.

The mono-helloworld project discussed above also provides a solution and project files to support build with xbuild, or indeed with an IDE such as Visual Studio.

If you have already built the examples using autotools remove the folder and start again.

 $ cd ~/host
 $ rm -Rf mono-helloworld

Check out the mono-helloworld project again

 $ git clone https://github.com/DynamicDevices/mono-helloworld

Run xbuild. (As you might guess from the name of the .sln file you could clone this example project to a Windows host and open it up with Visual Studio, and in fact that is how it was created)

 $ xbuild /p:Configuration=Debug mono-helloworld_vs2010.sln

This results in a number of new files, including two new Mono/.NET executables in bin/Debug helloworld.exe and helloworldform.exe

You can run the first with

 $ mono bin/Debug/helloworld.exe

It will output

HelloWorld

You can run the second with

 $ mono bin/Debug/helloworldform.exe

Depending on your host environment (e.g. using SSH) you may need to explicitly set the DISPLAY variable for this to work, with

 $ export DISPLAY=:0
 $ mono bin/Debug/helloworldform.exe

This will give you a basic Windows Forms window title

Monohelloworld.png

So you have now shown that you can successfully fetch configure and build the project on the host.

Next we will look at how Yocto automates the this process of fetching, configuring and building, then also installs and packages the output files.

Adding the meta-mono layer to the Yocto build system

A preferred method for adding recipes to the build environment, and the method shown with this guide, is to place them within a new layer.

Layers isolate particular sets of build meta-data based on machine, functionality or similar, and help to keep the environment clean.

The meta-mono layer contains Mono specific recipes to support execution of .NET applications on target boards. The layer can be found here.

To use a new layer such as this you first clone the layer from its git repository and then add the layer to your bitbake configuration by editing conf/bblayers.conf

 $ cd ~/yocto/poky-daisy-11.0.0
 $ git clone git://git.yoctoproject.org/meta-mono
 $ cd ~/yocto/poky-daisy-11.0.0/build_qemux86
 $ nano conf/bblayers.conf

Your bblayers.conf should look similar to this

 # LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
 # changes incompatibly
 LCONF_VERSION = "6"
 
 BBPATH = "${TOPDIR}"
 BBFILES ?= ""
 
 BBLAYERS ?= " \
   /home/user/yocto/poky-daisy-11.0.0/meta \
   /home/user/yocto/poky-daisy-11.0.0/meta-yocto \
   /home/user/yocto/poky-daisy-11.0.0/meta-yocto-bsp \
   "
 BBLAYERS_NON_REMOVABLE ?= " \
   /home/user/yocto/poky-daisy-11.0.0/meta \
   /home/user/yocto/poky-daisy-11.0.0/meta-yocto \
   "

Make the new layer visible to bitbake by adding a line to BBLAYERS

 BBLAYERS ?= " \
   /home/user/yocto/poky-daisy-11.0.0/meta \
   /home/user/yocto/poky-daisy-11.0.0/meta-yocto \
   /home/user/yocto/poky-daisy-11.0.0/meta-yocto-bsp \
   /home/user/yocto/poky-daisy-11.0.0/meta-mono \
   "

Now bitbake can see the recipes in the new layer.

You will also see when bitbake runs and shows the Build Configuration that the repository branch and hash of your layer is shown which is useful to know, particularly when comparing notes with others as to why a build fails, e.g.

 Build Configuration:
 BB_VERSION        = "1.22.0"
 BUILD_SYS         = "i686-linux"
 NATIVELSBSTRING   = "Ubuntu-12.04"
 TARGET_SYS        = "i586-poky-linux"
 MACHINE           = "qemux86"
 DISTRO            = "poky"
 DISTRO_VERSION    = "1.6"
 TUNE_FEATURES     = "m32 i586"
 TARGET_FPU        = ""
 meta
 meta-yocto
 meta-yocto-bsp    = "<unknown>:<unknown>"
 meta-mono         = "master:88c6d5f1961d58b3ec203ff19594f954c3e49cd9"

Build an image including Mono/.NET support

The meta-mono layer includes a recipe to build an image core-image-mono based on the Yocto standard image core-image-sato

To build this image

 $ bitbake core-image-mono

This may take a while, even if you have already built core-image-minimal as additional GUI support packages need to be built.

The core-image-mono recipe can be found here and pulls in an include file from here.

You can see in the include file that extra packages are added to the standard core-image-sato image.

 IMAGE_INSTALL += "mono mono-helloworld"
 

This is how you would add Mono support to your image within a recipe, or within a .bbappend file. In fact it should only be necessary to add the mono package as it is not necessary to have the examples unless you wish to for testing purposes.

The mono-helloworld recipe included here shows how to build the example project using autotools. For details see the recipe itself here, and more importantly the include file it pulls in here.

You could choose to replace mono-helloworld with mono-helloworld-xbuild which as the name suggests shows how to build the eaxmple project with xbuild.

Testing the .NET executable on an emulated target

Having built core-image-mono you can then run it up under qemu

To run up the image, simply use

$ runqemu qemux86

This will boot the emulator, load up the image, you'll see a kernel loading and then a basic user interface.

If you find that your keymap is incorrect you might wish to set this explicitly, for example

$ runqemu qemux86 qemuparams='-k en-gb'

or

$ runqemu qemux86 qemuparams='-k en-us'

Open up a terminal window using the appropriate icon, Log into the emulator as 'root', no password and run the examples.

You can run the first with

 $ mono helloworld.exe

Or alternatively the recipe installs a script to wrap use of Mono, so you can use the form

 $ helloworld

This will output

HelloWorld

Monoemulatedhelloworld.png

You can run the second with

 $ mono /usr/lib/helloworldform.exe

or

 $ helloworldform

Depending on your host environment (e.g. using SSH) you may need to explicitly set the DISPLAY variable for this to work, with

 $ export DISPLAY=:0
 $ mono /usr/lib/helloworld/helloworldform.exe

This will show a test Windows Forms form titled 'Hello World'

Monoemulatedhelloworldform.png

Lastly you can run a test GTK# application with

You can run the second with

 $ mono /usr/lib/helloworldgtk.exe

or

 $ helloworldgtk

Breakdown of an autotools recipe

This is the contents of the mono-helloworld_1.1.bb recipe here

require mono-helloworld.inc
SRC_URI[md5sum] = "79b0ba0044689789a54e3d55ec400fc0"
SRC_URI[sha256sum] = "56388435f29ce94007155acc39593c900b6d3248a7f281e83ed2101a6da455f0"

It can be seen that we provide a couple of checksums which relate to the release tarball that will be downloaded

Similarly the is the included mono-helloworld.inc file can be found here

 SUMMARY = "Mono Hello World"
 DESCRIPTION = "Test applications for Mono console and windows forms"
 AUTHOR = "Alex J Lennon <ajlennon@dynamicdevices.co.uk>"
 HOMEPAGE = "http://www.dynamicdevices.co.uk"
 SECTION = "mono/applications"
 PRIORITY = "optional"
 LICENSE = "GPLv3"
 LIC_FILES_CHKSUM = "file://LICENSE;md5=783b7e40cdfb4a1344d15b1f7081af66"
 DEPENDS = "mono"
 SRC_URI = "https://github.com/DynamicDevices/mono-helloworld/archive/v${PV}.tar.gz"
 inherit autotools
 FILES_${PN} = "${libdir}/helloworld/helloworld.exe \
 		${bindir}/helloworld \
        	${libdir}/helloworld/helloworldform.exe \
               ${bindir}/helloworldform \
 "

For more details on check-sums, licenses and so forth, see Building your own recipes from first principles and the Recipe & Style Patch Guide.

We have a dependency on the mono package, and again we inherit the autotools class to make use of the bitbake autotools functionality.

Lastly we override FILES_${PN} which controls the installed files which are added to the main output package. ${libdir} ${bindir} are standard GNU variable naming conventions for installation paths. For details see here and here.

In this case we have made sure that the helloworld executable goes to /usr/lib/helloworld/helloworld.exe as does the helloworldform.exe.

It might seem quite strange to be installing the executable assemblies to the /usr/lib location, but this is in line with Mono application deployment recommendations here.

We then install wrapper scripts to /usr/bin which can be called directly to run the respective examples. These scripts take the form

 #!/bin/sh
 exec @MONO@ @prefix@/lib/helloworld/@APP@.exe $MONO_EXTRA_ARGS "$@"

Breakdown of an xbuild recipe

The xbuild recipe is similar to the autotools recipe above, excepting that we override a couple of methods to ensure xbuild runs as we wish it too

This recipe can be found here.

First we include the definitions in the include file, and set the version specific checksums for the archive to be retrieved

require mono-helloworld.inc
SRC_URI[md5sum] = "79b0ba0044689789a54e3d55ec400fc0"
SRC_URI[sha256sum] = "56388435f29ce94007155acc39593c900b6d3248a7f281e83ed2101a6da455f0"

Then we set our source directory which must be correct for bitbake to find extracted files from the retrieved archive

REALPN = "mono-helloworld"
S = "${WORKDIR}/${REALPN}-${PV}"

Now we override the compilation method to call xbuild to build a particular .NET configuration against the a .SLN file in the archive

CONFIGURATION = "Debug"
do_compile() {
        xbuild /p:Configuration=${CONFIGURATION} ${REALPN}_vs2010.sln
}

Next we modify the installation method to make sure that the correct output files are installed and the executable scripts are modified to run the output assemblies

 do_install() {
         install -d "${D}${bindir}"
         install -d "${D}${libdir}/helloworld/.debug"
         install -m 0755 ${S}/bin/${CONFIGURATION}/*.mdb ${D}${libdir}/helloworld/.debug
         install -m 0755 ${S}/bin/${CONFIGURATION}/*.exe ${D}${libdir}/helloworld
 
         install -m 0755 ${S}/script.in ${D}${bindir}/helloworld
         sed -i "s|@MONO@|mono|g" ${D}${bindir}/helloworld
         sed -i "s|@prefix@|/usr|g" ${D}${bindir}/helloworld
         sed -i "s|@APP@|helloworld|g" ${D}${bindir}/helloworld
         install -m 0755 ${S}/script.in ${D}${bindir}/helloworldform
         sed -i "s|@MONO@|mono|g" ${D}${bindir}/helloworldform
         sed -i "s|@prefix@|/usr|g" ${D}${bindir}/helloworldform
         sed -i "s|@APP@|helloworld|g" ${D}${bindir}/helloworldform  
 }

Lastly we make sure that the .MDB debug files which are output are packaged correctly in the -dbg package. The other assemblies in ${libdir} and ${bindir} will be packaged correctly in the main output package by default

 FILES_${PN}-dbg += "${libdir}/helloworld/.debug/*"

For more details on check-sums, licenses and so forth, see Building your own recipes from first principles and the Recipe & Style Patch Guide.

Feedback

This is a living document. Please feel free to send comments, questions, corrections to Alex Lennon here