24

シェル関数を定義したい

#!/bin/sh

test ()
{
  do_some_complicated_tests $1 $2;
  if something; then
    build_thisway $1 $2;
  else
    build_otherway $1 $2;
  fi
}

次のようなMakefileのすべてのルールで使用できるように。

foo: bar
  test foo baz

明確にするために、シェル関数をMakefileの一部にしたいと思います。これを行うための最もエレガントな方法は何ですか?makeを再帰的に呼び出さずに実行できる場合は、ボーナスポイントが加算されます。


背景:私の実際の問題はmake -n、非常に長くて読めない出力を生成することです。各ルールは、読み取り不可能なシェルコマンドのほぼ同じシーケンスを使用し、多くのルールがあります。上記の解決策は、の出力をmake -nより有用にするでしょう。

4

7 に答える 7

15

このソリューションは、外部の一時ファイルに依存せず、SHELL変数をいじくり回すことを強制しません。

TESTTOOL=sh -c '\
  do_some_complicated_tests $$1 $$2; \
  if something; then
    build_thisway $$1 $$2;
  else
    build_otherway $$1 $$2;
  fi' TESTTOOL

ifneq (,$(findstring n,$(MAKEFLAGS)))
TESTTOOL=: TESTTOOL
endif

foo: bar
    ${TESTTOOL} foo baz

ブロックはコマンドラインでフラグをifneq…endifチェックし、読みやすく安全に実行できる展開を設定します。-nTESTTOOL: TESTTOOL

最善の解決策は、これがオプションである場合、シェル関数を実際のプログラムに変換することです。

于 2014-08-29T18:58:22.413 に答える
7

質問にタグが付けられているので、ベータ版の解決策に満足しているかもしれませんが、最善の解決策は1)関数の名前を( andなどの名前も避けgnu-makeて)以外の名前にすることだと思います。説明のために、名前を変更したと仮定します。2)という名前のスクリプトを記述し、Makefileから呼び出します。Makefileでシェル関数を本当に定義したい場合は、ルールごとに定義するだけです。testlscdfoofoo

F = foo() { \
  do_some_complicated_tests $$1 $$2; \
  if something; then \
    build_thisway $$1 $$2; \
  else \
    build_otherway $$1 $$2; \
  fi \
}

all: bar
  @$(F); foo baz bar

の定義の各行に行継続が必要であるというわけではありません。fooこれら$はすべてエスケープされて、シェルに渡されます。

于 2012-10-08T12:12:03.660 に答える
7

これは「エレガント」とは言えないと思いますが、あなたが望むことをしているようです。

##
## --- Start of ugly hack
##

THIS_FILE := $(lastword $(MAKEFILE_LIST))

define shell-functions
: BEGIN
  # Shell syntax here
  f()
  {
    echo "Here you define your shell function. This is f(): $@"
  }

  g()
  {
    echo "Another shell function. This is g(): $@"
  }
: END
endef

# Generate the file with function declarations for the shell
$(shell sed -n '/^: BEGIN/,/^: END/p' $(THIS_FILE) > .functions.sh)

# The -i is necessary to use --init-file
SHELL := /bin/bash --init-file .functions.sh -i

##
## -- End of ugly hack
##

all:
    @f 1 2 3 4
    @g a b c d

これを実行すると、次のようになります。

$ make -f hack.mk
Here you define your shell function. This if f(): 1 2 3 4
Another shell function. This is g(): a b c d

で実行すると、次のようになり-nます。

$ make -f hack.mk -n
f 1 2 3 4
g a b c d

defineこれは、マクロとの間で定義されたマクロが実際に使用されるまでendefまったく解釈されないという事実に依存しているmakeため、シェル構文を直接使用でき、各行をバックスラッシュで終了する必要はありません。もちろん、shell-functionsマクロを呼び出すと爆撃します。

于 2012-10-08T17:00:19.470 に答える
7

Makefileで.ONESHELLを使用して、bash関数のようなMakefile関数を定義してみませんか。

jeromesun@km:~/workshop/hello.test$ tree
.
├── Makefile
└── mkfiles
    └── func_test.mk

1 directory, 2 files
jeromesun@km:~/workshop/hello.test$ cat Makefile 
.ONESHELL:

-include mkfiles/*.mk

test:
        @$(call func_test, one, two)
jeromesun@km:~/workshop/hello.test$ cat mkfiles/func_test.mk 
.ONESHELL:

define func_test
    echo "func_test parameters: 0:$0, 1:$1, 2:$2"
    if [ ! -d abc ]; then
        mkdir abc
        echo "abc not found"
    else
       echo "abc found"
    fi
endef
jeromesun@km:~/workshop/hello.test$ 

結果:

jeromesun@km:~/workshop/hello.test$ make test 
func_test parameters: 0:func_test, 1: one, 2: two
abc not found
jeromesun@km:~/workshop/hello.test$ make test 
func_test parameters: 0:func_test, 1: one, 2: two
abc found
于 2018-11-01T03:38:28.933 に答える
5

これは本当にゲットーですが、何でも。私はzshを使用していますが、bashとshに相当するものがあると確信しています。

Makefile:

export ZDOTDIR := ./

SHELL := /usr/bin/env zsh

default:
    f

.zshenv、Makefileと同じディレクトリ:

f () { echo 'CHECK OUT THIS AWESOME FUNCTION!' }

ZDOTDIR変数を使用すると、zshは現在のディレクトリでドットファイルを検索します。次に、必要なものをに貼り付けます.zshenv

$ make
f
CHECK OUT THIS AWESOME FUNCTION!
于 2013-03-01T01:06:17.003 に答える
5

TL; DR:

makefile内:

SHELL=bash
BASH_FUNC_command%%=() { ... }
export BASH_FUNC_command%%

長い答え

ここで機能する非makeコンテキストでbashと同様のことを行いました。

シェル関数をbashで宣言してから、次のコマンドでエクスポートしました。

export -f function-name

同じシェルがサブプロセスとして呼び出された場合(あなたの場合はmakeから)、それらは自然に利用可能になります。

例:

$ # define the function
$ something() { echo do something here ; }
$ export -f something

$ # the Makefile
$ cat > Makefile <<END
SHELL=bash
all: ; something
END
$

やってみよう

$ make
something
do something here
$

これは環境でどのように見えますか?

$ env | grep something
BASH_FUNC_something%%=() { echo do something here

したがって、Makefile内から環境変数を設定する方法が問題になります。パターンはBASH_FUNC_function -name %% =(){ function-body }のようです

make内で直接

では、これはどのように機能しますか?このmakefileを試してください

SHELL=bash
define BASH_FUNC_something-else%%
() {
  echo something else
}
endef
export BASH_FUNC_something-else%%

all: ; something-else

そしてそれを試してみてください:

$ make
something-else
something else

Makefileでは少し醜いですが、 make-nの醜さはありません。

于 2016-06-06T12:26:10.983 に答える
4

の出力をフィルタリングしたほうがよいとのことmake -nですが、あなたが求めることは可能です。

define test
  @echo do some tests with $(1) and $(2); \
  SOMETHING=$(1)_3 ; \
  if [ $$SOMETHING == foo_3 ]; then \
    echo build this way $(1) $(2); \
  else \
    echo build another way $(1) $(2) ; \
  fi
endef

someTarget:
    $(call test,foo,bar)

someOtherTarget:
    $(call test,baz,quartz)
于 2012-10-08T03:53:13.807 に答える