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