fidry/makefile

用于解析 Makefile 并实现一些约定规则的实用工具。

资助包维护!
theofidry

1.0.2 2024-07-24 17:53 UTC

This package is auto-updated.

Last update: 2024-08-24 18:14:11 UTC


README

如果您不熟悉 Makefile,我建议您阅读这篇文章 这是一篇很好的介绍

我是 Makefile 的大粉丝,在使用了几乎每一个我参与过的项目(无论是私人还是公共的,开源或非开源)多年后,我形成了一些关于如何编写 Makefile 的约定。

这个库旨在提供一些助手,以便进行一些约定检查,并提供一些内置的检查。

我可能会使用的最简单的 Makefile 看起来是这样的

# See https://tech.davis-hansson.com/p/make/
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules

.DEFAULT_GOAL := default


#
# Commands
#---------------------------------------------------------------------------

# Provide a help command. In OSS projects where there is more contributors I tend to make this the
# default as it's a better entry point for newcomers.
# The command itself is a bit cryptic, but the result is simple: list all commands. See the following
# command declarations to see how I do it.
.PHONY: help
help:
	@printf "\033[33mUsage:\033[0m\n  make TARGET\n\n\033[32m#\n# Commands\n#---------------------------------------------------------------------------\033[0m\n"
	@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//' | awk 'BEGIN {FS = ":"}; {printf "\033[33m%s:\033[0m%s\n", $$1, $$2}'

# Technically this could be "inlined". I like to have it, but it's really up to you. When I do not
# have it, I tend to have an "all" command that executes _every_ checks including CS fixing.
.PHONY: default
default:   ## Runs the default task
default: cs test

# ... Declare your commands here. I often combine very specific commands with a few "meta" commands.
# For example with the CS, you likely want a `php_cs_fixer` command, maybe you use `ergebnis/composer-normalize`
# in which case you can have a `composer_normalize` command. Then, I have a meta command, e.g. "cs"
# that executes them all.
#
# You can find another example bellow where I have two distinct test steps: the composer validate
# and executing PHPUnit, and a final "test" meta command that does it all.

# This is how a "documented" command is declared:
# The first line is the PHONY target to make sure it will executed regardless of whether a file or
#   directory with that name does exist (here if the directory "test" exists, you likely want to
#   execute the _command_ test still.
# The second line is the "comment" line, this is optional and when added it will include the command
#   in the "make help" output.
# The third line is the actual rule declaration.
.PHONY: test
test:   ## Executes all the tests
test: composer_validate phpunit

.PHONY: composer_validate
composer_validate:  ## Validates the composer.json
composer_validate:
	composer validate --strict

.PHONY: phpunit
phpunit:   ## Runs PHPUnit
phpunit: $(PHPUNIT_BIN) vendor
	$(PHPUNIT)

#
# Rules
#---------------------------------------------------------------------------

# Vendor does not depend on the composer.lock since the later is not tracked
# or committed (this is not true if you have an application).
vendor: composer.json
	$(COMPOSER) update --no-scripts
	touch -c $@
	touch -c $(PHPUNIT_BIN)

$(PHPUNIT_BIN): vendor
	touch -c $@

用法

在上述简单的 Makefile 中,仍然有几个东西可能会出错

  • 声明命令的 2 或 3 行可能不一致
  • 一个命令可能会被声明多次
  • 帮助命令的输出对您很重要(例如,对您的贡献者),因此您希望确保它看起来很美观。

如果这对您很重要,那么您可以轻松创建以下测试

<?php declare(strict_types=1);

namespace Acme;

use Fidry\Makefile\Test\BaseMakefileTestCase;

/**
 * @coversNothing
 */
class MakefileTest extends BaseMakefileTestCase
{
    protected static function getMakefilePath(): string
    {
        return __DIR__.'/../Makefile';
    }

    protected function getExpectedHelpOutput(): string
    {
        // It looks a bit ugly due to the coloring, but in practice still remains easy to update.
        // If you find it tedious to do it manually, I recommend to manually check the output
        // with `make help` and then copy it, e.g. via `make help | pbcopy` and then paste it here.
        return <<<'EOF'
            �[33mUsage:�[0m
              make TARGET
            
            �[32m#
            # Commands
            #---------------------------------------------------------------------------�[0m
            �[33mdefault:�[0m Runs the default task
            �[33mtest:�[0m	  Runs all the tests
            �[33mcomposer_validate:�[0m  Validates the Composer package
            �[33mphpunit:�[0m    Runs PHPUnit

            EOF;
    }
}

进一步了解

在底层,这个包提供了一个简单的 Parser,它将 Makefile 内容解析为一系列 Rule(代表Makefile 规则)。

从这个结果中,很容易利用解析输出来实现更多针对您需求的定制检查。要了解更多细节,您可以查看 BaseMakefileTestCase 本身,它使用了它(没有魔法!)。