Make: Combining Pattern Rules and Wildcards in a Target Dependency - makefile

I have a few PDFLaTeX main files called ch*.tex with numbers replacing the asterick, a PDF file printed by compiling ch*.tex called ch*.pdf, and several LaTeX files input into each ch*.tex during compile that are saved into their respective ch*/ directories. With a Makefile I want my ch*.pdf files to be compiled by ch*.tex files, with TeX files in the ch* subdirectory as additional dependencies, without hardcoding each ch* instances.
However, in some cases the ch* subdirectory may not exist. This changes as my LaTeX projects develops, as some ch*.tex files may be split into subfiles while others may just be one big block file of code. So I want my Makefile to use ch* subdirectory files as dependencies if they exist, but not if they don't. Here are some failed trials:
%.pdf : %.tex %/*.tex
pdflatex $<
This trial successfully detects existing files in the ch* subdirectory, but fails to compile if there is no ch* directory at all.
%.pdf : %.tex $(wildcard %/*.tex)
pdflatex $<
This trial doesn't recognise $(wildcard %/*.tex) as a dependency and only uses ch*.tex.
How can I use files in the ch* subdirectory (without using files in other subdirectories) as dependencies for its respective ch*.pdf compilation?

One way to do it is to use secondary expansion:
.SECONDEXPANSION:
%.pdf : %.tex $$(wildcard $$*/*.tex)
pdflatex $<

Related

How do I read source files from a directory and create object files into another folder in a makefile?

I have the following source files:
% ls
data_lexicon.c data_lexicon.h lex.l makefile
And the following makefile:
% cat makefile
CC = cc
CFLAGS = -Wall -std=c89
LDFLAGS = -ll
OBJFILES = lex.o data_lexicon.o
TARGET = lexical_analyzer_1
all: $(TARGET) lex.c
lex.c: lex.l data_lexicon.h
lex -olex.c lex.l
$(TARGET): $(OBJFILES)
$(CC) $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LDFLAGS)
clean:
rm -f $(OBJFILES) lex.c $(TARGET)
If I do make all I get:
% ls
data_lexicon.c data_lexicon.o lex.l
lexical_analyzer_1 data_lexicon.h lex.c
lex.o makefile
So far so good.
However, I would like to move the source files (data_lexicon.c, data_lexicon.h, lex.l) to a folder src and generate the intermediate files (data_lexicon.o lex.c, lex.o) into a obj folder.
I create both folders but I do not understand how the makefile file shall be configured.
I am using FreeBSD make, so the more portable the solution given the better.
However, I would like to move the source files (data_lexicon.c,
data_lexicon.h, lex.l) to a folder src and generate the intermediate
files (data_lexicon.o lex.c, lex.o) into a obj folder.
It never ceases to amaze me how people insist on making extra work for themselves. You can certainly do what you describe, but it will require writing explicit rules for the object files.
First of all, however, you need to understand that make itself doesn't really know anything about directories. (Traditional make doesn't, anyway. GNU make and perhaps others know a little about them.) That is, it doesn't have any sense of varying directories against which it resolves file names. Rather, every target name is resolved against make's working directory. If you want to refer to something in a subdirectory, then you must say so. To begin with:
OBJFILES = obj/lex.o obj/data_lexicon.o
Similar goes for target and prerequisite names in rules:
obj/lex.c: src/lex.l src/data_lexicon.h
lex -o$# src/lex.l
That's also one reason to favor make's automatic variables, such as the $# in the above rule representing the name of the target being built.
Your makefile presently relies on make's built-in rule for building object files from corresponding C source files, but "corresponding" means target and prerequisite names are identical, including any path components, except for the suffixes (.c vs .o). You will no longer have that correspondence for data_lexicon.o, so you will need to write an explicit rule for it building it. This part is left as an exercise.

makefile ignore removed file names

A directory with css files in it and for each file in the directory I want a separate minified .min.css file in the same directory.
So for example my.css get minified into my.min.css in the same directory.
First I tried
css/*.css:
uglifycss $# > $(subst .css,.min.css,$#)
make -B yeaaa victorie its working :D
But after doing make -B again I get a new separate file each time resulting in my.min.css my.min.min.css my.min.min.min.css
Then I tried
.PHONY: clean
css/*.css: clean
uglifycss $# > $(subst .css,.min.css,$#)
clean:
-rm css/*.min.css
DOH! after clean it is still remembering the files it deleted in the first place resulting again in a my.min.min.min.css file
How can I tell make to stop doing my.min.min.min.css?
(make: GNU Make 3.81 OSX)
First get a list of all files with the suffix .css:
ALL := $(wildcard *.css)
then remove files that have the suffix .me.css:
NEW := $(filter-out %.me.css,$(ALL))
and add the suffix to remaining files:
ME := $(patsubst %.css,%.me.css,$(NEW))
Then you add those files as prerequisites to the default target, and add you own recipe that builds those files, in this case a simple echo:
%.me.css:
echo 123 > $#
default: $(ME)
Compared to your approach, this has the benefit that you don't have to use the flag -B, as only the files that need to be built are built. Therefore invoking make is done by simply caling make without any targets or flags (assuming the makefile is named makefile or Makefile):
make

Makefile: for each .x file, create a .html file

(Similar question here). For every .x file in the directory I want to run a command to generate an HTML file. The command already works fine, it's the Makefile that I'm having trouble with. Here's what I came up with:
all: $(OBJECTS)
OBJECTS := $(patsubst %.x,%.html,$(wildcard *.x))
%.html: %.x
generate $< > $#
The OBJECTS variable is meant to contain all html files I need to generate. Invoking make states nothing to be done for 'all', and there are no HTML files already in the directory.
Turns out make is sensitive to the order of your variable definitions. The Makefile works when the first two lines are switched!

Use directory path of target in list of prerequisites in Makefile

I wrote a script that takes in two files ending in .cfg and outputs a file ending in .cmp. I want to include this in my Makefile because a few source code files depend on this .cmp file.
In my Makefile, I want to do this:
%.cmp: %.cfg $(dir %)/default.cfg
./compare.pl $^ $#
There are two dependencies to generate the .cmp file. First is a .cfg file with the same name, and second is a .cfg file which is always named default. Both .cfg files and the output .cmp file will be in the same directory.
Is there a way to grab the directory path of the target and use it with the prereqs?
I guess Secondary Expansion is probably what you're looking for:
.SECONDEXPANSION:
%.cmp: %.cfg $$(dir %)default.cfg
./compare.pl $^ $#
Also note the absence of slash after $$(dir %), dir function always append one to the resulting value.

makefile problems (gnuplot)

I'm trying to produce some graphs using GNUplot with a makefile. I would like for every *.plt file in the directory to be run through GNUplot, however I can't see to get it to work.
Here's my makefile so far:
all: %.tex
%.tex: %.plt
<tab> gnuplot < $<
The recipe is working fine if I specify a .plt file individually but I want it to pick up my new plots as I produce them.
EDIT:
I think I've got it working now:
# plots all files in the folder with .plt extensions
SOURCES = $(wildcard *.plt)
TARGETS = $(SOURCES:.plt=.tex)
all: $(TARGETS)
%.tex: %.plt
gnuplot < $<
Can someone confirm whether my reasoning (as follows) is correct?
Previously I hadn't specified any files for all (I'm a little confused by %). Now assigning the variable SOURCES by picking up any .plt files using the wildcard (why doesn't it work when using .plt instead of *.plt?). Having assigned SOURCE, the TARGETS variable is then set, now all: has files specified to build. and the matching rule is now run.
all : %.tex won't work because there is no percent in the target name, in other words, it is not a patter rule.
Use wildcard function to get the list of all .plt files and add an all dependence on these files with the extension replaced by .tex:
PLT_FILES := $(wildcard *.plt)
TARGETS := $(PLT_FILES:%.plt=%.tex)
all: $(TARGET)
%.tex: %.plt
gnuplot < $<

Resources