Question

My makefile looks something like this:

FOO_OBJECT_FILES := $(OBJDIR)/Foo.cpp.o
BAR_OBJECT_FILES := $(OBJDIR)/Bar.cpp.o $(OBJDIR)Bar.c.o
ALL_OBJECT_FILES := $(FOO_OBJECT_FILES) $(BAR_OBJECT_FILES)

$(BINDIR)/Foo.a: $(FOO_OBJECT_FILES)
    # Rules for making a static library out of Foo's object files go here.

$(BINDIR)/Bar.a: $(BAR_OBJECT_FILES)
    # This uses the exact same command sequence as the previous rule.

$(BINDIR)/All.a: $(ALL_OBJECT_FILES)
       # Ditto.

# ...

When (not if) more targets are added to the project, the developer will have to update at least three things:

  1. The list of the new target's object files
  2. The list of all object files
  3. Targets for making the new target, even if it uses the same rules as the others

Is there a way to simplify this process, or am I stuck with it?

I tried using wildcard rules, but it doesn't look like they work with macros.

$(BINDIR)/%.a: $(%_OBJECT_FILES)
    # ...

You could treat the lists of object files as rules, but then the final target rules can't access them directly.

OBJECT_FILES_Foo: $(OBJDIR)/Foo.cpp.o
OBJECT_FILES_Bar: $(OBJDIR)/Bar.cpp.o $(OBJDIR)Bar.c.o
OBJECT_FILES_All: FOO_OBJECT_FILES BAR_OBJECT_FILES

$(BINDIR)/%.a: OBJECT_FILES_%
    # This rule can't see into the object file lists to use them to build.

Is there no better way?

Was it helpful?

Solution

There are probably plenty of ways to do this. One such way is the following. All that needs to be done for a new target is add its name to the list of modules, and give the list of dependencies for it.

BINDIR := bin
OBJDIR := obj

MODULES := Foo Bar

Foo_OBJS := $(OBJDIR)/Foo.cpp.o
Bar_OBJS := $(OBJDIR)/Bar.cpp.o $(OBJDIR)/Bar.c.o

#####################################################
#                                                   #
#   Nothing below here should need to be altered.   #
#                                                   #
#####################################################

All_OBJS := $(foreach mod, $(MODULES),$($(mod)_OBJS))

define rule
$(BINDIR)/$(1).a: $($(1)_OBJS)
    @echo
    @echo 'Target: $$@'
    @echo 'Deps  : $$^'
endef

$(foreach lib, All $(MODULES), $(eval $(call rule,$(lib))))

###########################################
#                                         #
# The next part is just here for testing. #
#                                         #
###########################################

.PHONY: all
all: $(foreach lib, All $(MODULES),$(BINDIR)/$(lib).a)

%.o:
    @echo Making $@

OTHER TIPS

You can't do much about 1 and 2, those are arbitrary things that Make cannot possibly deduce. You can improve 3 slightly:

$(BINDIR)/%.a:
    # commands for making a static library

# adding a new target:
QUARTZ_OBJECT_FILES := $(OBJDIR)/Quartz.cpp.o $(OBJDIR)Arbitrary.o
ALL_OBJECT_FILES += $(QUARTZ_OBJECT_FILES) 
$(BINDIR)/Quartz.a: $(QUARTZ_OBJECT_FILES)

You could use a template to reduce those three lines to one:

$(eval $(call template, QUARTZ_OBJECT_FILES, $(OBJDIR)/Quartz.cpp.o $(OBJDIR)Arbitrary.o))

but is it really worth it?

While the other answers have provided good solutions for manual makefile writing, you could simply use automake to ease the build process.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top