从零开始构建和运行嵌入式 Linux .NET 应用程序





5.00/5 (6投票s)
.NET 应用程序在 Yocto/OpenEmbedded Linux 上运行
概述
本教程的目的是引导您从一个干净的系统开始,使用 meta-mono 层将 Mono 集成到构建镜像中,然后构建和打包一个示例 .NET 项目以包含在该镜像中。
您可能已经安装了 Yocto,并且第一次接触 Mono,那么您可以直接跳到您觉得最相关的内容,例如 构建示例项目并在主机上进行测试(可选) 或 将 meta-mono 层添加到 Yocto 构建系统。
以下是基本假设。您
- 熟悉基本的 Linux 管理任务
- 了解 Yocto Project Reference Manual
- 使用 Ubuntu 14.04.4 LTS 作为您的主机构建系统
- 使用 Yocto 2.0 (Jethro) 版本
获取主机系统支持 Yocto 所需的软件包
首先,我们将安装 Ubuntu 的必需主机软件包,如快速入门指南中所述。
$ sudo apt-get install gawk wget git-core diffstat unzip texinfo
gcc-multilib build-essential chrpath socat libsdl1.2-dev xterm nano
有关系统要求和安装的完整详细信息,请参阅 Yocto Quickstart。
安装 Mono
另外,在您的主机系统上安装 Mono,因为我们将稍后使用它来构建和运行一些示例进行测试。
$ sudo apt-get install mono-complete
$ mono --version
使用 Ubuntu 14.04.4 LTS,这将安装 Mono 版本 3.2.8,现在它已经相当老旧了。
如果您想在主机系统上安装新版本的 Mono,可以遵循这些 说明。
$ sudo add-apt-repository ppa:directhex/monoxide
$ sudo apt-get update
$ sudo apt-get install mono-complete
$ mono --version
目前,这也会安装 Mono 3.2.8,但将来可能会提供更新的版本。
如果您想使用最新的 Mono,可以按照 此处的说明 从发布 tarball 构建,或者 此处 从 git 构建。请注意,此过程可能并不简单,并且可能存在问题,例如文件丢失。
此外,我撰写了一篇关于如何在 Windows 上构建 Mono(3.6.1 tarball / git)的详细教程,可以在 此处 找到。
下载并解压 Yocto 2.0 发行版
在撰写本文时,Yocto 的当前发行版 (2.0) 可以在 此处 找到。
$ cd ~
$ mkdir 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
这将为您提供 Yocto 2.0 的基础元数据和 bitbake
工具。您还可以添加额外的层,通常形式为“meta-foo
”,以提供机器支持和附加功能。
配置构建环境以构建仿真器镜像
$ cd ~/yocto/poky-jethro-14.0.0
$ source oe-init-build-env build_qemux86
这将创建一个名为 build_qemux86
的构建树,尽管您也可以使用其他名称,而不会产生任何负面影响。
完全有可能在不同的文件夹中并行拥有多个构建树,并使用 oe-init-build-env
在它们之间切换。
oe-init-build-env
将在 conf/local/conf 中创建一个默认配置文件,该文件将构建一个适合使用 qemu
执行的仿真器镜像。
构建一个基础镜像
配置环境后,您将停留在 build_qemux86 文件夹中。
然后,您应该构建一个基础镜像,这将花费一些时间(数小时)。
$ bitbake core-image-minimal
构建示例项目并在主机上进行测试(可选)
使用 autotools 构建
在 Yocto 中为不同目标编译非 .NET 项目的最直接方法是利用 autotools。
支持 autotools
的项目提供了一组模板文件,然后由 autotools
使用这些文件生成适合为目标环境构建的 Makefiles
和相关配置文件。
同样,也可以使用 autotools
编译 Mono/.NET 项目。
一个非常简单的示例“Hello World
”项目,名为 mono-helloworld
,已提交到 GitHub 此处。
如果您查看这两个源文件,helloworld.cs 和 helloworldform.cs,您会发现第一个文件在控制台输出“Hello World
”消息,第二个文件创建一个标题为“Hello World
”的 Windows 窗体。
关于 Mono 的 <code><code><code>autotools
模板配置的讨论超出了本指南的范围,但 mono-helloworld
项目基于 mono-skel
示例,您可以在 Mono Application Deployment 指南的 Autotools 部分找到它。
该项目本身构建了两个 .NET 可执行文件:helloworld
和 helloworldform
,第一个是控制台应用程序,第二个是简单的 Windows Forms 应用程序。
要在主机上独立于 Yocto 构建项目,请先克隆示例存储库
$ mkdir ~/host
$ cd ~/host
$ git clone https://github.com/DynamicDevices/mono-helloworld
然后运行 autotools,配置构建,并编译项目
$ cd mono-helloworld
$ ./autogen.sh
$ ./configure --enable-winformdemo
$ make
成功编译后,您将在构建文件夹的根目录中找到许多新文件。
有两个新的 .NET 可执行文件:src/helloworld.exe 和 src/helloworldform.exe。
您可以使用以下命令运行第一个:
$ mono src/helloworld.exe
它将输出:
HelloWorld
您可以使用以下命令运行第二个:
$ mono src/helloworldform.exe
根据您的主机环境(例如,使用 SSH),您可能需要显式设置 DISPLAY
变量才能使其正常工作,使用:
$ export DISPLAY=:0
$ mono src/helloworldform.exe
这将为您提供一个基本的 Windows Forms 窗口标题:
所以您现在已经证明您可以在主机上成功获取、配置和构建项目。
接下来,我们将研究 Yocto 如何自动化此获取、配置和构建过程,然后安装和打包输出文件。
使用 xbuild 构建
许多人使用 Visual Studio、Mono Develop、Xamarin Studio 或其他类似的集成开发环境 (IDE) 进行开发。
Mono 提供了 xbuild
,它是 Microsoft msbuild
的 Mono 实现,在此 处 进行了讨论。
本质上,这使得开发人员可以在他们选择的 IDE 中创建一个项目解决方案,然后使用 xbuild
在 Mono 环境中进行构建。
一个有用的工作流程可能是:在本地使用您选择的 IDE 进行开发,发布时提交到 git 存储库,然后使用 Yocto 配方将该发布版本构建到现有镜像中,或提供给包源以更新现场的现有目标。
上面讨论的 mono-helloworld
项目(构建与 autotools)也提供了解决方案和项目文件来支持使用 xbuild
进行构建,或者实际上支持像 Visual Studio 这样的 IDE。
如果您已经使用 autotools
构建了示例,请移动文件夹并重新开始。
$ cd ~/host
$ rm -Rf mono-helloworld
再次检出 mono-helloworld
项目。
$ git clone https://github.com/DynamicDevices/mono-helloworld
运行 xbuild
。(正如您从 .sln 文件名中可能猜到的那样,您可以将此示例项目克隆到 Windows 主机并使用 Visual Studio 打开它,实际上它就是这样创建的。)
<code> </code> $ xbuild /p:Configuration=Debug mono-helloworld_vs2010.sln
这将导致许多新文件,包括 bin/Debug 中的两个新的 Mono/.NET 可执行文件:helloworld.exe 和 helloworldform.exe。
您可以使用以下命令运行第一个:
$ mono bin/Debug/helloworld.exe
它将输出:
HelloWorld
您可以使用以下命令运行第二个:
$ mono bin/Debug/helloworldform.exe
根据您的主机环境(例如,使用 SSH),您可能需要显式设置 DISPLAY
变量才能使其正常工作,使用:
$ export DISPLAY=:0
$ mono bin/Debug/helloworldform.exe
这将为您提供一个基本的 Windows Forms 窗口标题。
所以您现在已经证明您可以在主机上成功获取、配置和构建项目。
接下来,我们将研究 Yocto 如何自动化此获取、配置和构建过程,然后安装和打包输出文件。
将 meta-mono 层添加到 Yocto 构建系统
将配方添加到构建环境的首选方法,也是本指南所示的方法,是将它们放在一个新的层中。
层根据机器、功能或类似项隔离特定于构建的元数据集,并有助于保持环境的清洁。
meta-mono
层包含 Mono 特定的配方,以支持在目标板上执行 .NET 应用程序。该层可以在 此处 找到。
要使用像这样的新层,您首先需要从其 git 存储库克隆该层,然后通过编辑 conf/bblayers.conf 将该层添加到您的 bitbake
配置中。
$ cd ~/yocto/poky-jethro-14.0.0
$ git clone git://git.yoctoproject.org/meta-mono
您还需要 meta-openembedded 层的 jethro 分支,因为它提供了 libgdiplus 所需的 giflib 配方。
$ cd ~/yocto/poky-jethro-14.0.0
$ git clone git://git.openembedded.org/meta-openembedded -b jethro
$ cd ~/yocto/poky-jethro-14.0.0/build_qemux86
$ nano conf/bblayers.conf
您的 bblayers.conf 应如下所示:
# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
LCONF_VERSION = "6"
BBPATH = "${TOPDIR}"
BBFILES ?= ""
BBLAYERS ?= " \
/home/user/yocto/poky-jethro-14.0.0/meta \
/home/user/yocto/poky-jethro-14.0.0/meta-yocto \
/home/user/yocto/poky-jethro-14.0.0/meta-yocto-bsp \
"
BBLAYERS_NON_REMOVABLE ?= " \
/home/user/yocto/poky-jethro-14.0.0/meta \
/home/user/yocto/poky-jethro-14.0.0/meta-yocto \
"
通过向 BBLAYERS
添加一行,使新层对 bitbake
可见。
BBLAYERS ?= " \
/home/user/yocto/poky-jethro-14.0.0/meta \
/home/user/yocto/poky-jethro-14.0.0/meta-yocto \
/home/user/yocto/poky-jethro-14.0.0/meta-yocto-bsp \
/home/user/yocto/poky-jethro-14.0.0/meta-openembedded/meta-oe \
/home/user/yocto/poky-jethro-14.0.0/meta-mono \
"
现在 bitbake
可以看到新层中的配方了。
您还将看到当 bitbake
运行时,并显示构建配置,您层的存储库分支和哈希会显示出来,这对于了解为什么构建失败很有用,例如:
Build Configuration:
BB_VERSION = "1.28.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "Ubuntu-14.04"
TARGET_SYS = "i586-poky-linux"
MACHINE = "qemux86"
DISTRO = "poky"
DISTRO_VERSION = "2.0"
TUNE_FEATURES = "m32 i586"
TARGET_FPU = ""
meta
meta-yocto
meta-yocto-bsp = "<unknown>:<unknown>"
meta-mono = "master:836115be90cac01cfbb677b24d6ad6d802a795e7"
meta-oe = "jethro:dc5634968b270dde250690609f0015f881db81f2"
构建包含 Mono/.NET 支持的镜像
meta-mono
层包含一个构建 core-image-mono
镜像的配方,该镜像基于 Yocto 标准镜像 core-image-sato
。
要构建此镜像:
$ bitbake core-image-mono
这可能需要一段时间,即使您已经构建了 core-image-minimal
,因为还需要构建额外的 GUI 支持包。
core-image-mono
配方可以在 此处 找到,并从中包含一个文件 此处。
您可以在包含文件中看到,标准 core-image-sato
镜像中添加了额外的包。
IMAGE_INSTALL += "mono mono-helloworld"
这就是您如何在配方中或在 .bbappend 文件中为镜像添加 Mono 支持。事实上,只需要添加 mono
包,因为除非您出于测试目的需要示例,否则不需要这些示例。
包含的 mono-helloworld
配方演示了如何使用 autotools
构建示例项目。有关详细信息,请参阅配方本身 此处
,更重要的是,它包含的文件 此处。
您可以选择将 mono-helloworld
替换为 mono-helloworld-xbuild
,顾名思义,它展示了如何使用 xbuild
构建示例项目。
在仿真目标上测试 .NET 可执行文件
构建完 core-image-mono
后,您就可以在 qemu
下运行它了。
要运行镜像,只需使用:
$ runqemu qemux86
这将启动仿真器,加载镜像,您将看到内核加载,然后是一个基本的图形用户界面。
如果您发现键盘映射不正确,您可能希望显式设置它,例如:
$ runqemu qemux86 qemuparams='-k en-gb'
或
$ runqemu qemux86 qemuparams='-k en-us'
使用相应的图标打开一个终端窗口,以“root
”身份登录仿真器(无密码),然后运行示例。
您可以使用以下命令运行控制台可执行文件:
$ mono helloworld.exe
或者,该配方安装了一个脚本来包装 Mono 的使用,因此您可以使用以下形式:
$ helloworld
这将输出:
HelloWorld
您可以使用以下命令运行 Windows Forms 可执行文件:
$ mono /usr/lib/helloworldform.exe
或
$ helloworldform
根据您的主机环境(例如,使用 SSH),您可能需要显式设置 DISPLAY
变量才能使其正常工作,使用:
$ export DISPLAY=:0
$ mono /usr/lib/helloworld/helloworldform.exe
这将显示一个标题为“Hello World
”的测试 Windows Forms 窗体。
您可以使用以下命令运行 GTK# 可执行文件:
$ mono /usr/lib/helloworldgtk.exe
或
$ helloworldgtk
根据您的主机环境(例如,使用 SSH),您可能需要显式设置 DISPLAY
变量才能使其正常工作,使用:
$ export DISPLAY=:0
$ mono /usr/lib/helloworld/helloworldgtk.exe
这将显示一个标题为“Hello World
”的测试 Windows Forms 窗体。
autotools 配方 breakdown
这是 mono-helloworld_1.2.bb 配方的内容。
require mono-helloworld.inc
SRC_URI[md5sum] = "ae22f282d36ae5cb82ae5a2e9bcbb8b5"
SRC_URI[sha256sum] = "365360d674bd63ab7ca1762e64e3d5d6c6d4841edf6e59f67ff8b40fafeb1137"
可以看到,我们提供了几个校验和,它们对应于将要下载的发行版 tarball。
同样,包含的 mono-helloworld.inc 文件可以在 此处 找到。
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"
SRC_URI = "https://github.com/DynamicDevices/mono-helloworld/releases/download/v${PV}/$
inherit autotools-brokensep
inherit mono
DEPENDS_${PN} = "mono"
RDEPENDS_${PN} = "mono"
EDEPENDS_X11 = "libgdiplus"
ERDEPENDS_X11 = "libgdiplus"
EDEPENDS_GTK = "gtk-sharp"
ERDEPENDS_GTK = "gtk-sharp"
EDEPENDS_WAYLAND = "wayland"
ERDEPENDS_WAYLAND = "wayland"
PACKAGECONFIG[x11] = "--enable-winformdemo=yes,,${EDEPENDS_X11},${ERDEPENDS_X11}"
PACKAGECONFIG[wayland] = ",,${EDEPENDS_WAYLAND},${ERDEPENDS_WAYLAND}"
PACKAGECONFIG[gtk] = "--enable-gtkdemo=yes,,${EDEPENDS_GTK},${ERDEPENDS_GTK}"
# Default configuration, distros might want to override
PACKAGECONFIG ??= "${@base_contains('DISTRO_FEATURES', 'x11', 'x11 gtk', '', d)} \
${@base_contains('DISTRO_FEATURES', 'wayland', 'wayland gtk', '', d$
"
FILES_${PN} = "${libdir}/helloworld/helloworld.exe \
${bindir}/helloworld \
${libdir}/helloworld/helloworldform.exe \
${bindir}/helloworldform \
${libdir}/helloworld/helloworldgtk.exe \
${bindir}/helloworldgtk \
"
有关校验和、许可证等的更多详细信息,请参阅 将第三方组件添加到 Yocto/OpenEmbedded Linux 和 Yocto Recipe & Style Patch Guide。
我们依赖于 mono
包,并且再次继承 autotools
类以利用 bitbake
的 autotools
功能。
最后,我们覆盖 FILES_${PN}
,它控制添加到主输出包的已安装文件。${libdir}
和 ${bindir}
是标准的 GNU 变量命名约定,用于安装路径。有关详细信息,请参阅 此处 和 此处。
在本例中,我们确保 helloworld
可执行文件以及 helloworldform.exe 都安装到 /usr/lib/helloworld/。
将可执行程序集安装到 /usr/lib 位置可能看起来很奇怪,但这符合 Mono 应用程序部署建议。
然后,我们将包装脚本安装到 /usr/bin,可以直接调用它们来运行各自的示例。这些脚本的形式如下:
#!/bin/sh
exec @MONO@ @prefix@/lib/helloworld/@APP@.exe $MONO_EXTRA_ARGS "$@"
xbuild 配方 breakdown
xbuild
配方与上面的 autotools
配方类似,除了我们覆盖了几个方法以确保 xbuild
按我们期望的方式运行。
此配方可以在 此处 找到。
首先,我们包含包含文件中的定义,并设置要检索的存档的版本特定校验和。
require mono-helloworld.inc
SRC_URI[md5sum] = "ae22f282d36ae5cb82ae5a2e9bcbb8b5"
SRC_URI[sha256sum] = "365360d674bd63ab7ca1762e64e3d5d6c6d4841edf6e59f67ff8b40fafeb1137"
然后,我们设置源目录,该目录对于 bitbake
找到从检索到的存档中提取的文件必须是正确的。
REALPN = "mono-helloworld"
S = "${WORKDIR}/${REALPN}-${PV}"
现在我们覆盖编译方法,调用 xbuild
以在存档中的 .SLN 文件上构建特定的 .NET 配置。
CONFIGURATION = "Debug"
do_compile() {
xbuild /p:Configuration=${CONFIGURATION} ${REALPN}_vs2010.sln
}
接下来,我们修改安装方法,以确保正确的文件被安装,并且可执行脚本被修改为运行输出程序集。
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
}
最后,我们确保输出的 .MDB 调试文件在 -dbg
包中正确打包。${libdir}
和 ${bindir}
中的其他程序集将默认在主输出包中正确打包。
FILES_${PN}-dbg += "${libdir}/helloworld/.debug/*"
有关校验和、许可证等的更多详细信息,请参阅 将第三方组件添加到 Yocto/OpenEmbedded Linux 和 Yocto Recipe & Style Patch Guide。
反馈
这是一个活文档。请随时将评论、问题、更正发送给Alex Lennon。
历史
- 23/05/14 v1.0 - 首次发布
- 22/02/16 v2.0 - 更新至 Yocto Jethro