in Makefile remove folders if a filename with the same basename exist - bash

I need to remove in the following case
.
├── a
│   └── index.html
├── a.rst
├── b
│   └── index.html
├── c
│   └── index.html
└── c.rst
folder a and c not b.
I make it work with this Makefile:
$ cat Makefile
.PHONY: clean
HTML_TARGETS:= $(patsubst %.rst,%.html,$(wildcard *.rst))
clean: $(HTML_TARGETS)
%.html: %.rst
#echo rm $(basename $# .html)
$
$ make
rm a
rm c
$
Is there a better way to write it ? (the patsubst use an unneeded .html sub)

What I mean is why don't you just do something like:
.PHONY: clean
HTML_DIRS := $(patsubst %/,%,$(dir $(wildcard */*.html)))
RST_FILES := $(basename $(wildcard *.rst))
clean:
echo rm -r $(filter $(RST_FILES),$(HTML_DIRS))

Related

with Makefile create folders from specific filenames

I need a Makefile that create for every <file.rst> a <file> folder to then execute
hovercraft on the <file.rst> which need a folder as second argument
$ tree
.
├── a.rst
├── b.rst
└── Makefile
With this Makefile
$ cat Makefile
.PHONY: html
HTML_TARGETS:= $(patsubst %.rst,%.html,$(wildcard *.rst))
html: $(HTML_TARGETS)
%.html: %.rst
#rm -fr $(basename $# .html)
#mkdir -p $(basename $# .html)
#hovercraft -Ns $< $(basename $# .html)
$
It kind of works
.
├── a
│   └── index.html
├── a.rst
├── b
│   └── index.html
├── b.rst
└── Makefile
I fell how baroquish this Makefile is, what could be a better way to write it ?
BTW I fail to add in the Makefile this echo:
#echo output done in $(basename $# .html)/index.html
I get:
output done in a /index.html
output done in b /index.html
^
└─ with an unwanted space
I whould like to print:
output done in a/index.html
output done in b/index.html
If I understand correctly that you want to make a directory "x", then execute hovercraft x.rst x/index.html for every file "x.rst", then this should be a succinct way to do so.
SOURCES := $(wildcard *.rst)
TARGETS := $(SOURCES:.rst=/index.html)
%/index.html: %.rst
mkdir -p $*
hovercraft $< $#
.PHONY: all
all: $(TARGETS)

Target is not bind to automatic variable in Makefile job expanded by macro

I'm trying to write jobs that contain a lot of similarities as below.
EMACS_VERS := 22.1 23.4 24.5 25.3 26.1
LOCAL_LISPDIRS := $(patsubst %,local/%/site-lisp,$(EMACS_VERS))
$(addsuffix /leaf, $(LOCAL_LISPDIRS)): site-lisp/leaf
mkdir -p $(#D)
cp -rf site-lisp/$(#F) $#
$(MAKE) --no-print-directory -C $(dir $(#D)) .make-repo-$(#F)
$(addsuffix /orglyth, $(LOCAL_LISPDIRS)): site-lisp/orglyth
mkdir -p $(#D)
cp -rf site-lisp/$(#F) $#
$(MAKE) --no-print-directory -C $(dir $(#D)) .make-repo-$(#F)
$(addsuffix /cort, $(LOCAL_LISPDIRS)): site-lisp/cort
mkdir -p $(#D)
cp -rf site-lisp/$(#F) $#
$(MAKE) --no-print-directory -C $(dir $(#D)) .make-repo-$(#F)
However, when those job was expanded by below macro, the target name was not bind to the automatic variable, and an error occurred.
define build_repo
$1: $2
mkdir -p $(#D)
cp -rf site-lisp/$(#F) $#
$(MAKE) --no-print-directory -C $(dir $(#D)) .make-repo-$(#F)
endef
$(eval $(call build_repo,$(addsuffix /leaf,$(LOCAL_LISPDIRS)),site-lisp/leaf))
$(eval $(call build_repo,$(addsuffix /orglyth,$(LOCAL_LISPDIRS)),site-lisp/orglyth))
$(eval $(call build_repo,$(addsuffix /cort,$(LOCAL_LISPDIRS)),site-lisp/cort))
The above code gets the following error. As I think, this happens because the name of the target is not an automatic variable bound.
mkdir -p
usage: mkdir [-pv] [-m mode] directory ...
make: *** [Makefile:72: local/22.1/site-lisp/leaf.el] Error 64
Is there a way to solve this problem?
On the other hand, the following code has been rejected as changes to leaf, orglyth, cort are all generated when change files in only leaf.
REPOS := leaf orglyth cort
REPODIRS := $(addprefix site-lisp/, $(REPOS))
LOCAL_REPOS := $(foreach repo, $(REPOS), $(addsuffix /$(repo), $(LOCAL_LISPDIRS)))
$(LOCAL_REPOS): $(REPODIRS)
mkdir -p $(#D)
cp -rf site-lisp/$(#F) $#
$(MAKE) --no-print-directory -C $(dir $(#D)) .make-repo-$(#F)
Directory tree:
local
├── 22.1
│   └── site-lisp
│   ├── cort
│   ├── leaf
│   └── orglyth
├── 23.4
│   └── site-lisp
│   ├── cort
│   ├── leaf
│   └── orglyth
├── 24.5
│   └── site-lisp
│   ├── cort
│   ├── leaf
│   └── orglyth
├── 25.3
│   └── site-lisp
│   ├── cort
│   ├── leaf
│   └── orglyth
└── 26.1
└── site-lisp
├── cort
├── leaf
└── orglyth
site-lisp
├── cort
├── leaf
└── orglyth
Your macro is expanded twice. Double all $ signs to escape the first expansion.
As you have two nested loops (versions and repos) it would be difficult to use pattern rules instead of macros. But you can probably use macros a bit more efficiently:
# $(1): repo
# $(2): version
define build_repo
local/$(2)/site-lisp/$(1): site-lisp/$(1)
mkdir -p $$(#D)
cp -rf site-lisp/$$(#F) $$#
$$(MAKE) --no-print-directory -C $$(dir $$(#D)) .make-repo-$$(#F)
endef
$(foreach r,$(REPOS),$(foreach v,$(EMACS_VERS),$(eval $(call build_repo,$(r),$(v)))))
Or:
# $(1): repo
# $(2): version
define build_repo
local/$(2)/site-lisp/$(1): site-lisp/$(1)
mkdir -p local/$(2)/site-lisp
cp -rf site-lisp/$(1) local/$(2)/site-lisp/$(1)
$(MAKE) --no-print-directory -C local/$(2) .make-repo-$(1)
endef
$(foreach r,$(REPOS),$(foreach v,$(EMACS_VERS),$(eval $(call build_repo,$(r),$(v)))))
The second version does not need any $ escape because everything is correctly and completely expanded at the first expansion. Yes, even $(MAKE) that, most likely in your case, expands the same during the first or the second expansion.
But remember that this is a special case. If you continue using the $(eval...) function do not forget the double expansion...
Thanks #Renaud Pacelet for your good reply!
define build_repo
$1: $2;
mkdir -p $$(#D)
cp -rf site-lisp/$$(#F) $$#
$$(MAKE) --no-print-directory -C $$(dir $$(#D)) .make-repo-$$(#F)
endef
$(call build_repo,$(addsuffix /leaf,$(LOCAL_LISPDIRS)),site-lisp/leaf)
$(call build_repo,$(addsuffix /orglyth,$(LOCAL_LISPDIRS)),site-lisp/orglyth)
$(call build_repo,$(addsuffix /cort,$(LOCAL_LISPDIRS)),site-lisp/cort)
With this code I got what I wanted without error. But is there a smarter another way to not use macros?
[Additional notes]
I looked at the answer of #Renaud Pacalet and reconcidered.
Actually, when repositories are changed, I have to build on all versions, so I can do one loop as follows.
LOCALDIRS := $(addprefix local/, $(EMACS_VERS))
define build_repo
$(addsuffix /site-lisp/$(1), $(LOCALDIRS)): $(LISPDIR)/$(1)
mkdir -p $$(#D)
cp -rf site-lisp/$$(#F) $$#
$$(MAKE) --no-print-directory -C $$(dir $$(#D)) .make-repo-$$(#F)
endef
$(foreach repo, $(REPOS), $(eval $(call build_repo,$(repo))))

makefile compile changed latex files in subdirectory

I am trying to create a makefile to compile LaTeX files in subdirectories. The desired directory structure should look like this, except instead of simply a, b, and c, there can be any number of subdirectories under the latex folder.
├── latex
│   ├── a
│   │   ├── output
│   │   │   └── stuff.pdf
│   │   └── stuff.tex
│   ├── b
│   │   ├── blah.tex
│   │   └── output
│   │   └── blah.pdf
│   └── c
│   ├── asdf.tex
│   └── output
│   └── asdf.pdf
└── makefile
I want to do this with only one makefile in the latex directory that will automatically compile the tex files in every subdirectory.
My current makefile looks like this:
TEX_COMMAND = pdflatex
TEX_FILES = $(wildcard **/*.tex)
OUTPUT_DIRECTORIES = $(addsuffix output/,$(wildcard */))
PDF_FILES = $(join $(dir $(TEX_FILES)),$(addprefix output/,$(notdir $(TEX_FILES:tex=pdf))))
all: mkdir $(PDF_FILES)
mkdir:
#mkdir -p $(OUTPUT_DIRECTORIES)
$(PDF_FILES): $(TEX_FILES)
#$(TEX_COMMAND) -file-line-error -halt-on-error -output-directory $(dir $#) -aux_directory=$(dir $#) $(subst output/,$(notdir $(#:pdf=tex)),$(dir $#))
#$(TEX_COMMAND) -file-line-error -halt-on-error -output-directory $(dir $#) -aux_directory=$(dir $#) $(subst output/,$(notdir $(#:pdf=tex)),$(dir $#))
clean:
#rm -rf $(OUTPUT_DIRECTORIES)
This will correctly generate the proper pdf, aux, log, toc, etc. files in the output directory in each subdirectory. However, if I change one tex file, then make will cause everything to be recompiled.
I've already looked at many other similar questions. For other questions, the number of subdirectories is known, so you can hardcode them into the makefile. For this situation, the number of subdirectories in the latex folder is constantly changing and being added to, etc, which is why I'm using the wildcard to grab all the tex files. I would prefer not having to create a makefile for each subdirectory and using recursive make.
One of the fundamental shortcomings of Make is its crude handling of wildcards.
In this case, you can use secondary expansion to write a pattern rule that will do what you want:
all: mkdir $(PDF_FILES)
.SECONDEXPANSION:
%.pdf: $$(subst /output/,/, $$(subst .pdf,.tex, $$#))
#echo buiding $# from $<

How I strip path of source file while writing a compilation rule in makefile?

In short: I want to compile sources from different directories, and put object files into current directory.
For example, I have files:
test.c
../../lib1/boot.c
../../lib2/startup.c
../common/utils.c
(also few files .s (assembly) and .cpp, but I hope this is not important).
All of their object-files I want to be in the current directory:
test.o
boot.o
startup.o
utils.o
And I can't figure out how to write such rule in my makefile.
For example,
%o.: %.c
does not work now because make can't find a rule to build boot.o from ../../lib1/boot.c, it can only find rule to build ../../lib1/boot.o from ../../lib1/boot.c.
I tried to use this:
%o.: %.c
(my compilation line, for example "gcc -c $^ -o $#")
%o.: ../../lib1/%.c
(my compilation line)
%o.: ../../lib2/%.c
(my compilation line)
%o.: ../common/%.c
(my compilation line)
and it works. But obviously this is not generic enough, and in addition, some user came to me today and said that his application has also some ../../some_other_lib/common_things.c, hence my makefile failed. I looked through our project, and found many such cases with a lot of different directories involved. With my approach, I'll have to write a separate rule for each such directory, with identical compilation line. This does not seem good to me.
So my question is: how to make some generic compilation rule that puts (and checks) object files in current directory, while operating with sources in different directories?
Thank you.
The directories can be extracted from the CSRC variable with $(dir ...) and this list can then be used in the vpath directive.
vpath %.c $(sort $(dir $(CSRC)))
vpath %.s $(sort $(dir $(SSRC)))
vpath %.cpp $(sort $(dir $(CPPSRC)))
(I've thrown in the sort function to remove duplicates, but that's not absolutely necessary.)
Now the rules can be kept simple and make will search the source files in the list of directories.
$(COBJ) := $(notdir $(CSRC))
$(SOBJ) := $(notdir $(SSRC))
$(CPPOBJ) := $(notdir $(CPPSRC))
.PHONY: all
all: $(EXECUTABLE)
$(EXECUTABLE): $(COBJ) $(SOBJ) $(CPPOBJ)
....
$(COBJ): %.o: %.c
...
$(SOBJ): %.o: %.s
...
$(CPPOBJ): %.o: %.cpp
...
Try to use makefile function notdir as this:
%.o: %.c
gcc -c $< -o $(notdir $#)
$# must be equal to the full path ex: ../../lib2/startup.o ad notdir will trunk it to: startup.o.
With this rule you will be able to compile all your source in the current directory.
Actually, your example is like that:
.
└── common
├── lib1
│   └── boot.c
├── lib2
│   └── startup.c
├── test
│   ├── Makefile
│   └── test.c
└── utils.c
I think i will be better like that:
.
├── common
│   ├── lib1
│   │   ├── Makefile
│   │   ├── obj
│   │   └── src
│   │   └── boot.c
│   ├── lib2
│   │   ├── Makefile
│   │   ├── obj
│   │   └── src
│   │   └── startup.c
│   ├── Makefile
│   ├── obj
│   ├── src
│   │   └── utils.c
│   └── test
│   ├── Makefile
│   ├── obj
│   └── src
│   └── test.c
└── Makefile
For that you need all your Makefiles to call the subdirs Makefiles.
and the src/obj dirs is a separation between your source and objects.
SRC := utils.c
OBJ := $(SRC:%.c=%.o)
NAME := project
SRC_D := src
OBJ_D := obj
SUBDIRS := lib1/ \
lib2/ \
test/
all: $(NAME) $(SUBDIRS)
#for dir in $(SUBDIRS); \
do \
$(MAKE) -C $$dir; \
done
$(NAME): $(OBJ:%.o=$(OBJ_D)/%.o)
$(OBJ_D)/%.o : $(SRC_D)/%.c
gcc -c $< -o $#
OK, took me some time, but finally I found the solution (using some threads on this site by the way):
# Defining compilation rules in a way that object files will be produced in current directory, and not in the directory of source files:
all: <List of my targets>
define my_c_rule
$(subst .c,.o,$(notdir $(1))): $(1)
$(CC) $(CFLAGS) $(CDEFINES) $$^ -o $$#
endef
$(foreach f, $(CSRC), $(eval $(call my_c_rule, $(f))))
$(CSRC) contains list of source files with their paths.
Just need to take into account that if earlier I had something like this:
.c.o:
$(CC) $(CFLAGS) $(CDEFINES) $^ -o $#
all: <List of my targets>
...now I have to put all sentence above the rules which I described in my_c_rule procedure. If I don't do this, make stops after compiling first source file. This is because old "wildcard" rules like .c.o or %.o: %.c do not replace all as a default target (even being written earlier), but non-wildcard rules like boot.o: ../../lib1/boot.c (result of the above macros) do replace the default target in case they are written earlier.

recreate directory structure and recursively process each file with gnu make

I have a directory tree like this:
├── dir_a
│   └── file_1.txt
├── dir_b
│   └── dir_c
│   ├── file_2.txt
| └── file_3.txt
└── file_4.txt
I want to mirror this directory structure to hold the results of a command that processes each text file. I.e., the output would look like this:
├── build
│   ├── dir_a
│   │   └── processed_file_1.txt
│   ├── dir_b
│   │   └── dir_c
│   │   ├── processed_file_2.txt
│   | └── processed_file_3.txt
│   └── processed_file_4.txt
├── dir_a
│   └── file_1.txt
├── dir_b
│   └── dir_c
│   ├── file_2.txt
| └── file_3.txt
└── file_4.txt
I'm not very adept with Makefiles, so my question is: how can I get a Makefile to recreate the directory structure and recursively process all text files to place them into the right place inside the build directory? I'll be running this repeatedly as the input files change, so a Makefile that doesn't process unchanged files seems like the right way to go.
Update:
I should also mention that new input files will be added frequently, so I don't want the Makefile to name them explicitly.
It would be easier if you used stems with different suffixes rather than inserting that "processed_" string, but here's an example that works for me here:
OUTPUTS := build/dir_a/processed_file_1.txt \
build/dir_b/dir_c/processed_file_2.txt \
build/dir_b/dir_c/processed_file_3.txt \
build/processed_file_4.txt
all: $(OUTPUTS)
.SECONDEXPANSION:
$(OUTPUTS): build/% : $$(subst processed_file_,file_,%)
mkdir -p $(dir $#)
cp $< $#
clean:
rm -rf build
You could remove the complication of .SECONDEXPANSION by changing the end of the filename instead of the beginning:
OUTPUTS := build/dir_a/file_1.out \
build/dir_b/dir_c/file_2.out \
build/dir_b/dir_c/file_3.out \
build/file_4.out
all: $(OUTPUTS)
$(OUTPUTS) : build/%.out : %.txt
mkdir -p $(dir $#)
cp $< $#
clean:
rm -rf build
As Carl suggested, you could use secondary expansion, but in conjunction with order-only prerequisites.
BUILD_DIR = build
IN_FILES := dir_a/file_1.out \
dir_b/dir_c/file_2.out \
dir_b/dir_c/file_3.out \
file_4.out
OUT_FILES := $(IN_FILES:%=$(BUILD_DIR)/%)
all: $(OUT_FILES)
.SECONDEXPANSION:
$(OUT_FILES) : $(BUILD_DIR)/%.out : %.txt | $$(#D)/.
# your text processing rule here...
%/. :
mkdir -p $*
| $$(#D) means:
during the secondary expansion calculate the value of $(#D) automatic variable (which is the directory part of the target), and
add the order-only dependency on it, that is ensure that the directory exists, but don't consider remaking the target if it is older than the directory (which is an often case)

Resources