文章

libgpiod在Nim中的使用

由于Ubuntu 20系统自带的libgpiod库(版本V1.4.1)存在bug:在监听一组gpio状态后,再一次读取多个gpio的状态时会得到错误的结果。虽然在后面的更新中,该bug已经修复,但为了不破坏系统软件包的版本,并且一劳永逸的避免其它的bug,我决定在Nim中使用最新的libgpiod库,并且静态链接到我的程序,摆脱对系统库的依赖。那就一步一步的开始吧!

下载最新的libgpiod库

1
git clone https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git

配置和编译

我的目标系统是arm64的linux,首先安装交叉编译工具:

1
sudo apt install gcc-aarch64-linux-gnu

然后开始配置libgpiod库。为了便于移植,我把库的安装路径配置为工程的out目录下:

1
./autogen.sh --enable-tools=yes --prefix=$(pwd)/out --host=aarch64-linux-gnu

配置完成后,就是make编译了:

1
make

最后链接的时候出错了:

/usr/lib/gcc-cross/aarch64-linux-gnu/9/../../../../aarch64-linux-gnu/bin/ld: ./.libs/libtools-common.a(tools-common.o): in function `chip_paths':
/linux/app/libgpiod/tools/tools-common.c:456: undefined reference to `rpl_malloc'
/usr/lib/gcc-cross/aarch64-linux-gnu/9/../../../../aarch64-linux-gnu/bin/ld: ./.libs/libtools-common.a(tools-common.o): in function `resolver_init':
/linux/app/libgpiod/tools/tools-common.c:580: undefined reference to `rpl_malloc'
collect2: error: ld returned 1 exit status
make[2]: *** [Makefile:493: gpiodetect] Error 1
make[2]: Leaving directory '/linux/app/libgpiod/tools'
make[1]: *** [Makefile:465: all-recursive] Error 1
make[1]: Leaving directory '/linux/app/libgpiod'
make: *** [Makefile:395: all] Error 2

错误原因是找不到rpl_malloc函数,直接使用系统的malloc函数就好。

打开config.h.in文件,将最后一行的#undef malloc注释掉,然后重新make即可。

最后进行安装:

1
make install

然后检查一下最终生成的文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
out/
├── bin
│   ├── gpiodetect
│   ├── gpioget
│   ├── gpioinfo
│   ├── gpiomon
│   ├── gpionotify
│   └── gpioset
├── include
│   └── gpiod.h
└── lib
    ├── libgpiod.a
    ├── libgpiod.la
    ├── libgpiod.so -> libgpiod.so.3.1.0
    ├── libgpiod.so.3 -> libgpiod.so.3.1.0
    ├── libgpiod.so.3.1.0
    └── pkgconfig
        └── libgpiod.pc

4 directories, 13 files

其中libgpiod.agpiod.h就是我们开发所需要的静态库和头文件,真是太好了!

库的使用

使用nimble新建一个Nim的工程,再在工程中新建一个libgpiod的目录,最后将libgpiod.agpiod.h放入其中。

将Futhark库的依赖添加到nimble项目文件中:

1
requires "futhark >= 0.12.0"

然后通过Futhark将libgpiod库自动化导入到Nim中,为了简便起见,我们只测试了libgpiod库的API版本号获取函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
when defined(useFuthark) :
  import futhark, os

  importc:
    outputPath currentSourcePath.parentDir / "libgpiod.nim"
    path "../libgpiod"
    "gpiod.h"
else:
  include "libgpiod.nim"

{.passL: "-Llibgpiod -lgpiod".}

echo gpiodapiversion()

首次交叉编译我们需要生成对应的libgpiod.nim接口文件:

1
nimble build --os:linux --cpu:arm64 -d:useFuthark

为了加快编译,以后每次交叉编译程序都不必强制生成接口文件了:

1
nimble build --os:linux --cpu:arm64

一切大功告成,剩下的就是堆代码了!

本文由作者按照 CC BY 4.0 进行授权