Carles Araguz
Carles Araguz

Reputation: 1177

Why does this makefile not work?

I'm new to Makefiles and I'm trying to write a simple one that would compile and link all applications listed in a variable like that:

APPLICATIONS = app1 app2 app3

All of them must have a source file (.c) and compile with the CFLAGS and LDFLAGS I define in the same Makefile, but for some reason, it is not working... The code is based on an example found here (page 23).

APPLICATIONS = one two three

DESTDIR=/home/carles/Develop/xenomai-2.5.6

TOOLCHAIN = arm-linux-gnueabi-gcc

OBJDIR      := bin
OBJS        := $(addprefix $(OBJDIR)/,$(addsuffix .o,$(APPLICATIONS)))
INCLUDE_PATH = $(DESTDIR)/usr/xenomai/include
CFLAGS       = -I$(INCLUDE_PATH) -D_GNU_SOURCE -D_REENTRANT -D__XENO__ -Wall -pipe
POSIX_CFLAGS = -I$(INCLUDE_PATH)/posix
LIB_PATH     = $(DESTDIR)/usr/xenomai/lib
LIBRARIES    = -lnative -lxenomai -lpthread -lrtdk -lrt
LDFLAGS      = $(LIBRARIES) -L$(LIB_PATH)
POSIX_LDFLAGS= -Wl,@$(LIB_PATH)/posix.wrappers -lnative -lpthread_rt -lxenomai -lpthread -lrt -L$(LIB_PATH) 


$(OBJDIR)/%.o : %.c
    @printf '------------------: $< -> $@ : '
    if [ $(TOOLCHAIN) $< -o $(OBJDIR)/$@ $(CFLAGS) $(LDFLAGS) -L$(LIB_PATH) ]
    then
        @echo 'done!'
    fi

all: $(OBJS) | show_config

$(OBJS): | $(OBJDIR)

$(OBJDIR):
    mkdir -p $(OBJDIR)

show_config:
    @echo '------------------: APPLICATIONS : $(APPLICATIONS)'
    @echo '------------------: DESTDIR      : $(DESTDIR)'
    @echo '------------------: INCLUDE PATH : $(INCLUDE_PATH)'
    @echo '------------------: LIB. PATH    : $(LIB_PATH)'
    @echo '------------------: TOOLCHAIN    : $(TOOLCHAIN)'
    @echo '------------------: LIBRARIES    : $(LIBRARIES)'
    @echo '------------------: OBJS         : $(OBJS)'

clean:
    @rm $(OBJDIR) -r -f

When I run $ make only the directory is created and the show_config is called, but object files are not created and no error is displayed. What is wrong here?

Upvotes: 0

Views: 570

Answers (2)

Beta
Beta

Reputation: 99084

You have two rules:

$(OBJDIR)/%.o : %.c
    ...

$(OBJS): | $(OBJDIR)

The first is a pattern rule, the second a regular rule. Ordinarily they can work together, but if the source files (one.c, two.c, three.c`) don't exist, then the first rule doesn't apply, the second calls for the construction of the directory, and that's all you get. You might as well combine them:

$(OBJDIR)/%.o : %.c | $(OBJDIR)
    ...

or better still:

$(OBJS): $(OBJDIR)/%.o : %.c | $(OBJDIR)
    ...

Once you get that straightened out, you'll notice another problem. The commands in this rule:

$(OBJDIR)/%.o : %.c
    @printf '------------------: $< -> $@ : '
    if [ $(TOOLCHAIN) $< -o $(OBJDIR)/$@ $(CFLAGS) $(LDFLAGS) -L$(LIB_PATH) ]
    then
        @echo 'done!'
    fi

don't do what you think they do. The first one (@printf ...) will work if printf works in your shell; you should test that, and if it doesn't, try @echo ... instead. The next four lines are clearly intended to work together. But in a Make rule, each line is a command unto itself, running in its own subshell, so this structure won't work. You can put the whole thing on one line:

    if [ $(TOOLCHAIN) ... ]; then @echo 'done!'; fi

(Note the semicolons.) It's a long line, so if it's hard on the eyes you can split it up by using backslashes to indicate line continuation:

    if [ $(TOOLCHAIN) $< -o $(OBJDIR)/$@ $(CFLAGS) $(LDFLAGS) -L$(LIB_PATH) ]; \
  then \
    @echo 'done!'; \
  fi

(Note that only one TAB is needed, in front of the if.)

Upvotes: 2

Carles Araguz
Carles Araguz

Reputation: 1177

It does not work because the files one.c, two.c, three.c did not exist, and hence they didn't have to be built.

Upvotes: 0

Related Questions