How to add dependencies to my makefile? - makefile

Hi say I have a program called "myProg", it doesn't take any argument but
I would like to add the dependancy to run ONLY when file1 is newer than the
outfile1 (outfile1 is produced the myProg)
The makefile I have is like the following
out : file1 outfile1
myProg
But it seems it always runs myProg to generate a new outfile1 no matter what.
Where am I missing? Do I have to involve the $< and $# in the command line in order
to make the dependency to work? Thanks

Ok, I figured out. its just that the outfile1 needs to be the "out" then it will just work.

Related

How to run different recipes for different sets of dependencies of the same target file

Make manual says I can have only one recipe per target. But I need to run different building tools depending on which dependencies has changed.
Something like this:
target.txt: subtarget.txt
cat $? >> $#
target.txt: header.txt
date >>$#
Is there some trick to archive it?
I'm not exactly sure what you want to do, but maybe double-colon rules will help you?
target.txt:: subtarget.txt
cat $? >> $#
target.txt:: header.txt
date >>$#

Can you use make to process command line specified files?

This is exactly what I want to do: I wonder if I can define a rule in make, such that I can provide make a .o file through the command line, and then that command line will be processed with the command
arm-none-eabi-objdump -D <object file>
The idea is to simplify debugging by not having to do that command by hand but rather do something like:
debug file.o
If make can't do this is there any way to do this?
Sort of. You can create a rule like:
%.dump : %.o; arm-none-eabi-objdump -D $^
then do:
$ make file.dump
hth

In make, can we use $^ to get the dependency list for just the current rule?

I've been learning make from the software carpentry tutorial (make patterns) and it says that we can use $^ to get the dependency list for our rule but have extra dependencies for our target by writing extra empty rules. For example
all:
touch f1.txt f2.txt a.txt
result: a.txt
result: f*.txt
#echo $^
I thought that this would print f1.txt f2.txt but instead I see f1.txt f2.txt a.txt. Am I missing something or is the tutorial wrong?
Clearly, I should have been explicit, in the example I run make to create the files for the test, then I run make result to get the result shown.
Not sure I understand your problem and what you would like to do but if you type just make it is like if you were typing make all because all is the first target and thus the default goal. It should create the 3 files (or update their last modification date if they already exist), echo the recipe and you should see:
touch f1.txt f2.txt a.txt
If you then type make result you should see the result of #echo $^, that is the list of all dependencies of result:
f1.txt f2.txt a.txt
It is absolutely normal as you declared them all as dependencies of result.
Finally, if you type make result before make or make all and if a.txt does not exist or if there is no file matching f*.txt, you will get an error because make needs a.txt and at least one file matching f*.txt to make result and it does not know how to make them.
I cannot imagine a use case where the behaviour you expected ($^ being expanded as dependencies of the current rule only) would be useful, but if really you need this feature you can use the rather obscure Double-Colon Rules (DCR):
all:
touch f1.txt f2.txt a.txt
result:: a.txt
#echo $^
result:: f*.txt
#echo $^
Note that if there is a DCR for a target, all rules of this target must also be DCR. Note also that all DCR must have a recipe. A DCR recipe is applied if one of the dependencies of this rule is newer than the target. If several DCR apply, they are executed in order of appearance in the Makefile. And finally, what you were interested in: the $^ automatic variable logically expands as the dependencies of the particular DCR.
No, $^ refers to the prerequisites for the current target, not the current rule.
Also, the results you are reporting are not correct; for make result I get make: *** No rule to make target `f*.txt', needed by `result'. Stop. like I very much expected.

Bash: replace part of filename

I have a command I want to run on all of the files of a folder, and the command's syntax looks like this:
tophat -o <output_file> <input_file>
What I would like to do is a script that loops over all the files in an arbitrary folder and also uses the input file names to create similar, but different, output file names. The file names looks like this:
input name desired output name
path/to/sample1.fastq path/to/sample1.bam
path/to/sample2.fastq path/to/sample2.bam
Getting the input to work seems simple enough:
for f in *.fastq
do
tophat -o <output_file> $f
done
I tried using output=${f,.fastq,.bam} and using that as the output parameter, but that doesn't work. All I get is an error: line 3: ${f,.fastq,.bam}: bad substitution. Is this the way to do what I want, or should I do something else? If it's the correct way, what am I doing wrong?
[EDIT]:
Thanks for all the answers! A bonus question, though... What if I have files named like this, instead:
path/to/sample1_1.fastq
path/to/sample1_2.fastq
path/to/sample2_1.fastq
path/to/sample2_2.fastq
...
... where I can have an arbitrary number of samples (sampleX), but all of them have two files associated with them (_1 and _2). The command now looks like this:
tophat -o <output_file> <input_1> <input_2>
So, there's still just the one output, for which I could do something like "${f/_[1-2].fastq/.bam}", but I'm unsure how to get a loop that only iterates once over every sampleX at the same time as taking both the associated files... Ideas?
[EDIT #2]:
So, this is the final script that did the trick!
for f in *_1.fastq
do
tophat -o "${f/_1.fastq/.bam}" $f "${f/_1.fastq/_2.fasq}"
done
You can use:
tophat -o "${f/.fastq/.bam}" "$f"
Testing:
f='path/to/sample1.fastq'
echo "${f/.fastq/.bam}"
path/to/sample1.bam
Not an answer but a suggestion: as a bioinformatician, you shoud use GNU make and its option -j (number of parallel jobs). The Makefile would be:
.PHONY:all
FASTQS=$(shell ls *.fastq)
%.bam: %.fastq
tophat -o $# $<
all: $(FASTQS:.bam=.fastq)
Alternative to anubhava's concise solution,
d=$(dirname path/to/sample1.fastq)
b=$(basename path/to/sample1.fastq .fastq)
echo $d/$b.fastq
path/to/sample1.fastq
tophat -o "$d/$b.fastq" "$f"

Makefile and rm -f file.{ext1,ext2,ext3} issue

Could you explain me, why Makefile rule:
clean:
rm -f foo.{bar1,bar2,bar3}
does not result in removing files: foo.bar1 foo.bar2 and foo.bar3?
I believe I saw pattern like that many times in various Makefiles, but I'm currently writing my own Makefile and can't make that rule work correctly (no files are removed).
I'm using:
gnu make 3.81
gnu bash 4.1.5
Bash evals that pattern as I suspect:
$ echo test.{a,b,c}
test.a test.b test.c
Thanks!
UPDATE
Thank to David's hint I found solution for the problem described above.
The gnu make uses the /bin/sh by default and that is why a.{1,2,3} isn't evaluated to a.1 a.2 a.3.
To make 'make' use bash instead of sh add following line to your Makefile:
SHELL=/bin/bash
from now a.{1,2,3} will be considered as a.1 a.2 a.3
Is there a file named clean in the directory? If so, make will consider that target up to date and won't run the corresponding command. To fix that, add this line to your makefile:
.PHONY: clean
If when you run make clean you get the output
make: `clean' is up to date.
then that's probably your problem.
It's because the shell isn't being invoked here, but rather rm is directly. Since the shell does the {} substitution, what rm 'sees' is the raw foo.{bar1,bar2,bar3} string. As there's no such file, nothing happens.
You should use one of GNUmake's string macros to have it perform the expansion for you.

Resources