Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Makefile generic target rule

Tags:

makefile

I'm trying to improve the naive solution (single rules for compiling targets and additional one for linking all the previous targets together) which I used im my makefile. I came up with the following Makefile (clipped):

.PHONY: clean

BASE_DIR = ../

CC = gcc
CROSS_COMPILE = arm-none-eabi-
CFLAGS =-g -I${BASE_DIR}/include 
LDFLAGS =-L${BASE_DIR}/lib -Ttarget.ld -nostdlib 

SOURCES = first.c second.c third.c fourth.c
OBJECTS = $(SOURCES:.c=.o)
EXECUTABLE = $(OBJECTS:.o=)

all: $(EXECUTABLE)

%:
    ${CROSS_COMPILE}$(CC) $(CFLAGS) $(LDFLAGS) $*.c -o $*

clean:
    rm ${EXECUTABLE}

This works fine but I'd like to separate the compilation and linking processes. Therefore I tried to modify it as follows:

.PHONY: clean

BASE_DIR = ../

CC = gcc
CROSS_COMPILE = arm-none-eabi-

CFLAGS =-c -g -I${BASE_DIR}/include 
LDFLAGS =-L${BASE_DIR}/lib -Ttarget.ld -nostdlib 

SOURCES = first.c second.c third.c fourth.c
OBJECTS = $(SOURCES:.c=.o)
EXECUTABLE = $(OBJECTS:.o=)

all : $(EXECUTABLE)

%.o : %.c
    @echo "Compiling c file into o file"
    ${CROSS_COMPILE}$(CC) $(CFLAGS) $< -o $@

% : %.o
    @echo "Linking o file into executable"
    ${CROSS_COMPILE}$(CC) $(LDFLAGS) $< -o $@

clean:
    rm ${EXECUTABLE}

This works ok then I invoke the Makefile as e.g. make first.o; make first or if I modify the EXECUTABLE = $(OBJECTS:.o=) to EXECUTABLE = $(OBJECTS:.o=.out) and % : %.o to %.out : %.o. If, however, I try to invoke compilation as make or make first the implicit rules are used.

I tried going through the Makefile manual but there is really a lot of information in there, I got a little confused.

How can I modify the Makefile to be allowed to invoke building separate targets as make <target> or all the targets as make as the same time?

like image 857
Sebastian Kramer Avatar asked May 06 '14 11:05

Sebastian Kramer


People also ask

What is a target and a rule in makefile?

A rule appears in the makefile and says when and how to remake certain files, called the rule's targets (most often only one per rule). It lists the other files that are the prerequisites of the target, and the recipe to use to create or update the target.

What is $@ in makefile?

The file name of the target of the rule. If the target is an archive member, then ' $@ ' is the name of the archive file. In a pattern rule that has multiple targets (see Introduction to Pattern Rules), ' $@ ' is the name of whichever target caused the rule's recipe to be run.

Can a makefile have multiple targets?

Multiple Targets in a RuleA rule with multiple targets is equivalent to writing many rules, each with one target, and all identical aside from that. The same commands apply to all the targets, but their effects may vary because you can substitute the actual target name into the command using `$@' .


1 Answers

The paragraph where you describe your problem is very confusing and hard to understand. When asking questions please be sure that the section describing the problem is the most clear: it's helpful if you provide sample output showing exactly what commands you typed and the results you got, and explain what you expected to get instead.

However, my interpretation is that if you run make first it uses the built-in rule to compile first directly from first.c, rather than your pattern rules (note that both the built-in rules and your pattern rules are considered "implicit rules").

That's because make will choose the "shorter" implicit rule chain so the rule building an executable directly from source, in one step, rather than building the object then the executable in two steps, will be preferred. If you don't want to use the built-in implicit rule then you need to either invoke make with the -r flag, or else delete it by adding:

% : %.c

(just that) to your makefile.

like image 90
MadScientist Avatar answered Sep 20 '22 16:09

MadScientist