Skip to content

Commit 0c3093b

Browse files
authored
Merge pull request #22254 from crasbe/pr/pkg_guide
doc: move Package Porting Tutorial to Guides and extend it
2 parents 5736599 + f8ed819 commit 0c3093b

7 files changed

Lines changed: 402 additions & 128 deletions

File tree

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
---
2+
title: Porting Packages
3+
description: Guide on how to port new libraries to RIOT OS
4+
---
5+
6+
import FileTree from '@components/FileTree.astro';
7+
8+
9+
This guide provides porting information for libraries and applications to use
10+
with RIOT (to build an external module). RIOT generally distinguishes between
11+
modules and packages, where modules are part of the source tree and packages
12+
are pulled in from external sources and repositories.
13+
The reason for using external packages is to avoid maintaining foreign code
14+
as part of the RIOT project and also to avoid potential license issues.
15+
16+
RIOT welcomes new and useful packages. If you'd like to share your work,
17+
consider [contributing](https://github.com/RIOT-OS/RIOT/tree/master/CONTRIBUTING.md).
18+
19+
Since you are now the specialist for this specific package, it would be nice
20+
if you stay contactable for some time after the port, so there is a knowledgeable
21+
person available to help with potential issues that surface later on.
22+
23+
## Structure of a package
24+
25+
If you'd like to add a package to RIOT, you need to add a directory with the
26+
name of your package to the `pkg/` directory.
27+
The directory structure should look like this, and the files marked with an
28+
asterisk are mandatory.
29+
30+
<FileTree>
31+
32+
- \<pkgname\>
33+
- patches
34+
- 0001-your-fancy-changes.patch
35+
- doc.md*
36+
- Makefile*
37+
- Makefile.dep
38+
- Makefile.include
39+
40+
</FileTree>
41+
42+
### doc.md (required)
43+
44+
To help people use your package, it is required to add a `doc.md` Markdown file
45+
to your package folder. Many packages have configuration options, other
46+
dependencies or limitations that might make it non-trivial to use for someone
47+
who is not yet familiar with the package.
48+
49+
### Makefile (required)
50+
51+
The `Makefile` describes how to fetch the upstream application,
52+
apply the patch(es) and how to build the package as a RIOT module.
53+
Two general templates for acquiring a package via git or downloading it via
54+
http are provided in `pkg/Makefile.git` and `pkg/Makefile.http`.
55+
You will have to define a set of variables prefixed with `PKG_` in the
56+
`Makefile`, which are described in more detail in the respective templates.
57+
58+
Depending on the code quality of the package, you might have to disable some
59+
compiler warnings when building the package by extending the `CFLAGS` variable,
60+
for example:
61+
62+
```makefile
63+
CFLAGS += -Wno-sign-compare
64+
CFLAGS += -Wno-strict-aliasing
65+
```
66+
67+
### Makefile.include
68+
69+
If your port or the package provide header files which you want to include
70+
from RIOT or application code, you need to extend the
71+
`INCLUDES` variable in the package's `Makefile.include`. This file is optional.
72+
73+
```makefile
74+
INCLUDES += -I$(RIOTPKG)/<pkg_name>/include # headers provided by the port
75+
INCLUDES += -I$(PKGDIRBASE)/<pkg_name> # headers provided by the package
76+
```
77+
78+
To avoid `clang` checking the documentation and integrety of the external
79+
headers, you can use `-Isystem$(PKGDIRBASE)/<pkg_name>` instead. This will
80+
treat the headers as system headers and not headers that are part of your
81+
code.
82+
83+
### Makefile.dep
84+
85+
The `Makefile.dep` is evaluated during the compilation of the RIOT application
86+
and can be used to pull additional dependencies that are required by your
87+
package. This file is optional.
88+
89+
### patches/
90+
91+
Patch files can be included in a `patches` directory in the package dir.
92+
These are applied to the upstream package to make it build with RIOT.
93+
The patch files should follow the general scheme `000x-descriptive-title.patch`,
94+
some examples are given below.
95+
96+
```
97+
0001-Initial-Changes.patch
98+
0002-Fix-encoding-issues.patch
99+
0003-Add-RIOT-porting-layer.patch
100+
...
101+
```
102+
103+
See [Creating a Patch with git](#creating-a-patch-with-git) for more
104+
information about how to create a patch.
105+
106+
### Additional Sources and Headers
107+
108+
Your package folder can also contain additional source or header files that
109+
are required for the package to work.
110+
Due to the heterogenous nature of external packages, this is highly specific
111+
to the package in question. It is best to look at other packages and their
112+
use of additional source or header files to understand how to use this
113+
feature.
114+
115+
To include the additional headers, you have to create a `Makefile.include` as
116+
discussed above.
117+
118+
## Using git to fetch Packages
119+
120+
***TODO:*** This section should have more information about how `pkg/pkg.mk` works
121+
internally and the steps of preparing a package.
122+
123+
### Using Sparse Checkout
124+
125+
Some repositories can have a considerable size (hundreds of megabytes or even
126+
gigabytes) when often only some files are required.
127+
To avoid having to pull the repository on every fresh rebuild, you can specify
128+
the files you want to use by setting the `PKG_SPARSE_PATHS` variable.
129+
130+
You can either specify subdirectories of the external repository or individual
131+
files:
132+
133+
```makefile
134+
PKG_SPARSE_PATHS += dist/Makefile # individual file
135+
PKG_SPARSE_PATHS += dist/platform/common # folder
136+
```
137+
138+
If you are using an old version of git, you might observe that more files are
139+
copied to your `build/<pkgname>` subdirectory than you have specified. This is
140+
normal and caused by git evaluating the given paths as patterns.
141+
142+
### Using a Local Copy for Development
143+
144+
The build system will always pull a fresh copy of the package from the git
145+
repository linked in your package's `Makefile`.
146+
147+
This can make the development challenging, as every local change will be
148+
overridden by a new compile run, leading to data loss and potentially the loss
149+
of many hours of work.
150+
151+
To avoid having to set up a separate development repository, you can temporarily
152+
specify a local folder using the `PKG_SOURCE_LOCAL` variable in your package's
153+
`Makefile` or by setting `PKG_SOURCE_LOCAL_<pkgname>` in your environment.
154+
155+
```shell
156+
PKG_SOURCE_LOCAL_<pkgname>=~/customized_package_folder make -C tests/pkg/<pkgname>
157+
```
158+
159+
It is recommended to specify an absolute path to avoid path confusion, depending
160+
on the `make` call you used and the current folder your shell is in.
161+
162+
While in theory you can also set `PKG_SOURCE_LOCAL` in the environment, this is
163+
not recommended as it will affect *all* packages and therefore lead to
164+
compilation issues for many microcontrollers, which rely on packages for vendor
165+
files etc.
166+
167+
:::note
168+
Remember to remove the `PKG_SOURCE_LOCAL` variable from your package's
169+
`Makefile` before submitting a Pull Request!
170+
:::
171+
172+
### Using a Mirror URL
173+
174+
Not all packages are hosted on GitHub, which offers nearly unlimited bandwidth
175+
for storing and fetching packages. Some are hosted on small servers that are
176+
easily overloaded or are unreliable.
177+
178+
In that case, you can ask the maintainers to host a mirror on
179+
[the RIOT OS pkgmirror](https://github.com/RIOT-OS-pkgmirror). You should
180+
still set `PKG_URL` to the original repository URL, but you can set
181+
`PKG_MIRROR_URL` to the mirror's URL.
182+
183+
The `PKG_USE_MIRROR` variable works as a switch to select between the original
184+
`PKG_URL` when set to `0` and the `PKG_MIRROR_URL` when set to `1`.
185+
186+
Please note that mirroring a repository should remain the exception.
187+
188+
### Building In-Source and Out-of-Source
189+
190+
Packages come with a variety of different build systems and different
191+
integration approaches. The default approach is called out-of-source building.
192+
The git repository will be cloned into `PKG_SOURCE_DIR`. The default path
193+
for it is `$(PKGDIRBASE)/$(PKG_NAME)`.
194+
If your package has to be built separately from the RIOT build process, for
195+
example when the package is using CMake, the separate `PKG_BUILD_DIR`
196+
directory should be used for the build process. The default path for
197+
it is `$(BINDIR)/pkg-build/$(PKG_NAME)`.
198+
If no separate build process is required, the `PKG_BUILD_DIR` can be left
199+
unused.
200+
201+
Below is a typical file tree for out-of-source building.
202+
`PKGDIRBASE` is typically set to `$(BUILD_DIR)/pkg` and `BUILD_DIR`
203+
is set to `$(RIOTBASE)/build`.
204+
205+
<FileTree>
206+
- $(RIOTBASE)
207+
- examples
208+
- \<application\>
209+
- bin = $(BINDIRBASE)
210+
- \<board\> = $(BINDIR)
211+
- pkg-build
212+
- \<pkgname\> = $(PKG_BUILD_DIR)
213+
- build = $(BUILD_DIR)
214+
- pkg = $(PKGDIRBASE)
215+
- \<pkgname\> = $(PKG_SOURCE_DIR)
216+
217+
</FileTree>
218+
219+
:::note
220+
You can change `PKG_SOURCE_DIR` and `PKG_BUILD_DIR` in your package's
221+
`Makefile`, but you should not change `PKGDIRBASE`, `BINDIR` or
222+
`BUILD_DIR`, as this can quickly lead to unforeseen side effects.
223+
:::
224+
225+
If your package can not be build out-of-source, you can set the
226+
`PKG_BUILD_OUT_OF_SOURCE` variable to `0`. This will cause the buildsystem
227+
to set `$(PKG_BUILD_DIR) = $(PKG_SOURCE_DIR) = $(BINDIR)/pkg/$(PKG_NAME)`.
228+
229+
The `PKG_SOURCE_DIR` can be changed, while the `PKG_BUILD_DIR` is fixed.
230+
231+
<FileTree>
232+
233+
- $(RIOTBASE)
234+
- examples
235+
- \<application\>
236+
- bin = $(BINDIRBASE)
237+
- \<board\> = $(BINDIR)
238+
- pkg
239+
- \<pkgname\> = $(PKG_SOURCE_DIR) = $(PKG_BUILD_DIR)
240+
241+
</FileTree>
242+
243+
Special precautions have been taken to avoid deleting source files, when the
244+
`clean` target is called, so only intermediate build files are deleted.
245+
246+
In-source builds are the exception and only very few packages require it.
247+
248+
## Using http to fetch Packages
249+
250+
If your package is not available in form of a repository, you can base your
251+
package's `Makefile` on the `pkg/Makefile.http` example and fill out the
252+
individual build steps that are required by your package.
253+
254+
The http-based process is lacking many of the quality-of-life features that
255+
the git-based process offers. For example, the automatic patching is currently
256+
only supported for git-based packages and has to be implemented manually
257+
for http based packages.
258+
259+
## Creating a Patch with git
260+
261+
Assuming your upstream library resides in a git repository, you can create the
262+
patch files as follows:
263+
- checkout the targeted version of the upstream application
264+
- create a new branch (e.g. `riot-port` by executing `git checkout -b riot-port`)
265+
- conduct necessary changes (e.g. edit, add, or remove some files)
266+
- commit your changes using `git commit`. Remember to add a detailed
267+
description in your commit, as this will be added to the patch as well.
268+
- create the patch files using `git format-patch -n riot-port`
269+
- move the resulting patch files to the `patches/` directory of your package
270+
- see [patches/](#patches) for more information about how to name your
271+
patch files
272+
273+
Try to keep the patches of reasonable size to help with the review process.
274+
Patches often have to be updated when changes in the upstream repository were
275+
made and having specific patches can make the update process a lot easier.
276+
277+
If you have discovered any bugs or changes that the upstream repository would
278+
also benefit from, you should of course create a Pull Request at the upstream
279+
repository and keep the patch singled out. Once your Pull Request was merged,
280+
you can remove the individual patch file.
281+
282+
## Packages outside of RIOTPKG
283+
284+
It can be beneficial to create packages outside of the RIOT tree. For example
285+
if one is working on new packages that aren't ready to be committed to
286+
upstream or if an application needs its own unique packages. For this, one
287+
can use the `EXTERNAL_PKG_DIRS` make variable. It works similar to the way
288+
[external modules](https://guide.riot-os.org/advanced_tutorials/creating_modules/#modules-outside-of-riotbase)
289+
are handled. In your application's `Makefile`, in addition to adding the package
290+
name to `USEPKG` as shown above, add the path to a folder that contains your
291+
external packages:
292+
293+
```makefile
294+
EXTERNAL_PKG_DIRS += <PATH_TO_FOLDER_CONTAINING_PACKAGES>
295+
```
296+
297+
The path is allowed to be relative to the application's directory.
298+
299+
:::note
300+
The name of an external package must be unique (both in regard to
301+
other external packages, as well to native RIOT packages). Additionally, the
302+
directory containing the packages must match the package name, e.g. package
303+
`foo` must be located in `<PATH_IN_EXTERNAL_PKG_DIRS>/foo`.
304+
:::
305+
306+
An example can be found in
307+
[`tests/build_system/external_pkg_dirs`](https://github.com/RIOT-OS/RIOT/tree/master/tests/build_system/external_pkg_dirs)

0 commit comments

Comments
 (0)