Solved make: How to treat dependency as filename instead of target name?

Hi!

(I realize that the case I will describe is very uncommon or even weird.)
I'm having trouble writing a makefile the only purpose of which is installing programs (not compiling or making them in any way). I have a dozen shell-scripts that I found difficult to manage (update and install in /usr/local/bin) without some automation. In fact, almost all scripts have to be installed in the same way: we just need to copy them to the directory of choice. But not only I want to be able to install all scripts in bulk ( make), but also to install specific scripts only ( make script1 script2). Obviously, I'm using bmake.

Here's the makefile I came up with:
Makefile:
SRCS= script1 script2 script3
PREFIX= /tmp/usr/local

.for src in ${SRCS}
# Here I want dependency ${src} to be treated as _filename_, not _target_ name.
#                        |
#                        v
${PREFIX}/bin/${src}: ${src}
    @install -v ${src} ${PREFIX}/bin
.PHONY: ${src}
${src}: ${PREFIX}/bin/${src}
.endfor

But as you may expect, when I run it, I got:
Code:
$ make script1
make: Graph cycles through script1
`script1' not remade because of errors.

The trick is that in case of pure shell scripts we don't have to 'make' anything, just install. But I want to be able to make this operation by typing make script1, i.e. I have to use 'script1' (filename) as target name as well. And also I don't want installation to be done in case the latest version is already installed. So the only choice is to have two targets: one for the destination file ( ${PREFIX}/bin/${src}) and second - as 'alias' for the first, to be able to run make script1. But error occurs because on this line
Makefile:
${PREFIX}/bin/${src}: ${src}
dependency ${src} is interpreted as name of target (which we use as an alias) and this causes dependency loop.

In short, the only thing I have to do now is to tell make to treat dependency ${src} as _filename_. I could not find a way to do it so far.

Is it possible?

Thanks.
 
make(1) is a very simple tool to manage targets. It is not made to support verbs like git(1), cmake(1) or any other modern tools do by separating the command, verb, and arguments. make(1) treats all arguments (modulo flags) as targets. Conceptually make(1) command is:
Code:
make [flags] [vars] target [target ...]

Conventionally we create a "phony" (not real) target install to do something and treat it like a verb in Makefile.

The files are also targets, but implicit - make(1) uses file modification time to detect out of date files and invalidate any other target that depends on it.

Given the above mental model, there are couple straight options:
- Put the source code into an .sh suffixed file but use suffix-less targets to install, e.g. make foo:
Code:
install: foo
foo: /path/to/bin/foo
/path/to/bin/foo: foo.sh
- Create per-script install-xxx target and make install depend on all these, e.g make install-foo:
Code:
install: install-foo
install-foo: /path/to/bin/foo
/path/to/bin/foo: foo

The second option explicitly shows the intent when one writes make install-foo vs the first one make foo.
 
Thank you!
I had this two ideas about renaming either target or script files to .sh. I suspected that these are the only available solutions, but I just wanted to really make sure that what I've described in the post is not implementable :)
So good, now I just know it's not possible.
 
I'm not sure to follow what you want to do, but you can't state ${src} in ${PREFIX}/bin/${src}: ${src} will be handled like a file when you declare a target below ${src}:, as you can see .PHONY doesn't prevent cyclic failure.

Make is a great tool, not only to compile, I use it to control all the build system, handling targets and files, plus some shell scripts.
 
Back
Top