Linux におけるC言語のビルド環境構築 - とりあえず編


<!-- TOC depthFrom:2 -->

- [1. やりたい事](#1-やりたい事)
- [2. Linux におけるC言語のビルド環境](#2-linux-におけるc言語のビルド環境)
- [3. gyp](#3-gyp)
    - [3.1. gyp のインストール](#31-gyp-のインストール)
    - [3.2. gyp の設定](#32-gyp-の設定)
    - [3.3. gyp の実行 ( ninja 用のビルドファイル生成)](#33-gyp-の実行--ninja-用のビルドファイル生成)
- [4. ninja](#4-ninja)
    - [4.1. ninja のインストール](#41-ninja-のインストール)
    - [4.2. ninja の実行と動作確認](#42-ninja-の実行と動作確認)
- [5. まとめ](#5-まとめ)

<!-- /TOC -->

## 1. やりたい事

Linux ディストリビューションで動作するC言語アプリケーションを作ることになったので、 Linux におけるC言語のビルド環境を構築したい。この時点では CMake くらいしか知らない（単語レベル）。

## 2. Linux におけるC言語のビルド環境

単語としての CMake しか知らなかったので少し調べてみると、 CMake はメタビルドツールであり、既存のビルドツール（ make や XCode など）向けの設定ファイルを出力するものであることが分かった。同様のツールとして SCons 、 gyp があるらしい。

gyp は、 CMake や SCons の課題を解決するために生まれたものらしいので、とりあえず gyp を使ってみることにする。 gyp は、Node.js のビルドにも使われてるらしいし。

* [gyp ( Qiita の記事)](https://qiita.com/izariuo440/items/c9de0a3739e67548f41a)
* [GYP (公式)](https://gyp.gsrc.io/docs/UserDocumentation.md)

ビルドツールとして make 以外にどんなものがあるのか調べてみると、 ninja というものがあるらしい。斜め読みする限り make よりも高速だし名前も面白そうなので、特に何も考えることなく ninja を使うことにする。公式のウェブサイトが渋い。

* [ninja (公式)](https://ninja-build.org/)

つまり、以下のツールを使って環境を構築する。

* メタビルドツール
    * gyp
* ビルドツール
    * ninja

## 3. gyp

gyp のインストールから簡単なソースコードをビルドするまでの手順。とりあえず macos で試す（ Linux ... ）。

### 3.1. gyp のインストール

gyp を使うには Python 2.7.x 系が必要で Python 3 は今の所サポートしていない。

[pyenv](https://github.com/pyenv/pyenv) を使って Python をインストールする。

```
$ pyenv install 2.7.13
$ pyenv global 2.7.13
$ pyenv rehash
$ python --version
Python 2.7.13
```

gyp をインストールする。 Chromium のコード内に gyp があるらしく、必要なものだけ `git clone` した後、 `setup.py` を実行してインストールする。 `setup.py` を実行するとグローバル環境にインストールするので、もしローカル運用をしたければ、 `git clone` した gyp を直接実行すればよいはず（ `$ python tools/gyp/gyp_main.py` ）。

```
$ git clone https://chromium.googlesource.com/external/gyp.git tools/gyp
$ cd tools/gyp
$ python setup.py install
$ pyenv rehash
$ which gyp
/Users/xxx/.anyenv/envs/pyenv/shims/gyp
$ gyp --help
Usage: gyp [options ...] [build_file ...]

Options:
  -h, --help            show this help message and exit
  --build=CONFIGS       configuration for build after project generation
  --check               check format of gyp files
  --config-dir=CONFIG_DIR
                        The location for configuration files like
                        include.gypi.
  -d DEBUGMODE, --debug=DEBUGMODE
                        turn on a debugging mode for debugging GYP.  Supported
                        modes are "variables", "includes" and "general" or
                        "all" for all of them.
  -D VAR=VAL            sets variable VAR to value VAL
  --depth=PATH          set DEPTH gyp variable to a relative path to PATH
  -f FORMATS, --format=FORMATS
                        output formats to generate
  -G FLAG=VAL           sets generator flag FLAG to VAL
  --generator-output=DIR
                        puts generated build files under DIR
  --ignore-environment  do not read options from environment variables
  -I INCLUDE, --include=INCLUDE
                        files to include in all loaded .gyp files
  --no-circular-check   don't check for circular relationships between files
  --no-duplicate-basename-check
                        don't check for duplicate basenames
  --no-parallel         Disable multiprocessing
  -S SUFFIX, --suffix=SUFFIX
                        suffix to add to generated files
  --toplevel-dir=DIR    directory to use as the root of the source tree
  -R TARGET, --root-target=TARGET
                        include only TARGET and its deep dependencies
```

### 3.2. gyp の設定

`*.gyp` というファイルが、 gyp の設定ファイルになる。 `*.gyp` は、 Python の  dictionary 形式で記述する。実際のところこれは `JSON` 形式だけど、 `#` でコメントが書けたり、リストの終端に `,` ( カンマ ) を使えたりする。

次のディレクトリ構成に対して、 `app.gyp` というファイル名で gyp の設定を記述する。

```
project_root/
  |
  +-- app.gyp
  +-- src/
       +-- gyp_sample.c
```

実行形式のアプリをビルドする設定。勿論この他にも、ライブラリをビルドするための設定や、依存ライブラリ、ヘッダファイルの場所を指定できるけど、とりあえずビルドして、実行できるところまでを確認する。

```py:app.gyp
{
  'targets': [
    {
      'target_name': 'app',
      'type': 'executable',
      'sources': [
        'src/gyp_sample.c',
      ],
    },
  ],
}
```

何の変哲も無いソースコード。

```c:gyp_sample.c
#include <stdio.h>

int main(int argc, char* argv[])
{
  fprintf(stdout, "%s\n", "Hello world!!");

  return 0;
}
```

### 3.3. gyp の実行 ( ninja 用のビルドファイル生成)

以下のコマンドで、 ninja 用のビルドファイルを生成する。

```
$ gyp app.gyp -f ninja --depth=.
```

`out` ディレクトリが生成されて、ビルド用の設定ファイルが出力される。

```
project_root/
  |
  +-- app.gyp
  +-- out/
  |    +-- ...
  +-- src/
       +-- gyp_sample.c
```

## 4. ninja

ninja のインストールと、ビルド手順。

### 4.1. ninja のインストール

ninja がインストールされていなければ Homebrew でインストールする。

```
$ brew install ninja
```

### 4.2. ninja の実行と動作確認

ninja のビルドファイルが存在するディレクトリまで移動して `ninja` コマンドを実行すると、 `target_name` で指定した名前で実行ファイルが生成される。

```
$ cd out/Default
$ ninja
$ ls | grep app
app
```

動作確認をする。

```
$ ./app
Hello world!!
```

## 5. まとめ

gyp と ninja を使って簡単なソースコードをビルドできた。次はもう少し複雑な環境を構築してビルドしてみたい。