mkdir kullanılırken makefile'da "dizin zaten var hatası" nasıl önlenir


109

Makefile dosyamda bir dizin oluşturmam gerekiyor ve "dizin zaten var" hatasını kolayca görmezden gelebilsem bile defalarca almak istemiyorum.

Esas olarak mingw / msys kullanıyorum ama diğer kabuklar / sistemler arasında da çalışan bir şey istiyorum.

Bunu denedim ama işe yaramadı, herhangi bir fikir?

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

Yanıtlar:


106

UNIX'te sadece şunu kullanın:

mkdir -p $(OBJDIR)

Mkdir için -p seçeneği, dizin mevcutsa hata mesajını engeller.


39
"Genel olarak, bu programların yaygın olarak desteklenen (genellikle posix ile belirtilen) seçeneklerine ve özelliklerine bağlı kalın. Örneğin, 'mkdir -p' kullanmayın, ne kadar uygun olursa olsun, çünkü birkaç sistem onu ​​desteklemiyor hiçbir şekilde ve diğerleri ile paralel yürütme için güvenli değildir. " gnu.org/s/hello/manual/make/Utilities-in-Makefiles.html
greg.kindel

8
-pWindows üzerinde çalışmıyor, muhtemelen sorunun sorduğu şey bu. Bunun nasıl kabul edildiğinden emin değilim.
Antimon


1
@Antimony MinGW kabuğunun dışında GNU Make kullanıyorsanız muhtemelen yanlış bir şey yaptınız. Yine de senin seçimin.
yyny

"UNIX'te Sadece şunu kullanın ..." - make -pUnix mi yoksa Linux mu?
jww

122

Resmi marka belgelerine baktığımızda , işte bunu yapmanın iyi bir yolu:

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)

Burada | boru operatörü, sadece bir ön koşul tanımlayan bir sipariş. Bunun anlamı, $(OBJDIR)hedef (yerine mevcut olmalıdır daha yeni akım hedefini inşa etmek için).

Kullandığımı unutmayın mkdir -p. -pBayrak dokümanlar örneğine kıyasla ilave edildi. Başka bir alternatif için diğer cevaplara bakın.


4
Bu kesinlikle bu sorunun resmi yoludur.
lcltj

@CraigMcQueen: Gerçekten demek " $(OBJDIR)hedef olmalıdır mevcut " . Hedefi oluşturması gerekip gerekmediğine karar vermek için dosya varlığını (ve zaman damgalarını) kontrol edin. Dolayısıyla burada, eğer $(OBJDIR)is yokluğunda o yüzden o, onu inşa edecek mevcut akım hedef inşa etmek için $(OBJS)içini oluşturulacak.
ofavre

Sanırım bunu bulmadan önce bu problemi çözmenin diğer tüm kombinasyonlarını denedim (windows / linux arasında yapabildiğim kadar jenerik olan makefiles oluşturmaya çalışıyorum) - bu hemen hemen çalışabildiğim tek dosya, ama bu çok iyi çalışıyor! :)
code_fodder

67

Test komutunu kullanabilirsiniz:

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

7
Makefile dosyalarınızın hem Windows'ta (gnuwin32 ve PowerShell ile) hem de POSIX uyumlu işletim sistemlerinde çalışmasına ihtiyacınız varsa bu tercih edilen yoldur.
Kris Hardy

6
SAĞLANMIŞTIR, 'test' yardımcı programını sağlamak için gnuwin32 CoreUtils paketine sahipsiniz.
davenpcj

2
Burada çok geç, ancak make -jdizinin varoluş açısından test edildiği ve yaratıldığı zaman arasındaki bir yarış durumu nedeniyle paralel ( ) oluştururken bu çözümün bozulabileceğini belirtmek isterim . Bir iş orada olmadığını test edebilir, ancak onu oluşturmadan önce başka bir iş dizini oluşturur. Daha sonra ilk kez yapmaya çalıştığında, dizin zaten mevcut olduğundan başarısız olacaktır. Bu durumda en iyi çözüm, yalnızca @ TeKa'nın cevabında belirtildiği gibi ön koşulları kullanmaktır (kabul edilen cevap bu olmalıdır).
C0deH4cker

@MarcusJ OS X El Capitan'ımda çalışıyor. Hangi versiyon onu bozdu?
Franklin Yu

@ C0deH4cker - Cehaletimi affet ... TeKa hangi cevap? Yorum yaptığınızdan beri TeKa'nın adını değiştirdiğini düşünüyorum.
jww

18

İşte GNU make ile derleyici-çıktı dizinleri oluşturmak için kullandığım bir numara. Önce bu kuralı tanımlayın:

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

Ardından, dizine giden tüm dosyaları o dizindeki .d dosyasına bağımlı yapın:

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

$ ^ Yerine $ <kullanımına dikkat edin.

Son olarak, .d dosyalarının otomatik olarak kaldırılmasını önleyin:

 .PRECIOUS: %/.d

.D dosyasını atlamak ve doğrudan dizine bağlı olarak, bu dizine bir dosya her yazıldığında dizin değiştirme zamanı güncellendiğinden ve make'in her çağrısında yeniden oluşturmaya zorlayacağından işe yaramaz.


1
Ah, teşekkürler, böyle bir şeyin çalışmasını sağlamaya çalışıyordum. Birkaç hedef için "test -d foo || mkdir foo" istemiyorum, çünkü o zaman "make -j2" kullanmak onları aynı anda test edecek, her iki test de false veriyor ve sonra iki işlem mkdir, sonuncusu başarısız oluyor.
unhammer

13

Dizinin zaten mevcut olması sizin için bir sorun değilse, bu komut için stderr'i yeniden yönlendirebilir ve hata mesajından kurtulabilirsiniz:

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

Bunun Windows üzerinde de çalışma avantajı vardır. Komutun önündeki '-' işaretini unutmayın, bu yüzden make kurtarılmasın.
Michael Burr

11

Makefile dosyanızın içinde:

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

10

Windows'ta

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

Unix'te | Linux

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

Bu, Windows için.
sağlama toplamı

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

İlk sürüm Windows içindir, ikinci seçenek Linux'ta @checksum'un dediği gibi çalışır
Edgard Leal

İlki olan Windows sürümü atomik değildir, bu nedenle başka bir işlem (örneğin paralel moddaki bir kural) "yok" ve "mkdir" arasındaki dizini oluşturduğunda çalışmaz.
Petr Vepřek

7
ifeq "$(wildcard $(MY_DIRNAME) )" ""
  -mkdir $(MY_DIRNAME)
endif

Bu, ilave alet gerektirmeden mingw markaları için işe yarar.
davenpcj

6
$(OBJDIR):
    mkdir $@

Aynı zamanda birden fazla dizin için de çalışır, örn.

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

$(OBJDIRS):
    mkdir $@

$(OBJDIR)İlk hedef olarak eklemek işe yarar.


3

Mingw32 / msys / cygwin / linux altında çalışır

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

0

Dönüş kodunu açıkça görmezden gelirseniz ve hata akışını dökerseniz, make'iniz hata oluştuğunda bunu yok sayacaktır:

mkdir 2>/dev/null || true

Bu, paralel yapımda yarış tehlikesine neden olmamalıdır - ancak emin olmak için test etmedim.


0

Lars'ın cevabından biraz daha basit:

something_needs_directory_xxx : xxx/..

ve genel kural:

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

Temizlemek veya .PRECIOUS :-) yapmak için dokunma dosyaları yok

Başka bir küçük genel gmake numarası görmek istiyorsanız ya da minimum iskele ile yinelemeli olmayan yapımla ilgileniyorsanız, bu blogdaki iki ucuz gmake numarası ve diğer markayla ilgili gönderilere göz atabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.