Sort prequisites list in makefile - makefile

Is there a makefile way to get the list of prequisites ($^) alphabetically sorted?
i have a Makefile like:
some_pdfs = $(wildcard src/*.pdf)
big_pdf: ${some_pdfs}
pdftk $^ cat ouput $<
the problem is that the source pdfs are in unsorted order, but i want them to be alphabetically.

Use sort:
some_pdfs = $(sort $(wildcard src/*.pdf))
If you like, you can sort the list within the rule:
big_pdf: ${some_pdfs}
pdftk $(sort $^) cat ouput $<

Related

How do I write a prerequisite to loop through two lists of files together?

This is an example illustrating the output I would like:
LIST1 := hello.o world.o
LIST2 := hello.c world.c
# Make the first object
# hello.o: hello.c
$(word 1, $(LIST1)): $(word 1, $(LIST2))
cc -c $^ -o $#
# Make the second object
# world.o: world.c
$(word 2, $(LIST1)): $(word 2, $(LIST2))
cc -c $^ -o $#
Is there a way to summarise the target: prerequisite text so that it loops through two entire lists?
I have tried using foreach functions with word functions but I don't get the output. I get non-numeric arguments to word and other invalid expressions.
You actually can do it, but it's really ugly (and would be hard to maintain), I'm showing the answer, but I am definitely not suggesting using it... If you can use pattern rules as #MadScientist suggests, that would be best. If not (say the names differ, you can do something like):
LIST1 := hello.o bob.o
hello.o : hello.c
bob.o : sally.c
$(LIST1):
cc -c $< -o $#
Which allows you to specify custom prereqs for each target. If you really need two lists, the technical answer to your question would be as follows:
LIST1 := hello.o bob.o
LIST2 := hello.c sally.c
all:
define recursive_def
$(firstword $(1)) : $(firstword $(2))
cc -c $$^ -o $$#
$(if $(wordlist 2,3,$1),$(call recursive_def,$(wordlist 2,$(words $(1)),$1),$(wordlist 2,$(words $(2)),$(2))))
endef
$(info -v---v-)
$(info $(call recursive_def,$(LIST1),$(LIST2)))
$(info -^---^-)
$(eval $(call recursive_def,$(LIST1),$(LIST2)))
The short answer is "no". Why don't you just write a pattern rule?
all: $(LIST1)
%.o : %.c
cc -c $^ -o $#
? In fact you don't even need to write a pattern rule at all: make already has a default rule that can build object files from C source files.
ETA
If you have source files in different directories, you have two choices. The best choice is to have one pattern rule and create all your objects in a subdirectory structure that mimics your source directories. So, like this:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(SRCS))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<
If you really don't want to do that and you want to put all the object files into the same directory (a bad idea because if you have two source files with the same name in different source directories, your build will fail) you can use VPATH:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(notdir $(SRCS)))
VPATH := $(sort $(dir $(SRCS)))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<

How to create a makefile to sort all the .txt files in the directory and save it as .sorted using makefile?

How to create a makefile to sort all the .txt files in the directory and save it as .sorted using makefile?
%.sorted: %.txt
sort $< -o $#
all: (*.sorted)
default:all
(*.sorted) is just looking for a file with that literal name. You probably want
all: $(patsubst %.txt,%.sorted,$(wildcard *.txt))
%.sorted: %.txt
sort $< -o $#
The $(wildcard *.txt) generates a list of all your text files, and the $(patsubst ...) generates a parallel list with .sorted instead of .txt.
(Notice that Stack Overflow renders tabs as spaces, so you will not be able to simply copy/paste this code from the rendered page.)
For just make to do what you want, you need the target to be the first one in the Makefile. Perhaps see also Makefile: all vs default targets

makefile not expanding dynamic prerequisites

I want to have a makefile that will take some strings as prefixes for some files (NAMES) and from there work on the target and prerequisite file names. In the example below, for example, the idea would be to convert 2 a csv files (foo.csv and bar.csv) to tabular (although I'm just echoing the target and prerequisite).
NAMES = foo bar
PR = $(patsubst %,%.csv,$(NAMES))
TB = $(patsubst %,%.tsv,$(NAMES))
all: $(TB)
%.tsv: $(PR)
#echo $< $#
This prints:
foo.csv foo.tsv
foo.csv bar.tsv
So, it looks like that makefile is not expanding correctly the prerequisites in PR as I would expect to see bar.csv bar.tsv on the second line.
However, if I print $PR and $TB, both seem to be set properly:
$(info $$PR is [${PR}])
$(info $$TB is [${TB}])
# prints
$PR is [foo.csv bar.csv]
$TB is [foo.tsv bar.tsv]
Any idea how to get this working properly?
Note that I have both foo.csv and bar.csv files in the working directory.
The problem lies in the way you're using the built in variable $<. If you expand the variables manually and rewrite the makefile it becomes...
NAMES = foo bar
PR = $(patsubst %,%.csv,$(NAMES))
TB = $(patsubst %,%.tsv,$(NAMES))
all: foo.tsv bar.tsv
%.tsv: foo.csv bar.csv
#echo $< $#
But $< refers to the first prerequisite which is always foo.csv regardless of the target.
One solution might be to use a scoped static pattern rule. So something like...
NAMES = foo bar
PR = $(patsubst %,%.csv,$(NAMES))
TB = $(patsubst %,%.tsv,$(NAMES))
all: $(TB)
# Tell make how to build a .tsv from a .csv but constrain the rule
# so that it only applies to .tsv files that are part of $(TB).
#
$(TB): %.tsv: %.csv
#echo 'building target [$#] with $$< = [$<]'
The above results in...
building target [foo.tsv] with $< = [foo.csv]
building target [bar.tsv] with $< = [bar.csv]

GNU Make get the list of all files in a directory that were generated by previous rule

I am looking for Makefile macro to get list of all files in a directory that were generated as rule1 processing and using this list for rule2 processing.
Here's what I am trying to achieve :
Rule 1: Generate source .c files (using xml files) and place them in $(MYDIR) directory.
Rule 2: Get the list of all files in $(MYDIR) and create object files and place them in $(OBJDIR).
Problem is, I want to update list of files in Rule2 after Rule 1 has been processed, else list of files in $(MYDIR) will be empty.
all : rule_1 rule_2
rule1 : $(MYDIR)/generated_source1.c $(MYDIR)/generated_source2.c
$(MYDIR)/generated_source1.c:
xsltproc generator1.xml style_generator.xsl -o $(MYDIR)/generated_source_1.c
$(MYDIR)/generated_source2.c:
xsltproc generator2.xml style_generator.xsl -o $(MYDIR)generated_source_2.c
#Get list of all $(MYDIR).*c , create corresponding $(OBJDIR)/*.o list.
SOURCES := $(wildcard $(MYDIR)/*.c)
OBJECTS := $(notdir ${SOURCES})
GENERATED_OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(OBJECTS))
#This rule is compiling of all .c generated in rule1.
rule2 : $(GENERATED_OBJS)
ld -r -o $(OBJDIR)/generated_lib.o $(GENERATED_OBJS)
$(OBJDIR)/%.o: $(MYDIR)/%.c
gcc $(CFLAGS) -c -o $# $<
$(SOURCES) is shown empty, but actually it should contain generated_source1.c and generated_source2.c
I am not sure how .SECONDEXPANSION rule will work for my case.
You can't really (and don't really want to) play around with getting make to re-evaluate file existence during the running of the make process.
What you want to do is track the files from start to finish in make and then you have all your lists.
You can start at either direction but starting with the initial source tends to be easier.
So start with
MYDIR:=dir
OBJDIR:=obj
XML_SOURCES := $(wildcard $(MYDIR)/*.xml)
then translate from there to the generated source files
SOURCES := $(subst generator,generated_source,$(XML_SOURCES:.xml=.c))
and from there to the generated object files
GENERATED_OBJS := $(patsubst $(MYDIR)/%.c,$(OBJDIR)/%.o,$(SOURCES))
At which point you can define the default target
all: $(OBJDIR)/generated_lib.o
and then define the rules for each step
$(MYDIR)/%.c:
cat $^ > $#
$(OBJDIR)/%.o: $(MYDIR)/%.c
cat $^ > $#
$(OBJDIR)/generated_lib.o: $(GENERATED_OBJS)
ld -r -o $# $^
The $(MYDIR)/%.c rule needs a bit of extra magic to actually work correctly. You need to define the specific input/output pairs so that they are used correctly by that rule.
$(foreach xml,$(XML_SOURCES),$(eval $(subst generator,generated_source,$(xml:.xml=.c)): $(xml)))
This .xml to .c step would be easier if the input and output files shared a basename as you could then just use this and be done.
%.c: %.xml
cat $^ > $#

Makefile Dynamic Rules w/ No GNU-make Pattern

I have a set of .cpp files that I want to compile. These .cpp files are in a hierarchical directory structure. I want the corresponding .o files to all end up in one build folder.
Here's how I get GNU make to enumerate the files:
SRCS = \
$(wildcard $(CODE)/**/*.cpp) \
$(wildcard $(CODE)/AlgebraLibraries/**/*.cpp) \
$(wildcard $(CODE)/Calculator/Environments/**/*.cpp)
BARE_SRCS = $(notdir $(SRCS))
BARE_OBJS = $(BARE_SRCS:.cpp=.o)
OBJS = $(addprefix $(BUILD)/, $(BARE_OBJS))
Having done this, I have no idea how to create the rules that will create the .o files from the .cpp files. Intuitively, what I want to do is the following pseudocode:
for i=0, N do # <-- a for-loop!
$(OBJS)[i]: $(SRCS)[i] # <-- the rule!
$(CPP) -c $(SRCS)[i] -o $(OBJS)[i] # <-- the recipe
end
Of course, this is not valid GNU make code, but I trust you understand what it is here that I'm trying to do. The following will not work.
%.o: %.cpp
$(CPP) -c $< -o $#
This doesn't work, because GNU make is matching up the % signs, assuming that the .o files live along-side the .cpp files.
The alternative to all of this, which I know will work, but will be extremely tedious, is to enumerate all of the rules by-hand as explicit rules. There has to be a better way!
I've been researching GNU make's ability to generate rules, but there appears to be no way to do it without the built-in logic. It would be really nice if I could utilize some flow-control statements to generate the rules that I want to make. Is this asking too much of GNU-make?
In any case, is there a way to do what it is I'm trying to do with GNU make? If so, how?
This looks like a job for... several advanced Make tricks:
all: $(OBJS)
define ruletemp
$(patsubst %.cpp, $(BUILD)/%.o, $(notdir $(1))): $(1)
$$(CPP) -c $$< -o $$#
endef
$(foreach src,$(SRCS),$(eval $(call ruletemp, $(src))))
If $(BUILD) is constant, you can always just do:
$(BUILD)/%.o: %.cpp
$(CPP) -c $< -o $#

Resources