makefile furcsaság

Fórumok

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 2

Nem 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?

Hozzászólások

Szerkesztve: 2025. 10. 22., sze – 15:37

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).

(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.

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.

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).

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.)

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.

+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