5

I thought my makefile is pretty good but then I tried to update only a header file and recompile my library, but it doesn't change anything.

How can I make it work and recompile also the code in the h file.

My makefile:

SHELL = /bin/sh
SOURCE_FILES_DIRS = -I./../frmwrk/ -I./../Utils/
CXX = g++
CXXFLAGS = $(SOURCE_FILES_DIRS) -std=c++17 -rdynamic -fPIC -g -Wall
LDFLAGS = -shared

LIBS_DIR = ../../libs/
LIB_NAME = libIni.so
TARGET  = $(LIBS_DIR)$(LIB_NAME)
SOURCES = $(shell echo *.cpp)
HEADERS = $(shell echo *.h)
OBJECTS = $(SOURCES:.cpp=.o)
LINK_LIBS = -lFrmwrk -lUtils

PREFIX = $(DESTDIR)/usr/local
BINDIR = $(PREFIX)/bin

all: $(TARGET)

$(TARGET): $(OBJECTS) $(HEADERS)
    $(CXX) $(CXXFLAGS) -L$(LIBS_DIR) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(HEADERS) $(LINK_LIBS)

clean:
    rm -f *.o $(TARGET)/*.so
    rm -rf $(TARGET)
Yaron Israeli
  • 321
  • 3
  • 13
  • Which header did you change? – Eljay Aug 19 '20 at 21:41
  • I personally prefer to have a more detailed or explicit listing of the header dependencies for each file. Every file will not have the same header file dependencies (or very unlikely that they do). Your stating that all the objects have the same header file dependencies, which may not be true. – Thomas Matthews Aug 19 '20 at 21:46
  • If you want your makefile to only build the files that have changed, you are going to need to list the objects individually and their dependencies. Otherwise, you have kind of taken away the usefulness of a makefile (i.e. you are rebuilding everything if one header file changes, instead of only the CPP files that include the header). – Thomas Matthews Aug 19 '20 at 21:48
  • Sams answer gives much detail but just to be very clear about it, when you write a rule like `$(TARGET) : $(OBJECTS) $(HEADERS)` that tells make that that specific target, `$(TARGET)`, should be rebuilt if any of the files in `$(OBJECTS)` or `$(HEADERS)` is newer. But that just re-links the binary. That rule says nothing about needing to rebuild the _object files_ (recompile the source) if any header changes. For that, you have to declare dependency relationships between the _objects_ and their headers. – MadScientist Aug 20 '20 at 13:44
  • More efficient than `SOURCES = $(shell echo *.cpp)` is `SOURCES := $(wildcard *.cpp)` – MadScientist Aug 20 '20 at 13:49

2 Answers2

4
$(TARGET): $(OBJECTS) $(HEADERS)
   [relink command]

This forces only a relink when the header file is changed. make has no idea, whatsoever, which C++ source file includes which header file. make knows only about dependencies explicitly declared in the header file. The only dependency stated here is that $(TARGET), the executable, has a dependency on the header file.

In order to force, for example, main.o to be recompiled when declarations.h are included, because main.cpp #includes declarations.h, you have to be explicit:

main.o: declarations.h

This directs make to rebuild main.o, from main.cpp, whenever declarations.h changes, which is what you want.

Manually tracking which object modules need to be rebuilt due to changes to which header files does not scale. make, of course, has no knowledge about anything C++ related, so you'll have to manually keep track of all the dependencies, manually, but that again doesn't scale.

The solution here is to migrate to some higher level build tools, like GNU autoconf and automake which will write the Makefile for you, complete with a bunch of rules that use compiler flags to dump the dependencies, and update the rules automatically, for you. You can always use the same compiler flags (there are flags that, and build all the scaffolding yourself, without autoconf and automake. But why bother, when autoconf automake will do it for you?

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • I agree that autoconf/automake will do all that for you but they are not trivial to get working. Another option for straightforward automatic dependency computation that can be done with just GCC or clang and doesn't require extra tools is here: http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/ – MadScientist Aug 20 '20 at 13:48
0

I know that this might be totally late but a quick solution to this would simply be to run a make clean such that you rm (remove command) remove the executables. By doing this I found a quick solution to this sort of problem.

a_confused_student
  • 349
  • 1
  • 3
  • 13
  • 1
    The general idea of a Makefile is that you need to do only the steps that *need* to be done. A "make clean" means you have to recompile the whole project. It's a crude workaround, not a solution, sorry. – DevSolar Nov 12 '22 at 22:14