help-make
[Top][All Lists]
Advanced

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

Re: can't compute prerequisites in static pattern rule


From: Noel Yap
Subject: Re: can't compute prerequisites in static pattern rule
Date: Tue, 16 Dec 2003 12:19:11 -0500

CC'ing address@hidden

Evgeny Sologubov wrote:
> 
> Hello, Noel,
> Tuesday, December 16, 2003, 5:02:03 PM, You wrote:
> >>[...]
> NY> For example, in the end, I think what you want is to generate
> NY> a dependency file for a project.  The usual way to do this is to
> NY> include that dependency file within the makefile.  This inclusion
> NY> cannot be done generically, but this really shouldn't be a
> NY> problem since, presumably, you should know what project
> NY> you're trying to build, anyway.  Is this not so?
> 
> Assume that I have four projects situated in four folders: .\Main,
> .\Lib1, .\Lib2 and .\Lib3
> Where
> 1. Main depends on Lib1
> 2. Lib1 depends on Lib2 and Lib3
> 3. Lib2 depends on Lib3
> 
> As you can see project Main doesn't know a bit about projects Lib2 and Lib3.
> I wanted to create such universal rule to recursively build "Main" and
> all of the Libs it (directly or indirectly) depends on:

I see.  I think you might benefit from reading 
http://aegis.sourceforge.net/auug97.pdf.

> all: prj-Main
> prj-%: $(addprefix prj-, $(shell cat -s %/Makefile.dep))
>        $(MAKE) -C $*
> 
> where files %/Makefile.dep contain names of prerequisites.
> E.g. Lib1/Makefile.dep = "Lib2 Lib3".
> 
> It comes to mind only 2 ways how I can rewrite it:
> 1. Just place all the knowledge about dependencies into my main Makefile.
> So it will look like that:
> all: Main
> Main: Lib1
>       $(MAKE) -C $@
> ....
> Lib17: Lib15 Lib13 ... Lib1
>        $(MAKE) -C $@

In the past, I've created a file that describes the dependencies, something 
like:

# contents of GNUdependencies.mk
ifndef $(__FILE__)
$(__FILE__) := 1

$(__FILE__).dependencies := \
        lib/l0 \
        lib/l1

$(__FILE__)!returns := $(__FILE__).dependencies

endif

and I've got an infrastructure that would include this file and process the 
dependencies (which typically means including their dependencies makefiles).  
There's more to it, of course, the largest of which describes how to build each 
library.

> 2. Makefile of every project must invoke making of all the Libs it
> depends on.

This is more a recursive make way of thinking.

In the non-recursive way of thinking, each "module" includes its dependencies' 
makefiles which describe how they're built and include their dependencies' 
makefiles.

> I believe that 2nd way better than 1st because of "incapsulation" of
> prerequisites info. But there is some problem with it - making of Lib3
> will be invoked twice (by Lib1 and by Lib2) and that could cause
> noticeable time penalties (especially when number of Libs much greater
> than 3)!

This penalty goes away if the DAG is built correctly.  OTOH, there's an added 
penalty of opening the Lib3 makefile multiple times (which also exists in 
recursive make).  This penalty can be alleviated by caching the contents of the 
makefile.  For example,
the above GNUdependencies.mk becomes:

define $(__FILE__)!contents
../install/common/make/l2/GNUdependencies.mk: ../src/lib/l2/GNUdependencies.mk 
| ../install/common/make/l2/.

clean: FILES += ../install/common/make/l2/GNUdependencies.mk

ifndef $(__FILE__)
$(__FILE__) := 1

$(__FILE__).dependencies := \
        lib/l0 \
        lib/l1

$(__FILE__)!returns := $(__FILE__).dependencies

endif
endef

$(__FILE__)!contents := $(value $(__FILE__)!contents)

$(eval $($(__FILE__)!contents))


in my build.  Those that include this makefile will do:

$(call include-makefile,../install/common/make/l2/GNUdependencies.mk)


which calls:

# sets __FILE__ macro to file to be included, then includes the file.
# allows included file to know where it is in relation to includer.
# caching of included makefile is allowed if $(2)!contents is defined as the 
contents of the makefile.
# customization of return value assignment allowed if $(3) elements define a 
!assign property; default is :=.
# $(1) is the include method, either "include" or "-include"
# $(2) is the file to be included
# $(3) is the list of macros to set from return value list
# $(4) is the list of macros to pass into included makefile
# $(5) is the includer
define _include-makefile
  __FILE__ := $(2)

  # call a series of binary assignment operators or functions
  # $(1) is the list of macro names that will take on values
  # $(2) is the list of macro names whose values are taken
  ifndef _include-makefile_assign-from-indirect
    define _include-makefile_assign-from-indirect
      $$(if $$(firstword $$(1)),
        $$(eval $$(call call-binary,$$(firstword $$($$(firstword $$(1))!assign) 
:=),$$(firstword $$(1)),$$($$(firstword $$(2)))))
        $$(call _include-makefile_assign-from-indirect,$$(call 
pop-front,$$(1)),$$(call pop-front,$$(2))))
    endef
  endif

  $(2)!outputs := $(3)
  $(2)!inputs := $(4)

  ifndef $(2)!contents
    $(2): | $(dir $(2)).

    $(1) $(2)
  else
    $$(eval $$($(2)!contents))
  endif

  $(if $(strip $(3)), \
    $$(eval $$(call _include-makefile_assign-from-indirect, \
      $(3), \
      $$($(2)!returns))))

  __FILE__ := $(5)
endef

# include makefile passing in its name as __FILE__
# allows included file to know where it is in relation to includer.
# caching of included makefile is allowed if $(2)!contents is defined as the 
contents of the makefile.
# customization of return value assignment allowed if $(3) elements define a 
!assign property; default is :=.
# $(1) is the file to be included
# $(2) is the list of macros to set from return value list
# $(3) is the list of macros to pass into included makefile
include-makefile = $(foreach \
  m, \
  $(1), \
  $(eval $(call _include-makefile,include,$(m),$(2),$(3),$(__FILE__))))


> I'd appreciate any ideas about ways to solve that problem.
> thanks in advance.

I hope the above is enough to give you some ideas (and not enough to scare you 
away).  I'm sure you have some more questions, so, ask away.

HTH,
Noel
-- 
NOTICE: If received in error, please destroy and notify sender.  Sender does 
not waive confidentiality or privilege, and use is prohibited.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]