Writing dependencies in makefile, with makefile
Asked Answered
H

2

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.

Ha answered 3/5, 2013 at 12:55 Comment(4)
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 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.Collation
+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.Ha
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.Collation
+1 Alright, bro, I'm closing the question (:Ha
T
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.

Thalassography answered 3/5, 2013 at 14:27 Comment(1)
+1 That's actually what I've seen first -- and is exactly what is exemplified here. I just thought evaluating the dependency would save me some extra rules, and extra vars on clean rules, and the like. Must have been wrong, anyway x=Ha
L
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"

Libelant answered 3/5, 2013 at 13:11 Comment(1)
I guess you meant '*.cpp', to avoid expansions in the shell. Even with this, the error is exactly the same. Thanks for pointing, anyway.Ha

© 2022 - 2024 — McMap. All rights reserved.