Print targets that need to be remade - makefile

I need to see the list of targets (files) that would be remade if I run make command for specific target. I guess this can be done by parsing debug output of make utility.

To list the targets that would be remade, you can run the following command:
make -dn MAKE=: your_target | sed -rn "s/^ *Must remake target '(.*)'\.$/\1/p"
If you remove MAKE=: then targets for sub-makes will be printed too.
Unfortunately some files that are imported to your Makefile using the include directive will be listed too. They can be filtered out using the following shell script (list-targs):
#!/bin/sh -e
dbg="`make -dn "$#"`"
all="`echo -n "$dbg" | sed -rn "s/^ *Must remake target '(.+)'\.$/\1/p"`"
mks="`echo -n "$dbg" | sed -rn "s/^ *Reading makefile '([^']+)'.*$/\1/p"`"
echo -n "$all" | grep -vxF "$mks"
Now you can see the targets to remake using this command:
list-targs MAKE=: your_target
If you need list all dependencies (not only those that are to be remade), see this answer.

Related

Recursive Makefile always remakes targets

I am trying to create a Makefile target which will call itself with different options.
# Include config.mk which sets design-specific variables
`include $(CONFIG)
# This command runs the script once with current options
$(LOG_DIR)/compare.log: $(RESULTS_DIR)/final.bin
tclsh $(UTILS_DIR)/script.tcl | tee $#
# Alias for above command
compare: $(LOG_DIR)/compare.log
# This command runs make once for each config file
.PHONY: compare_all
compare_all:
for config in designs/*/config.mk; do \
$(MAKE) CONFIG=$$config compare; \
done
$(UTILS_DIR)/compare_all.py
The problem is that the compare_all target works as expected, but it always thinks that the sub-make targets are out-of-date.
When I run, for example
make CONFIG=designs/a/config.mk compare
make CONFIG=designs/b/config.mk compare
make CONFIG=designs/c/config.mk compare
I get:
make: Nothing to be done for 'compare'.
make: Nothing to be done for 'compare'.
make: Nothing to be done for 'compare'.
But when I run make compare_all -n, I get
tclsh utils/script.tcl | tee logs/a/compare.log
tclsh utils/script.tcl | tee logs/b/compare.log
tclsh utils/script.tcl | tee logs/c/compare.log
showing that it's going to rebuild all designs even though they're already up-to-date.

How to Copy and Rename multiple files using shell

I want to copy only 20180721 files from Outgoing to Incoming folder. I also want to remove the first numbers from the file name and want to rename from -1 to -3. I want to keep my commands to minimum so I am using pax command below.
Filename:
216118105741_MOM-09330-20180721_102408-1.jar
Output expected:
MOM-09330-20180721_102408-3.jar
I have tried this command and it's doing most of the work apart from removing the number coming in front of the file name. Can anyone help?
Command used:
pax -rw -pe -s/-1/-3/ ./*20180721*.jar ../Incoming/
Try this simple script using just parameter expansion:
for file in *20180721*.jar; do
new=${file#*_}
cp -- "$file" "/path/to/destination/${new%-*}-3.jar"
done
You can try this
In general
for i in `ls files-to-copy-*`; do
cp $i `echo $i | sed "s/rename-from/rename-to/g"`;
done;
In your case
for i in `ls *_MOM*`; do
cp $i `echo $i | sed "s/_MOM/MOM/g" | sed "s/-1/-3/g"`;
done;
pax only applies the first successful substitution even if the -s option is specified more than once. You can pipe the output to a second pax instance, though.
pax -w -s ':^[^_]*_::p' *20180721*.jar | (builtin cd ../Incoming; pax -r -s ':1[.]jar$:3.jar:p')

Why is make complaining "Nothing to be done for 'clean' "?

I want make to remove all files except the source files and the make rule file (i.e. the file named makefile), so I added a phony rule at the end of my makefile:
.PHONY:clean
clean:
$(shell ls | grep -v "[.][ch]" | grep -v makefile | xargs rm)
This does what I intend. But make always complains
make: Nothing to be done for 'clean'.
After I run make clean. Why does this message appear? And how can I make it disappear?
The use of $(shell ...) is unnecessary. It runs the command, then the output is used as if it was part of the Makefile. There is no output, so the resulting rule is:
clean:
i.e. the actual list of commands to update the clean target is empty.

Iterate Over for an Input File Flag

I am using a software in Unix on a computing cluster, for which I need hundreds of input files for a combinative analysis, which wants each file specified with an -f flag, it is like:
software -f file1.ext -f file2.ext -f file3.ext
Simple bash loop doesn't work to let it comprehend each file, such as:
for i in *ext; do software -f ${i}; done
Even simpler way doesn't work, either:
software -f *ext
Specifying the folder where the files are doesn't work, either:
software -f .
Even a cooler bash script doesn't work (actually not really different from the simple loop):
#/bin/bash
for i in $(ls *.ext | rev | cut -c 5- | rev | uniq)
do
software -f ${i}.ext
done
So what I need is a way to make the software recognize all my files in the same input flag by iterating the -f as well I believe. Something like:
for i in *ext; for each -f; do software -f ${i}; done
Any help is much appreciated!
You can iteratively build an array with the appropriate options.
for f in *ext; do
opts+=(-f "$f")
done
software "${opts[#]}"

Modifying file extensions using Makefiles

I'm new to Makefiles and I want to modify the extension of a set of files. The following command works on the shell:
for file in path/*.ext1; do j=`echo $file | cut -d . -f 1`;j=$j".ext2";echo mv $file $j; done
However, I'm not sure how to run this in a Makefile. I tried running
$(shell for file in path/*.ext1; do j=`echo $file | cut -d . -f 1`;j=$j".ext2";echo mv $file $j; done)
But this never did what I needed it to do. What do I need to do to make this work on the Makefile? How do I call it in a section?
The immediate answer to your question is that the $ character is special to make: it introduces a make variable. If you want to pass a $ to the shell, you'll have to write two of them: $$.
So, your shell function invocation would have to be written as:
$(shell for file in path/*.ext1; do j=`echo $$file | cut -d . -f 1`;j=$$j".ext2";echo mv $$file $$j; done)
However, this is almost certainly not a good way to do what you want. You don't really describe clearly what you want to do, however. If you just want to have a target in a makefile that can be invoked to make this change, you can use:
fixext:
for file in path/*.ext1; do \
j=`echo $$file | cut -d . -f 1`; \
j=$$j".ext2"; \
echo mv $$file $$j; \
done
Or, taking advantage of some useful shell shortcuts, you could just run:
fixext:
for file in path/*.ext1; do \
echo mv $$file $${file%.*}.ext2; \
done
Now if you run make fixext it will perform those steps.
But, a much more make-like way to do it would be to write a single rule that knows how to rename one file, then use prerequisites to have them all renamed:
TARGETS = $(patsubst %.ext1,%.ext2,$(wildcard path/*.ext1))
fixext: $(TARGETS)
%.ext2 : %.ext1
mv $< $#
Now you can even run make -j5 and do 5 of the move commands in parallel...
you can also add rename blocks at the top of your file eg to change a suffix
output := $(input:.mov=.mp4)
but this won't work inside a make command as far as I can see
check:
output := $(input:.mov=.mp4)
gives
$ input=walkthrough.mov make check
output := walkthrough.mp4
make: output: No such file or directory
make: *** [check] Error 1

Resources