Makefile의 현재 상대 디렉토리를 얻는 방법?


202

다음과 같이 앱 특정 디렉토리에 여러 개의 Makefile이 있습니다.

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

각 Makefile에는이 경로에 .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
나는 이것이 오래된 질문이라는 것을 알고 있지만 방금 뛰어 들었고 이것이 유용 할 것이라고 생각했습니다. makefile의 상대 경로에 공간이 있으면 작동하지 않습니다. 특히, $(lastword "$(MAKEFILE_LIST)")경로에있는 makefile은 "Sub Directory/Makefile"당신에게 줄 것이다 "Directory/Makefile". $(MAKEFILE_LIST)두 개의 makefile을 사용하면 "Makefile One Makefile Two공백을 처리 할 수없는 단일 문자열을 제공하기
때문에이 문제를 해결할

2
그것은 current_dir나를 위해 작동하지 않습니다. $(PWD)그리고 훨씬 간단합니다.
CaTx

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
IMHO 후행 문자 가있는 경로 이름을 얻는 dir대신 내부 make 기능을 사용하는 것이 좋습니다 . shell dirname/
Roussak Serge

3
외부 도구에 대한 의존성이 감소했기 때문입니다. 즉 어떤 시스템에서 dirname 명령의 별칭이 있다면 어떻게 될까요? ..
Serge Roussak

6
이것은 거의 나를 위해 일했지만 DIR에는 공백이 있었으므로 사소한 변경으로 완벽하게 작동했습니다.DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
Thorsten Lorenz

9
현재 makefile 을 참조하려면 $MAKEFILE_LIST모든 include작업 ( docs ) 을 사용해야합니다 .
nobar

2
dirname경로에 공백이있는 경우 적어도 인수 주위에 따옴표를 사용해야합니다 .
nobar

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

4
이전 의견에서 Simon Peverett가 언급 한대로 답변이 기술적으로 정확하지 않기 때문에 하향 투표되었습니다.
Subfuzion

5
@SimonPeverett : 괄호 안의 표현은 "현재 작업 디렉토리 AFTER -C opts apply"를 의미합니다. 즉 $ (CURDIR)은 "make -C xxx"와 "cd xxx; make"에 대해 동일한 결과를 제공합니다. 또한 후행을 제거합니다 /. gmakev3.81로 묶어 보았습니다. 그러나 make이라고 불리는 경우 귀하는 옳습니다 make -f xxx/Makefile.
TrueY

CURDIR내가 PWD하지 않은 곳에서 나를 위해 일합니다 . 그런 mkdir -p a/s/d다음 각 폴더에 makefile이 PWD있었고 CURDIR이전에 인쇄했습니다 +$(MAKE) <subdir>.
Mark K Cowan

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

12
... 경로에 공백이없는 한.
크레이그 링거

9
... 이전 줄에 다른 makefile을 포함시키지 않은 경우
robal

1
@robal p. 그것이 내가 방금 마주 친 것입니다. 이 작품 당신이 두 메이크 (주 하나 플러스 포함 하나)이있는 경우.
셔 렐크

6

나는이 답변 중 많은 것을 시도했지만 gnu make 3.80을 사용하는 AIX 시스템에서 구식 일을해야했습니다.

밝혀 lastword, abspath그리고는 realpath3.81까지 추가되지 않았습니다. :(

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

다른 사람들이 말했듯이, 쉘을 두 번 호출 할 때 가장 우아하지는 않지만 여전히 공백 문제가 있습니다.

그러나 경로에 공백이 없으므로 시작 방법에 관계없이 작동합니다 make.

  • make -f ../whereever/makefile
  • 어디든지 -C ../
  • 어디든지 -C ~ /
  • cd ../where; 하다

모든 줘 wherever위해 current_dir그리고 절대 경로 wherever에 대한 mkfile_dir.


나는 aix (5-6-7)에서 gnu-make-3.82를 문제없이 컴파일했습니다.
Zsigmond Lőrinczy

예. 3.81까지 이전 솔루션에 필요한 기능이 구현되었습니다. 내 대답은 3.80 이하의 이전 시스템에 대한 것입니다. 안타깝게도 직장에서 도구를 AIX 시스템에 추가하거나 업그레이드 할 수 없습니다. :(
Jesse Chisholm

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
중요한 중요성! 위의 두 번째 예에는 : = 대입 연산자가 필요합니다. 그렇지 않으면 복잡한 makefile을 사용하여 매우 이상하고 화를 낼 수 있습니다 (믿습니다)
EMon

1
첫 번째는 반복되는 오류이며 트리 외부 빌드에서는 작동하지 않습니다.
Johan Boulé

2

해결책은 여기에 있습니다 : https://sourceforge.net/p/ipt-netflow/bugs-requests-patches/53/

해결책은 다음과 같습니다. $ (CURDIR)

당신은 그것을 다음과 같이 사용할 수 있습니다 :

CUR_DIR = $(CURDIR)

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

3
스택 오버플로에 오신 것을 환영합니다. 답변에 더 자세한 내용을 추가 할 수 있습니까? 이 질문 $(CURDIR)은 이미 성공적으로 시도되지 않았 음을 나타냅니다.
Sean

4
빠른 Google 직원 경고 :이은 하지 메이크 파일이있는 디렉토리는하지만, 현재 작업 디렉토리 (여기서 make발사되었다). 실제로 OP가 실제로 원했던 것은 아니지만 질문 제목은 허위이므로 질문 자체는 일관성이 없습니다. 따라서 이것은 잘못된 질문에 대한 정답입니다. ;)
Sz.

이것은 정답이
아니며

0

내가 아는 한 이것은 공백으로 올바르게 작동하는 유일한 대답입니다.

space:= 
space+=

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

본질적으로 공백 문자를 대체하여 이스케이프 처리 ' ' 하여 '\ 'Make를 올바르게 구문 분석 할 수있게 한 다음 MAKEFILE_LIST다른 대체를 수행 하여 makefile의 파일 이름을 제거 하므로 makefile이있는 디렉토리가 그대로 유지됩니다. 세상의 일이지만 작동합니다.

모든 공간이 탈출되는 다음과 같은 결과가 나타납니다.

$(info CURRENT_PATH = $(CURRENT_PATH))

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

-2

다음과 같이 참조하십시오.

폴더 구조는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

두 개의 Makefile이있는 경우 각각 아래와 같습니다.

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'

부모 / 홈 디렉토리를 environment-flag에 저장하고 내보낼 수 있으므로 모든 하위 디렉토리 메이크 파일에서 사용할 수 있습니다.


2
makefile의 홈 디렉토리가 아닌 현재 작업 디렉토리를 가져옵니다.
Jesse Chisholm

이것들은 Makefile의 라인입니다. 이제 Makefile 명령이 실행될 때 Makefile이있는 경로를 얻게됩니다. "makefile 홈 디렉토리"가 동일하다는 것을 이해합니다. 즉, Makefile이 실행되는 디렉토리 경로입니다.
parasrish

@Jesse Chisholm을 다시 방문하십시오. 사용법에 대해 설명했습니다.
parasrish

반복되는 오류 : 트리 외부 빌드에서는 작동하지 않습니다. 또한, 그놈 터미널은 텍스트를 복사하는 간단한 방법을 제공합니다. 그냥 선택하십시오. 소문에 따르면 이머 구르는 파산했다.
Johan Boulé

-2

2018/03/05 업데이트로 나는 이것을 사용합니다 :


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
"다른 쉘과 다른 디렉토리가 실행되면 제대로 표시 될 수 있습니다"는 영어로 이해가되지 않습니다. 다시 설명해 주시겠습니까?
Keith M

내 가난한 영어에 대해 죄송합니다
zhukunqian

편집 해 주셔서 감사합니다. 이제 IN을 의미합니다. 시도하기 전에 이것이 무엇을하는지 설명해 주시겠습니까? 사용 방법을 잘 모르겠습니다. "other shell"의 의미
Keith M

1
이 답변에는 해결 할 수없는 많은 잘못된 것들이 있습니다. 간단한 제거를 제안합니다.
Johan Boulé

-2

Makefile에서 한 줄이면 충분합니다.

DIR := $(notdir $(CURDIR))

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.