6

Based on some SO questions -- and some further reference found --, I'm trying to build a makefile able to:

  • find, given the directories in $(SRC), the .cpp files to be compiled;
  • compile the .cpp, producing .o objects;
  • generate .so shared objects from each .o formerly compiled.

What the make file is supposed to do to achieve that is:

  • find, given the directories in $(SRC), the .cpp files to be compiled;
  • build the dependency list for each .cpp using -MM compiler's flag;
  • annotate/add each dependency using $(eval ...);
  • evaluate/solve each dependency found, producing both the .o and .so files.

What do I have so far: I've been able to do quite the whole thing, except for making it work (: The error I'm getting states that there is, somehow, an empty label '' as dependency:

$ make make: * No rule to make target ', needed by /home/rubens/bin/label.o'. Stop.

So, here is the makefile I'm yet not able to run:

# Directories
SRC := process init
BIN := $(HOME)/bin

LIB := watershed
LIBPATH := $(WATERSHED)/lib
INC := $(WATERSHED)/include $(XERCES)/include

# Paths
MPICPP := mpic++
SOURCES := $(shell find $(SRC) -name '*.cpp')
OBJECTS := $(addprefix $(BIN)/, $(notdir $(SOURCES:.cpp=.o)))
SHARED := $(OBJECTS:.o=.so)

# Flags 
CFLAGS := -std=c++0x -O2 -Wall -fPIC
CFLAGS += $(foreach inc, $(INC), -I $(inc))
LFLAGS :=
LFLAGS += $(foreach lib, $(LIB), -l $(lib))
LFLAGS += $(foreach path, $(LIBPATH), -L $(lib))

# Rules
$(SHARED): | bindir
%.o:
        @echo $@ -- [$<][$^][$*]
        @echo $(MPICPP) $(CFLAGS) -c $< -o $@

%.so: %.o
        @echo $(MPICPP) $(LFLAGS) -shared $< -o $@

bindir:
        @mkdir -p $(BIN)

# Utilities
.PHONY: all clean
all: $(SHARED)
clean:
        @rm -f $(OBJECTS) $(SHARED)

# Dependencies
define dependencies
$(addprefix $(BIN)/, $(notdir $(1:.cpp=.o))): \
        $(shell $(MPICPP) $(CFLAGS) -MM $(1) | sed 's/^.*\.o:[ ]*//')
endef
$(foreach src, $(SOURCES), $(eval $(call dependencies, $(src))))

Where exactly seems to be the error: It seems to be caused by the dependency generation step, as, when I remove any empty lines , piping the output to grep, as follows:

define dependencies
$(addprefix $(BIN)/, $(notdir $(1:.cpp=.o))): \
        $(shell $(MPICPP) $(CFLAGS) -MM $(1) | sed 's/^.*\.o:[ ]*//' | \
        grep -v ^$)
endef

The error somehow digivolves to an empty list of dependencies; I'm able to see the list is actually empty with the echo's in rule %.o: -- the only variables not empty are $@ and $*.

/home/rubens/bin/label.o -- [][][/home/rubens/bin/label]

mpic++ -std=c++0x -O2 -Wall -fPIC -I /home/rubens/libwatershed/include -I /home/rubens/xerces-c-3.1.1/include -c -o /home/rubens/bin/label.o

mpic++ -l watershed -L -shared /home/rubens/bin/label.o -o /home/rubens/bin/label.so

Any advice on better ways to solve this are very, very welcome; yet, I would really like to finish writing this makefile, before I get to use something like Cmake or Scons.

Rubens
  • 14,478
  • 11
  • 63
  • 92
  • 1
    I don't recommend trying to do dependency generation with eval. It's really unpleasant. You should use included makefiles. There's a good example on how to do it at http://make.mad-scientist.net/autodep.html although if you're using GCC, or a compiler with compatible flags, you can simplify with your `-MM` option. – MadScientist May 03 '13 at 14:14
  • +1 Alright, I guess the best to do is to either use included makefiles or get to use `cMake`/`Scons`. I'll leave the question opened, anyway, so someone may give it a solution. – Rubens May 03 '13 at 19:21
  • 1
    Even if you got it to work, you would never want to use it. It's so inefficient: every time you run make, for any reason (even "make clean") it's going to run the preprocessor on ALL the source files, then massage them. It will make your builds very slow once you get more than a few source files. Using include files is much, much better since it saves the dependency information as a file so it can be read directly when you run make next time. Plus, it will only recompute the dependency information on files that change, not on every single file every single time you run make. – MadScientist May 03 '13 at 22:52
  • +1 Alright, bro, I'm closing the question (: – Rubens May 03 '13 at 23:20

2 Answers2

1

-MM will already generate the dependencies on a Makefile format so you could simplify this by generating the dependencies for each *.cpp into a same file, then just doing an -include $(DEPS_FILE). That's probably more maintainable than using eval.

roschach
  • 8,390
  • 14
  • 74
  • 124
Nico Brailovsky
  • 318
  • 2
  • 7
  • +1 That's actually what I've seen first -- and is exactly what is exemplified [here](http://www.gnu.org/software/make/manual/make.html#Automatic-Prerequisites). I just thought `eval`uating the dependency would save me some extra rules, and extra vars on `clean` rules, and the like. Must have been wrong, anyway x= – Rubens May 03 '13 at 19:21
0

At line of definition of makefile variable SOURCES, search for the cpp files, you probably have to rewrite like this: find $(SRC) -name "*.cpp"

oohtj
  • 129
  • 5
  • I guess you meant `'*.cpp'`, to avoid expansions in the shell. Even with this, the error is exactly the same. Thanks for pointing, anyway. – Rubens May 03 '13 at 13:14