Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing dependencies in makefile, with makefile

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.

like image 898
Rubens Avatar asked May 03 '13 12:05

Rubens


People also ask

What are dependencies in a makefile?

A dependency is a file that is used as input to create the target. A target often depends on several files. A command is an action that make carries out. A rule may have more than one command, each on its own line.

What does %O %c mean in makefile?

The simple answer is that %.o is a target that matches any file ending in .o. "%.o: %. c" means that any file ending in .o depends on the same filename ending in . c to be present.

What is $$ in makefile?

If you want a string to have a dollar sign, you can use $$ . This is how to use a shell variable in bash or sh . Note the differences between Makefile variables and Shell variables in this next example.

What is the difference between makefile and makefile?

makefile and Makefile are special names because if make is called without the -f option it automatically searches for them, in this order, and use the first it finds. Note that GNU make also considers GNUmakefile , and prefers it over makefile and Makefile . Other make implementations can have other default names.


1 Answers

-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.

like image 138
Nico Brailovsky Avatar answered Sep 28 '22 08:09

Nico Brailovsky