Makefileの現在の相対ディレクトリを取得する方法?


202

次のようなアプリ固有のディレクトリにいくつかのMakefileがあります。

/project1/apps/app_typeA/Makefile
/project1/apps/app_typeB/Makefile
/project1/apps/app_typeC/Makefile

各Makefileには、このパスに1レベル上の.incファイルが含まれています。

/project1/apps/app_rules.inc

app_rules.inc内で、ビルド時にバイナリを配置する場所の宛先を設定しています。すべてのバイナリをそれぞれのapp_typeパスに入れたい:

/project1/bin/app_typeA/

私は$(CURDIR)このように使ってみました

OUTPUT_PATH = /project1/bin/$(CURDIR)

しかし、代わりに次のようにパス名全体にバイナリを埋め込んだ:(冗長性に注意)

/project1/bin/projects/users/bob/project1/apps/app_typeA

実行の「現在のディレクトリ」を取得してapp_typeX、バイナリをそれぞれのタイプのフォルダに配置するためだけを知ることができるようにするにはどうすればよいですか?

回答:


272

シェル関数。

次のshell関数を使用できますcurrent_dir = $(shell pwd)。またはshellとの組み合わせでnotdir、あなたは絶対パスをする必要はないとします current_dir = $(notdir $(shell pwd))

更新。

与えられたソリューションmakeは、Makefileの現在のディレクトリから実行している場合にのみ機能します。
@Flimmが指摘したように:

これは、Makefileの親ディレクトリではなく、現在の作業ディレクトリを返すことに注意してください。
たとえば、を実行するcd /; make -f /home/username/project/Makefileと、current_dir変数はで/はなくになり/home/username/project/ます。

以下のコードは、任意のディレクトリから呼び出されるMakefileで機能します。

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))

5
それは機能しません。同じ問題です。PWDは、私はちょうど私がいるよ、実際の現在のフォルダの名前をしたい、フルパス名を出力します。
boltup_im_coding

6
:=演算子を使用する必要があるため、値をすぐに展開する必要があります。mkfile_path:=およびcurrent_dir =の場合と同じです(そうしないと、他のMakefileが含まれた後にMAKEFILE_LISTが変更されたときに、右側の値が後で評価される可能性があります
Tom Gruner

10
私はこれが古い質問であることを知っていますが、私はたまたまそれに遭遇し、これが役に立つかもしれないと思いました。これは、メイクファイルの相対パスにスペースがある場合にも機能しません。具体的には、$(lastword "$(MAKEFILE_LIST)")パスでのメイクファイルの"Sub Directory/Makefile"あなたを与えるだろう"Directory/Makefile"$(MAKEFILE_LIST)2つのmakefileを使用すると、"Makefile One Makefile Twoスペースを処理できない単一の文字列が提供されるため、これを回避する方法はないと思います
mrosales

2
それcurrent_dirは私にはうまくいきません。 $(PWD)し、それははるかに簡単です。
CaTx 2018

3
"solution only works when you are running make from the Makefile's current directory"「実際には機能していない」という穏やかな言い方です。私は答えの一番上に最新の作品を置きます。
Victor Sergienko、

138

ここから取られるよう ;

ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))

次のように表示されます。

$ cd /home/user/

$ make -f test/Makefile 
/home/user/test

$ cd test; make Makefile 
/home/user/test

お役に立てれば


3
私見では、末尾の文字を含むパス名を取得するのではdirなく、内部のmake-functionを使用する方が適切です。shell dirname/
Serge Roussak、2015年

3
外部ツールへの依存度が減ったためです。つまり、あるシステムでdirnameコマンドのエイリアスがある場合はどうなるのでしょうか?..
Serge Roussak '23 / 01/15

6
これは、ほとんど私のために働いたが、軽微な変更は、完全に仕事をしたので、DIRは、先頭の空白があった:DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
トルステンローレンツを

9
現在のメイクファイルを参照するには、を使用する$MAKEFILE_LIST必要がありますincludedocs)。
nobar 2015

2
dirnameパスにスペースがある場合は、少なくとも引数の前後に引用符を使用する必要があります。
nobar 2015

46

GNU makeを使用している場合、$(CURDIR)は実際には組み込み変数です。これは、Makefileが存在 する現在の作業ディレクトリ場所です。これは、Makefileがある場所ですが、常にそうとは限りません

OUTPUT_PATH = /project1/bin/$(notdir $(CURDIR))

http://www.gnu.org/software/make/manual/make.htmlの付録Aクイックリファレンスを参照してください。


18
GNU Makeマニュアル(51ページ)から:「GNU makeが起動すると(-Cオプションを処理した後)、変数CURDIRを現在の作業ディレクトリのパス名に設定します。」Makefileが置かれている場所ではありませんが、同じ場合もあります。
Simon Peverett 2014

4
以前のコメントでSimon Peverettが指摘したように、答えが技術的に正しくないため、反対票が投じられました。
Subfuzion 14

5
@SimonPeverett:括弧内の表現は、「-C optsが適用された後の現在の作業ディレクトリ」を意味します。つまり、$(CURDIR)は、「make -C xxx」と「cd xxx; make」の場合とまったく同じ結果になります。また、末尾を削除し/ます。私はgmakev3.81で縛ってみました。しかし、makeと呼ばれてmake -f xxx/Makefileいる場合、あなたは正しいです。
TrueY

CURDIRPWDうまくいかなかった私のために働く。mkdir -p a/s/dそれから私は各フォルダにPWDCURDIR以前に印刷されたメイクファイルがありました+$(MAKE) <subdir>
Mark K Cowan

27
THIS_DIR := $(dir $(abspath $(firstword $(MAKEFILE_LIST))))

12
...パスにスペースがない限り。
クレイグリンガー

9
...あなたは、前の行でいくつかの他のメイクファイルが含まれている場合を除き
robal

1
@robalはい。それが私が今出会ったことです。これは、Makefileが2つしかない場合(メインファイルとインクルードファイルの両方)に最適です。
sherrellbc

6

私はこれらの答えの多くを試しましたが、gnu make 3.80を使用した私のAIXシステムでは、昔ながらのことをする必要がありました。

ことが判明しlastwordabspathそしてがrealpath3.81になるまで追加されませんでした。:(

mkfile_path := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
mkfile_dir:=$(shell cd $(shell dirname $(mkfile_path)); pwd)
current_dir:=$(notdir $(mkfile_dir))

他の人が言ったように、シェルを2回呼び出すので最もエレガントではなく、スペースの問題がまだあります。

しかし、パスにスペースがないため、開始方法に関係なく機能しますmake

  • make -f ../wherever/makefile
  • make -C ../wherewhere
  • make -C〜/ wherewhere
  • cd ../wherever; 作る

すべては私を与えるwhereverためcurrent_dirと絶対パスwhereverのためmkfile_dir


一例として、aix(5-6-7)でgnu-make-3.82を問題なくコンパイルしました。
ZsigmondLőrinczy16年1

はい、3.81年までに、以前のソリューションに必要な機能が実装されました。私の答えは3.80以前の古いシステムです。悲しいことに、職場では、AIXシステムにツールを追加またはアップグレードすることはできません。:(
ジェシー・チザム

5

私は選ばれた答えが好きですが、実際に機能していることを説明するよりも実際に示す方が役立つと思います。

/tmp/makefile_path_test.sh

#!/bin/bash -eu

# Create a testing dir
temp_dir=/tmp/makefile_path_test
proj_dir=$temp_dir/dir1/dir2/dir3
mkdir -p $proj_dir

# Create the Makefile in $proj_dir
# (Because of this, $proj_dir is what $(path) should evaluate to.)
cat > $proj_dir/Makefile <<'EOF'
path := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
cwd  := $(shell pwd)

all:
    @echo "MAKEFILE_LIST: $(MAKEFILE_LIST)"
    @echo "         path: $(path)"
    @echo "          cwd: $(cwd)"
    @echo ""
EOF

# See/debug each command
set -x

# Test using the Makefile in the current directory
cd $proj_dir
make

# Test passing a Makefile
cd $temp_dir
make -f $proj_dir/Makefile

# Cleanup
rm -rf $temp_dir

出力:

+ cd /tmp/makefile_path_test/dir1/dir2/dir3
+ make
MAKEFILE_LIST:  Makefile
         path: /private/tmp/makefile_path_test/dir1/dir2/dir3
          cwd: /tmp/makefile_path_test/dir1/dir2/dir3

+ cd /tmp/makefile_path_test
+ make -f /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
MAKEFILE_LIST:  /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
         path: /tmp/makefile_path_test/dir1/dir2/dir3
          cwd: /tmp/makefile_path_test

+ rm -rf /tmp/makefile_path_test

注:この関数$(patsubst %/,%,[path/goes/here/])は、末尾のスラッシュを取り除くために使用されます。


2

Makefileシェル構文を使用してファイルへの絶対パスを取得するためのワンライナーは次のとおりです。

SHELL := /bin/bash
CWD := $(shell cd -P -- '$(shell dirname -- "$0")' && pwd -P)

そして、ここに@ 0xff回答に基づいたシェルなしのバージョンがあります

CWD := $(abspath $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))))

次のように印刷してテストします。

cwd:
        @echo $(CWD)

1
重要な重要性!上記の2番目の例では、:=代入演算子が必要です。そうでない場合、複雑なmakefileで非常に奇妙で怒りが生じる可能性があります(信頼してください)
EMon

1
最初のエラーは繰り返し発生するエラーであり、ツリー外ビルドでは機能しません。
JohanBoulé19年

2

解決策はここにあります:https : //sourceforge.net/p/ipt-netflow/bugs-requests-patches/53/

解決策は次のとおりです:$(CURDIR)

あなたはそれをそのように使うことができます:

CUR_DIR = $(CURDIR)

## Start :
start:
    cd $(CUR_DIR)/path_to_folder

3
Stack Overflowへようこそ。回答に詳細を追加できますか?質問は、$(CURDIR)すでに失敗したことを述べています。
Sean、

4
WARNING、クイックのGoogler:これはないメイクファイルがあるディレクトリ、が、現在の作業(ディレクトリmakeに発売されました)。それは確かに、OPが本当に欲しかったものですが、質問のタイトルは偽であり、質問自体に一貫性がありません。したがって、これは誤った質問に対する正しい答えです。;)
Sz。

これは
完全に

0

私が知っている限り、これはスペースで正しく機能する唯一の答えです:

space:= 
space+=

CURRENT_PATH := $(subst $(lastword $(notdir $(MAKEFILE_LIST))),,$(subst $(space),\$(space),$(shell realpath '$(strip $(MAKEFILE_LIST))')))

それは本質的に置換することにより、スペース文字をエスケープすることで動作' 'のために'\ 'メイクを正しくそれを解析することを可能にする、そしてそれは中にメイクファイルのファイル名を削除しMAKEFILE_LISTますが、メイクファイルがであることをディレクトリが残っているので、他の置換を行うことで。ない正確に最もコンパクトに世の中にあるものですが、それは機能します。

すべてのスペースがエスケープされる次のようなものになります。

$(info CURRENT_PATH = $(CURRENT_PATH))

CURRENT_PATH = /mnt/c/Users/foobar/gDrive/P\ roje\ cts/we\ b/sitecompiler/

-2

以下のように、参照の例:

フォルダー構造は次のようになります。

ここに画像の説明を入力してください

Makefileが2つある場合、それぞれ以下のようになります。

sample/Makefile
test/Makefile

ここで、Makefileの内容を見てみましょう。

サンプル/メイクファイル

export ROOT_DIR=${PWD}

all:
    echo ${ROOT_DIR}
    $(MAKE) -C test

テスト/メイクファイル

all:
    echo ${ROOT_DIR}
    echo "make test ends here !"

次に、sample / Makefileを次のように実行します。

cd sample
make

出力:

echo /home/symphony/sample
/home/symphony/sample
make -C test
make[1]: Entering directory `/home/symphony/sample/test'
echo /home/symphony/sample
/home/symphony/sample
echo "make test ends here !"
make test ends here !
make[1]: Leaving directory `/home/symphony/sample/test'

説明は、親/ホームディレクトリを環境フラグに保存し、エクスポートして、すべてのサブディレクトリのmakefileで使用できるようにすることです。


2
これは、makefileのホームディレクトリではなく、現在の作業ディレクトリを取得します。
Jesse Chisholm

これらはMakefileの行です。Makefileコマンドが実行されると、Makefileがあるパスが取得されます。「makefileホームディレクトリ」が同じこと、つまりMakefileが実行されているディレクトリパスを指していることを理解しています。
Parasrish 2016年

@Jesse Chisholmを再訪してください。使い方を説明しました。
Parasrish

繰り返し発生するエラー:ツリー外ビルドでは機能しません。また、gnomeターミナルはテキストをコピーする簡単な方法を提供します。それを選択するだけです。噂によると、Immurはつまらない。
JohanBoulé19年

-2

更新2018/03/05 finnaly私はこれを使用します:


shellPath=`echo $PWD/``echo ${0%/*}`

# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
    shellPath=${shellPath2}
fi

相対パスでも絶対パスでも正しく実行できます。crontabによって呼び出された正しい実行。他のシェルで正しく実行されました。

例、a.shの自己パスを表示します。

[root@izbp1a7wyzv7b5hitowq2yz /]# more /root/test/a.sh
shellPath=`echo $PWD/``echo ${0%/*}`

# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
    shellPath=${shellPath2}
fi

echo $shellPath
[root@izbp1a7wyzv7b5hitowq2yz /]# more /root/b.sh
shellPath=`echo $PWD/``echo ${0%/*}`

# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
    shellPath=${shellPath2}
fi

$shellPath/test/a.sh
[root@izbp1a7wyzv7b5hitowq2yz /]# ~/b.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz /]# /root/b.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz /]# cd ~
[root@izbp1a7wyzv7b5hitowq2yz ~]# ./b.sh
/root/./test
[root@izbp1a7wyzv7b5hitowq2yz ~]# test/a.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz ~]# cd test
[root@izbp1a7wyzv7b5hitowq2yz test]# ./a.sh
/root/test/.
[root@izbp1a7wyzv7b5hitowq2yz test]# cd /
[root@izbp1a7wyzv7b5hitowq2yz /]# /root/test/a.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz /]# 

古い:私はこれを使います:

MAKEFILE_PATH := $(PWD)/$({0%/*})

他のシェルおよび他のディレクトリで実行された場合、それは正しく表示できます。


1
「他のシェルや他のディレクトリを実行すると、正しく表示されます」は英語では意味がありません。もう一度説明してみてください。
キースM

英語が下手でごめんなさい
zhukunqian

編集をありがとう、私はあなたが今INを意味していたと思います。これを試す前にこれが何をするのか説明してくれませんか?使い方がわかりません。「その他のシェル」とはどういう意味ですか
キースM

1
この回答には、修正できない可能性のある多くの間違った点があります。簡単な削除をお勧めします。
JohanBoulé19年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.