CMake で C ファイルのビルド環境をつくる

macOS 環境で CMake を試してみる。

CMake を使用することで環境に依存しないビルドのための作業を自動できる。

具体的にはソースファイルから環境によってことなるビルド構成ファイル(Makefile, Xcode プロジェクト)を作成できる。

https://cmake.org/

関連

CMake インストール

brew 経由でインストールする

$ brew install cmake

インストールされたかを確認する

$ cmake --version
cmake version 3.15.4

テスト用のファイルを用意する

今回は以下のファイルでテストする

main.c

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

int main() {
    func();

    return 0;
}

sub.h

#ifndef ___SUB_H_
#define ___SUB_H_

extern void func();

#endif  // ___SUB_H_

sub.c

#include <stdio.h>

void func() {
    printf("this is func.\n");
}

CMakeList.txt

cmake_minimum_required(VERSION 3.1)       # 要求する最低限の CMake バージョン
project(test C)     # プロジェクト名とプログラミング言語の指定
add_executable(test_app main.c sub.c)   # 実行ファイル名とソースファイルの指定

CMake を実行する

ビルド用のフォルダを作成する。

$ mkdir build

この時点でフォルダ構成はこうなっている。

  • フォルダ
    • CMakeLists.txt
    • main.c
    • sub.h
    • sub.c
    • build/


先ほど作成した build フォルダに移動して CMake を実行する。
cmake .. は上の階層にある CMakeLists.txt を参照することを意味する。

$ cd build
$ cmake ..

成功すると build フォルダ内に CMake の成果物ができる。
私の環境の場合は Makefile ができた。


もし Xcode のプロジェクトファイルを生成したい場合は以下にする。

$ cmake .. -G Xcode

これで xcodeproj が生成される。

GCC で C ファイルをコンパイルする

https://gcc.gnu.org/

GCCGNU コンパイラ コレクション)を使って C ファイルのコンパイルを試す。

macOS であれば GCC は最初からインストールされている。

テスト用のファイル

今回は以下のファイルでテストする

main.c

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

int main() {
    func();

    return 0;
}

sub.h

#ifndef ___SUB_H_
#define ___SUB_H_

extern void func();

#endif  // ___SUB_H_

sub.c

#include <stdio.h>

void func() {
    printf("this is func.\n");
}

GCCコンパイル

まずは -c オプションでコンパイルする。

$ gcc -c main.c sub.c 

コンパイルに成功すると main.osub.o のオブジェクトファイルが生成される。


次に -o オプションで、オブジェクトファイルをリンクして実行ファイルを生成する。

$ gcc -o a.out main.o sub.o

成功すると a.out ファイルが生成される。


最後に a.out を実行してみる。

$  ./a.out 
this is func.


以上で C ファイルのコンパイル〜実行までを確認できた。

malloc に代わるアロケーターいろいろ

jemalloc

Facebook で採用されていることが有名
https://www.facebook.com/notes/facebook-engineering/scalable-memory-allocation-using-jemalloc/480222803919

FreeBSD にも組み込まれている
https://www.facebook.com/notes/facebook-engineering/scalable-memory-allocation-using-jemalloc/480222803919

tcmalloc

元々は Google が公開したパフォーマンスツール。
Go 言語のバージョンもあり Google が管理している
https://github.com/google/pprof

nedmalloc

mimalloc

Microsoft による Allocator。
2019/6/20 公開なのでこの中では一番歴史が若い。

rbenv 導入メモ

これは macOS での rbenv 導入に関するメモである。

rbenv / https://github.com/rbenv/rbenv

rbenv 導入前の問題

fastlane など Ruby に関係したツールを macOS にインストールする場合、以下の問題が起きる

  • macOS にプリインストールされている Ruby バージョンが古い
  • しかし OS 全体の Ruby のバージョンは変更させたくない
  • もしくはツール活用のため、複数バージョンの Ruby を共存させたい

この問題に対処するため rbenv を導入する

rbenv でできること

rbenv でできること、メリット

  • 複数のバージョンの Ruby を環境内にもつことができる
  • 使用したい Ruby のバージョンを必要に応じて切り替えすることができる

rbenv 導入

rbenv インストール

$ brew install rbenv ruby-build

brew 経由でインストールする

$ rbenv init
# Load rbenv automatically by appending
# the following to ~/.bash_profile:

eval "$(rbenv init -)"

init でセットアップをする。
コマンドの結果、コメントで指示されたとおりに ~/.bash_profile に必要な記述を追加する。

$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

このコマンドの後に Terminal に変更を反映させるために Terminal アプリを一度終了させ、再度起動させる。

インストールできる Ruby バージョンの一覧を確認する

$ rbenv install --list
Available versions:
  1.8.5-p52
  1.8.5-p113
  1.8.5-p114
  (中略)
  2.6.3
  2.6.4
  2.6.5

このような感じで rbenv でインストールできる Ruby のバージョン一覧が確認できる。

特定バージョンの Ruby をインストールする

$ rbenv install 2.6.5

2.6.5 をインストールする場合はこれ

管理している Ruby バージョン一覧を確認する

$ rbenv versions
* system (set by /Users/<ユーザ名>/.rbenv/version)
  2.6.5

system(最初から入っているバージョン)、2.6.5(前段でインストールしたバージョン)が管理されていることが確認できる

有効な Ruby バージョンを切り替える

$ rbenv global 2.6.5

rbenv global でシステムで使用する Ruby のバージョンを設定できる(またほかに local によるプロジェクトごとの Ruby バージョンの指定も可能だ)

$ ruby --version
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]

問題なくシステムの Ruby バージョンが変わったか確認する。この例では 2.6.5 に変わっているので OK。

OS 標準の Ruby バージョンに戻す

$ rbenv global system

system をバージョン指定することにより標準の Ruby バージョンに戻せる。

$ ruby --version
ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin18]

きちんと標準のバージョンに戻ったことが確認できた(本環境では 2.3.7 がもともと macOS にインストールされていたバージョン)

AVCaptureSession でマイク入力を得る / AudioBufferList.allocate() 後のメモリリーク

https://github.com/daisuke-t-jp/AVCaptureAudioDataOutputSampleBufferTesting

iOS でマイク入力を取得してみたかったので試してみた。↑が、そのサンプルプロジェクト。

今回、いろいろなプロジェクトを参考にしてやってみたのだが、気になる点がひとつ。

AVCaptureAudioDataOutputSampleBufferDelegatecaptureOutput() を下のような感じで実装するパターンが多いのだが

extension ViewController: AVCaptureAudioDataOutputSampleBufferDelegate {
  func captureOutput(_ output: AVCaptureOutput,
                     didOutput sampleBuffer: CMSampleBuffer,
                     from connection: AVCaptureConnection) {
    
    var blockBuffer: CMBlockBuffer?
    let audioBufferList = AudioBufferList.allocate(maximumBuffers: 1)

    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
      sampleBuffer,
      bufferListSizeNeededOut: nil,
      bufferListOut: audioBufferList.unsafeMutablePointer,
      bufferListSize: MemoryLayout<AudioBufferList>.size,
      blockBufferAllocator: nil,
      blockBufferMemoryAllocator: nil,
      flags: UInt32(kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment),
      blockBufferOut: &blockBuffer
    )
  }
}


AudioBufferList.allocate()

https://github.com/apple/swift/blob/6e7051eb1e38e743a514555d09256d12d3fec750/stdlib/public/Darwin/CoreAudio/CoreAudio.swift#L67

f:id:daisuke-t-jp:20191015080703p:plain:w500

ということで free() を要することがコメントされている。
これを Xcode の Instruments で実際に試してみると


f:id:daisuke-t-jp:20191015081216p:plain:w500

やはりこんな感じでメモリリークを確認できた。

なので先ほどの AudioBufferList.allocate の周りのコードはこんな感じに修正するとメモリリークが消える。(defer はこんな風なリソース解放の時に便利だ)

let audioBufferList = AudioBufferList.allocate(maximumBuffers: 1)
    defer {
      free(audioBufferList.unsafeMutablePointer)
    }




・・・というリークが AVCaptureSession のコードで参考にした https://github.com/google/science-journal-ios のプロジェクトでも起きていたので、この修正をプルリクエストしてみたら、レビューが通ってマージされたので、なんか一件落着という感じで落ち着きましたよ。

本『孤独論 逃げよ、生きよ』(田中慎弥)の感想

孤独論 逃げよ、生きよ

孤独論 逃げよ、生きよ

田中さんの本を読んだことはなかったけど、ラジオ番組(http://www.joqr.co.jp/golden/2016/08/post-508.html)に出ているのをたまたま聴いて興味を持ったので読んでみた。

"孤独"というものが、人生を深くすることが書かれている。

本の第一印象は、装丁が黒色で、タイトルが"孤独"なので、暗く突き離した印象がしたけど、そんなことはなく読みやすい。

田中さんは高校卒業後、就職することなく30歳を超えて新人賞を受賞してデビュー。毎日毎日、家族以外とコミュニケーションを取ることなく、書くことを自分に課して、それを続けられたので孤独に対して人一倍耐性があるのではないかと思った。

しかし、孤独が自分の時間を濃くし、自分を保ち、深くするというエッセンス自体は、多くの人に共通するだろう。

SwiftUI 位置情報をトラッキングする

LocationManager でトラッキングした位置情報を、地図上に表示する SwiftUI のサンプルを作成した。上のリンクから完全なプロジェクトを持ってこれる。


動作させると、こんな感じ。


シミュレータの設定で Freeway Drive にしておくと自動で位置が更新され、確認しやすい。


位置情報の取得自体は SwiftUI 以前とあまり変わらないが @ObservedObject @Published など、データの配信・伝搬の概念がキモと感じた。