Subscribed unsubscribe Subscribe Subscribe

Islands in the byte stream

Technical notes by a software engineer

Makefileを自己文書化するハックを注入するスクリプト: inject-make-help

Re: Makefileを自己文書化する make2help | おそらくはそれさえも平凡な日々

ぼくもmakeはわりと使う方で、AndroidプロジェクトだろうとiOSプロジェクトだろうとよく使うコマンドセットをMakefileとして追加するのが大好きなんですが、self-documented Makefileは存在はしっていたもののセットアップが面倒でやっていませんでした。

じゃあ make2help はどうかというと、ただひとつのコマンドをインストールすると常self-documented Makefileを使えるという点では優れたアイデアなんですが、じゃあ今度はプロジェクトメンバーに make2help をインストールするように指示しないといけなくなってしまうのがイマイチだなあと。makeのメリットの一つは、敢えてインストールしなくてもだいたい入っているという点だと思うので。

というわけで、self-documented Makefile hackをMakefileに注入するスクリプトを書きました。まあホントはこのhackもgrep(1) とか awk(1) ではなく perl(1) で書き直したいところですが、とりあえずオリジナルのものを注入するだけです。すでに注入済みなら何もしません。

これなら、誰か一人が inject-make-help を実行したあとの Makefile をコミットしておけば誰でも make help が使えます。どうでしょう。

#!/usr/bin/env perl
# inject-make-help(1): To inject help hacks to the Makefile
use 5.10.0;
use strict;
use warnings;
use autodie;

# FIXME: use perl(1) instead of grep(1), sort(1), and awk(1)
my $help_task = q{
help:
    @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
} =~ s/^[ ]{4}/\t/xmsgr;

my $makefile = shift(@ARGV) // 'Makefile';

my $content = do {
    local $/;
    open my $fh, '<', $makefile;
    <$fh>;
};

if ($content !~ /\Q$help_task/xms) {
    $content .= $help_task;
    
    my($phony_tasks) = ($content =~ /^\.PHONY:([^\n]+)/xms);
    if (not defined $phony_tasks) {
        $content .= q{
.PHONY: help
} =~ s/^[ ]{4}/\t/xmsgr;
    } elsif ($phony_tasks !~ /\bhelp\b/xms) {
        $content =~ s/^(\.PHONY:[^\n]+)/$1 help/xms;
    }

    say "Inject help triks to $makefile";
    open my $fh, '>', $makefile;
    print $fh $content;
    close $fh;
}

ターゲットの Makefile はこんな感じ:

.DEFAULT_GOAL := help

foo: ## The foo task
  echo foo

bar: ## The bar task
  echo bar

これに対して inject-make-help をするとこんな感じになります:

.DEFAULT_GOAL := help

foo: ## The foo task
  echo foo

bar: ## The bar task
  echo bar

help:
   @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

.PHONY: help

.PHONY は既存のものがあればそれに対して help を追加します。