-1

I would like to add dependencies to a Makefile of mine such that every time a header is modified the correspondent translation unit is recompiled. Currently only changes to source files are considered. I followed this example quite closely.

Below you can find a MWE, which outputs undefined reference to `main'. As soon as the variable DEPFILES is removed from the compilation steps the code compiles successfully.

Makefile:

CC = g++
EXEC = v1_beam.exe
RM = rm -f

BASEDIR := $(shell pwd)
SRCDIR  := src
INCDIR  := include
DEPDIR  := .deps

DEPFLAGS = -M -MT $@ -MMD -MP -MF $(DEPDIR)/$*.d
DEBUG_LEVEL := -g -fdiagnostics-color=always
EXTRA_CCFLAGS := -Wall -std=c++17 -O -pedantic -pedantic-errors
CXXFLAGS        = $(DEBUG_LEVEL) $(EXTRA_CCFLAGS)
CCFLAGS         = $(CXXFLAGS)

SRCS := $(wildcard *.cc) \
    $(wildcard $(SRCDIR)/*.cc)

OBJS := $(patsubst %.cc, %.o, $(SRCS))

DEPFILES := $(patsubst %.cc, $(DEPDIR)/%.d, $(notdir $(SRCS)))

.PHONY: all clean
.DEFAULT_GOAL = all

all: $(DEPDIR) $(EXEC)

$(EXEC): $(OBJS)
    @echo 3
    @echo Dependencies: $(wildcard $(DEPFILES))
    $(CC) $(CCFLAGS) $^ -o $@
    @echo Executable $(EXEC) created.

%.o: %.cc
%.o: %.cc Makefile
    @echo 1 
    $(CC) $(DEPFLAGS) $(CCFLAGS) -c $< -I$(BASEDIR) -o $@

$(SRCDIR)/%.o: $(SRCDIR)/%.cc $(DEPDIR)/%.d | $(DEPDIR)
    @echo 2
    $(CC) $(DEPFLAGS) $(CCFLAGS) -c $< -I$(BASEDIR) -o $@

$(DEPDIR):
    mkdir -p $@

$(DEPFILES):

clean:
    $(RM) $(OBJS) $(EXEC)

include $(wildcard $(DEPFILES))

main.cc:

#include <iostream>
#include "include/dummy.h"

int main() {
  MyClass obj;
  obj.print();
  return 0;
}

include/dummy.h:

#ifndef DUMMY
#define DUMMY

#include <iostream>

class MyClass {
  MyClass() { std::cout << "constructor" << std::endl; }
  void print();
};

#endif 

src/dummy.cc:

#include "include/dummy.h"

void MyClass::print()  {
  std::cout << "print" << std::endl;
}

Edit:

The issue seemed to lie not in the Makefile (although one should use -include to avoid potential issues in a clean compilation, where the dependencies still do not exist), but in the conda environment I was using. Multiple packages from the default and conda-forge channels were being mixed. To find some of these packages and verify they come from different conda channels I run:

conda list | grep gcc
conda list | grep compiler

To fix the issue:

conda upgrade -c conda-forge --all

thus making sure all packages being used come from the conda-forge channel.

unvarnished
  • 95
  • 1
  • 8

1 Answers1

1

I do this:

ifneq (,$(wildcard ${DEPDIR}/*}
include ${DEPDIR}/*
endif

And compile with:

DEPFLAGS = -MT $@ -MMD -MP -MF ${DEPDIR}/$*.Td

I think your approach is going to have problems. I don't know what happens on a clean compile, but your DEPFILES won't exist yet.

Joseph Larson
  • 8,530
  • 1
  • 19
  • 36
  • 2
    To do an optional include, you can simply use `-include`. – HolyBlackCat Jul 14 '21 at 19:16
  • @HolyBlackCat Thank you for the tip. It turned out the ```Makefile``` was essentially correct, and what was causing the issue was the ```conda``` installation I was using. Specifically, some ```*cxx*``` packages were coming from the ```default``` channel while other ```*gcc*``` packages were using ```conda-forge```. Sorry for not having specified this in the original question, as I did not suspect this could be the issue (and I am still missing why this is connected to the dependencies in the ```Makefile```). I will mark the answer as correct and update the original question. Thank you. – unvarnished Jul 15 '21 at 08:38