Bir komutun çıktısını Makefile değişkenine atama


225

Yüklü Python belirli bir sürümden daha büyükse, bazı kurallar koşullu yürütmek gerekir (diyelim 2.5).

Yürütmek gibi bir şey yapabileceğimi düşündüm:

python -c 'import sys; print int(sys.version_info >= (2,5))'

ve bir ifeqmake deyiminde çıktıyı (tamamsa '1', aksi takdirde '0') kullanarak .

Basit bir bash kabuk betiğinde sadece:

MY_VAR=`python -c 'import sys; print int(sys.version_info >= (2,5))'`

ama bu bir Makefile'de işe yaramıyor.

Baska öneri? Bunu başarmak için başka herhangi bir geçici çözümü kullanabilirim.


Bir Makefile'de benim için diğer komut dosyalarını yürütmek için komut çalışmasını garip bir şekilde keneler. Başka bir şey olabilir.
Leif Gruenwoldt

Yanıtlar:


346

Make shellyerleşimini aşağıdaki gibi kullanınMY_VAR=$(shell echo whatever)

me@Zack:~$make
MY_VAR IS whatever

me@Zack:~$ cat Makefile 
MY_VAR := $(shell echo whatever)

all:
    @echo MY_VAR IS $(MY_VAR)

34
kabuk standart bir yerleşik yerleşik komut değildir. Bu bir GNU Make yerleşiktir.
Dereckson

12
stackoverflow.com/a/2373111/12916 kaçış hakkında önemli bir not ekler $.
Jesse Glick

6
Bu basit örnek işe yarıyor. Ayrıca kabuk komutları boru hattı ile çalışır. Ancak kabuk komutunda $'ı temsil etmek için $$ kullanmanız önemlidir
Sergey P. aka azure

28
Soru biraz eski olsa da, MY_VAR: = $ (shell ...) yapmak en iyisidir, aksi takdirde MY_VAR her değerlendirildiğinde, tekrar $ (shell ...) yürütür.
Russ Schultz

Kabuk ve açılış parantezleri arasında bir boşluk vardı ve sadece alanı çıkardıktan sonra makefile çıktı metnimi yaptı
peterchaula 28:17

29

Ödevi sarmak evalbenim için çalışıyor.

# dependency on .PHONY prevents Make from 
# thinking there's `nothing to be done`
set_opts: .PHONY
  $(eval DOCKER_OPTS = -v $(shell mktemp -d -p /scratch):/output)

6
"Not: @true, Make'in yapılacak bir şey olmadığını düşünmesini engelliyor." Um, bunun .PHONY always make these targetsiçin var.
underscore_d

Teşekkür ederim! Bu bana makefile "garip bash" atlamak yardımcı olur
Nam G VU

19

İşte tarif içinde boru ve değişken atama ile biraz daha karmaşık bir örnek:

getpodname:
    # Getting pod name
    @eval $$(minikube docker-env) ;\
    $(eval PODNAME=$(shell sh -c "kubectl get pods | grep profile-posts-api | grep Running" | awk '{print $$1}'))
    echo $(PODNAME)

2
Kullanışlı olması durumunda PODNAME, dağıtım adına göre biraz benzer bir yaklaşım kullanıyorum :$(eval PODNAME=$(shell sh -c "kubectl get pod -l app=sqlproxy -o jsonpath='{.items[0].metadata.name}'"))
Jan Richter

Sözdizimi, hem shell builtin eval (docker-env satırında) hem de make işlevi eval (sonraki satırda) kullandığınızı fark edene kadar bir saniye boyunca beni şaşırttı .
Brian Gordon

17

Sorunu çözen gerçek sözdiziminin görünürlüğünü artırmak için bir cevap yazıyorum. Ne yazık ki, birinin önemsiz olarak görebileceği şey, makul bir soruya basit bir cevap arayan biri için çok önemli bir baş ağrısı olabilir.

Aşağıdakileri "Makefile" dosyasına koyun.

MY_VAR := $(shell python -c 'import sys; print int(sys.version_info >= (2,5))')

all:
    @echo MY_VAR IS $(MY_VAR)

Görmek istediğiniz davranış şudur (en son python yüklü olduğu varsayılarak).

make
MY_VAR IS 1

Yukarıdaki metni kopyalayıp Makefile'a yapıştırırsanız, bunu alacak mısınız? Muhtemelen değil. Muhtemelen burada bildirilenler gibi bir hata alırsınız:

makefile: 4: *** eksik ayırıcı. Dur

Neden: Şahsen orijinal bir sekme kullanmama rağmen, Yığın Taşması (yardımcı olmaya çalışarak) sekmimi birkaç boşluğa dönüştürür. Hayal kırıklığına uğramış internet vatandaşı olarak, şimdi kullandığım metnin aynısına sahip olduğunuzu düşünerek bunu kopyalayın. Make komutu artık boşlukları okur ve "all" komutunun yanlış biçimlendirildiğini bulur. Bu yüzden yukarıdaki metni kopyalayın, yapıştırın ve "@echo" dan önce boşlukları bir sekmeye dönüştürün ve bu örnek eninde sonunda sizin için çalışmalıdır.


Hangi editöre yapıştırdığınıza bağlıdır. Bir Eclipse Makefile editörüne kopyaladım ve yapıştırdım ve önde gelen bir sekme aldım (gerektiği gibi).
Technophile

Bunu düşünmedim. Atom burada.
AlanSE

11

Bunun gibi tariflere dikkat edin

target:
    MY_ID=$(GENERATE_ID);
    echo $MY_ID;

İki şeyi yanlış yapar. Tarifteki ilk satır, ikinci satırdan ayrı bir kabuk örneğinde yürütülür. Değişken bu arada kaybolur. İkinci yanlış olan şey $ise kaçmamasıdır.

target:
    MY_ID=$(GENERATE_ID); \
    echo $$MY_ID;

Her iki sorun da düzeltildi ve değişken kullanılabilir. Ters eğik çizgi, her iki satırı tek bir kabukta çalışacak şekilde birleştirir, bu nedenle değişkenin ayarı ve değişken sözcüklerin okunması işe yarar.

Orijinal yazının bir MAKE değişkenine kabuk komutunun sonuçlarının nasıl alınacağını söylediğini ve bu cevabın bir kabuk değişkenine nasıl alınacağını gösterdiğini anlıyorum. Ancak diğer okuyucular faydalanabilir.

Son bir iyileştirme, tüketici bir "ortam değişkeni" ayarlanmasını beklerse, bunu dışa aktarmanız gerekir.

my_shell_script
    echo $MY_ID

bunu makefile içinde

target:
    export MY_ID=$(GENERATE_ID); \
    ./my_shell_script;

Umarım birine yardım eder. Genel olarak, tarifler dışında herhangi bir gerçek iş yapmaktan kaçınılmalıdır, çünkü birisi '- kuru çalışma' seçeneğiyle makefile kullanırsa, sadece ne yapacağını GÖRMEK için istenmeyen yan etkileri olmaz. Her $(shell)çağrı derleme zamanında değerlendirilir ve yanlışlıkla bazı gerçek işler yapılabilir. Kimliğini oluşturmak gibi gerçek işi mümkünse tariflerin içine bırakmak daha iyidir.


9

GNU Make ile, kullanabilir shellve evalkeyfi komut satırı çağırmaları gelen deposunda, kaçak ve atama çıkışına. Aşağıdaki örnek ile kullanılanlar arasındaki fark :=, :=ödev bir kez (karşılaşıldığında) ve herkes için gerçekleşir. Tekrarlanan genişletilmiş değişkenler =biraz daha "tembel"; diğer değişkenlere yapılan başvurular, değişkenin kendisine referans verilinceye kadar devam eder ve müteakip özyinelemeli değişkene her başvuru yapıldığında gerçekleşir , bu da "tutarlı, çağrılabilir, parçacıklar" yapmak için arzu edilir. Daha fazla bilgi için değişkenleri ayarlama kılavuzuna bakın .

# Generate a random number.
# This is not run initially.
GENERATE_ID = $(shell od -vAn -N2 -tu2 < /dev/urandom)

# Generate a random number, and assign it to MY_ID
# This is not run initially.
SET_ID = $(eval MY_ID=$(GENERATE_ID))

# You can use .PHONY to tell make that we aren't building a target output file
.PHONY: mytarget
mytarget:
# This is empty when we begin
    @echo $(MY_ID)
# This recursively expands SET_ID, which calls the shell command and sets MY_ID
    $(SET_ID)
# This will now be a random number
    @echo $(MY_ID)
# Recursively expand SET_ID again, which calls the shell command (again) and sets MY_ID (again)
    $(SET_ID)
# This will now be a different random number
    @echo $(MY_ID)

Her karşılaştığım ilk güzel açıklamaya sahipsiniz. Teşekkür ederim. Eklenecek bir şey olsa da, yanlış$(SET_ID) olan bir ifcümlenin içinde yaşıyorsa , o zaman hala çağrılır .
Roman

Yine de çağrılır, çünkü stmts çalışma zamanında değil makefile derleme zamanında değerlendirilir. Çalışma zamanına özel talimatlar için bunları tariflere koyun. Şartlıysa, tarifin bir parçası olarak bash / shell ile yazılmış stmts ekleyin.
Juraj

0

Aşağıdaki örnekte, Makefile klasör yolunu sakladım LOCAL_PKG_DIRve sonra LOCAL_PKG_DIRdeğişkenlerde hedefler kullandım.

Makefile:

LOCAL_PKG_DIR := $(shell eval pwd)

.PHONY: print
print:
    @echo $(LOCAL_PKG_DIR)

Terminal çıkışı:

$ make print
/home/amrit/folder
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.