mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
doc: update porting guide to new port mechanism
This commit is contained in:
parent
f2d38443f7
commit
bdfe634fdf
@ -31,8 +31,14 @@ sections:
|
||||
:[http:porting_device_drivers - Porting devices drivers]:
|
||||
This chapter describes the concepts of how to port a device driver to the
|
||||
Genode framework. It requires the basic knowledge introduced in the previous
|
||||
chapters and should be read last. Before reading this guide, it is strongly
|
||||
advised to read the "The Genode Build System" documentation.
|
||||
chapters and should be read last.
|
||||
|
||||
Before reading this guide, it is strongly advised to read the "The Genode
|
||||
Build System" documentation:
|
||||
|
||||
:Build-system manual:
|
||||
|
||||
[http://genode.org/documentation/developer-resources/build_system]
|
||||
|
||||
|
||||
Porting third-party code to Genode
|
||||
@ -55,22 +61,22 @@ Steps in porting applications to Genode
|
||||
e.g. what functionality needs to be provided by the target system and
|
||||
which libraries does it use.
|
||||
|
||||
# Create a port Makefile
|
||||
# Create a port file
|
||||
|
||||
Prepare the source code of the application for the use within Genode. The
|
||||
Genode build-system infrastructure uses fetch rules, so called port-files,
|
||||
which describe how the source is obtained, what patches are applied to the
|
||||
source code, if needed, and where the source code will be stored and
|
||||
Genode build-system infrastructure uses fetch rules, so called port files,
|
||||
which declare where the source is obtained from, what patches are applied
|
||||
to the source code, and where the source code will be stored and
|
||||
configured.
|
||||
|
||||
# Check platform dependent code and create stub code
|
||||
|
||||
This step may require changes to the original source code
|
||||
of the application to be compilable to Genode. At this point, it
|
||||
of the application to be compilable for Genode. At this point, it
|
||||
is not necessary to provide a working implementation for required
|
||||
functions. Just creating stubs of the various functions is fine.
|
||||
|
||||
# Create build Makefile
|
||||
# Create build-description file
|
||||
|
||||
To compile the application we need build rules. Within these rules
|
||||
we also declare all dependencies (e.g. libraries) that are needed
|
||||
@ -176,61 +182,75 @@ libraries are already available on Genode. For now all we have to do is to
|
||||
keep them in mind.
|
||||
|
||||
|
||||
Creating the port Makefile
|
||||
==========================
|
||||
Creating the port file
|
||||
======================
|
||||
|
||||
Since DosBox is an application, which depends on several ported
|
||||
libraries (e.g., libSDL), the 'ports' repository within the Genode
|
||||
source tree is a natural fit. On that account, the port Makefile
|
||||
_ports/ports/dosbox.mk_ is created. It is often reasonable to also
|
||||
create a corresponding _ports/ports/dosbox.inc_ file that contains
|
||||
the used version of the program which is included by _dosbox.mk_ as
|
||||
well as by the associated build Makefile. Through this approach it is
|
||||
easier to update ports whose structures stays the same but varies only
|
||||
in its version string.
|
||||
libraries (e.g., libSDL), the _ports_ repository within the Genode
|
||||
source tree is a natural fit. On that account, the port file
|
||||
_ports/ports/dosbox.port_ is created.
|
||||
|
||||
For DosBox the _dosbox.inc_ looks as follows:
|
||||
For DosBox the _dosbox.port_ looks as follows:
|
||||
|
||||
! DOSBOX_REV := 3837
|
||||
! DOSBOX_VERSION := svn-$(DOSBOX_REV)
|
||||
! DOSBOX := dosbox-$(DOSBOX_VERSION)
|
||||
|
||||
In addition, the corresponding _dosbox.mk_ contains:
|
||||
|
||||
! include ports/dosbox.inc
|
||||
! LICENSE := GPLv2
|
||||
! VERSION := svn
|
||||
! DOWNLOADS := dosbox.svn
|
||||
!
|
||||
! DOSBOX_SVN_URL = http://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk
|
||||
!
|
||||
! #
|
||||
! # Interface to top-level prepare Makefile
|
||||
! #
|
||||
! PORTS += $(DOSBOX)
|
||||
!
|
||||
! prepare:: $(CONTRIB_DIR)/$(DOSBOX)
|
||||
!
|
||||
! #
|
||||
! # Port-specific local rules
|
||||
! #
|
||||
! $(CONTRIB_DIR)/$(DOSBOX):
|
||||
! $(ECHO) "checking out 'dosbox rev. $(DOSBOX_REV)' to '$@'"
|
||||
! $(VERBOSE)svn export $(DOSBOX_SVN_URL)@$(DOSBOX_REV) $@
|
||||
! URL(dosbox) := http://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk
|
||||
! DIR(dosbox) := src/app/dosbox
|
||||
! REV(dosbox) := 3837
|
||||
|
||||
_The variable_ 'CONTRIB_DIR' _always contains the path to the directory_
|
||||
_that holds the contributed source code relatively to the particular_
|
||||
_Genode repository (e.g., ports/contrib)._
|
||||
First, we define the license, the version and the type of the source code
|
||||
origin. In case of DosBox, we checkout the source code from a Subversion
|
||||
repository. This is denoted by the '.svn' suffix of the item specified in
|
||||
the 'DOWNLOADS' declaration. Other valid types are 'file' (a plain file),
|
||||
'archive' (an archive of the types tar.gz, tar.xz, tgz, tar.bz2, or zip)
|
||||
or 'git' (a Git repository).
|
||||
To checkout the source code out from the Subversion repository, we also need
|
||||
its URL, the revision we want to check out and the destination directory
|
||||
that will contain the sources afterwards. These declarations are mandatory and
|
||||
must always be specified. Otherwise the preparation of the port will fail.
|
||||
|
||||
! PATCHES := $(addprefix src/app/dosbox/patches/,\
|
||||
! $(notdir $(wildcard $(REP_DIR)/src/app/dosbox/patches/*.patch)))
|
||||
!
|
||||
! PATCH_OPT := -p2 -d src/app/dosbox
|
||||
|
||||
As next step, we declare all patches that are needed for the DosBox port.
|
||||
Since in this case, the patches are using a different path format, we have
|
||||
to override the default patch settings by defining the _PATCH_OPT_ variable.
|
||||
|
||||
Each port file comes along with a hash file. This hash is generated by taking
|
||||
several sources into account. For one, the port file, each patch and the
|
||||
port preparation tool (_tool/ports/prepare_port_) are the ingredients for
|
||||
the hash value. If any of these files is changed, a new hash will be generated,
|
||||
For now, we just write "dummy" in the '_ports/ports/dosbox.hash_ file.
|
||||
|
||||
The DosBox port can now be prepared by executing
|
||||
|
||||
! $ make PKG=dosbox prepare
|
||||
! $ <genode-dir>/tool/ports/prepare_port dosbox
|
||||
|
||||
from within Genode's 'ports' repository. The 'prepare::' rule is evaluated
|
||||
and the checkout will be triggered.
|
||||
However, we get the following error message:
|
||||
|
||||
Error: <rep-dir>/ports/dosbox.port is out of date, expected <fingerprint>
|
||||
|
||||
We get this message because we had specified the "dummy" hash value in
|
||||
the _dosbox.hash_ file. The prepare_port tool computes a fingerprint
|
||||
of the actual version of the port and compares this fingerprint with the
|
||||
hash value specified in _dosbox.hash_. The computed fingerprint can
|
||||
be found at _<genode-dir>/contrib/dosbox-dummy/dosbox.hash_. In the final
|
||||
step of the port, we will replace the dummy fingerprint with the actual
|
||||
fingerprint of the port. But before finalizing the porting work, it is
|
||||
practical to keep using the dummy hash and suppress the fingerprint check.
|
||||
This can be done by adding 'CHECK_HASH=no' as argument to the prepare_port tool:
|
||||
|
||||
! $ <genode-dir>/tool/ports/prepare-port dosbox CHECK_HASH=no
|
||||
|
||||
|
||||
Check platform-dependent code
|
||||
=============================
|
||||
|
||||
At this point, it is important to spot platform dependent source files or
|
||||
At this point, it is important to spot platform-dependent source files or
|
||||
rather certain functions that are not yet available on Genode. These source
|
||||
files should be omitted. Of course they may be used as a guidance when
|
||||
implementing the functionality for Genode later on, when creating the
|
||||
@ -249,11 +269,18 @@ we assemble a list of needed source files. If an application just
|
||||
uses a simple Makefile and not a build tool, it might be easier to just
|
||||
reuse the contents of this Makefile instead.
|
||||
|
||||
First we include _dosbox.inc_ and for convenience set the source directory
|
||||
of DosBox:
|
||||
First of all, we create a shortcut for the source directory of DosBox by calling
|
||||
the 'select_from_ports' function:
|
||||
|
||||
! include $(REP_DIR)/ports/dosbox.inc
|
||||
! DOSBOX_DIR = $(REP_DIR)/contrib/$(DOSBOX)
|
||||
! DOSBOX_DIR := $(call select_from_ports,dosbox)/src/app/dosbox
|
||||
|
||||
Under the hood, the 'select_from_ports' function looks up the
|
||||
fingerprint of the specified port by reading the corresponding
|
||||
<port-name>.hash file. It then uses this hash value to construct the
|
||||
directory path within the _<genode-dir>contrib/_ directory that belongs to
|
||||
the matching version of the port. If there is no hash file that matches the
|
||||
port name, or if the port directory does not exist, the build system
|
||||
will back out with an error message.
|
||||
|
||||
Examining the log file leaves us with the following list of source files:
|
||||
|
||||
@ -274,7 +301,7 @@ Examining the log file leaves us with the following list of source files:
|
||||
! […]
|
||||
|
||||
_The only variable here that is actually evaluated by Genode's build-system is_
|
||||
'SRC_CC' _. The rest of the variables are little helpers that make our_
|
||||
'SRC_CC'. _The rest of the variables are little helpers that make our_
|
||||
_life more comfortable._
|
||||
|
||||
In this case, it is mandatory to use GNUMake's 'notdir' file name function
|
||||
@ -286,7 +313,7 @@ why you have to use a build directory for each platform. The Genode build
|
||||
system will create the needed directory hierarchy within the build directory
|
||||
automatically. By combining GNUMake's 'notdir' and 'wildcard' function, we
|
||||
can assemble a list of all needed source files without much effort. We then
|
||||
use 'vpath' to point GNUMake to the right source file within the _contrib_
|
||||
use 'vpath' to point GNUMake to the right source file within the dosbox
|
||||
directory.
|
||||
|
||||
The remaining thing to do now is setting the right include directories and proper
|
||||
@ -324,7 +351,7 @@ environment. Below is a skimmed diff of these changes:
|
||||
!
|
||||
! […]
|
||||
|
||||
Thereafter we specify the compiler flags:
|
||||
Thereafter, we specify the compiler flags:
|
||||
|
||||
! CC_OPT = -DHAVE_CONFIG_H -D_GNU_SOURCE=1 -D_REENTRANT
|
||||
! ifeq ($(filter-out $(SPECS),x86_32),)
|
||||
@ -343,7 +370,7 @@ As noted in the commentary seen in the diff we define 'C_TARGETCPU'
|
||||
and adjust the include directories ourselves according to the target
|
||||
architecture.
|
||||
|
||||
While debugging compiler warnings for 3rd-party code are really helpful but
|
||||
While debugging, compiler warnings for 3rd-party code are really helpful but
|
||||
tend to be annoying after the porting work is finished, we can
|
||||
remove the hashmark to keep the compiler from complaining too
|
||||
much.
|
||||
@ -351,13 +378,13 @@ much.
|
||||
Lastly, we need to add the required libraries, which we acquired in step 1:
|
||||
|
||||
! LIBS += libc libm libpng sdl stdcxx zlib
|
||||
! LIBS += libc_log libc_fs libc_lwip_nic_dhcp config_args
|
||||
! LIBS += libc_lwip_nic_dhcp config_args
|
||||
|
||||
In addition to the required libraries, a few Genode specific
|
||||
libraries are also needed. These libraries implement certain
|
||||
functions in the libc via the libc's plugin mechanism.
|
||||
libc_log, for example, is used to print message on stdout via
|
||||
Genode's LOG service.
|
||||
libc_lwip_nic_dhcp, for example, is used to connect the BSD socket interface
|
||||
to a NIC service such as a network device driver.
|
||||
|
||||
|
||||
Creating the run script
|
||||
@ -418,18 +445,16 @@ Nextm we provide the scenario's configuration 'config':
|
||||
! <resource name="RAM" quantum="1M"/>
|
||||
! <provides><service name="Timer"/></provides>
|
||||
! </start>
|
||||
! <start name="tar_fs">
|
||||
! <resource name="RAM" quantum="4M"/>
|
||||
! <provides> <service name="File_system"/> </provides>
|
||||
! <config>
|
||||
! <archive name="dosbox.tar" />
|
||||
! <policy label="" root="/" />
|
||||
! </config>
|
||||
! </start>
|
||||
! <start name="dosbox">
|
||||
! <resource name="RAM" quantum="128M"/>
|
||||
! <config>
|
||||
! <sdl_audio_volume value="100"/>
|
||||
! <libc stdout="/dev/log" stderr="/dev/log">
|
||||
! <vfs>
|
||||
! <tar name="dosbox.tar"/>
|
||||
! <dir name="dev"> <log/> </dir>
|
||||
! </vfs>
|
||||
! </libc>
|
||||
! </config>
|
||||
! </start>
|
||||
! </config>}
|
||||
@ -442,9 +467,9 @@ Thereafter we declare all boot modules:
|
||||
|
||||
! set boot_modules {
|
||||
! core init timer audio_out_drv fb_drv ps2_drv ld.lib.so
|
||||
! libc_fs.lib.so libc.lib.so libc_log.lib.so libm.lib.so
|
||||
! libc.lib.so libm.lib.so
|
||||
! lwip.lib.so libpng.lib.so stdcxx.lib.so sdl.lib.so
|
||||
! pthread.lib.so zlib.lib.so tar_fs dosbox dosbox.tar
|
||||
! pthread.lib.so zlib.lib.so dosbox dosbox.tar
|
||||
! }
|
||||
! build_boot_image $boot_modules
|
||||
|
||||
@ -496,19 +521,15 @@ application that is ported.
|
||||
Since 'ftime(3)' is a deprecated function anyway we change the code of
|
||||
DosBox to use 'gettimeofday(2)'.
|
||||
|
||||
After this was fixed we face another problem:
|
||||
After this was fixed, we face another problem:
|
||||
|
||||
! /src/genode/ports/contrib/dosbox-svn-3837/src/ints/int10_vesa.cpp:48:33: error:
|
||||
! unable to find string literal operator ‘operator"" VERSION’
|
||||
|
||||
The fix is quite simple and the compile error was due to the fact
|
||||
that Genode uses C++11 by now. It often happens that 3rd party code
|
||||
is not well tested with a C++11 enabled compiler. In any case a patch file
|
||||
should be created which will be applied when executing the fetch-rules:
|
||||
|
||||
! $(CONTRIB_DIR)/$(DOSBOX):
|
||||
! […]
|
||||
! $(VERBOSE)patch -N -p0 < src/app/dosbox/int10_vesa.patch
|
||||
is not well tested with a C++11 enabled compiler. In any case, a patch file
|
||||
should be created which will be applied when preparing the port.
|
||||
|
||||
Furthermore it would be reasonable to report the bug to the DosBox
|
||||
developers so it can be fixed upstream. We can then get rid of our
|
||||
@ -537,13 +558,13 @@ Debugging the application
|
||||
DosBox was successfully compiled but unfortunately it did not run.
|
||||
To be honest that was expected and here the fun begins.
|
||||
|
||||
At this point there are several options to chose from. By running
|
||||
Genode/Fiasco.OC within Qemu we can use the kernel debugger (JDB)
|
||||
to take a deeper look at what went wrong (e.g. backtraces of the
|
||||
At this point, there are several options to chose from. By running
|
||||
Genode/Fiasco.OC within Qemu, we can use the kernel debugger (JDB)
|
||||
to take a deeper look at what went wrong (e.g., backtraces of the
|
||||
running processes, memory dumps of the faulted DosBox process etc.).
|
||||
Doing this can be quite taxing but fortunately Genode runs on multiple
|
||||
kernels and often problems on one kernel can be reproduced on another
|
||||
kernel. For this reason we choose Genode/Linux where we can use all
|
||||
kernel. For this reason, we choose Genode/Linux where we can use all
|
||||
the normal debugging tools like 'gdb(1)', 'valgrind(1)' and so on. Luckily
|
||||
for us, DosBox also fails to run on Genode/Linux. The debugging steps
|
||||
are naturally dependent on the ported software. In the case of DosBox,
|
||||
@ -553,8 +574,8 @@ Linux as a host platform.
|
||||
For the sake of completeness here is a list of all files that were created by
|
||||
porting DosBox to Genode:
|
||||
|
||||
! ports/ports/dosbox.inc
|
||||
! ports/ports/dosbox.mk
|
||||
! ports/ports/dosbox.hash
|
||||
! ports/ports/dosbox.port
|
||||
! ports/run/dosbox.run
|
||||
! ports/src/app/dosbox/config.h
|
||||
! ports/src/app/dosbox/patches/bios.patch
|
||||
@ -566,16 +587,32 @@ porting DosBox to Genode:
|
||||
[image dosbox]
|
||||
DosBox ported to Genode
|
||||
|
||||
Finally, after having tested that both the preparation-step and the
|
||||
build of DosBox work as expected, it is time to
|
||||
finalize the fingerprint stored in the _<genode-dir>/ports/ports/dosbox.hash_
|
||||
file. This can be done by copying the content of the
|
||||
_<genode-dir>/contrib/dosbox-dummy/dosbox.hash file_.
|
||||
Alternatively, you may invoke the _tool/ports/update_hash_ tool with the
|
||||
port name "dosbox" as argument. The next time, you
|
||||
invoke the prepare_port tool, do not specify the 'CHECK_HASH=no' argument.
|
||||
So the fingerprint check will validate that the _dosbox.hash_ file
|
||||
corresponds to your _dosbox.port_ file. From now on, the
|
||||
_<genode-dir>/contrib/dosbox-dummy_ directory will no longer be used because
|
||||
the _dosbox.hash_ file points to the port directory named after the real
|
||||
fingerprint.
|
||||
|
||||
|
||||
Native Genode port of a library
|
||||
###############################
|
||||
|
||||
Porting a library to be used natively on Genode is similar to porting
|
||||
an application to run natively on Genode. The source codes has to be
|
||||
an application to run natively on Genode. The source codes have to be
|
||||
obtained and, if needed, patched to run on Genode.
|
||||
As an example on how to port a library to natively run on Genode, we
|
||||
will describe the porting of SDL_net in more detail. Ported libraries
|
||||
are placed in the _libports_ repository of Genode.
|
||||
are placed in the _libports_ repository of Genode. But this is just a
|
||||
convention. Feel free to host your library port in a custom repository
|
||||
of your's.
|
||||
|
||||
|
||||
Checking requirements/dependencies
|
||||
@ -592,85 +629,43 @@ process:
|
||||
! $ make > build.log 2>&1
|
||||
|
||||
|
||||
Creating the port Makefile
|
||||
==========================
|
||||
Creating the port file
|
||||
======================
|
||||
|
||||
We start by creating 'libports/ports/sdl_net.inc':
|
||||
We start by creating _<genode-dir>/libports/ports/sdl_net.port:
|
||||
|
||||
! SDL_NET_VERSION = 1.2.8
|
||||
! SDL_NET = SDL_net-$(SDL_NET_VERSION)
|
||||
|
||||
Following this we create the actual fetch-rules
|
||||
in _libports/ports/sdl_net.mk_
|
||||
|
||||
! include ports/sdl_net.inc
|
||||
! LICENSE := BSD
|
||||
! VERSION := 1.2.8
|
||||
! DOWNLOADS := sdl_net.archive
|
||||
!
|
||||
! SDL_NET_TGZ = $(SDL_NET).tar.gz
|
||||
! SDL_NET_URL = http://www.libsdl.org/projects/SDL_net/release/$(SDL_NET_TGZ)
|
||||
! URL(sdl_net) := http://www.libsdl.org/projects/SDL_net/release/SDL_net-$(VERSION).tar.gz
|
||||
! SHA(sdl_net) := fd393059fef8d9925dc20662baa3b25e02b8405d
|
||||
! DIR(sdl_net) := src/lib/sdl_net
|
||||
!
|
||||
! #
|
||||
! # Interface to top-level prepare Makefile
|
||||
! #
|
||||
! # Register SDL_net port as lower case to be consistent with the
|
||||
! # other libraries.
|
||||
! #
|
||||
! PORTS += sdl_net-$(SDL_NET_VERSION)
|
||||
!
|
||||
! prepare-sdl_net: $(CONTRIB_DIR)/$(SDL_NET) include/SDL/SDL_net.h
|
||||
!
|
||||
! $(CONTRIB_DIR)/$(SDL_NET): clean-sdl_net
|
||||
! PATCHES := src/lib/sdl_net/SDLnet.patch src/lib/sdl_net/SDL_net.h.patch
|
||||
|
||||
While extracting the archive, we omit certain directories and files that we
|
||||
do not need and that otherwise would only pollute the 'contrib' directory:
|
||||
|
||||
! #
|
||||
! # Port-specific local rules
|
||||
! #
|
||||
! $(DOWNLOAD_DIR)/$(SDL_NET_TGZ):
|
||||
! $(VERBOSE)wget -c -P $(DOWNLOAD_DIR) $(SDL_NET_URL) && touch $@
|
||||
!
|
||||
! $(CONTRIB_DIR)/$(SDL_NET): $(DOWNLOAD_DIR)/$(SDL_NET_TGZ)
|
||||
! $(VERBOSE)tar xfz $< \
|
||||
! --exclude Xcode --exclude VisualC --exclude Xcode-iOS \
|
||||
! --exclude VisualCE --exclude Watcom-OS2.zip --exclude debian \
|
||||
! -C $(CONTRIB_DIR) && touch $@
|
||||
! $(VERBOSE)patch -N -p0 < src/lib/sdl_net/SDLnet.patch
|
||||
In addition to the URL the SHA1 checksum of the SDL_net archive needs to
|
||||
specified because _tool/prepare_port_ validates the downloaded archive
|
||||
by using this hash.
|
||||
|
||||
Applications that want to use SDL_net have to include the 'SDL_net.h' header
|
||||
file. Hence it is necessary to make file visible to applications. This is
|
||||
done by creating a symbolic link from the original location to
|
||||
_libports/include/SDL/SDL_net.h_
|
||||
file. Hence it is necessary to make this file visible to applications. This is
|
||||
done by populating the _<genode-dir>/contrib/sdl-<hash>/include_ directory:
|
||||
|
||||
! #
|
||||
! # Install SDL_net headers
|
||||
! #
|
||||
! include/SDL/SDL_net.h:
|
||||
! $(VERBOSE)mkdir -p $(dir $@)
|
||||
! $(VERBOSE)ln -fs ../../$(CONTRIB_DIR)/$(SDL_NET)/SDL_net.h include/SDL/
|
||||
! DIRS := include/SDL
|
||||
! DIR_CONTENT(include/SDL) := src/lib/sdl_net/SDL_net.h
|
||||
|
||||
Since we created a symbolic link that is placed in Genode's _libports_
|
||||
repository,
|
||||
we have to provide a 'clean' rule. This rule is responsible for removing all
|
||||
extracted files and the link we created:
|
||||
For now, we also use a dummy hash in the _sdl_net.hash_ file like it was done
|
||||
while porting DosBox. We will replace the dummy hash with the proper one at
|
||||
the end.
|
||||
|
||||
! clean-sdl_net:
|
||||
! $(VERBOSE)rm -rf include/SDL/SDL_net.h
|
||||
! $(VERBOSE)rmdir include/SDL 2>/dev/null || true
|
||||
! $(VERBOSE)rm -rf $(CONTRIB_DIR)/$(SDL_NET)
|
||||
|
||||
_It is important to write the_ 'clean' _rule in way that does not remove_
|
||||
_files that are still needed by other components of Genode or ported_
|
||||
_applications. In this example we only delete include/SDL if it is_
|
||||
_empty. Otherwise_ 'rmdir(1)' _will not remove the directory and we_
|
||||
_simply ignore it._
|
||||
|
||||
Creating the build Makefile
|
||||
===========================
|
||||
|
||||
We create the build rules in _libports/lib/mk/sdl_net.mk_:
|
||||
|
||||
! include $(REP_DIR)/ports/sdl_net.inc
|
||||
! SDL_NET_DIR = $(REP_DIR)/contrib/$(SDL_NET)
|
||||
! SDL_NET_DIR := $(call select_from_ports,sdl_net)/src/lib/sdl_net
|
||||
!
|
||||
! SRC_C = $(notdir $(wildcard $(SDL_NET_DIR)/SDLnet*.c))
|
||||
!
|
||||
@ -685,11 +680,11 @@ have to add the following statement to the 'mk' file:
|
||||
|
||||
! SHARED_LIB = yes
|
||||
|
||||
_If we omit this statement, Genode's build-system will automatically_
|
||||
_If we omit this statement, Genode's build system will automatically_
|
||||
_build SDL_net as a static library called_ 'sdl_net.lib.a' _that_
|
||||
_is linked directly into the application._
|
||||
|
||||
It is a reasonable to create a dummy application that uses the
|
||||
It is reasonable to create a dummy application that uses the
|
||||
library because it is only possible to build libraries automatically
|
||||
as a dependency of an application.
|
||||
|
||||
@ -702,16 +697,15 @@ _libports/src/test/libports/sdl_net/target.mk_ with the following content:
|
||||
|
||||
! vpath main.cc $(PRG_DIR)/..
|
||||
|
||||
At this point we normally would also create _lib/import/import-sdl_net.mk_
|
||||
At this point we also create _lib/import/import-sdl_net.mk_
|
||||
with the following content:
|
||||
|
||||
! REP_INC_DIR += include/SDL
|
||||
! SDL_NET_PORT_DIR := $(call select_from_ports,sdl_net)
|
||||
! INC_DIR += $(SDL_NET_PORT_DIR)/include $(SDL_NET_PORT_DIR)/include/SDL
|
||||
|
||||
However in this case this is not necessary because _SDL_net_ depends on
|
||||
libSDL which already provides its own _import-sdl.mk_ file with exactly
|
||||
the same content. While preparing SDL_net we placed a symbolic link in
|
||||
just this directory and therefore every user of SDL_net already knows
|
||||
about this directory.
|
||||
Each port that depends on SDL_net and has added it to its LIBS variable
|
||||
will automatically include the _import-sdl_net.mk_ file and therefore
|
||||
will use the specified include directory to find the _SDL_net.h_ header.
|
||||
|
||||
|
||||
Compiling the library
|
||||
@ -737,13 +731,13 @@ Porting applications or libraries to Genode always may involve this kind of
|
||||
choice. Which way is the best has to be decided by closely examining the
|
||||
matter at hand. Sometimes it is better to implement the missing functions
|
||||
and sometimes it is more beneficial to change the contributed code.
|
||||
In this case we opt for changing SDL_net because the former function is
|
||||
In this case, we opt for changing SDL_net because the former function is
|
||||
obsolete anyway and implementing 'gethostbyaddr(3)' involves changes to
|
||||
several libraries in Genode, namely libc and the network related
|
||||
libc plugin. Although we have to keep in mind that is likely to encounter
|
||||
libc plugin. Although we have to keep in mind that it is likely to encounter
|
||||
another application or library that also uses this function in the future.
|
||||
|
||||
With this change in place SDL_net compiles fine.
|
||||
With this change in place, SDL_net compiles fine.
|
||||
|
||||
_(*) Actually this function is implemented in the Genode's_ libc _but is_
|
||||
_only available by using libc_resolv which we did not do for the sake of_
|
||||
@ -755,15 +749,16 @@ Testing the library
|
||||
|
||||
The freshly ported library is best tested with the application, which was the
|
||||
reason the library was ported in the first place, since it is unlikely that
|
||||
we port a library just for fun and profit. Therefore, it is not necessary to
|
||||
we port a library just for fun and no profit. Therefore, it is not necessary to
|
||||
write a run script for a library alone.
|
||||
|
||||
For the records, here is a list of all files that were created by
|
||||
porting SDL_net to Genode:
|
||||
|
||||
! libports/lib/mk/sdl_net.mk
|
||||
! libports/ports/sdl_net.inc
|
||||
! libports/ports/sdl_net.mk
|
||||
! libports/lib/mk/import/import-sdl_net.mk
|
||||
! libports/ports/sdl_net.hash
|
||||
! libports/ports/sdl_net.port
|
||||
! libports/src/lib/sdl_net/SDLnet.patch
|
||||
! libports/test/libports/sdl_net/target.mk
|
||||
|
||||
@ -774,14 +769,14 @@ Porting an application to Genode's Noux runtime
|
||||
Porting an application to Genode's Noux runtime is basically the same as
|
||||
porting a program to natively run on Genode. The source code has to be
|
||||
prepared and, if needed, patched to run in Noux. However in contrast to
|
||||
this there are Noux build rules (_ports/mk/noux.mk_) that enable us to use
|
||||
this, there are Noux build rules (_ports/mk/noux.mk_) that enable us to use
|
||||
the original build-tool if it is based upon Autotools. Building the
|
||||
application is done within a cross-compile environment. In this environment
|
||||
all needed variables like 'CC', 'LD', 'CFLAGS' and so on are set to their
|
||||
proper values. In addition to these precautions, using _noux.mk_ simplifies certain things.
|
||||
The system-call handling/functions is/are implemented in the libc plugin
|
||||
_libc_noux_ (the source code is found in _ports/src/lib/libc_noux_). All
|
||||
application running in Noux have to be linked against this library which is
|
||||
applications running in Noux have to be linked against this library which is
|
||||
done implicitly by using the build rules of Noux.
|
||||
|
||||
As an example on how to port an application to Genode's Noux runtime, we
|
||||
@ -801,58 +796,33 @@ process:
|
||||
! $ make > build.log 2>&1
|
||||
|
||||
|
||||
Creating the port Makefile
|
||||
==========================
|
||||
Creating the port file
|
||||
======================
|
||||
|
||||
We start by creating the port Makefile _ports/ports/tar.mk_:
|
||||
|
||||
! GNUTAR = tar-1.27
|
||||
! GNUTAR_TXZ = $(GNUTAR).tar.xz
|
||||
! GNUTAR_SIG = $(GNUTAR_TXZ).sig
|
||||
! GNUTAR_URL = http://ftp.gnu.org/gnu/tar
|
||||
! GNUTAR_KEY = GNU
|
||||
! LICENSE := GPLv3
|
||||
! VERSION := 1.27
|
||||
! DOWNLOADS := tar.archive
|
||||
!
|
||||
! URL(tar) := http://ftp.gnu.org/gnu/tar/tar-$(VERSION).tar.xz
|
||||
! SHA(tar) := 790cf784589a9fcc1ced33517e71051e3642642f
|
||||
! SIG(tar) := ${URL(tar)}.sig
|
||||
! KEY(tar) := GNU
|
||||
! DIR(tar) := src/noux-pkg/tar
|
||||
|
||||
_As of release 13.08 Genode includes integrity checks for downloaded_
|
||||
_3rd-party software. The signature of the downloaded archive will be_
|
||||
_checked prior to extraction. New ports to Genode should always use_
|
||||
_this checks if it is possible. Unfortunately not all projects provide signature_
|
||||
_files though._
|
||||
_As of version 14.05, Genode does not check the signature specified via_
|
||||
_the SIG and KEY declaration but relies the SHA checksum only. However,_
|
||||
_as signature checks are planned in the future, we use to include the_
|
||||
_respective declarations if signature files are available._
|
||||
|
||||
The remaining part of the port Makefile looks like this:
|
||||
|
||||
! #
|
||||
! # Interface to top-level prepare Makefile
|
||||
! #
|
||||
! PORTS += $(GNUTAR)
|
||||
!
|
||||
! prepare:: $(CONTRIB_DIR)/$(GNUTAR)
|
||||
!
|
||||
! #
|
||||
! # Port-specific local rules
|
||||
! #
|
||||
! $(DOWNLOAD_DIR)/$(GNUTAR_TXZ):
|
||||
! $(VERBOSE)wget -c -P $(DOWNLOAD_DIR) $(GNUTAR_URL)/$(GNUTAR_TXZ) && touch $@
|
||||
!
|
||||
! $(DOWNLOAD_DIR)/$(GNUTAR_SIG):
|
||||
! $(VERBOSE)wget -c -P $(DOWNLOAD_DIR) $(GNUTAR_URL)/$(GNUTAR_SIG) && touch $@
|
||||
!
|
||||
! $(CONTRIB_DIR)/$(GNUTAR): $(DOWNLOAD_DIR)/$(GNUTAR_TXZ).verified
|
||||
! $(VERBOSE)tar xfJ $(<:.verified=) -C $(CONTRIB_DIR) && touch $@
|
||||
!
|
||||
! $(DOWNLOAD_DIR)/$(GNUTAR_TXZ).verified: $(DOWNLOAD_DIR)/$(GNUTAR_TXZ) \
|
||||
! $(DOWNLOAD_DIR)/$(GNUTAR_SIG)
|
||||
! $(VERBOSE)$(SIGVERIFIER) $(DOWNLOAD_DIR)/$(GNUTAR_TXZ) \
|
||||
! $(DOWNLOAD_DIR)/$(GNUTAR_SIG) $(GNUTAR_KEY)
|
||||
! $(VERBOSE)touch $@
|
||||
|
||||
Its almost the same as the previous shown port Makefile but adds rules for
|
||||
verifying the archive signature.
|
||||
While porting GNU tar we will use a dummy hash as well.
|
||||
|
||||
|
||||
Creating the build rule
|
||||
=======================
|
||||
|
||||
Build rules for Noux packages are located in _ports/src/noux-pkgs_.
|
||||
Build rules for Noux packages are located in _<genode-dir>/ports/src/noux-pkgs_.
|
||||
|
||||
The _tar/target.mk_ corresponding to GNU tar looks like this:
|
||||
|
||||
@ -964,13 +934,8 @@ Now we can trigger the compilation of tar by executing
|
||||
_At least on the first compilation attempt, it is wise to unset_ 'VERBOSE'
|
||||
_because it enables us to see the whole output of the_ 'configure' _process._
|
||||
|
||||
If configure is not able to find a particular header file the first place
|
||||
to look is generally _libports/include/libc_. This directory is populated by
|
||||
the rules in _libports/ports/libc.mk_. So if a header file is indeed
|
||||
missing, adding the relevant header there is necessary.
|
||||
|
||||
By now Genode provides almost all libc header files that are used by
|
||||
typical POSIX programs. In most cases it is rather a matter of enabling
|
||||
By now, Genode provides almost all libc header files that are used by
|
||||
typical POSIX programs. In most cases, it is rather a matter of enabling
|
||||
the right definitions and compilation flags. It might be worth to take a
|
||||
look at FreeBSD's ports tree because Genode's libc is based upon the one
|
||||
of FreeBSD 8.2.0 and if certain changes to the contributed code are needed,
|
||||
@ -1060,7 +1025,7 @@ system call and it is difficult to see in which.
|
||||
|
||||
Anyhow, 'fstatat' is not properly implemented. At this point, we either have
|
||||
to add this function to the Genode's libc or rather add it to libc_noux.
|
||||
If we add it to the libc not only applications running in Noux will
|
||||
If we add it to the libc, not only applications running in Noux will
|
||||
benefit but all applications using the libc. Implementing it in
|
||||
libc_noux is the preferred way if there are special circumstances because
|
||||
we have to treat the function differently when used in Noux (e.g. 'fork').
|
||||
@ -1068,10 +1033,12 @@ we have to treat the function differently when used in Noux (e.g. 'fork').
|
||||
For the sake of completeness here is a list of all files that were created by
|
||||
porting GNU tar to Genode's Noux runtime:
|
||||
|
||||
! ports/ports/tar.mk
|
||||
! ports/ports/tar.hash
|
||||
! ports/ports/tar.port
|
||||
! ports/run/noux_tar.run
|
||||
! ports/src/noux-pkg/tar/target.mk
|
||||
|
||||
|
||||
Extensive build rules example
|
||||
=============================
|
||||
|
||||
@ -1091,7 +1058,7 @@ porting a program to Noux:
|
||||
! --sbindir=/bin \
|
||||
! --libexecdir=/bin
|
||||
|
||||
In addition to the normal configure options we have to also define the
|
||||
In addition to the normal configure options, we have to also define the
|
||||
path prefixes. The OpenSSH build system embeds certain paths in the
|
||||
ssh binary, which need to be changed for Noux.
|
||||
|
||||
@ -1106,7 +1073,7 @@ Noux build rules.
|
||||
|
||||
! LIBS += libcrypto libssl zlib libc_resolv
|
||||
|
||||
As OpenSSH depends on several libraries we need to include these in the
|
||||
As OpenSSH depends on several libraries, we need to include these in the
|
||||
build Makefile. These libraries are runtime dependencies and need to be
|
||||
present when running OpenSSH in Noux.
|
||||
|
||||
@ -1138,7 +1105,7 @@ way is to do it before building the Noux package:
|
||||
The target _noux_built.tag_ is a special target defined by the Noux build
|
||||
rules. It will be used by the build rules when building the Noux package.
|
||||
We add the 'Makefile_patch' target as a dependency to it. So after configure
|
||||
is executed the generated Makefile will be patched.
|
||||
is executed, the generated Makefile will be patched.
|
||||
|
||||
Autoconf's configure script checks if all requirements are fulfilled and
|
||||
therefore, tests if all required libraries are installed on the host system.
|
||||
@ -1162,6 +1129,7 @@ script by providing dummy libraries:
|
||||
! libz.a:
|
||||
! $(VERBOSE)$(AR) -rc $@
|
||||
|
||||
|
||||
Porting devices drivers
|
||||
#######################
|
||||
|
||||
@ -1194,14 +1162,15 @@ Basic driver structure
|
||||
|
||||
The first step in porting a driver is to identify the driver code that has to be
|
||||
ported. Once the code is located, we usually create a new Genode repository and
|
||||
write a Makefile that downloads and extracts the code to a directory called
|
||||
_contrib_ (see 'dde_linux/Makefile') thus implementing the 'make prepare'
|
||||
command for the repository. Having the source code ready, there are three main
|
||||
tasks the environment must implement. The first is the driver back end, which is
|
||||
responsible for raw device access using Genode primitives, the actual
|
||||
environment that emulates Linux function calls the driver code is using, and the
|
||||
front end, which exposes for example some Genode-session interface (like NIC or
|
||||
block session) that client applications can connect to.
|
||||
write a port file to download and extract the code. It is good practice to name
|
||||
the port and the hash file like the new repository, e.g. _dde_linux.port_ if
|
||||
the repository directory is called _<genode-dir>/repos/dde_linux_.
|
||||
Having the source code ready, there are three main tasks the environment must
|
||||
implement. The first is the driver back end, which is responsible for raw device
|
||||
access using Genode primitives, the actual environment that emulates Linux
|
||||
function calls the driver code is using, and the front end, which exposes for
|
||||
example some Genode-session interface (like NIC or block session) that client
|
||||
applications can connect to.
|
||||
|
||||
|
||||
Further preparations
|
||||
@ -1241,14 +1210,14 @@ following code snippet in your _*.mk_ file which does the trick:
|
||||
!# Determine the header files included by the contrib code. For each
|
||||
!# of these header files we create a symlink to _lx_emul.h_.
|
||||
!#
|
||||
!GEN_INCLUDES := $(shell grep -rh "^\#include .*\/" $(CONTRIB_DIR) |\
|
||||
!GEN_INCLUDES := $(shell grep -rh "^\#include .*\/" $(DRIVER_CONTRIB_DIR) |\
|
||||
! sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" | \
|
||||
! sort | uniq)
|
||||
!
|
||||
!#
|
||||
!# Filter out original Linux headers that exist in the contrib directory
|
||||
!#
|
||||
!NO_GEN_INCLUDES := $(shell cd $(CONTRIB_DIR); find -name "*.h" | sed "s/.\///" | \
|
||||
!NO_GEN_INCLUDES := $(shell cd $(DRIVER_CONTRIB_DIR); find -name "*.h" | sed "s/.\///" | \
|
||||
! sed "s/.*include\///")
|
||||
!GEN_INCLUDES := $(filter-out $(NO_GEN_INCLUDES),$(GEN_INCLUDES))
|
||||
!
|
||||
@ -1275,6 +1244,12 @@ following code snippet in your _*.mk_ file which does the trick:
|
||||
Make sure 'LX_INC_DIR' is the directory containing the _lx_emul.h_ file. Note
|
||||
that 'GEN_INC' is added to your 'INC_DIR' variable.
|
||||
|
||||
The 'DRIVER_CONTRIB_DIR' variable is defined by calling the _select_from_port_
|
||||
function at the beginning of a Makefile or a include file, which is used by
|
||||
all other Makefiles:
|
||||
|
||||
! DRIVER_CONTRIB_DIR := $(call select_from_ports,driver_repo)/src/lib/driver_repo
|
||||
|
||||
The process of function definition and type declaration continues until the code
|
||||
compiles. This process can be quite tiresome. When the driver code finally compiles, the
|
||||
next stage is linking. This will of course lead to another whole set of errors
|
||||
@ -1428,7 +1403,7 @@ When 'probe' returns successful, you may either test other driver functions by
|
||||
hand or start building the front-end.
|
||||
|
||||
|
||||
The front-end
|
||||
The front end
|
||||
=============
|
||||
|
||||
An important design question is how the front end is attached to the driver. In
|
||||
|
Loading…
x
Reference in New Issue
Block a user