Bir makefile 'cd' komutunu nasıl yazarım?


355

Örneğin, benim makefile böyle bir şey var:

all:
     cd some_directory

Ama makeyazdığımda echokomutta olduğu gibi sadece 'cd some_directory' gördüm .


5
Ne yapmak istediğiniz belli değil, ama, tecrübelerime göre make, dizini asla böyle değiştirmek istemedim. Belki çözümünüz için başka bir yaklaşım denemelisiniz?
P

2
Dizininizin önemli olduğuna inanmak yaygın bir acemi hatasıdır. Çoğu şey için değil; cd dir; cmd fileneredeyse her zaman daha faydalı olarak ifade edilebilir cmd dir/file.
tripleee

34
Mevcut çalışma dizininizin önemsiz olduğuna inanmak yaygın bir acemi hatasıdır. Birçok program, özellikle de kabuk betikleri, belirli bir değeri dikkate alınarak yazılır .. Çoğu aracın, pwd'nizi değiştirmenize gerek kalmayacak şekilde tasarlandığı doğrudur. Ancak bu her zaman doğru değildir ve dizininizin önemli olabileceğine inanmak için "hata" demenin iyi bir fikir olduğunu düşünmüyorum.
Evelyn Kokemoor

İpucu: cd komutu (göreceli) dizin bile, "Böyle bir dosya veya dizin" derse yapar mevcut, sizin CDPATH ortam değişkeni ya check olduğunu boşaltmak veya içeren "". Make komutu, ayarlanmışsa yalnızca CDPATH üzerinden göreceli bir yol bulan "sh" komutlarını çalıştırır. Bu deneyecek olan bash ile tezat oluşturuyor. CDPATH danışmadan önce.
Denis Howe

Yanıtlar:


621

Aslında komutu yürütür, dizini olarak değiştirir some_directory, ancak bu bir alt işlem kabuğunda gerçekleştirilir ve ne make ne de çalıştığınız kabuğu etkilemez.

İçinde daha fazla görev yapmak some_directoryistiyorsanız, noktalı virgül eklemeniz ve diğer komutları da eklemeniz gerekir. Yeni satırları kuralın sonu olarak make ile yorumlandıkları için kullanamayacağınızı unutmayın, bu nedenle açıklık için kullandığınız yeni satırların ters eğik çizgiden kaçması gerekir.

Örneğin:

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

Ayrıca, ters eğik çizgi ve satırsonu eklemenize rağmen, her komut arasında noktalı virgül gerektiğini unutmayın. Bunun nedeni, tüm dizginin kabuk tarafından tek bir satır olarak ayrıştırılmasıdır. Yorumlarda belirtildiği gibi, komutlara katılmak için '&&' işaretini kullanmalısınız; bu, yalnızca önceki komut başarılı olduğunda yürütülecekleri anlamına gelir.

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

Bu, temizlik gibi yıkıcı işler yaparken, başka türlü yanlış bir şey cdolursa olsun , yanlış şeyleri yok edeceğiniz için özellikle önemlidir .

Yine de yaygın bir kullanım, bakmak istediğiniz alt dizinde make'i çağırmaktır. Bunun için bir komut satırı seçeneği var, bu yüzden cdkendinizi aramanıza gerek yok , bu yüzden kuralınız şöyle görünecek

all:
        $(MAKE) -C some_dir all

hedef "all" ile oraya dönüşecek some_dirve Makefileorada çalışacaktır . En iyi uygulama olarak, doğru çağrı örneğini çağırmaya özen göstereceğinden (örneğin, yapı ortamınız için özel bir make sürümü kullanıyorsanız) ve ayrıca çalışırken biraz farklı davranışlar sağladığından doğrudan aramak $(MAKE)yerine kullanın. makegibi belirli anahtarları kullanarak -t.

Kayıt için, çıktısı olmasa bile, gördüğünüz komutun yürüttüğü komutu (açıkça bastırılmadıkça) her zaman echos yapın.


8
Her zaman değil . Yankıyı bastırmak için satırın başına @ koymanız yeterlidir.
Beta

2
@Beta: evet, ve tire öneki hata durumunu da yok sayar. Belki biraz taşındım, ne tür bir komut olduğuna bakılmaksızın, markanın emrinin emri yaptığını belirtmek istedim. Ve bu durumda, çıktısı olmayan bir komuttur, bu da yankılanmanın markaya aşina olmayan birine daha da yabancı görünmesini sağlar.
falstro

46
İki nit: 1. Komutlar gerçekten birleştirilmelidir &&, çünkü ;dizin yoksa ve cdbaşarısız olursa, kabuk geçerli dizindeki komutların geri kalanını çalıştırmaya devam eder ve bu da gizemli “dosya değil "derleme mesajları, make çağrılırken sonsuz döngüler veya gibi kurallar için felaket clean:: cd dir; rm -rf *. Alt markaları yürütmesini zaman 2. çağrı $(MAKE)yerine makeböylece seçeneklerinin doğru geçirilir .
andrewdotn

2
@perreal, genellikle şöyle bir kalıp kuralı tanımlarım: %-recursive:body ile: @T="$@";$(MAKE) -C some_dir $${T%-*}( Alt dizinler listesi üzerinde döngü yapmak için genellikle for döngüsü de var, hedef adının bir kısmını $${T%-*}kaldıran bir bash genişletmesi -recursive) ve sonra her biri için açık kısa el (ve .PHONY) hedeflerini tanımlamak gibi all: all-recursive, check: check-recursive, clean: clean-recursive.
falstro

1
@ChristianStewart, true, yorum 2 ve 3'te bahsedildiği gibi
falstro

95

GNU make 3.82'den (Temmuz 2010) başlayarak, .ONESHELLtüm tarif çizgilerini kabuğun tek bir örneğinde çalıştırmak için özel hedefi kullanabilirsiniz (cesur vurgu mayını):

  • Yeni özel hedef: .ONESHELLtalimatını yapmak çağırmak için kabuğun tek bir örneğini ve birlikte bunu sağlamak tamamı tarifi içerirse kaç satır arasında. [...]
.ONESHELL: # Only applies to all target
all:
    cd ~/some_dir
    pwd # Prints ~/some_dir if cd succeeded

6
Sadece dikkat pwdkendisi hem de işleri `pwd`(ters tırnakların ile), ancak $(shell pwd)ve $(PWD)hala yapmadan önce dizini dönecektir cddoğrudan onlara kullanamaması için, komutu.
anol

3
Oysa Evet değişken ve işlev genişlemesi, make komutları çalıştırmadan önce yapılır, çünkü pwdve `pwd`kabuğun kendisine tarafından yürütülür.
Chnossos

2
Herkes eski makyaj malzemeleri üzerinde çalışmaz ve o zaman bile bu cevap bu olasılığın var olduğunu bilmekle ilgilidir .
Chnossos

1
Bu, can sıkıcı / tehlikeli bir seçenek olabilir, çünkü yalnızca bir hedef için son komut bir hataya neden olabilir (önceki komut hatalarını göz ardı eder) ve muhtemelen sizinle çalışan hiç kimse bunu beklemeyecektir.
tobii

1
Set SHELLFLAGSiçin -e -cve kabuk başarısız ilk komut ile çıkılacak.
Timothy Baldwin

21

İşte dizinlerle başa çıkmak ve yapmak için sevimli bir numara. Çok satırlı dizeler veya "cd;" her komutta, basit bir chdir işlevini şu şekilde tanımlayın:

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

O zaman tek yapmanız gereken onu kuralınızda çağırmaktır:

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

Aşağıdakileri bile yapabilirsiniz:

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

41
"Şirin"? Daha çok kendinizi ayağa vurmak için yeterli ip gibi.
üçlü

1
Bu geçerli dizin daha sonra yalnızca bu kuraldaki komutlar için mi yoksa daha sonra yürütülen tüm kurallar için mi ayarlanmış? Ayrıca, bunun bazı varyasyonları Windows altında çalışır mı?
user117529

8
Paralel yürütme (kurs sonları bu -jntüm noktasıdır), marka gerçekten.
Haziran'da bobbogo

5
Bu kötü bir hack. Eğer böyle bir şeye başvurmak zorunda kalırsanız, onlar için ne için Makefiles kullanmıyorsunuz.
gatopeich

4
Kesinlikle kötü bir kesmek olduğunu kabul etmeyeceğim. Ama yapabileceğiniz bazı kötü şeyleri gösteriyor.
JoeS

9

Oraya vardığında ne yapmasını istiyorsun? Her komut bir alt kabukta yürütülür, bu nedenle alt kabuk dizini değiştirir, ancak sonuçta sonraki komut hala geçerli dizinde olur.

GNU markası ile aşağıdakileri yapabilirsiniz:

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

5
Ne $(shell ...)zaman cd $(BIN); lsveya cd $(BIN) && ls(@andrewdotn'un işaret ettiği gibi) yeterli olur.
vapace

1

Dir değiştirmek için

foo: 
    $(MAKE) -C mydir

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

-6

Bunun gibi:

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

İyi şanslar!


1
Hayır, bu yanlış. Özellikle, $(shell cd ....)Makefile başlangıçta ayrıştırıldığında yürütülür, bu özel tarif çalıştırıldığında çalıştırılmaz.
tripleee

@triplee oldukça Değil - $(shell)Yalnızca genişletilir yapmak inşa etmeye karar verir hedefe . Eğer yapmak tarifi ihtiyacı asla, onu genişlemez.
14'te bobbogo
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.