JPMartha's Pancake

This blog is the way to brush up my poor English.

Carthage の Makefile について調べたこと ?

コマンドラインツールを作成する際に Carthage をベースにしたのですが、そのツールを公開するからには自分で挙動を理解しておく必要があるので調べたことを記事にします。

Thanks Carthage ! ?

github.com

Makefile とは

Wikipedia を参照してください。

たまに誤った情報もあるようなのであくまで参考に。

サンプル

作成中の ツール をサンプルとして説明します。Makefileこちらです。

github.com

ざっくり言うと

  • ビルドやパッケージ(pkg形式)作成、インストールなどの処理をまとめたファイルです。
  • サンプルでは $ make install コマンドでビルド、パッケージ作成やインストールなどを実行します。
  • その他もろもろあります。

説明

前提

  • すべて書くと長すぎるので外部ファイルを参照している部分は説明を省略しています。
  • 用語に誤りなどがあればちょいちょい直していきます。
  • 断片的でわかりづらいかもしれませんが上から順に区切って説明します。
  • Part は説明用に付けた独自のものです。

Part 1

TEMPORARY_FOLDER?=/tmp/Pancake.dst
PREFIX?=/usr/local
BUILD_TOOL?=xcodebuild

?= は未設定の場合に設定されます。

xcodebuild -- build Xcode projects and workspaces

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html

Part 2

XCODEFLAGS=-workspace 'Pancake.xcworkspace' -scheme 'pancake' DSTROOT=$(TEMPORARY_FOLDER)
  • XCODEFLAGS

    -workspace 'Pancake.xcworkspace' -scheme 'pancake' DSTROOT=/tmp/Pancake.dst になります。

Part 3

OUTPUT_PACKAGE=Pancake.pkg
OUTPUT_FRAMEWORK=PancakeKit.framework
  • OUTPUT_PACKAGE

    生成するパッケージ名です。

  • OUTPUT_FRAMEWORK

    生成するフレームワーク名です。

Part 4

BUILT_BUNDLE=$(TEMPORARY_FOLDER)/Applications/pancake.app
PANCAKEKIT_BUNDLE=$(BUILT_BUNDLE)/Contents/Frameworks/$(OUTPUT_FRAMEWORK)
PANCAKE_EXECUTABLE=$(BUILT_BUNDLE)/Contents/MacOS/pancake
  • BUILT_BUNDLE

    /tmp/Pancake.dst/Applications/pancake.app になります。

  • PANCAKEKIT_BUNDLE

    /tmp/Pancake.dst/Applications/pancake.app/Contents/Frameworks/PancakeKit.framework になります。

  • PANCAKE_EXECUTABLE

    /tmp/Pancake.dst/Applications/pancake.app/Contents/MacOS/pancake になります。

Part 5

FRAMEWORKS_FOLDER=/Library/Frameworks
BINARIES_FOLDER=/usr/local/bin
  • FRAMEWORKS_FOLDER

    PancakeKit.framework のコピー先フォルダです。

  • BINARIES_FOLDER

    pancake(pancake.app/Contents/MacOS/pancake)のコピー先フォルダです。

Part 6

VERSION_STRING=$(shell agvtool what-marketing-version -terse1)
COMPONENTS_PLIST=Sources/pancake/components.plist
  • VERSION_STRING

    $ agvtool what-marketing-version -terse1 コマンドが返す値を設定します。サンプルでは 1.0 が返されます。

agvtool -- Apple-generic versioning tool for Xcode projects

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/agvtool.1.html

  • COMPONENTS_PLIST

    依存フレームワークを記述した plist 形式のファイルですが説明は省略します。

Part 7

.PHONY: all bootstrap clean install package test uninstall

.PHONY の説明は省略しますがそれぞれ一括りのプログラムの宣言と考えればよいと思います。

  • ターゲット
    • all
    • bootstrap
    • clean
    • install
    • package
    • test
    • uninstall

なおコマンドの前はスペースではなくタブです。

  • 例)$(BUILD_TOOL) の前

Part 8

all: bootstrap
  $(BUILD_TOOL) $(XCODEFLAGS) build

$ make コマンドで実行する内容です。

  • bootstrap を実行します。
  • $ xcodebuild -workspace 'Pancake.xcworkspace' -scheme 'pancake' DSTROOT=/tmp/Pancake.dst build を実行します。

Part 9

bootstrap:
  scripts/bootstrap

$ make bootstrap コマンドで実行する内容です。

  • scripts/bootstrap を実行しますが説明は省略します。 (Carthage では script/bootstrap

?追記:こちらの記事 に書きました。

Part 10
test: clean bootstrap
  $(BUILD_TOOL) $(XCODEFLAGS) test

$ make test コマンドで実行する内容です。

  • cleanbootstrap を実行します。
  • $ xcodebuild -workspace 'Pancake.xcworkspace' -scheme 'pancake' DSTROOT=/tmp/Pancake.dst test を実行します。

Part 11

clean:
  rm -f "$(OUTPUT_PACKAGE)"
  rm -rf "$(TEMPORARY_FOLDER)"
  $(BUILD_TOOL) $(XCODEFLAGS) clean

$ make clean コマンドで実行する内容です。

  • $ rm -f "Pancake.pkg"

    Pancake.pkg を有無を言わさず(-f)削除(rm)します。

  • $ rm -rf "/tmp/Pancake.dst"

    /tmp/Pancake.dst を中身ごと(-r)有無を言わさず(-f)削除(rm)します。

  • $ xcodebuild -workspace 'Pancake.xcworkspace' -scheme 'pancake' DSTROOT=/tmp/Pancake.dst clean を実行します。

Part 12

install: package
  sudo installer -pkg Pancake.pkg -target /

$ make install コマンドで実行する内容です。

  • package を実行します。
  • $ sudo installer -pkg Pancake.pkg -target / を実行します。

sudo - execute a command as another user

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man8/sudo.8.html

installer -- system software and package installer tool.

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man8/installer.8.html

Part 13

uninstall:
  rm -rf "$(FRAMEWORKS_FOLDER)/$(OUTPUT_FRAMEWORK)"
  rm -f "$(BINARIES_FOLDER)/pancake"

$ make uninstall コマンドで実行する内容です。

?追記?

Permission denied が返されたら $ sudo make uninstall を実行します。

  • $ rm -rf "/Library/Frameworks/PancakeKit.framework"

    PancakeKit.framework を中身ごと(-r)有無を言わさず(-f)削除(rm)します。

  • $ rm -f "/usr/local/bin/pancake"

    pancake を有無を言わさず(-f)削除(rm)します。

Part 14

installables: clean bootstrap
  $(BUILD_TOOL) $(XCODEFLAGS) install

    mkdir -p "$(TEMPORARY_FOLDER)$(FRAMEWORKS_FOLDER)" "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)"
    mv -f "$(PANCAKEKIT_BUNDLE)" "$(TEMPORARY_FOLDER)$(FRAMEWORKS_FOLDER)/$(OUTPUT_FRAMEWORK)"
    mv -f "$(PANCAKE_EXECUTABLE)" "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)/pancake"
    rm -rf "$(BUILT_BUNDLE)"
  • cleanbootstrap を実行します。

  • $ xcodebuild -workspace 'Pancake.xcworkspace' -scheme 'pancake' DSTROOT=/tmp/Pancake.dst install を実行します。

  • $ mkdir -p "/tmp/Pancake.dst/Library/Frameworks" "/tmp/Pancake.dst/usr/local/bin" を実行します。

    ディレクトリを作成(mkdir)します。上の階層がなければそれも作成(-p)します。

  • $ mv -f "/tmp/Pancake.dst/Applications/pancake.app/Contents/Frameworks/PancakeKit.framework" "/tmp/Pancake.dst/Library/Frameworks/PancakeKit.framework" を実行します。

    PancakeKit.framework を有無を言わさず(-f)移動(mv)します。 (元)→(先)

  • $ mv -f "/tmp/Pancake.dst/Applications/pancake.app/Contents/MacOS/pancake" "/tmp/Pancake.dst/usr/local/bin/pancake" を実行します。

    pancake を有無を言わさず(-f)移動(mv)します。 (元)→(先)

  • $ rm -rf "/tmp/Pancake.dst/Applications/pancake.app" を実行します。

    pancake.app を中身ごと(-r)有無を言わさず(-f)削除(rm)します。

Part 15

prefix_install: installables
  mkdir -p "$(PREFIX)/Frameworks" "$(PREFIX)/bin"
  cp -Rf "$(TEMPORARY_FOLDER)$(FRAMEWORKS_FOLDER)/$(OUTPUT_FRAMEWORK)" "$(PREFIX)/Frameworks/"
  cp -f "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)/pancake" "$(PREFIX)/bin/"
  install_name_tool -add_rpath "@executable_path/../Frameworks/$(OUTPUT_FRAMEWORK)/Versions/Current/Frameworks/"  "$(PREFIX)/bin/pancake"

$ make prefix_install コマンドで実行する内容です。

?追記?

Permission denied が返されたら $ sudo make prefix_install を実行します。

  • installables を実行します。
  • $ mkdir -p "/usr/local/Frameworks" "/usr/local/bin" を実行します。

    ディレクトリを作成(mkdir)します。上の階層がなければそれも作成(-p)します。

  • $ cp -Rf "/tmp/Pancake.dst/Library/Frameworks/PancakeKit.framework" "/usr/local/Frameworks/" を実行します。

    PancakeKit.framework を中身ごと(-R)有無を言わさず(-f)コピー(cp)します。 (元)→(先)

  • $ cp -f "/tmp/Pancake.dst/usr/local/bin/pancake" "/usr/local/bin/" を実行します。

    pancake を有無を言わさず(-f)コピー(cp)します。 (元)→(先)

  • $ install_name_tool -add_rpath "@executable_path/../Frameworks/PancakeKit.framework/Versions/Current/Frameworks/" "/usr/local/bin/pancake" を実行してパスを追加します。

?追記?

$ install_name_tool help

Usage: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/install_name_tool [-change old new] ... [-rpath old new] ... [-add_rpath new] ... [-delete_rpath old] ... [-id name] input

Part 16

package: installables
  pkgbuild \
      --component-plist "$(COMPONENTS_PLIST)" \
      --identifier "jp.martha.pancake" \
      --install-location "/" \
      --root "$(TEMPORARY_FOLDER)" \
      --version "$(VERSION_STRING)" \
      "$(OUTPUT_PACKAGE)"

$ make package コマンドで実行する内容です。\ は改行です。

  • installables を実行します。
  • 次のコマンドを実行します。

    pkgbuild --component-plist "Sources/pancake/components.plist" --identifier "jp.martha.pancake" --install-location "/" --root "/tmp/Pancake.dst" --version "1.0" "Pancake.pkg"

pkgbuild -- Build an OS X Installer component package from on-disk files

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/pkgbuild.1.html

以上が Makefile の説明です。

説明が不足している点は後日追記するか新しい記事としてまとめます。

参考