0

Originally I wanted to automatically include helpers to unit-test static functions by using --include gcc keyword like described in the link below:

How to test a static function

The idea is to automatically include a foo.cu ( c/c++ for unit ) making calls to static functions defined in foo.cc

I read several answers like

How to conditional set up a Makefile variable by testing if a file exists

Define make variable at rule execution time

How do I check if file exists in Makefile so I can delete it?

but syntax like the one below was not successful (even with characters alignment to the target...)

#did not work
ifneq ($(wildcard $(UT_FILE_LOC)),)
    $(eval LOC_CPPFLAGS := $(CPPFLAGS) --include $(UT_FILE_LOC))
else
    $(eval LOC_CPPFLAGS := $(CPPFLAGS) )
endif

and I ended-up with syntax

$(eval LOC_CPPFLAGS := $(shell [[ -e $(UT_FILE_LOC) ]] && echo $(CPPFLAGS) --include $(UT_FILE_LOC) || echo $(CPPFLAGS) ))

Question: Is this a correct way to modify/orientate the value of a makefile variable ?

=========================================================

MCVE for the makefile itself

SRCDIR   = src
SRCFILES = $(wildcard src/*.cc)
OBJDIR   = obj
DEPDIR   = dep
OBJFILES = $(patsubst %.cc,$(OBJDIR)/%.o, $(SRCFILES))
DEPFILES = $(patsubst %.cc,$(DEPDIR)/%.d, $(SRCFILES))

#just some flags for this MCVE
CPPFLAGS = -std=c++11 -Wall -Weffc++

main: $(OBJFILES)
    g++ -o $@ $^ 

# Include dependencies ( change in foo.cu are seen )
-include $(DEPFILES)

$(OBJDIR)/%.o: %.cc
    @echo '> Compiling source file: $<'
    @install -d $(OBJDIR)/$(dir $<)
    @install -d $(DEPDIR)/$(dir $<)
    $(eval UT_FILE_LOC  :=  $(patsubst %.cc,%.cu,$<))
    $(eval LOC_CPPFLAGS := $(shell [[ -e $(UT_FILE_LOC) ]] && echo $(CPPFLAGS) --include $(UT_FILE_LOC) || echo $(CPPFLAGS) ))

    g++ -c $(LOC_CPPFLAGS) -MMD -MP -MF"$(DEPDIR)/$*.d" -o $@ $<

clean:
    $(RM) -r $(OBJDIR)/*
    $(RM) -r $(DEPDIR)/*

and with basic C++ files (foo.cc, foo.cu and main)

#include <iostream>
static void foo() {
   std::cout << "foo" << "\n" << std::flush;
}

void bar() {  foo(); } //avoid unused foo() warning for this MCVE
static void foo();

void ut_foo() {
    return foo();
}
void ut_foo();

int main(int argc, char* argv[]) {
    ut_foo();
    return 0;
}

--include src/foo.cu is visible for foo.cc compilation and not for the other files (well, here just the main...).

> Compiling source file: src/foo.cc
g++ -c -std=c++11 -Wall -Weffc++ --include src/foo.cu -MMD -MP -MF"dep/src/foo.d" -o obj/src/foo.o src/foo.cc
> Compiling source file: src/main_unit.cc
g++ -c -std=c++11 -Wall -Weffc++ -MMD -MP -MF"dep/src/main_unit.d" -o obj/src/main_unit.o src/main_unit.cc
g++ -o main obj/src/foo.o obj/src/main_unit.o 

./main 
foo

Interestingly foo.cu appears in foo.o dependency and a change to foo.cu restart the compilation of foo.c (so no extra work to be done for this point)

obj/src/foo.o: src/foo.cc src/foo.cu

src/foo.cu:

=========================================================

NGI
  • 852
  • 1
  • 12
  • 31
  • Solution proposed by MadScientist : remove $( eval ... ) lines and put g++ -c $(CXXFLAGS) $(if $(wildcard $*.cu),--include $*.cu) -MMD -MP -MF"$(DEPDIR)/$*.d" -o $@ $ – NGI Jun 18 '21 at 22:54

1 Answers1

1

In my opinion it's (virtually) never correct to use $(eval ...) inside of a rule. Whenever you see any "tutorial" or "advice" blog that shows using eval (or $(shell ...)) inside a recipe, unless it's some extraordinarily bizarre situation, it's probably best to skip it.

Firstly, CPPFLAGS is not the right variable; the "CPP" here stands for "C preprocessor" not "C++". This variable is traditionally expected to contain preprocessor flags like -I, -D, etc. The standard variable for C++-specific options is CXXFLAGS.

Secondly, this solution seems very over-complex to me. Wouldn't this work:

CXXFLAGS = -std=c++11 -Wall -Weffc++ $(if $(wildcard $*.cu),--include $*.cu)

??

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • It makes me very sad to see the number of upvotes for the answer you link to recommending `eval`. The right answer to that question is https://stackoverflow.com/a/29085760/939557 not the accepted answer. – MadScientist Jun 18 '21 at 22:33
  • Your proposed solution works perfectly. Thank you for recalling the CXXFLAGS correct naming. I will have a look to the right answer you pointed – NGI Jun 18 '21 at 22:38