[bootlin/training-materials updates] master: sysdev/beagleplay: add thirdparty lab (39021c87)

Michael Opdenacker michael.opdenacker at bootlin.com
Mon Aug 7 16:25:54 CEST 2023


Repository : https://github.com/bootlin/training-materials
On branch  : master
Link       : https://github.com/bootlin/training-materials/commit/39021c87495b6f85689890b5de57f63d02baddda

>---------------------------------------------------------------

commit 39021c87495b6f85689890b5de57f63d02baddda
Author: Clément Ramirez <clement.ramirez at bootlin.com>
Date:   Wed Jul 19 18:32:49 2023 +0200

    sysdev/beagleplay: add thirdparty lab


>---------------------------------------------------------------

39021c87495b6f85689890b5de57f63d02baddda
 labs/sysdev-thirdparty-beagleplay/dependencies.dia |   1 +
 .../sysdev-thirdparty-beagleplay.tex               | 837 +++++++++++++++++++++
 mk/embedded-linux-beagleplay.mk                    |   1 +
 3 files changed, 839 insertions(+)

diff --git a/labs/sysdev-thirdparty-beagleplay/dependencies.dia b/labs/sysdev-thirdparty-beagleplay/dependencies.dia
new file mode 120000
index 00000000..a834fb5e
--- /dev/null
+++ b/labs/sysdev-thirdparty-beagleplay/dependencies.dia
@@ -0,0 +1 @@
+../sysdev-thirdparty-stm32/dependencies.dia
\ No newline at end of file
diff --git a/labs/sysdev-thirdparty-beagleplay/sysdev-thirdparty-beagleplay.tex b/labs/sysdev-thirdparty-beagleplay/sysdev-thirdparty-beagleplay.tex
new file mode 100644
index 00000000..18a805c1
--- /dev/null
+++ b/labs/sysdev-thirdparty-beagleplay/sysdev-thirdparty-beagleplay.tex
@@ -0,0 +1,837 @@
+\subchapter{Third party libraries and applications}{Objective: Learn
+  how to leverage existing libraries and applications: how to
+  configure, compile and install them}
+
+To illustrate how to use existing libraries and applications, we will
+extend the small root filesystem built in the {\em A tiny embedded
+system} lab to add the {\em ALSA} libraries and tools to run
+basic sound support tests, and the {\em libgpiod} library and
+executables to manage GPIOs. {\em ALSA} stands for {\em Advanced Linux
+Sound Architecture}, and is the Linux audio subsystem.
+
+We'll see that manually re-using existing libraries is quite tedious,
+so that more automated procedures are necessary to make it
+easier. However, learning how to perform these operations manually
+will significantly help you when you face issues with more
+automated tools.
+
+\section{Figuring out library dependencies}
+
+We're going to integrate the {\em alsa-utils}, {\em libgpiod}
+and {\em ipcalc} executables. In our case, the dependency chain
+for {\em alsa-utils} is quite simple, it only depends on the
+{\em alsa-lib} library. {\em libgpiod} and {\em ipcalc} are standalone
+and don't have any dependency.
+
+\includegraphics[width=\textwidth]{labs/sysdev-thirdparty-beagleplay/dependencies.pdf}
+
+Of course, all these libraries rely on the C library, which is not
+mentioned here, because it is already part of the root filesystem
+built in the {\em A tiny embedded system} lab. You might wonder how to
+figure out this dependency tree by yourself. Basically, there are
+several ways, that can be combined:
+
+\begin{itemize}
+\item Read the library documentation, which often mentions the
+  dependencies;
+\item Read the help message of the \code{configure script} (by running
+  \code{./configure --help}).
+\item By running the \code{configure} script, compiling and looking
+  at the errors.
+\end{itemize}
+
+To configure, compile and install all the components of our system,
+we're going to start from the bottom of the tree with {\em alsa-lib},
+then continue with {\em alsa-utils}. Then, we will also build
+{\em libgpiod} and {\em ipcalc}.
+
+\section{Preparation}
+
+For our cross-compilation work, we will need two separate spaces:
+\begin{itemize}
+\item A \emph{staging} space in which we will directly install all the
+  packages: non-stripped versions of the libraries, headers,
+  documentation and other files needed for the compilation. This
+  \emph{staging} space can be quite big, but will not be used on our
+  target, only for compiling libraries or applications;
+\item A \emph{target} space, in which we will only copy the required
+  files from the \emph{staging} space: binaries and libraries, after
+  stripping, configuration files needed at runtime, etc. This target
+  space will take a lot less space than the \emph{staging} space, and
+  it will contain only the files that are really needed to make the
+  system work on the target.
+\end{itemize}
+
+To sum up, the {\em staging} space will contain everything that's
+needed for compilation, while the {\em target} space will contain only
+what's needed for execution.
+
+Create the \code{$HOME/__SESSION_NAME__-labs/thirdparty} directory,
+and inside, create two directories: \code{staging} and \code{target}.
+
+For the target, we need a basic system with BusyBox and
+initialization scripts. We will re-use the system built in the {\em A
+  tiny embedded system} lab, so copy this system in the target
+directory:
+
+\bashcmd{$ cp -a $HOME/__SESSION_NAME__-labs/tinysystem/nfsroot/* target/}
+
+Note that for this lab, a lot of typing will be required. To save time
+typing, we advise you to copy and paste commands from the electronic
+version of these instructions.
+
+\section{Testing}
+
+Make sure the \code{target/} directory is exported by your NFS server
+to your board by modifying \code{/etc/exports} and restarting your NFS
+server.
+
+Make your board boot from this new directory through NFS.
+
+\section{alsa-lib}
+
+{\em alsa-lib} is a library supposed to handle the interaction with
+the ALSA subsystem. It is available at \url{https://alsa-project.org}.
+Download version 1.2.9, and extract it
+in \code{$HOME/__SESSION_NAME__-labs/thirdparty/}.
+
+{\bf Tip}: if the website for any of the source packages that we
+need to download in the next sections is down, a great mirror
+that you can use is \url{http://sources.buildroot.net/}.
+
+Back to {\em alsa-lib} sources, look at the \code{configure} script
+and see that it has been generated by \code{autoconf} (the header
+contains a sentence like {\em Generated by GNU Autoconf 2.69}). Most of
+the time, \code{autoconf} comes with \code{automake}, that generates
+Makefiles from \code{Makefile.am} files. So {\em alsa-lib} uses a rather
+common build system. Let's try to configure and build it:
+
+\begin{bashinput}
+$ ./configure
+$ make
+\end{bashinput}
+
+If you look at the generated binaries, you'll see that they are
+x86 ones because we compiled the sources with gcc, the default compiler.
+This is obviously not what we want, so let's clean-up the generated objects
+and tell the \code{configure} script to use the AARCH64 cross-compiler:
+
+\begin{bashinput}
+$ make clean
+$ CC=aarch64-linux-gcc ./configure
+\end{bashinput}
+
+Of course, the \code{aarch64-linux-gcc} cross-compiler must be in your
+\code{PATH} prior to running the configure script. The \code{CC} environment
+variable is the classical name for specifying the compiler to
+use.
+
+Quickly, you should get an error saying:
+
+%\footnotesize
+\begin{terminaloutput}
+checking whether we are cross compiling... configure: error: in `/home/tux/__SESSION_NAME__-labs/thirdparty/alsa-lib-1.2.9':
+configure: error: cannot run C compiled programs.
+If you meant to cross compile, use `--host'.
+See `config.log' for more details
+\end{terminaloutput}
+\normalsize
+
+If you look at the \code{config.log} file, you can see that the
+\code{configure} script compiles a binary with the cross-compiler
+and then tries to run it on the development workstation. This is a
+rather usual thing to do for a \code{configure} script, and that's
+why it tests so early that it's actually doable, and bails out if not.
+
+Obviously, it cannot work in our case, and the scripts exits. The job
+of the \code{configure} script is to test the configuration of the system. To
+do so, it tries to compile and run a few sample applications to test
+if this library is available, if this compiler option is supported,
+etc. But in our case, running the test examples is definitely not
+possible.
+
+We need to tell the \code{configure} script that we are cross-compiling, and
+this can be done using the \code{--build} and \code{--host} options,
+as described in the help of the \code{configure} script:
+
+\begin{verbatim}
+System types:
+  --build=BUILD	configure for building on BUILD [guessed]
+  --host=HOST	cross-compile to build programs to run on HOST [BUILD]
+\end{verbatim}
+
+The \code{--build} option allows to specify on which system the
+package is built, while the \code{--host} option allows to specify on
+which system the package will run. By default, the value of the
+\code{--build} option is guessed and the value of \code{--host} is the
+same as the value of the \code{--build} option. The value is guessed
+using the \code{./config.guess} script, which on your system should
+return \code{x86_64-pc-linux-gnu}. See
+\url{https://www.gnu.org/software/autoconf/manual/html_node/Specifying-Names.html}
+for more details on these options.
+
+So, let's override the value of the \code{--host} option:
+
+\bashcmd{$ ./configure --host=aarch64-linux}
+
+Note that \code{CC} is not required anymore. It is implied
+by \code{--host}.
+
+The \code{configure} script should end properly now, and create a
+Makefile.
+
+However, there is one subtle issue to handle.
+We need to tell {\em alsa-lib} to disable a feature called alsa topology.
+{\em alsa-lib} will build fine but we will encounter some
+problems afterwards, during {\em alsa-utils} building.
+So you should configure {\em alsa-lib} as follows:
+
+\bashcmd{$ ./configure --host=aarch64-linux --disable-topology}
+
+Run the \code{make} command, which should run just fine.
+
+Look at the result of compiling in \code{src/.libs}: a set of object files
+and a set of \code{libasound.so*} files.
+
+The \code{libasound.so*} files are a dynamic version of the
+library. The shared library itself is \code{libasound.so.2.0.0}, it has
+been generated by the following command line:
+
+\begin{bashinput}
+$ aarch64-linux-gcc -shared conf.o confmisc.o input.o output.o async.o error.o dlmisc.o socket.o shmarea.o userfile.o names.o -lm -ldl -lpthread -lrt -Wl,-soname -Wl,libasound.so.2 -o libasound.so.2.0.0
+\end{bashinput}
+
+And creates the symbolic links \code{libasound.so} and
+\code{libasound.so.2}.
+
+\begin{bashinput}
+$ ln -s libasound.so.2.0.0 libasound.so.2
+$ ln -s libasound.so.2.0.0 libasound.so
+\end{bashinput}
+
+These symlinks are needed for two different reasons:
+
+\begin{itemize}
+\item \code{libasound.so} is used at compile time when you want to
+  compile an application that is dynamically linked against the
+  library. To do so, you pass the \code{-lLIBNAME} option to the
+  compiler, which will look for a file named
+  \code{lib<LIBNAME>.so}. In our case, the compilation option is
+  \code{-lasound} and the name of the library file is
+  \code{libasound.so}. So, the \code{libasound.so} symlink is needed
+  at compile time;
+\item \code{libasound.so.2} is needed because it is the {\em SONAME}
+  of the library. {\em SONAME} stands for {\em Shared Object Name}. It
+  is the name of the library as it will be stored in applications
+  linked against this library. It means that at runtime, the dynamic
+  loader will look for exactly this name when looking for the shared
+  library. So this symbolic link is needed at runtime.
+\end{itemize}
+
+To know what's the {\em SONAME} of a library, you can use:
+\bashcmd{$ aarch64-linux-readelf -d libasound.so.2.0.0}
+
+and look at the \code{(SONAME)} line. You'll also see that this
+library needs the C library, because of the \code{(NEEDED)} line on
+\code{libc.so.0}.
+
+The mechanism of \code{SONAME} allows to change the library without
+recompiling the applications linked with this library. Let's say that
+a security problem is found in the {\em alsa-lib} release that provides
+{\em libasound 2.0.0}, and fixed in the next {\em alsa-lib} release, which will
+now provide {\em libasound 2.0.1}.
+
+You can just recompile the library, install it on your target system,
+change the \code{libasound.so.2} link so that it points to
+\code{libasound.so.2.0.1} and restart your applications. And it will
+work, because your applications don't look specifically for
+\code{libasound.so.2.0.0} but for the {\em SONAME}
+\code{libasound.so.2}.
+
+However, it also means that as a library developer, if you break the
+ABI of the library, you must change the {\em SONAME}: change from
+\code{libasound.so.2} to \code{libasound.so.3}.
+
+Finally, the last step is to tell the \code{configure} script where the
+library is going to be installed. Most \code{configure} scripts consider that
+the installation prefix is \code{/usr/local/} (so that the library is
+installed in \code{/usr/local/lib}, the headers in
+\code{/usr/local/include}, etc.). But in our system, we simply want
+the libraries to be installed in the \code{/usr} prefix, so let's tell
+the \code{configure} script about this:
+
+\begin{bashinput}
+$ ./configure --host=aarch64-linux --disable-topology --prefix=/usr
+$ make
+\end{bashinput}
+
+For this library, this option may not change anything to the resulting
+binaries, but for safety, it is always recommended to make sure that
+the prefix matches where your library will be running on the target
+system.
+
+Do not confuse the {\em prefix} (where the application or library will
+be running on the target system) from the location where the
+application or library will be installed on your host while building
+the root filesystem.
+
+For example, {\em libasound} will be installed in
+\code{$HOME/__SESSION_NAME__-labs/thirdparty/target/usr/lib/} because this is
+the directory where we are building the root filesystem, but once our
+target system will be running, it will see {\em libasound} in
+\code{/usr/lib}.
+
+The prefix corresponds to the path in the target system and {\bf
+  never} on the host. So, one should {\bf never} pass a prefix like
+\code{$HOME/__SESSION_NAME__-labs/thirdparty/target/usr}, otherwise at
+runtime, the application or library may look for files inside this
+directory on the target system, which obviously doesn't exist! By
+default, most build systems will install the application or library in
+the given prefix (\code{/usr} or \code{/usr/local}), but with most
+build systems (including {\em autotools}), the installation prefix can
+be overridden, and be different from the configuration prefix.
+
+We now only have the installation process left to do.
+
+First, let's make the installation in the {\em staging} space:
+\bashcmd{$ make DESTDIR=$HOME/__SESSION_NAME__-labs/thirdparty/staging install}
+
+Now look at what has been installed by {\em alsa-lib}:
+\begin{itemize}
+\item Some configuration files in \code{/usr/share/alsa}
+\item The headers in \code{/usr/include}
+\item The shared library and its libtool (\code{.la}) file in \code{/usr/lib}
+\item A pkgconfig file in \code{/usr/lib/pkgconfig}. We'll come back
+  to these later
+\end{itemize}
+
+Finally, let's install the library in the {\em target} space:
+
+\begin{enumerate}
+\item Create the \code{target/usr/lib} directory, it will contain the
+  stripped version of the library
+\item Copy the dynamic version of the library. Only
+  \code{libasound.so.2} and \code{libasound.so.2.0.0} are needed,
+  since \code{libasound.so.2} is the {\em SONAME} of the library and
+  \code{libasound.so.2.0.0} is the real binary:
+  \begin{itemize}
+  \item \bashcmd{$ cp -a staging/usr/lib/libasound.so.2* target/usr/lib}
+  \end{itemize}
+\item Measure the size of the \code{target/usr/lib/libasound.so.2.0.0}
+  library before stripping.
+\item Strip the library:
+  \begin{itemize}
+  \item \bashcmd{$ aarch64-linux-strip target/usr/lib/libasound.so.2.0.0}
+  \end{itemize}
+\item Measure the size of the \code{target/usr/lib/libasound.so.2.0.0}
+  library library again after stripping. How many unnecessary bytes
+  were saved?
+\end{enumerate}
+
+Then, we need to install the {\em alsa-lib} configuration files:
+
+\begin{bashinput}
+$ mkdir -p target/usr/share
+$ cp -a staging/usr/share/alsa target/usr/share
+\end{bashinput}
+
+Now, we need to adjust one small detail in one of the configuration
+files. Indeed, \code{/usr/share/alsa/alsa.conf} assumes a UNIX group
+called \code{audio} exists, which is not the case on our very small
+system. So edit this file, and replace \code{defaults.pcm.ipc_gid
+audio} by \code{defaults.pcm.ipc_gid 0} instead.
+
+And we're done with {\em alsa-lib}!
+
+\section{Alsa-utils}
+
+Download {\em alsa-utils} from the ALSA offical webpage. We tested the lab
+with version 1.2.9.
+
+Once uncompressed, we quickly discover that the {\em alsa-utils} build
+system is based on the {\em autotools}, so we will work once again
+with a regular \code{configure} script.
+
+As we've seen previously, we will have to provide the prefix and host
+options and the CC variable:
+
+\bashcmd{$ ./configure --host=aarch64-linux --prefix=/usr}
+
+Now, we should quiclky get an error in the execution of the
+\code{configure} script:
+
+\begin{verbatim}
+checking for libasound headers version >= 1.2.5 (1.2.5)... not present.
+configure: error: Sufficiently new version of libasound not found.
+\end{verbatim}
+
+Again, we can check in \code{config.log} what the \code{configure}
+script is trying to do:
+
+%\footnotesize
+\begin{terminaloutput}
+configure:15855: checking for libasound headers version >= 1.2.5 (1.2.5)
+configure:15902: aarch64-linux-gcc -c -g -O2  conftest.c >&5
+conftest.c:24:10: fatal error: alsa/asoundlib.h: No such file or directory
+\end{terminaloutput}
+\normalsize
+
+Of course, since {\em alsa-utils} uses {\em alsa-lib}, it includes
+its header file! So we need to tell the C compiler where the headers
+can be found: there are not in the default directory
+\code{/usr/include/}, but in the \code{/usr/include} directory of our
+{\em staging} space. The help text of the \code{configure} script says:
+
+\begin{verbatim}
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+\end{verbatim}
+
+Let's use it:
+
+\begin{bashinput}
+$ CPPFLAGS=-I$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/include \%\linebreak
+./configure --host=aarch64-linux --prefix=/usr
+\end{bashinput}
+
+Now, it should stop a bit later, this time with the error:
+\begin{verbatim}
+checking for snd_ctl_open in -lasound... no
+configure: error: No linkable libasound was found.
+\end{verbatim}
+
+The \code{configure} script tries to compile an application against {\em
+  libasound} (as can be seen from the \code{-lasound} option): {\em
+  alsa-utils} uses {\em alsa-lib}, so the \code{configure} script
+wants to make sure this library is already installed. Unfortunately,
+the \code{ld} linker doesn't find it. So, let's tell the
+linker where to look for libraries using the \code{-L} option followed
+by the directory where our libraries are (in
+\code{staging/usr/lib}). This \code{-L} option can be passed to the
+linker by using the \code{LDFLAGS} at configure time, as told by the
+help text of the \code{configure} script:
+
+\begin{verbatim}
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+\end{verbatim}
+
+Let's use this \code{LDFLAGS} variable:
+
+\begin{bashinput}
+$ LDFLAGS=-L$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/lib \
+     CPPFLAGS=-I$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/include \
+     ./configure --host=aarch64-linux --prefix=/usr
+\end{bashinput}
+
+Once again, it should fail a bit further down the tests, this time
+complaining about a missing {\em curses helper header}. {\em curses}
+or {\em ncurses} is a graphical framework to design UIs in the
+terminal. This is only used by {\em alsamixer}, one of the tools
+provided by {\em alsa-utils}, that we are not going to use.
+Hence, we can just disable the build of {\em alsamixer}.
+
+Of course, if we wanted it, we would have had to build {\em ncurses} first,
+just like we built {\em alsa-lib}.
+
+\begin{bashinput}
+$ LDFLAGS=-L$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/lib \
+     CPPFLAGS=-I$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/include \
+     ./configure --host=aarch64-linux --prefix=/usr \
+     --disable-alsamixer
+\end{bashinput}
+
+Then, run the compilation with \code{make}. You should hit a final
+error:
+
+\begin{verbatim}
+Making all in po
+make[2]: Entering directory '/home/tux/embedded-linux-beagleplay-labs/thirdparty/alsa-utils-1.2.9/alsaconf/po'
+mv: cannot stat 't-ja.gmo': No such file or directory
+\end{verbatim}
+
+This can be fixed by disabling support for \code{alsaconf} too:
+
+\begin{bashinput}
+$ LDFLAGS=-L$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/lib \
+     CPPFLAGS=-I$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/include \
+     ./configure --host=arm-linux --prefix=/usr \
+     --disable-alsamixer --disable-alsaconf
+\end{bashinput}
+
+You can now run \code{make} again.  It should work this time.
+
+Let's now begin the installation process.  Before really installing in
+the staging directory, let's install in a dummy directory, to see
+what's going to be installed (this dummy directory will not be used
+afterwards, it is only to verify what will be installed before
+polluting the staging space):
+
+\bashcmd{$ make DESTDIR=/tmp/alsa-utils/ install}
+
+The \code{DESTDIR} variable can be used with all Makefiles based on
+\code{automake}. It allows to override the installation directory:
+instead of being installed in the configuration prefix directory, the
+files will be installed in \code{DESTDIR/configuration-prefix}.
+
+Now, let's see what has been installed in \code{/tmp/alsa-utils/} (run
+\code{tree /tmp/alsa-utils}):
+
+\begin{verbatim}
+/tmp/alsa-utils/
+|-- lib
+|   `-- udev
+|       `-- rules.d
+|           `-- 90-alsa-restore.rules
+|-- usr
+|   |-- bin
+|   |   |-- aconnect
+|   |   |-- alsabat
+|   |   |-- alsaloop
+|   |   |-- alsaucm
+|   |   |-- amidi
+|   |   |-- amixer
+|   |   |-- aplay
+|   |   |-- aplaymidi
+|   |   |-- arecord -> aplay
+|   |   |-- arecordmidi
+|   |   |-- aseqdump
+|   |   |-- aseqnet
+|   |   |-- axfer
+|   |   |-- iecset
+|   |   `-- speaker-test
+|   |-- sbin
+|   |   |-- alsa-info.sh
+|   |   |-- alsabat-test.sh
+|   |   `-- alsactl
+|   `-- share
+|       |-- alsa
+|       |   `-- init
+|       |       |-- 00main
+|       |       |-- ca0106
+|       |       |-- default
+|       |       |-- hda
+|       |       |-- help
+|       |       |-- info
+|       |       `-- test
+|       |-- locale
+|       |   |-- de
+|       |   |   `-- LC_MESSAGES
+|       |   |       `-- alsa-utils.mo
+|       |   |-- eu
+|       |   |   `-- LC_MESSAGES
+|       |   |       `-- alsa-utils.mo
+|       |   |-- fr
+|       |   |   `-- LC_MESSAGES
+|       |   |       `-- alsa-utils.mo
+|       |   |-- ja
+|       |   |   `-- LC_MESSAGES
+|       |   |       `-- alsa-utils.mo
+|       |   |-- ka
+|       |   |   `-- LC_MESSAGES
+|       |   |       `-- alsa-utils.mo
+|       |   `-- sk
+|       |       `-- LC_MESSAGES
+|       |           `-- alsa-utils.mo
+|       |-- man
+|       |   |-- man1
+|       |   |   |-- aconnect.1
+|       |   |   |-- alsa-info.sh.1
+|       |   |   |-- alsabat.1
+|       |   |   |-- alsactl.1
+|       |   |   |-- alsaloop.1
+|       |   |   |-- amidi.1
+|       |   |   |-- amixer.1
+|       |   |   |-- aplay.1
+|       |   |   |-- aplaymidi.1
+|       |   |   |-- arecord.1 -> aplay.1
+|       |   |   |-- arecordmidi.1
+|       |   |   |-- aseqdump.1
+|       |   |   |-- aseqnet.1
+|       |   |   |-- axfer-list.1
+|       |   |   |-- axfer-transfer.1
+|       |   |   |-- axfer.1
+|       |   |   |-- iecset.1
+|       |   |   `-- speaker-test.1
+|       |   `-- man7
+|       `-- sounds
+|           `-- alsa
+|               |-- Front_Center.wav
+|               |-- Front_Left.wav
+|               |-- Front_Right.wav
+|               |-- Noise.wav
+|               |-- Rear_Center.wav
+|               |-- Rear_Left.wav
+|               |-- Rear_Right.wav
+|               |-- Side_Left.wav
+|               `-- Side_Right.wav
+`-- var
+    `-- lib
+        `-- alsa
+\end{verbatim}
+
+So, we have:
+\begin{itemize}
+\item The {\em udev} rules in \code{lib/udev}
+\item The {\em alsa-utils} binaries in \code{/usr/bin} and \code{/usr/sbin}
+\item Some sound samples in \code{/usr/share/sounds}
+\item The various translations in \code{/usr/share/locale}
+\item The manual pages in \code{/usr/share/man/}, explaining how to
+  use the various tools
+\item Some configuration samples in \code{/usr/share/alsa}.
+\end{itemize}
+
+Now, let's make the installation in the {\em staging} space:
+
+\bashcmd{$ make DESTDIR=$HOME/__SESSION_NAME__-labs/thirdparty/staging/ install}
+
+Then, let's manually install only the necessary files in the {\em target}
+space. We are only interested in \code{speaker-test}:
+
+\begin{bashinput}
+$ cd ..
+$ cp -a staging/usr/bin/speaker-test target/usr/bin/
+$ aarch64-linux-strip target/usr/bin/speaker-test
+\end{bashinput}
+
+And we're finally done with {\em alsa-utils}!
+
+Now test that all is working fine by running the \code{speaker-test} util on
+your board, with the headset provided by your instructor plugged
+in. You may need to add the missing libraries from the toolchain
+install directory.
+
+Now you can use:
+
+\begin{itemize}
+
+\item \code{speaker-test} with no arguments to generate {\em pink noise}
+
+\item \code{speaker-test -t sine} to generate a {\em sine wave},
+optionally with \code{-f <freq>} for a specific frequency
+
+\end{itemize}
+
+There you are: you built and ran your first program depending
+on a library different from the C library.
+
+\section{libgpiod}
+
+\subsection{Compiling libgpiod}
+
+We are now going to use {\em libgpiod} (instead of the
+deprecated interface in \code{/sys/class/gpio}, whose executables
+(\code{gpiodetect}, \code{gpioset}, \code{gpioget}...) will
+allow us to drive and manage GPIOs from shell scripts.
+
+Here, we will be using the 2.0.x version of {\em libgpiod}.
+
+\begin{bashinput}
+git clone https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
+cd libgpiod
+git checkout v2.0.x
+\end{bashinput}
+
+As we are not starting from a release, we will need to install
+further development tools to generate some files like the
+\code{configure} script:
+
+\bashcmd{sudo apt install autoconf-archive pkg-config}
+
+Now let's generate the files which are present in a release:
+
+\bashcmd{./autogen.sh}
+
+Run \code{./configure --help} script, and see that this script provides
+a \code{--enable-tools} option which allows to build the userspace
+executables that we want.
+
+As this project doesn't have any external library dependency, let's
+configure {\em libgpiod} in a similar way as {\em alsa-utils}:
+
+\begin{bashinput}
+$ ./configure --host=aarch64-linux --prefix=/usr --enable-tools
+\end{bashinput}
+
+Now, compile the software:
+
+\bashcmd{$ make}
+
+Installation to the {\em staging} space can be done using the
+classical \code{DESTDIR} mechanism:
+
+\begin{bashinput}
+$ make DESTDIR=$HOME/__SESSION_NAME__-labs/thirdparty/staging/ install
+\end{bashinput}
+
+And finally, only manually install and strip the files
+needed at runtime in the {\em target} space:
+
+\begin{bashinput}
+$ cd ..
+$ cp -a staging/usr/lib/libgpiod.so.3* target/usr/lib/
+$ aarch64-linux-strip target/usr/lib/libgpiod*
+$ cp -a staging/usr/bin/gpio* target/usr/bin/
+$ aarch64-linux-strip target/usr/bin/gpio*
+\end{bashinput}
+
+\subsection{Testing libgpiod}
+
+First, connect \code{GPIO1_9} (\code{INT} pin of \code{MiCKROBUS} connector)
+connected to ground (\code{GND} pin of \code{MiCKROBUS} connector), as in the
+{\em Accessing Hardware Devices} lab.
+
+Now, let's run the \code{gpiodetect} command on the target, and check that
+you can list the various GPIO banks on your system.
+
+\begin{bashinput}
+# gpiodetect
+gpiochip0 [4201000.gpio] (24 lines)
+gpiochip1 [600000.gpio] (92 lines)
+gpiochip2 [601000.gpio] (52 lines)
+\end{bashinput}
+
+But how can we know which gpiochip is actually driving our \code{INT} gpio ?
+To do so, different methods can be used. We can look at the device tree of the
+BeaglePlay and see that the controller driving the \code{GPIO1_9} pin has 52 I/O.
+Therefore we can assume that the controller is the \code{gpiochip2}.
+
+We can then get details on GPIOE GPIOs by running \code{gpioinfo
+gpiochip2} or on all GPIOs by simply running \code{gpioinfo}.
+
+You can now read the state of \code{GPIO1_9}:
+
+\begin{bashinput}
+# gpioget -c gpiochip2 9
+"9"=inactive
+\end{bashinput}
+
+Now, connect your wire to 3V3 (pin 3 or 4 of connector P9). You should now
+read:
+
+\begin{bashinput}
+# gpioget -c gpiochip2 9
+"9"=active
+\end{bashinput}
+
+You see that you didn't have to configure the GPIO as input. {\em
+libgpiod} did that for you.
+
+If you have an LED and a small breadboard (or M-F breadboard wires),
+you could also try to drive the GPIO in output mode. Connect the short
+pin of the LED to GND, and the long one to the GPIO. Then then following
+command should light up the diode:
+
+\begin{bashinput}
+# gpioset -c gpiochip2 9=1
+\end{bashinput}
+
+Here's how to turn it off:
+
+\begin{bashinput}
+# gpioset -c gpiochip2 9=0
+\end{bashinput}
+
+\code{gpioset} offers many more options. Run \code{gpioset -h} to
+check by yourself.
+
+\section{ipcalc}
+
+After practicing with autotools based packages, let's build {\em ipcalc}, which
+is using {\em Meson} as build system. We won't really need this utility
+in our system, but at least it has no dependencies and therefore
+offers an easy way to build our first {\em Meson} based package.
+
+So, first install the \code{meson} package:
+
+\bashcmd{$ sudo apt install meson}
+
+In the main lab directory, then let's check out the sources through
+\code{git}:
+
+\begin{bashinput}
+$ git clone https://gitlab.com/ipcalc/ipcalc.git
+$ cd ipcalc/
+$ git checkout 1.0.3
+\end{bashinput}
+
+To cross-compile with {\em Meson}, we need to create a {\em cross file}.
+Let's create the \code{../cross-file.txt} file with the below contents:
+
+\begin{verbatim}
+[binaries]
+c = 'aarch64-linux-gcc'
+
+[host_machine]
+system = 'linux'
+cpu_family = 'aarch64'
+cpu = 'cortex-a53'
+endian = 'little'
+\end{verbatim}
+
+We also need to create a special directory for building:
+
+\begin{bashinput}
+$ mkdir cross-build
+$ cd cross-build
+\end{bashinput}
+
+We can now have \code{meson} create the Ninja build files for us:
+
+\begin{bashinput}
+$ meson --cross-file ../../cross-file.txt --prefix /usr ..
+\end{bashinput}
+
+We are now ready to build {\em ipcalc}:
+
+\begin{bashinput}
+$ ninja
+\end{bashinput}
+
+And now install \code{ipcalc} to the build space:
+
+\begin{bashinput}
+$ DESTDIR=$HOME/__SESSION_NAME__-labs/thirdparty/staging ninja install
+\end{bashinput}
+
+Check that the \code{staging/usr/bin/ipcalc} file is indeed an aarch64
+executable.
+
+The last thing to do is to copy it to the target space and strip it:
+
+\begin{bashinput}
+$ cd ../..
+$ cp staging/usr/bin/ipcalc target/usr/bin/
+$ aarch64-linux-strip target/usr/bin/ipcalc
+\end{bashinput}
+
+Note that we could have asked \code{ninja install} to strip the
+executable for us when installing it into the staging directory.
+To do, this, we would have added a \code{strip} entry in the cross file,
+and passed \code{--strip} to {\em Meson}. However, it's better to keep
+files unstripped in the staging space, in case we need to debug them.
+
+You can now test that \code{ipcalc} works on the target:
+
+\begin{bashinput}
+# ipcalc 192.168.0.100
+Address:	192.168.0.100
+Address space:	Private Use
+\end{bashinput}
+
+\section{Final touch}
+
+To finish this lab completely, and to be consistent with what we've done before,
+let's strip the C library and its loader too.
+
+First, check the initial size of the binaries:
+\bashcmd{$ ls -l target/lib}
+
+Then strip the binaries in \code{/lib}:
+\begin{bashinput}
+$ chmod +w target/lib/*.so.*
+$ aarch64-linux-strip target/lib/*.so.*
+\end{bashinput}
+
+And check the final size:
+\bashcmd{$ ls -l target/lib/}
diff --git a/mk/embedded-linux-beagleplay.mk b/mk/embedded-linux-beagleplay.mk
index 4ed23093..835ee85c 100644
--- a/mk/embedded-linux-beagleplay.mk
+++ b/mk/embedded-linux-beagleplay.mk
@@ -57,3 +57,4 @@ EMBEDDED_LINUX_BEAGLEPLAY_LABS = setup \
 		sysdev-tinysystem \
 		sysdev-accessing-hardware-beagleplay \
 		sysdev-block-filesystems-beagleplay \
+		sysdev-thirdparty-beagleplay \




More information about the training-materials-updates mailing list