Kedves Fórumozók!
Egy makefile-t próbálok átírni, és beletenni pár feltételes kifejezést, de csak nem akar összejönni, és nem értem, hogy miért.
Röviden, ez az egyszerűsített szerkezete:
UNAME = $(shell uname)
.PHONY: build
build: ## perform build
@echo "Building..."
@ifeq ($(UNAME), Linux)
shell_command_1
else
ifeq ($(UNAME), Darwin)
shell_command_2
endif
endif
.DEFAULT_GOAL = build
Ha meghívom, ezt a hibaüzenetet kapom:
Building...
/bin/sh: 1: Syntax error: word unexpected (expecting ")")
make: *** [Makefile:7: build] Error 2Nem világos, hogy mi lehet a gond, ráadásul a shell parancsokat sem piszkáltam, hogy elromlottak volna.
Van esetleg valakine ötlete, hogy mit ronthattam el?
- 486 megtekintés
Hozzászólások
Ne tabuláld (azaz a sor elején legyen az "ifeq", "else", "endif"). Makefileban egyébként viccesen működik az if, félúton van a precompiler direktíva és az interpretált között. Azaz nem a helyén hajtódik végre a rule-ban, hanem lefuttás előtt "szabja át" a rule parancsait.
Még pár észrevétel: a legelső rule-t szokás "all:"-nak hívni, és itt szokás megadni a célfájlt, jellemzően TARGET változóban. Szóval valami ilyesmi:
TARGET=build all: $(TARGET) ...
Ez azért jó, mert paraméter nélkül meghívva a make-t az a legelső rule-t hajtja végre (jelen esetben az "all"-t, aminek meg az előfeltétele a tényleges kimenet, ez meg azért jó, ha külön van, mert később bővítheted az "all"-t annélkül, hogy szét kéne mást barmolni).
- A hozzászóláshoz be kell jelentkezni
(az all-ra vonatozóan)
Köszönöm, ha előzmény nélkül csinálnám, valószínű így járnék el én is, de ez már egy létező valami volt és nem akarom kidobni az egészet.
(a tabulálásra vonatkozóan)
Köszönöm, átírtam és most egy lépéssel tovább jutottam:
UNAME = $(shell uname)
.PHONY: build
build: ## perform build
@echo "Building..."
ifeq ($(UNAME), Linux)
shell_command_1
else
ifeq ($(UNAME), Darwin)
shell_command_2
endif
endif
.DEFAULT_GOAL = build
A hibaüzenet pedig:
$ make
Makefile:5: *** missing separator. Stop.... The vision and the mission lost,
For those with corporate souls ...
Slackware Linux current | 5.10.38-janos
- A hozzászóláshoz be kell jelentkezni
De hát megmondja pontosan, mi a baja:
Makefile:5: *** missing separator. Stop.
Az ötödik sorban a parancs elől is kivetted a tabot. A "@echo" elé továbbra is kell, mert hát az parancs, a recept része. Arra is figyelj, hogy ezelőtt (illetve a "shell_command_X" előtt) konkrétan egy tab karakter kell, ha a szövegszerkesztőd lecseréli szóközökre, akkor sem fog működni. Pontosan egy darab U+00009 karakter legyen az utasítások előtt, ez fontos.
- A hozzászóláshoz be kell jelentkezni
de az @echo "Building..." az egy shell script, szóval tabulálni kell.
amúgy meg a recipe alá tartozó (ugy tabbal behúzott) rész egésze nem egy shell scriptként fut le, hanem megannyi
sh -e 'echo "Building..."'
sh -e 'shell_command_1'
sh -e 'shell_command_2'
system parancsként. tehát mondjuk változókat nem tudsz átadni.
hacsak nem definiálod a .ONESHELL: speckó targetet (lásd make-doc section 5.3.1 Using One Shell) vagy vigyázol hogy minden sort backslash-sel zárj (azaz gyakorlatilag egyetlen sor lesz a scripted).
- A hozzászóláshoz be kell jelentkezni
tehát mondjuk változókat nem tudsz átadni.
De, simán megy, csak a parancs elé kell írni, és környezeti változó lesz belőle. Pl. "DEBUG=$(DEBUG) VERBOSE=$(VERBOSE) shell_command_1" esetén a DEBUG és a VERBOSE is a shell_command_1 environment-jébe kerül. (Elismerem, nem kényelmes megoldás, de működik.)
- A hozzászóláshoz be kell jelentkezni
ez nem furcsaság, ez a jó működés, mert a Makefile-ben az ifeq/else/endif feltételek a make szintjén értelmezendők, nem a shellben. te viszont a recept részen, egy tabbal behúzva próbáltad használni az ifeq-et, így a make elküldte azt a /bin/sh-nek, a shell pedig nem ismeri az ifeq-et, ergó syntax error.
4 és fél éve csak vim-et használok. elsősorban azért, mert még nem jöttem rá, hogy kell kilépni belőle.
- A hozzászóláshoz be kell jelentkezni
Köszönöm, átírtam.
Most más hibaüzenetet kapok.
... The vision and the mission lost,
For those with corporate souls ...
Slackware Linux current | 5.10.38-janos
- A hozzászóláshoz be kell jelentkezni
És akkor azt is tegyük ide, hogy a Makefile-beli ifeq és társai elé nem kell a @, ami a szabályokban arra szolgál hogy kussban fussanak le a mögöttes parancsok (azaz nem fogod látni, hogy most az echo-t futtatja, csak az echo kimenetét).
- A hozzászóláshoz be kell jelentkezni
+1 proba (tessek megprobalni megmenteni a tanulatorokat)
UNAME = $(shell uname)
.PHONY: build
build: ## perform build
@echo "Building..."
ifeq ($(UNAME), Linux)
echo 'Ez Linux'
else
ifeq ($(UNAME), Darwin)
echo 'Ez egy pintyfele'
endif
endif
- A hozzászóláshoz be kell jelentkezni
Egy kis megtakarítás (vagyis csak egy shell/uname-hívás lesz):
UNAME := $(shell uname)Illusztráció:
UN1 = $(shell uname)
UN2 := $(shell uname)
valuetest:
$(info UN1=${UN1}, $$(value UN1)=$(value UN1))
$(info UN2=${UN2}, $$(value UN2)=$(value UN2))
@echo 'UN1=${UN1}, $$(value UN1)=$(value UN1)'
@echo 'UN2=${UN2}, $$(value UN2)=$(value UN2)'A biztonság kedvéért info-val és echo-val is kiiratjuk ugyanazt:
UN1=Linux, $(value UN1)=$(shell uname)
UN2=Linux, $(value UN2)=Linux
UN1=Linux, $(value UN1)=$(shell uname)
UN2=Linux, $(value UN2)=LinuxEbből azt kellene látni, hogy az 'UN1' egy 'programot' tárol, amit a ${UN1} használatakor futatt, az 'UN2' viszont rögtön a program kimenetét tárolja.
- A hozzászóláshoz be kell jelentkezni
Ebből azt kellene látni, hogy az 'UN1' egy 'programot' tárol, amit a ${UN1} használatakor futatt, az 'UN2' viszont rögtön a program kimenetét tárolja.
Az UN1 deklaráláskor kiértékelődik (a shell hívás miatt). Innentől már az uname által visszaadott értéket tárolja, tehát nem fut le többször.
Egy egyszerű teszt:
VAL= $(shell date)
all:
@date
@sleep 2
@echo ${VAL}
@sleep 2
@echo ${VAL}
Mindhárom dátum ugyanaz lesz, nem lesznek 2 másodperces eltérések (azaz 2 másodperc múlva nem fut le még egyszer) - max. ha épp nagyon olyankor futtatod, hogy a VAL-féle date után az all első date-je között másodperc-váltás történik :D
- A hozzászóláshoz be kell jelentkezni
Ez jogos, legjobb mindent kísérletileg ellenőrizni; esetünkben az a gond, hogy a ${VAL} kiértékelése során megtörténik a ugyan a date futása, de a ${VAL} összes előfordulásának kiértékelése még azelőtt megtörténik, hogy a parancsok bármelyikét futtatná a make. Egy pontosabb idő-kiírás segíthet:
# Makefile
VAL=$(shell date +%Y%m%d.%H%M%S.%N)
all:
@date +%Y%m%d.%H%M%S.%N
@sleep 2
@echo ${VAL}
@sleep 2
@echo ${VAL}
Kimenete:
20251023.201042.442597716
20251023.201042.440473821
20251023.201042.441549365
Ha az értékadást kicseréljük a := -re, akkor ilyen lesz a kimenet:
20251023.201643.425711831 20251023.201643.423886032 20251023.201643.423886032
- A hozzászóláshoz be kell jelentkezni
Hm, érdekes. Ha BSD make-kel csinálom:
VAL!= date +%Y%m%d.%H%M%S.%N
all:
@date +%Y%m%d.%H%M%S.%N
@sleep 2
@echo ${VAL}
@sleep 2
@echo ${VAL}
Akkor a kimenet:
20251024.140313.795873645
20251024.140313.792335024
20251024.140313.792335024Mentségemre szóljon, BSD make-et használok (ebből indultam ki), de a GNU make tényleg úgy működik, ahogy írtad.
- A hozzászóláshoz be kell jelentkezni
GNU, pontosan mit vártál? 😜
- A hozzászóláshoz be kell jelentkezni
Ez már az alap szabványon túl van, így lehet eltérés a make-variánsok között. Ha dokumentálva van, akkor szerintem nincs vele semmi gond :)
- A hozzászóláshoz be kell jelentkezni
Ebböl azt mondanám, hogy ott a != felel meg a gmake := operátorának. Érdemes lenne a doksit is összenézni...
Szerk: Itt még több is van, mint amiről eddig tudni véltem:
https://www.gnu.org/software/make/manual/make.html#Variable-Assignment
- A hozzászóláshoz be kell jelentkezni
Nem. A != operátor a shelles értékadás, tehát az egyenlőségjel utáni kifejezés "lefuttatásra kerül" és az stdout-ja lesz a változó értéke. A shell-es értékadásra nincs variáció. Bocsánat, ezt nem írtam.
A := operátor itt is ugyanaz, de a += és a ?= van még és ennyi.
- A hozzászóláshoz be kell jelentkezni
Bocsánat, igen, akartam is editálni, de elkéstem. Az eddigiek alapján azt mondanám, hogy legalább az alábbiak egyformák a két verzióban:
var = deferred
var := immediate
var != immediate-shell- A hozzászóláshoz be kell jelentkezni
Ja, teljesen együttérzek, a makefile-nak nem a legjobb a szintaxisa, hasonlóan balfék a POSIX shell-hez meg a Perl-hez hasonlóan, csak itt nem a pontosvesszővel, meg akármivel szívsz (Lisp-nél ez a zárójelegyeztetés, Python-ban a behúzási szintek), hanem hogy itt a tab, hol a tab móka megy, én is mindig elcseszem. De még mindig inkább ez, mint az m4, ninja, meg urambocsá az undorító Visual Studio .project / .vsproj szintaxis, csak arról sokan azért nem érzik, hogy szar, mert pl. XML-t is ismerik, meg automatice valami más generálja le, de ettől még egy förmedvény, ha kézzel kéne írni, 100x rosszabb, mint a makefile. Utóbbinak legalább ha megszokod a hülyeségeit, lehet azért vele dolgozni, de egy bonyolultsági szint felett szopás lehet kő keményen. Ezek mind specializált fejlesztői eszközök, egyik se valami felhasználóbarát, ha mélyebben benne vagy.
“Windows 95/98: 32 bit extension and a graphical shell for a 16 bit patch to an 8 bit operating system originally coded for a 4 bit microprocessor, written by a 2 bit company that can't stand 1 bit of competition.”
- A hozzászóláshoz be kell jelentkezni
Én most gondolkodom azon, hogy a Makefile jellegű feladatokat leváltom Ruby/Rake alapúakkal. Mostanában a legtöbb esetben nem vagy alig használom ki a Makefile output-specifikus képességeit (azaz, hogy ha egy adott output létezik, akkor nem fut meg), mert nincs rá szükségem. Helyette marad a függőség-alapú folyamatépítés. Pl: a vimes git repómban két task van: meghívni a vim-plug plugin telepítő képességét, illetve bedobálni néhány symlinket helyekre. Merev is, nem is működik pl Windowson, és nem tudom úgy bővíteni, ahogy szeretném. A Rake lehetővé tenné, hogy a Ruby scriptnyelv teljes tudásával operáljak és pl automatikusan kidobáljak dolgokat a pluginek közül amik már nincsenek benne, anélkül, hogy szerkesztgetnem kellene.
- A hozzászóláshoz be kell jelentkezni
itt a tab, hol a tab móka megy, én is mindig elcseszem
Megfelelő szerkesztő kell hozzá. Meg érteni, hogy most a make-nek kell a "parancsot" végrehajtania vagy a shellnek.
mint az m4
Pedig nem olyan rossz az, még egy statikus weboldal-generátort is csináltam vele :)
- A hozzászóláshoz be kell jelentkezni