Re: make: need help reducing boilerplate repetition

Doug <[email protected]>
Newsgroups gmane.comp.gnu.utils
Organization http://groups.google.com
Message-ID <[email protected]>
On Feb 28, 3:05 pm, Derekasaurus Rex <[email protected]> wrote:
> I have written a simple makefile that builds all of the C++ source
> files in a folder and turns them into a static library. Ultimately I
> need to build multiple libraries, so I need to accomplish this:
>
> Src/Lib/libfoo/*.cpp --> Lib/libfoo.a
> Src/Lib/libbar/*.cpp --> Lib/libbar.a
> Src/Lib/libbaz/*.cpp --> Lib/libbaz.a
> etc.
>
> I have accomplished this by writing the following code for each
> library, shown here just for libfoo.a:
>
> # source are just all .cpp files in the libfoo directory
> libfoo_SOURCES = $(wildcard Src/Lib/libfoo/*.cpp)
>
> # replace .cpp with .o to create list of objects
> libfoo_OBJECTS = $(patsubst %.cpp, %.o, $(libfoo_SOURCES))
>
> # this is how we link the objects in Src/Lib/libfoo to mkae Lib/
> libfoo.a
> libfoo: $(libfoo_OBJECTS)
>         $(AR) $(ARFLAGS) Lib/libfoo.a $(libfoo_OBJECTS)
>
> # here is how we compile objects; needed so .o files end up in Src/Lib/
> libfoo
> Src/Lib/libfoo/%.o : Src/Lib/libfoo/%.cpp
>         $(COMPILE) -c $< -o $@
>
> It's all simple enough, except that I have about 15 libraries to
> build. That translates to a lot of boilerplate repetition Can anyone
> suggest how to structure my makefile such that I could build multiple
> libraries without writing the above lines for each and every one?

Rex,

It's possible to get what you want by using a combination of the
foreach, eval, and template features of Make. I have done it, but
unfortunately can't post my actual Makefile, and don't have time to
work through a full example. Here's an untested snippet which may help
you get started. You need the double $$'s inside calls to eval for
things to work (I think). The Make documentation should help with any
questions.

# Library names
LIBNAMES = foo bar baz

# Build src/obj lists of form lib<name>_SOURCES, lib<name>_OBJECTS
$(foreach name, $(LIBNAMES), $(eval lib$(name)_SOURCES=$$(wildcard Src/
Lib/lib$$(name)/*.cpp)))
$(foreach name, $(LIBNAMES), $(eval lib$(name)_OBJECTS=$$(patsubst
%.cpp, %.o, $$(lib$$(name)_SOURCES))))

You can then create a template for other targets/rules and eval a call
to the template for each library.
I think you would want something like...

define COMPILE_TEMPLATE
Src/Lib/lib$(1)/%.o : Src/Lib/lib$(1)/%.cpp
    $$(COMPILE) -c $$< -o $$@
endef

# The you call the compile template for each library
$(foreach name, $(LIBNAMES), $(eval $(call COMPILE_TEMPLATE,$(name))))

Hope that helps...
-Doug
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.