makefile에 'cd'명령을 작성하는 방법


354

예를 들어, makefile에 다음과 같은 것이 있습니다.

all:
     cd some_directory

그러나 입력 할 때 명령 make과 같이 'cd some_directory'만 보았습니다 echo.


5
당신이하고 싶은 일이 분명하지 않지만,에 대한 경험에서 make, 나는 이와 같은 디렉토리를 바꾸고 싶지 않았습니다. 어쩌면 솔루션에 다른 접근법을 시도해야합니까?
P Shved

2
디렉토리가 중요하다고 믿는 것은 흔한 초보자 실수입니다. 대부분의 경우 그렇지 않습니다. cd dir; cmd file거의 항상보다 유용하게 표현할 수 있습니다 cmd dir/file.
tripleee

34
현재 작업 디렉토리가 중요하지 않다고 믿는 것은 일반적인 초보자 실수입니다. 많은 프로그램, 특히 쉘 스크립트는 특정한 가치를 .염두에두고 작성되었습니다. 대부분의 도구는 암호를 변경할 필요가 없도록 설계되었습니다. 그러나 이것이 항상 사실은 아니며, 디렉토리가 중요하다고 믿기 위해 "실수"라고 부르는 것은 좋은 생각이 아닙니다.
Evelyn Kokemoor

팁 : cd 명령에 "이러한 파일 또는 디렉토리가 없습니다"라고 표시되면 (상대) 디렉토리 존재 하더라도 CDPATH 환경 변수가 비어 있거나 "."를 포함하는지 확인하십시오. Make는 "sh"를 사용하여 명령을 실행합니다.이 경로는 설정된 경우 CDPATH를 통해서만 상대 경로를 찾습니다. 이것은 bash와 대조되어 시도합니다. CDPATH를 참조하기 전에.
Denis Howe

답변:


620

실제로 명령을 실행하고 디렉토리를로 변경 some_directory하지만 하위 프로세스 쉘에서 수행되며 작업중 인 쉘이나 쉘에 영향을 미치지 않습니다.

에서 더 많은 작업을 수행 some_directory하려면 세미콜론을 추가하고 다른 명령도 추가해야합니다. 규칙의 끝으로 make로 해석되는 줄 바꿈을 사용할 수 없으므로 명확성을 위해 사용하는 줄 바꿈은 백 슬래시로 이스케이프해야합니다.

예를 들면 다음과 같습니다.

all:
        cd some_dir; echo "I'm in some_dir"; \
          gcc -Wall -o myTest myTest.c

백 슬래시와 개행을 추가하더라도 모든 명령간에 세미콜론이 필요합니다. 이것은 전체 문자열이 쉘에 의해 단일 행으로 구문 분석되기 때문입니다. 주석에서 언급했듯이 '&&'를 사용하여 명령을 결합해야합니다. 즉, 이전 명령이 성공한 경우에만 실행됩니다.

all:
        cd some_dir && echo "I'm in some_dir" && \
          gcc -Wall -o myTest myTest.c

cd어떤 이유로 든 실패 하면 잘못된 것을 파괴 할 수 있으므로 정리와 같은 파괴적인 작업을 수행 할 때 특히 중요합니다 .

그러나 일반적인 사용법은 하위 디렉토리에서 make를 호출하는 것입니다. 이에 대한 명령 행 옵션이 있으므로 cd직접 전화 할 필요가 없으므로 규칙은 다음과 같습니다.

all:
        $(MAKE) -C some_dir all

타겟 "all" 로 변경되어 in을 some_dir실행합니다 Makefile. 모범 사례 로서 직접 $(MAKE)호출 하는 대신 make올바른 make 인스턴스를 호출하는 데주의를 기울여야하며 (예를 들어 빌드 환경에 특수한 make 버전을 사용하는 경우) 실행시 약간 다른 동작을 제공해야합니다. 와 같은 특정 스위치 사용 -t.

레코드의 경우 출력이없는 경우에도 make가 명시 적으로 억제하지 않는 한 항상 실행하는 명령을 에코합니다.


8
항상 그렇지는 않습니다 . 반향을 억제하려면 줄의 시작 부분에 @를 넣으십시오.
Beta

2
@Beta : 예, 대시 접두사는 오류 상태도 무시합니다. 어쩌면 나는 조금 도망 쳤으며, 명령의 종류에 관계없이 make가 명령을 에코한다는 사실을 지적하고 싶었습니다. 그리고이 경우 출력이없는 명령이므로 에코에 익숙하지 않은 사람에게는 에코가 더 이상하게 보입니다.
falstro 2016

46
두 니트 : 1. 명령이 정말로 합류해야 &&하기 때문에와 ;디렉토리가 존재하지 않고,이 경우 cd"파일을하지 쉘은 신비 등을 일으킬 수있는, 현재 디렉토리에있는 명령의 나머지 부분을 계속 실행됩니다 실패 컴파일 "메시지, make 호출시 무한 루프 또는와 같은 규칙 재난 메시지 clean:: cd dir; rm -rf *. 2. 하위 메이크를 호출 할 때 옵션이 올바르게 전달 되도록 $(MAKE)대신 호출하십시오 . make
andrewdotn

2
@perreal, 나는 일반적으로 다음과 같은 패턴 규칙을 정의합니다 : %-recursive:body : @T="$@";$(MAKE) -C some_dir $${T%-*}(보통 for-loop도 있고 하위 디렉토리 목록을 반복하기 위해 대상 이름 $${T%-*}-recursive일부 를 제거하는 bash 확장입니다 ) 각각 명시 쇼트 핸드 (및 .PHONY) 대상 정의, 등 all: all-recursive, check: check-recursive, clean: clean-recursive.
falstro

1
@ChristianStewart, 의견 2와 3에서 언급 한 바와 같이, true
falstro

94

에서 시작 GNU 메이크 3.82 (7 월 2010), 당신은 사용할 수있는 .ONESHELL쉘 (굵게 강조 광산)의 단일 인스턴스의 모든 레시피 라인을 실행하는 데 특별한 목표를 :

  • 새로운 특수 대상 : .ONESHELL에 지시가 만들어 호출 쉘의 단일 인스턴스를 하고 그것을 제공하는 전체 조리법 에 관계없이 포함 얼마나 많은 라인. [...]
.ONESHELL: # Only applies to all target
all:
    cd ~/some_dir
    pwd # Prints ~/some_dir if cd succeeded

6
그냥 참고 pwd자체뿐만 아니라, 작동 `pwd`(역 따옴표 포함) 만 $(shell pwd)하고 $(PWD)계속하기 전에 디렉토리를 반환합니다 cd당신이 직접 사용할 수 있도록 명령을 사용합니다.
anol

3
반면 예 변수 및 기능 확장은, 메이크업으로 명령을 실행하기 전에 수행되기 때문에 pwd그리고 `pwd`쉘 자체에 의해 실행된다.
Chnossos

2
모든 사람이 레거시 메이크 파일에서 작업하는 것은 아니며,이 대답은 이러한 가능성이 존재 한다는 것을 알고 있습니다.
Chnossos

1
이것은 대상에 대한 마지막 명령 만 실패를 일으킬 수 있기 때문에 성가 시거나 위험한 옵션이 될 수 있습니다 (이전의 명령 실패는 무시 됨).
tobii

1
설정 SHELLFLAGS-e -c쉘이 실패 첫 번째 명령에 종료됩니다.
티모시 볼드윈

21

디렉토리를 다루고 만드는 귀여운 트릭이 있습니다. 여러 줄 문자열 또는 "cd;"를 사용하는 대신 각 명령에서 간단한 chdir 함수를 다음과 같이 정의하십시오.

CHDIR_SHELL := $(SHELL)
define chdir
   $(eval _D=$(firstword $(1) $(@D)))
   $(info $(MAKE): cd $(_D)) $(eval SHELL = cd $(_D); $(CHDIR_SHELL))
endef

그런 다음 규칙에 따라 호출하면됩니다.

all:
          $(call chdir,some_dir)
          echo "I'm now always in some_dir"
          gcc -Wall -o myTest myTest.c

다음을 수행 할 수도 있습니다.

some_dir/myTest:
          $(call chdir)
          echo "I'm now always in some_dir"
          gcc -Wall -o myTest myTest.c

41
"귀엽다"? 발에 몸을 쏠 수있는 충분한 밧줄.
tripleee

1
이 현재 디렉토리가 해당 규칙의 명령 또는 이후에 실행되는 모든 규칙에 대해 설정되어 있습니까? 또한 Windows 에서이 변형이 작동합니까?
user117529

8
이것은 물론 병렬 실행 ( -jn)을 중단합니다. 이것은 실제로 만드는 모든 요점입니다 .
bobbogo 2016 년

5
이것은 나쁜 해킹입니다. 그런 것에 의지해야한다면, Makefile을 사용하지 마십시오.
gatopeich

4
나는 그것이 나쁜 해킹이라는 것에 동의하지 않을 것입니다. 그러나 당신이 할 수있는 악한 일들을 보여줍니다.
JoeS

9

일단 도착하면 무엇을 하시겠습니까? 각 명령은 서브 쉘에서 실행되므로 서브 쉘은 디렉토리를 변경하지만 최종 결과는 다음 명령이 여전히 현재 디렉토리에 있다는 것입니다.

GNU make를 사용하면 다음과 같은 작업을 수행 할 수 있습니다.

BIN=/bin
foo:
    $(shell cd $(BIN); ls)

5
$(shell ...)cd $(BIN); ls또는 cd $(BIN) && ls(@andrewdotn 지적으로) 충분하다.
vapace

1

dir을 변경하려면

foo: 
    $(MAKE) -C mydir

multi:
    $(MAKE) -C / -C my-custom-dir   ## Equivalent to /my-custom-dir

-6

이처럼 :

target:
    $(shell cd ....); \
    # ... commands execution in this directory
    # ... no need to go back (using "cd -" or so)
    # ... next target will be automatically in prev dir

행운을 빕니다!


1
아니요, 잘못되었습니다. 특히, $(shell cd ....)이 특정 레시피가 실행될 때가 아니라 Makefile이 처음 구문 분석 될 때 실행됩니다.
tripleee

@triplee 확실하지 않음 — maketarget 빌드를 결정할 $(shell)때만 확장됩니다 . 경우 make가 제조법을 필요로하지, 그것을 확장하지 않습니다.
bobbogo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.