Included Makefile's parent directory

2019-01-20 19:21发布

I want to describe each submake's dependencies in a file that a top-level Makefile can include. This is to allows for a recursive make setup (with all of the power of instanced variables and relative pathing) but with all dependencies described in a top-level make to increase compile speed and parallelism.

For instance, let's assume we have a directory tree that looks like this:

project/
|-- lib1
|   |-- Makefile
|   `-- Makefile.reg
|-- lib2
|   |-- Makefile
|   `-- Makefile.reg
|-- Makefile
`-- Makefile.reg

The file for project/lib1/Makefile.reg file may look like this:

REG := lib1
include ../Makefile.reg

The file for project/lib2/Makefile.reg file may look like this:

REG := lib2
DEP := lib1
include ../Makefile.reg

The file project/Makefile.reg will look like this:

$(REG)_DIR = ????
$(REG): $(DEP)
  $(MAKE) -C $($@_DIR)

And finally, the top-level project/Makefile would look like this:

include $(shell find . -name "Makefile.reg")

Now, the top-level Makefile has all of the dependency information for every target and can intelligently call recursive make and utilize full parallelism while keeping the dependency tree intact.

The issue is that I'm not sure how to let project/Makefile.reg know what the current submake's Makefile.reg's path is. make will always be called from the top-level directory, so $(shell pwd) will always report project/. One solution would be to include the line from this SO answer, however I would like each Makefile.reg to only specify a target and an optional dependency list.

Is there a way to include the directory path discovery in the common project/Makefile.reg rather than putting a new line in every single submake Makefile.reg? In other words, can an included makefile deduce the parent makefile's directory? I see potential in some different parsing of the MAKEFILE_LIST variable.

1条回答
Evening l夕情丶
2楼-- · 2019-01-20 19:50

As the snippet of documentation included in the answer on your linked ticket indicates. The value of MAKEFILE_LIST is updated as make goes. The latest entry in the list is the current makefile which makes the penultimate entry in the list the most recently included makefile before that. If you are willing to assert that the main project/Makefile.reg will only ever be included from a sub-directory makefile then it could simply examine that entry in MAKEFILE_LIST.

Alternatively you could simply define a canned recipe in the main Makefile and call it in each project makefile to define the appropriate targets.

Unfortunately make does make getting the penultimate entry a little more difficult than is pleasant. But the following should work:

FOO=a b c d e f g
BAR=h i j k l m n
BAZ=o p q r s t u
QUX=v w x y z 1 2

penultimateword = $(wordlist $(words $1),$(words $1), x $1)

REG=FOO
$(REG)_DIR= $(call penultimateword,$($(REG)))
$(info REG_DIR=$($(REG)_DIR))

REG=BAR
$(REG)_DIR= $(call penultimateword,$($(REG)))
$(info REG_DIR=$($(REG)_DIR))

REG=BAZ
$(REG)_DIR= $(call penultimateword,$($(REG)))
$(info REG_DIR=$($(REG)_DIR))

REG=QUX
$(REG)_DIR= $(call penultimateword,$($(REG)))
$(info REG_DIR=$($(REG)_DIR))

all: ;

Inspiration for the above came from the chop function from the fantastic GMSL.

查看更多
登录 后发表回答