背景
組み込み機器を扱っているとしばしば発生するのが「メーカー提供のライブラリを使用してください」というシチュエーション。そのライブラリはコンパイル済のものでARMだと.aの拡張子で提供されていたりします。
Zephyrベースのサンプルはある
nRF Connect SDKのセットにも含まれていますが、external_libというプロジェクト名で用意されています。
ただし、このサンプルプロジェクトはmain.c以外にmylib.cとmylib.hがあり、同時にコンパイルをして生成されたlibmylib.aを最後にリンクするというものになっています。つまり、最初のシチュエーションで説明した「メーカー提供のコンパイル済ライブラリ」を結合するのとは微妙に異なります。
メーカーもソースコードレベルで提供してくれればどんなに楽なことか…。
今はGithubで公開する時代だと思っていたんだけど…。
libmylib.aを使う
とりあえずSDKにあるexternal_libを動かしてみましょう。ビルドするとbuildフォルダの下にlibというフォルダがあり、そこにlibmylib.aというライブラリファイルが生成されているのでそれを流用します。
たったこれだけのものでも自分で作るのはめんどくさいので…。
続いてhello_worldのサンプルを作ります。別に何のプロジェクトでも構わないのですが、目的からはhello_worldが一番よいでしょう。
まずは先ほどの.aファイルと.hをコピーします。どこに置いてもよいのですが分かりやすくsrcフォルダと同階層にlibフォルダを作って置くことにします。


CMakeLists.txtを編集する
ライブラリを取り込むためにはCmakeLists.txtに追記が必要になります。元々参考にしたサンプルのexternal_libのCMakeLists.txtは非常に複雑な記述がされていますが、今回追加した形に対応するには以下のような形で大丈夫です。
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hello_world_lib)
target_sources(app PRIVATE src/main.c)
include_directories(${APPLICATION_SOURCE_DIR}/lib)
add_library(libmylib.a STATIC IMPORTED)
target_link_libraries(app PUBLIC ${APPLICATION_SOURCE_DIR}/lib/libmylib.a)
追加されたのはtarget_sources以下の部分で、上から順に
・インクルードパスの追加
・結合するライブラリの指定
・ライブラリの絶対パス
になります。
実はこのあたりの記述は完全には理解できておりません…。
main.cからライブラリ内の関数を呼び出す
元々引用したexternal_libのソースコードを見てみると、それぞれ以下のようになっています。
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <mylib.h>
int main(void)
{
printf("Hello World! %s\n", CONFIG_BOARD);
mylib_hello_world();
return 0;
}
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "mylib.h"
#include <stdio.h>
int mylib_hello_world(void)
{
printf("mylib says: Hello World!\n");
return 0;
}
hello_worldプロジェクト内のmain.cからmylib_hello_world()でライブラリ内の関数を呼び出す手続きが必要になります。
実行結果
これをビルドして実行してみると…。

ちゃんとmain.cからライブラリ内の関数を呼び出して実行しています。
余談
メーカー提供のライブラリを組み込むと動かないのでこんなものを作って動作検証していたりします…。誰か助けて!(笑)