Raulillo
Raulillo

Reputation: 316

How to add requisites dynamically in makefile

I'm learning how to use makefiles for complex projects. I got it working but I don't know how to add pre-requisites under certain conditions without specifying them one by one. In this particular case I'm trying to add header files as requisites of objects goals so if any header file is modified, that particular cpp has to be rebuild again and linked with the rest.

After looking for clues on the manual I tried to use some shell scripting but I guess the substitution I'm doing is expanded after checking for dependencies so it does nothing. I have tried to use the $(if ) expression in the requisites too but I ended up moving it just in case it was some kind of conflict with using it inside a static pattern rule.

Some additional notes:

I have the following files in my working directory:

.
├── Makefile
└── src
    ├── main.cpp
    └── somemodule
        ├── module.cpp
        └── module.h

My makefile has to generate the following structure:

.
├── app
├── Makefile
├── obj
│   ├── main.o
│   └── somemodule
│       └── module.o
└── src
    ├── main.cpp
    └── somemodule
        ├── module.cpp
        └── module.h

My current makefile:

APP := app
SRCDIR := src
OBJDIR := obj
OBJS := obj/main.o obj/somemodule/module.o
SRCS := $(OBJS:.o=.cpp)

$(APP): $(OBJDIR) $(OBJS)
    g++ $(OBJS) -o $(APP)

$(OBJDIR):
    mkdir -p $(patsubst $(SRCDIR)%,$(OBJDIR)%,$(shell tree src -fid --noreport))

$(OBJS): HEADERS += $(if $(shell if [ -e $(@:obj%.o=src%.h) ]; then echo "y"; fi), $(@:obj%.o=src%.h))
$(OBJS): $(OBJDIR)%.o: $(SRCDIR)%.cpp $(HEADERS)
    g++ -c $(patsubst $(OBJDIR)%.o,$(SRCDIR)%.cpp,$@) -o $@

.PHONY: clean
clean:
    rm -rf $(OBJDIR)
    rm $(APP)

Upvotes: 0

Views: 140

Answers (1)

MadScientist
MadScientist

Reputation: 101081

trying to add header files as requisites of objects goals so if any header file is modified, that particular cpp has to be rebuild again and linked with the rest doesn't sound complex: that's table-stakes for a good build system, if I understood it correctly.

I don't understand what your syntax of setting HEADERS is trying to do here but there's no way it can work. Please read carefully the introduction to automatic variables in the GNU make manual; in particular this text:

It’s very important that you recognize the limited scope in which automatic variable values are available: they only have values within the recipe. In particular, [...] they cannot be accessed directly within the prerequisite list of a rule.

Luckily I see no need for any of that. Have you considered using dependency generation methods such as the one discussed here?

In response to the requirement you added when you updated the question:

I also prefer to avoid solutions tied to the language I'm using in the example as it should work with any compiler and other kind of files and goals/requisites.

I answered:

There is no way to do this only using only make because make doesn't know how to parse your code, and so it can't figure out what the dependencies of a source file are. Similarly, you can't do it in a generic way for all different languages because different languages use different syntax for declaring dependencies. If you want to have automatic dependency tracking, and not do it by hand, you must have SOME tool that can parse your source to find the dependencies. You can use GCC or makedepend or even some fancy shell script if you don't need it to be too accurate.

Upvotes: 1

Related Questions