mkdir을 사용할 때 makefile에서 "directory already exists error"를 방지하는 방법


109

내 makefile에 디렉토리를 생성해야하며 쉽게 무시할 수 있지만 "디렉토리가 이미 존재 함 오류"를 반복해서 표시하지 않으려 고합니다.

나는 주로 mingw / msys를 사용하지만 다른 쉘 / 시스템에서도 작동하는 것을 원합니다.

나는 이것을 시도했지만 작동하지 않았다, 어떤 아이디어?

ifeq (,$(findstring $(OBJDIR),$(wildcard $(OBJDIR) )))
-mkdir $(OBJDIR)
endif

답변:


106

UNIX에서는 다음을 사용하십시오.

mkdir -p $(OBJDIR)

mkdir에 대한 -p 옵션은 디렉토리가 존재하는 경우 오류 메시지를 방지합니다.


39
"일반적으로 이러한 프로그램의 광범위하게 지원되는 (일반적으로 posix 지정) 옵션 및 기능을 고수하십시오. 예를 들어 편리한 'mkdir -p'는 사용하지 마십시오. 일부 시스템에서는 지원하지 않기 때문입니다. 전혀 그리고 다른 사람들과 함께 병렬 실행에 안전하지 않습니다. " gnu.org/s/hello/manual/make/Utilities-in-Makefiles.html
greg.kindel

8
-pWindows에서 작동하지 않습니다. 아마도 질문이 묻는 것입니다. 이것이 어떻게 받아 들여 졌는지 확실하지 않습니다.
Antimony 2014 년


1
@Antimony MinGW 셸 외부에서 GNU Make를 사용하는 경우 아마도 뭔가 잘못되었을 것입니다. 그래도 당신의 선택.
yyny

"UNIX에서는 이것을 사용하십시오 ..." - make -pUnix 또는 Linux입니까?
jww

122

보면 공식 메이크업 문서 , 여기에 그것을 할 수있는 좋은 방법입니다 :

OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)

$(OBJDIR)/%.o : %.c
    $(COMPILE.c) $(OUTPUT_OPTION) $<

all: $(OBJS)

$(OBJS): | $(OBJDIR)

$(OBJDIR):
    mkdir -p $(OBJDIR)

여기에서 | 파이프 연산자, 주문 전용 전제 조건을 정의합니다. 현재 대상을 빌드하려면 대상 $(OBJDIR)더 최근 대신 존재해야 함을 의미합니다 .

내가 mkdir -p. -p플래그가 문서의 예를 비교 하였다. 다른 대안에 대해서는 다른 답변을 참조하십시오.


4
이것은 확실히이 문제에 대한 공식적인 방법입니다.
lcltj 2011

@CraigMcQueen : 나는 진정한 의미 의 " $(OBJDIR)대상이 있어야 할 존재 " . 파일 존재 여부 (및 타임 스탬프)를 확인하여 대상을 빌드해야하는지 결정합니다. 따라서 여기서 $(OBJDIR)가 없으면 빌드하므로 현재 대상을 빌드하기 위해 존재 하며 $(OBJS)내부에 생성됩니다.
ofavre

나는 이것을 찾기 전에 말 그대로이 문제를 해결하는 다른 모든 조합을 시도했다고 생각합니다 (나는 Windows / Linux 사이에서 가능한 한 일반적인 makefile을 생성하려고합니다)-이것은 내가 작업 할 수있는 유일한 것입니다. 잘 작동합니다! :)
code_fodder

67

test 명령을 사용할 수 있습니다.

test -d $(OBJDIR) || mkdir $(OBJDIR)

7
Windows (gnuwin32 및 PowerShell 사용) 및 POSIX 호환 OS에서 모두 작동하도록 makefile이 필요한 경우 선호되는 방법입니다.
Kris Hardy

6
'test'유틸리티를 제공하는 gnuwin32 CoreUtils 패키지가 제공됩니다.
davenpcj

2
여기에 늦었지만이 솔루션은 make -j디렉터리가 존재하는지 테스트 할 때와 생성 될 때 사이의 경쟁 조건으로 인해 병렬로 빌드 할 때 ( ) 중단 될 수 있음을 지적하고 싶습니다 . 한 작업은 자신이 없는지 테스트 할 수 있지만 생성하기 전에 다른 작업이 디렉토리를 생성합니다. 그런 다음 첫 번째 시도가 디렉토리가 이미 존재하기 때문에 실패합니다. 이 경우 가장 좋은 해결책은 @TeKa의 답변에 언급 된 전제 조건 만 주문하는 것입니다 (수용된 답변이어야 함).
C0deH4cker

@MarcusJ는 내 OS X El Capitan에서 작동합니다. 어떤 버전이 고장 났습니까?
Franklin Yu

@ C0deH4cker-내 무지를 용서하세요 ... TeKa는 어떤 대답입니까? 당신이 댓글을 달고 나서 테 카가 이름을 바꾼 것 같아요.
jww

18

다음은 컴파일러 출력 디렉토리를 만들기 위해 GNU make와 함께 사용하는 트릭입니다. 먼저이 규칙을 정의하십시오.

  %/.d:
          mkdir -p $(@D)
          touch $@

그런 다음 해당 디렉토리의 .d 파일에 종속 된 디렉토리로 이동하는 모든 파일을 만듭니다.

 obj/%.o: %.c obj/.d
    $(CC) $(CFLAGS) -c -o $@ $<

$ ^ 대신 $ <를 사용하십시오.

마지막으로 .d 파일이 자동으로 제거되지 않도록합니다.

 .PRECIOUS: %/.d

.d 파일을 건너 뛰고 디렉토리에 직접 의존하는 것은 파일이 해당 디렉토리에 기록 될 때마다 디렉토리 수정 시간이 업데이트되어 make를 호출 할 때마다 강제로 다시 작성되므로 작동하지 않습니다.


1
아, 고마워요. 이런 일을하려고 했어요. 여러 목표에 대해 "test -d foo || mkdir foo"를 원하지 않습니다. "make -j2"를 사용하면 동시에 테스트하고 두 테스트 모두 거짓을 제공하고 두 프로세스가 mkdir을 시도합니다. 마지막 실패.
unhammer

13

디렉토리가 이미 존재하는 것이 문제가되지 않는 경우 해당 명령에 대한 stderr을 리디렉션하여 오류 메시지를 제거 할 수 있습니다.

-mkdir $(OBJDIR) 2>/dev/null

이것은 Windows에서도 작업 할 수 있다는 장점이 있습니다. 명령 앞의 '-'를 잊지 마세요. 그래서 make가 보석금을 내지 않습니다.
Michael Burr

11

메이크 파일 내부 :

target:
    if test -d dir; then echo "hello world!"; else mkdir dir; fi

10

Windows에서

if not exist "$(OBJDIR)" mkdir $(OBJDIR)

유닉스에서 | 리눅스

if [ ! -d "$(OBJDIR)" ]; then mkdir $(OBJDIR); fi

이것은 Windows 용입니다.
검사

/bin/sh: 1: Syntax error: end of file unexpected (expecting "then")
wotanii

첫 번째 버전은 Windows 용이고 두 번째 옵션은 @checksum이 말한대로 Linux에서 작동합니다.
Edgard Leal

첫 번째, Windows 버전은 원 자성이 아니므로 다른 프로세스 (예 : 병렬 모드의 규칙)가 "존재하지 않음"과 "mkdir"사이에 디렉토리를 만들 때 작동하지 않습니다.
Petr Vepřek


6
$(OBJDIR):
    mkdir $@

또한 여러 디렉토리에서 작동합니다.

OBJDIRS := $(sort $(dir $(OBJECTS)))

$(OBJDIRS):
    mkdir $@

$(OBJDIR)첫 번째 대상으로 추가하면 잘 작동합니다.


3

mingw32 / msys / cygwin / linux에서 작동합니다.

ifeq "$(wildcard .dep)" ""
-include $(shell mkdir .dep) $(wildcard .dep/*)
endif

0

리턴 코드를 명시 적으로 무시하고 오류 스트림을 덤프하면 오류가 발생하면 make가 오류를 무시합니다.

mkdir 2>/dev/null || true

이것은 병렬 메이크에서 레이스 위험을 유발해서는 안되지만 확실하게 테스트하지는 않았습니다.


0

Lars의 대답보다 조금 더 간단합니다.

something_needs_directory_xxx : xxx/..

및 일반 규칙 :

%/.. : ;@mkdir -p $(@D)

정리하거나 .PRECIOUS를 만들 터치 파일이 없습니다. :-)

좀 더 일반적인 gmake 트릭을보고 싶거나 최소한의 스캐 폴딩을 사용 하는 비재 귀적 make에 관심이 있다면 해당 블로그에서 두 가지 더 저렴한 gmake 트릭 과 다른 make 관련 게시물을 확인하는 것이 좋습니다.

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