Copying a bunch of files with GNU make
Let's say I have a makefile where I want to copy multiple files from one location to another, for example:
-
include/mylib/mylib.h
todist/include/mylib/mylib.h
-
include/mylib/platform/linux/platform.h
todist/include/mylib/platform.h
This is part of the installation rule. What comes to my mind is something like:
EXTRA_INSTALL += include/mylib/mylib.h=dist/include/mylib/mylib.h
EXTRA_INSTALL += include/mylib/platform/linux/platform.h=dist/include/mylib/platform.h
# All other dependecies (objects, .so, etc.) go through `$(TARGET)`
install: $(TARGET) $(EXTRA_INSTALL)
$(EXTRA_INSTALL):
@cp $(firstword $(subst =, ,$@)) $(lastword $(subst =, ,$@))
.PHONY: install $(EXTRA_INSTALL)
I think this is kind of a hack, but I couldn't think of a proper way to do it. So is there a better way to achieve the same? Note that there is no visible relationship between the input filename and the output, so the sorting rule is dist/include/%.h:include/%.h
not appropriate.
source to share
Something like the following might be more readable (although it adds a bit of duplication), it has the advantage of updating files if they may have changed.
EXTRA_INSTALL := dist/include/mylib/mylib.h dist/include/mylib/platform.h
.PHONY: install
install: $(EXTRA_INSTALL)
dist/include/mylib/mylib.h: include/mylib/mylib.h
dist/include/mylib/platform.h: include/mylib/platform/linux/platform.h
.SECONDEXPANSION:
$(EXTRA_INSTALL): $$^
cp $^ $@
You can also opt out .SECONDEXPANSION
entirely at the cost of an extra line per file
EXTRA_INSTALL := dist/include/mylib/mylib.h dist/include/mylib/platform.h
.PHONY: install
install: $(EXTRA_INSTALL)
dist/include/mylib/mylib.h: include/mylib/mylib.h
cp $^ $@
dist/include/mylib/platform.h: include/mylib/platform/linux/platform.h
cp $^ $@
source to share
This is a terrible hack. Doing this kind of thing is exactly what it is for make
, you don't have to invent your own mini-language internally make
.
Define the mapping source=target
as a precondition make
and then define the recipe to create it via cp
:
dist/include/mylib/mylib.h: include/mylib/mylib.h
cp $^ $@
This suggests that the creation of a file dist/include/mylib/mylib.h
depends on another file (so it will be recreated if the other file changes) and that it must be created by copying it.
The answer from user @ user657267 shows how to reduce duplication by decoupling the dependency definition from the recipe for the actual copy, so you don't have to repeat the recipe cp
for every file. However, since the recipe is incredibly simple, I see no harm in just repeating it. You can always replace the recipe with a function call if it gets more complex:
CP := cp -f
copy_file := $(CP) $(1) $(2)
dist/include/mylib/mylib.h: include/mylib/mylib.h
$(call copy_file,$^,$@)
dist/include/mylib/platform.h: include/mylib/platform/linux/platform.h
$(call copy_file,$^,$@)
source to share