galah92
galah92

Reputation: 3991

Makefile: different variable's value based on rule

I've got the following situation in my makefile:

SDLINC_NOVA = -I/usr/local/lib/sdl_2.0.5/include/SDL2 -D_REENTRANT
SDLLIB_NOVA = -L/usr/local/lib/sdl_2.0.5/lib -Wl,-rpath,/usr/local/lib/sdl_2.0.5/lib -Wl,--enable-new-dtags -lSDL2 -lSDL2main
SDLINC_MAC  = -I/usr/local/SDL/include -D_REENTRANT
SDLLIB_MAC  = -L/usr/local/SDL/lib -Wl,-rpath,/usr/local/SDL/lib -Wl,-install_name,--enable-new-dtags -lSDL2 -lSDL2main
....
.PHONY: all nova mac clean

all: nova

nova: SDLINC = $(SDLINC_NOVA)
nova: SDLLIB = $(SDLLIB_NOVA)
nova: build
mac: SDLINC = $(SDLINC_MAC)
mac: SDLLIB = $(SDLLIB_MAC)
mac: build

build: $(TARGET)

$(TARGET): $(OBJECTS)
    $(CC) $(OBJECTS) $(SDLLIB) -o $@

$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
    $(CC) $(CFLAGS) $(SDLINC) -c $< -o $@

It feels like I'm doing something wrong.. Basically the SDLINC and SDLLIB variables should contain different value based on the rule that is called, and then the build rule should be called.

What is the right convention to achieve that in a makefile?

Upvotes: 1

Views: 245

Answers (2)

jfMR
jfMR

Reputation: 24738

The problem is that the build target is a common prerequisite of both nova and mac. Therefore, the rule for the target build is only matched once. That is, it is matched for the first target that requires it, then it remains updated for the second target that requires it.

You can set up your makefile, so that those targets above depend on different prerequisites:

nova: SDLINC = $(SDLINC_NOVA)
nova: SDLLIB = $(SDLLIB_NOVA)
nova: build-nova

mac: SDLINC = $(SDLINC_MAC)
mac: SDLLIB = $(SDLLIB_MAC)
mac: build-mac

With this new setup, mac depends on build-mac and nova depends on build-nova.

Then, by adding the following rule:

build-nova build-mac:
    $(MAKE) --no-print-directory $(TARGET)

its recipe will be executed for each target (i.e.: build-nova and build-mac) separately.

What the recipe of that rule does is to call make recursively for the target specified (i.e.: the result of expanding TARGET). You need however to export both SDLINC and SDLLIB variables in your makefile, so that the new process which runs make obtains them:

export SDLINC
export SDLLIB

Upvotes: 0

igagis
igagis

Reputation: 2079

Basically, the right approach would be not to have two different rules for Mac and Linux. This is because both of those are Unix-based systems and are quite common.

The approach is to automatically detect the system you are running on, this can be done using uname shell command:

 OS := $(shell uname)
 ifeq ($(OS), Darwin)
        OS := mac
 else ifeq ($(OS), Linux)
        OS := linux
 else
        $(info Warning: unknown OS, assuming linux)
        OS := linux
 endif

And then just add ifeq conditions to assign your variables:

ifeq ($(OS), linux)
    SDLINC = $(SDLINC_NOVA)
    SDLLIB = $(SDLLIB_NOVA)
else ifeq ($(OS), mac)
    SDLINC = $(SDLINC_MAC)
    SDLLIB = $(SDLLIB_MAC)
endif

and remove your rules for mac and nova, now you only need one build rule.

You can check what is the output of uname command on your Nova machine and adjust it accordingly in your makefile, but I'm pretty sure it will be Linux.

Upvotes: 1

Related Questions