8

I have a set of .cpp files that I want to compile. These .cpp files are in a hierarchical directory structure. I want the corresponding .o files to all end up in one build folder.

Here's how I get GNU make to enumerate the files:

SRCS = \
    $(wildcard $(CODE)/**/*.cpp) \
    $(wildcard $(CODE)/AlgebraLibraries/**/*.cpp) \
    $(wildcard $(CODE)/Calculator/Environments/**/*.cpp)

BARE_SRCS = $(notdir $(SRCS))
BARE_OBJS = $(BARE_SRCS:.cpp=.o)
OBJS = $(addprefix $(BUILD)/, $(BARE_OBJS))

Having done this, I have no idea how to create the rules that will create the .o files from the .cpp files. Intuitively, what I want to do is the following pseudocode:

for i=0, N do  # <-- a for-loop!
  $(OBJS)[i]: $(SRCS)[i]   # <-- the rule!
    $(CPP) -c $(SRCS)[i] -o $(OBJS)[i] # <-- the recipe
end

Of course, this is not valid GNU make code, but I trust you understand what it is here that I'm trying to do. The following will not work.

%.o: %.cpp
    $(CPP) -c $< -o $@

This doesn't work, because GNU make is matching up the % signs, assuming that the .o files live along-side the .cpp files.

The alternative to all of this, which I know will work, but will be extremely tedious, is to enumerate all of the rules by-hand as explicit rules. There has to be a better way!

I've been researching GNU make's ability to generate rules, but there appears to be no way to do it without the built-in logic. It would be really nice if I could utilize some flow-control statements to generate the rules that I want to make. Is this asking too much of GNU-make?

In any case, is there a way to do what it is I'm trying to do with GNU make? If so, how?

Jeff Schaller
  • 2,352
  • 5
  • 23
  • 38
user2125275
  • 83
  • 1
  • 3

2 Answers2

17

This looks like a job for... several advanced Make tricks:

all: $(OBJS)

define ruletemp
$(patsubst %.cpp, $(BUILD)/%.o, $(notdir $(1))): $(1)
    $$(CPP) -c $$< -o $$@
endef

$(foreach src,$(SRCS),$(eval $(call ruletemp, $(src))))
Beta
  • 96,650
  • 16
  • 149
  • 150
  • Wouldn't gcc complain if it is trying to create `$(BUILD)/dir1/dir2/file.o` for `dir1/dir2/file.c` since the directory structure `$(BUILD)/dir1/dir2` would not exist ? – Tuxdude Mar 02 '13 at 02:42
  • 2
    Thank you, thank you! (http://www.gnu.org/software/make/manual/make.html#Eval-Function) -- I will read more on this and see if I can use this. I think this is what I was looking for...a way to abstract make-file syntax. BTW, even if I shouldn't try to do what I was trying to do in my situation, I was sure that the kind of thing I was trying to do would be at least legitimate in other situations. I also started to look into going with jam, but I don't like the fact that nobody supports it anymore. – user2125275 Mar 02 '13 at 05:51
  • This worked, BTW. Thanks again! My makefile seems fairly cryptic, but it at least serves as an example of some stuff that can be done in make. – user2125275 Mar 02 '13 at 06:51
  • @Tuxdude: try it and see what happens. – Beta Mar 02 '13 at 13:50
  • @user2125275: Yeah, sorry it's so cryptic, but Make doesn't handle wildcards very well, and constructing lists of files with `wildcard` creates a lot of loose ends. – Beta Mar 02 '13 at 14:00
2

If $(BUILD) is constant, you can always just do:

$(BUILD)/%.o: %.cpp
    $(CPP) -c $< -o $@
Ponkadoodle
  • 5,777
  • 5
  • 38
  • 62