ソフトな忘却力(4) 自動生成のCMakeLists.txtを改造して「自分の」にする

Joseph Halfmoon

前回はVS Code拡張 ”CMake Tools” のクイックスタートを使ってみました。これでとりあえず空のディレクトリを「CMakeできる」ようにしてくれた、と。ここを出発点に自分でCMakeLists.txtを書き換えて「お好み」な感じにしてみます。CMake Tools自体、設定すればいろいろやってくれそうではあるのですが、CMakeのお勉強かねて直接。

(PC上のVS Codeから、リモート接続したRaspberry Pi OS<32bit>機で作業しています。使用しているコンパイラは gcc 8.3.0 です。)

前回 VS CodeのExtensionである CMake Toolsのクイックスタートを使ってみました。これで、CPPソースからの実行ファイル生成プロジェクトの雛形と、ライブラリ生成プロジェクトの雛形が作れることが分かりました。実際には Hello world レベルです。も少し機能を追加したいです。今回は実行ファイル生成用の雛形ディレクトリの CMakeLists.txtを出発点に「改造」を試みました。改造にあたっては、以下のリファレンス・ドキュメントを参照させていただきましたが、ともかく分量多くて彷徨いますです。

CMake Reference Documentation

まず、前回生成のCMakeLists.txt を見てみます。CTest と CPACK を除くと実体は以下のたった3行であることに気づきました。CTestはテストランナー、CPACKはインストーラという理解です。どちらも「後でやるつもり」です(本当にやれよ自分。)

cmake_minimum_required(VERSION 3.0.0)
project(tst000 VERSION 0.1.0)
add_executable(tst000 main.cpp)

なんだ3行じゃん、などと言いながら改造の方針は以下としました。

  1. 使用言語をCPPからCに変更
  2. 複数のソースファイルと階層をもったディレクトリ内のライブラリ・プロジェクトを含む

デフォルトで何も指定しないとCPPになるようです。今回はともかく「改造」ということで勝手にCに変更してみます。また、mainだけだったソースに、subという別ファイルやら、libサブディレクトリ内のfuncやらを追加してみました。階層構造はこんな感じになります。

  • Project Root
    • CMakeList.txt
    • main.c
    • sub.c
    • sub.h
    • lib
      • CMakeList.txt
      • func.c
    • include
      • func.h

さて、ルートにおかれたCMakeLists.txtの改造からです。まずは、cmake_minimum_requiredで指定しているバージョンを実際に使用されるcmakeのバージョンに合わせてみました。そうでなければならない理由はないのですが「改造」ということで。殊更に変更してみただけ。

cmake_minimum_required(VERSION 3.16.3)

次に project()を改造。自動生成されたものは、プロジェクト名とVERSIONのみを指定しており、言語については何も指定していませんでした。多分デフォはCPPなので、殊更に ”LANGUAGES C” 指定。当然ですが、実際のソースファイル類もCで書いておかねばなりませぬ。

project(tst000
    VERSION 0.2.0
    LANGUAGES C)

続いて肝心のビルドのターゲットですが、以下のような3行としてみました。まず、add_executable()は、ターゲット tst000、ソース入力ファイル main.cpp だったものを、ソース入力ファイルとして main.c と sub.c の2つを記述しました(当然、簡単なソースファイルを作成の上。)

続いてサブディレクトリ lib を掘ってその中に ライブラリ・プロジェクトを格納してみます。サブディレクトリを巻き込むため add_subdirectory(lib)などとしてみました。そしてサブディレクトリ内の処理の結果として、静的なライブラリ libfunc.a が生成される筈なので、ターゲット tst000 にライブラリ funcをリンクしてもらうため、target_link_libraries()行を加えてみました。Linuxなので、生成されるライブラリファイル名は libfunc.a ですが、ライブラリとしては func だけで通じてしまう、と。

なお、libfunc.a内の関数を参照するためのヘッダファイルは、libとは別なincludeディレクトリ内に保存してあるのですが、そこについては特に指定はしていませぬ。main.c内で#includeするときに相対パスで書いてあるので「見える」筈という目論見。ほんとか。

add_executable(tst000 main.c sub.c)
add_subdirectory(lib)
target_link_libraries(tst000 func)

続いて、libサブディレクトリ内のCMakeLists.txtです。ここのメインは只1行、add_libraryで、ソースファイル func.c から、ライブラリ func を作れ、という指令。これを処理すれば、buildディレクトリの配下に lib/libfunc.a が生成される筈。

cmake_minimum_required(VERSION 3.16.3)
project(libfunc
    VERSION 0.1.0
    LANGUAGES C)

add_library(func func.c)

一応、肝心の main.c のソースはこちら。形だけの簡単なもの。

#include <stdio.h>
#include "sub.h"
#include "include/func.h"

int main(int argc, char *argv[]) {
    printf("tst001\n");
    printf("sub1: %d\n", sub1(1, 1));
    printf("func1: %d\n", func1(3, 4));
}

次にmain.cの隣においてある、sub.h と sub.c。まずは sub.hの方です。

#ifndef SUB_H
#define SUB_H

int sub1(int a, int b);

#endif /* SUB_H */

続いて sub.c、これまた形だけ。

int sub1(int a, int b) {
    return a + b;
}

さて、ライブラリ用のヘッダ、includeサブディレクトリに格納されている func.hはこんな感じ。これまた代わり映えしない。

#ifndef FUNC_H
#define FUNC_H

int func1(int a, int b);

#endif /* FUNC_H */

そして libサブディレクトリのライブラリ・ソースの実体がこちら。こんなものでライブラリ言うな、という感じ。

int func1(int a, int b) {
    return a * b;
}

ともあれ、「こんなもん」でもビルドは通りました。コマンドラインから実行してみるとこんな感じ。

$ ./tst000
tst001
sub1: 2
func1: 12

動いたです。当然か。

次回はCPPに戻して、今度はシステムのライブラリモジュールとリンク必要になるような「も少し、まともなプログラム」をやってみますか。CTestはまだその先だな、先は長いです。

ソフトな忘却力(3) リモートVS Code、CMake Toolsでcmakeするのだ へ戻る

ソフトな忘却力(5) CMakeLists.txtにリンク・ライブラリ指定、Boost へ進む