lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Mon, Oct 16, 2006 at 10:38:34PM +0100, David Given wrote:
> Sam Roberts wrote:
> [...]
> > make doesn't care what directory your files are in, you haven't figured
> > out how to use the tool yet if that is causing you trouble.
> 
> All right, try this: I have fifty files in directory A, all with .c
> extensions, that need to be built with one particular set of compilation
> options. I also have fifty files in directory B, all with .c extensions, that
> need to be built with *another* set of compilation options. How do you write a
> single makefile that deals with this cleanly?

> The answer is, you can't. make automatically determines what rule to apply to
> each file based on the file extension. (Actually, a file pattern. It might be

Thats true of POSIX make. I should have been clear that I was talking
about the GNU dialect (I thought you'd mentioned it specifically, but I
confused you with another).

> possible to use patterns of the form 'A/%.c' and 'B/%.c', but I'd be hesitant
> to use it.) However, it only allows you to specify a *single* rule for each
> pattern. In order to solve the above problem, you have two options: firstly,
> you can specify manually which files each rule should apply to --- which
> rather defeats the purpose of make's automatic rule mechanism --- or else you
> write two makefiles, which is much less effort, but which blows a big hole in
> the dependency management.

This is possible in various ways. We do this in our build system,
off the top of my head, something like:

    CFLAGS = ... common flags
	CFLAGS_FOR_A = .... flags for A

	A_SRC = $(wildcard A/*.c)
	A_OBJ = $(A_SRC:.c=.o)
	$(A_OBJ): CFLAGS+=$(CFLAGS_FOR_A)

	B_SRC = $(wildcard B/*.c)
	B_OBJ = $(B_SRC:.c=.o)
	$(B_OBJ): CFLAGS+=$(CFLAGS_FOR_B)

	libstuff.a: $(A_OBJ) $(B_OBJ)
    # etc....

That's only 3 lines per-subdir, but you can also factor the common stuff
into a sub makefile, and then include that sub-makefile multiple times,
each time doing something different:

    CFLAGS = ... common flags
	CFLAGS_FOR_A = .... flags for A

	DIR:=A
	include dir.mk

	DIR:=B
	include dir.mk

	libstuff.a: $(A_OBJ) $(B_OBJ)
    # etc....

dir.mk:

	$(DIR)_SRC := $(wildcard $(DIR)/*.c)
	$(DIR)_OBJ := $($(DIR)_SRC:.c=.o)

	$($(DIR)_OBJ): CFLAGS+=$(CFLAGS_FOR_$(DIR))

Thats arguably no longer a "single makefile", but it is NOT a recursive
makefile.

> Here's a real-world example I had to cope with in my day job: I'm building
> fifty different Special Objects. Each Special Object is made up of several
> source files (.cc files). Each .cc file needs to be preprocessed via a custom
> program before compilation, where the preprocessor flags vary according to the
> Special Object --- and the *first* source file of each Special Object, when
> preprocessed, produces an extra .o file that needs to be passed directly to
> the linker. This all has to handle C dependencies correctly, and it would be
> nice if we could build parallel debug and optimisation versions.

For situations like the above there are some things that might help.
It's possible for the variable expansion on the right to depend on the
target, for example:

  %.o: %.c CFLAGS+=$(*)_CFLAGS

so you can get a.c to have a_CFLAGS appended to CFLAGS when a.o is built.

> (If you're interested, I solved that one by writing a Lua makefile generator,
> where the makefile specified absolutely everything explicitly. Prime Mover
> actually developed from that program.)

Thats a time-honored approach, and I would say its a very good one.  Its
what I meant by using make as a tool only for rule evaluation, not
necessarily for writing the rules.

> Trust me. I know how to use make.

Sorry, David, I didn't mean to offend.

Sam