I've this directory structure:
root/
build/ #I'm inside this directory
dir1/
build
obj #.o files inside this
dir2/
build
obj #.o files inside this
dir3/
build
obj #.o files inside this
As you see my makefile is in root/build — the makefile defines a variable as:
DIRS = dir1 dir2 dir3 #there could be many
and then I try to create a variable as:
OBJDIRS = $(DIRS:%=../%/build/obj)
$(info $(OBJDIRS)) #lets print the list
Here info prints this list:
../dir1/build/obj ../dir2/build/obj ../dir3/build/obj
Now I want to get a list of all the object files inside obj directories of all the dir* directories. How to get that? I tried this:
OBJECTS = $(wildcard $(OBJDIRS)/*.o)
$(info $(OBJECTS))
which prints this only:
../dir1/build/obj
The wildcard doesn't seem to work on a list of directories. Is there any way to achieve that?
I see two things wrong with your current attempt.
$(wildcard) doesn't use % as its wildcard character. It uses *. So you need $(wildcard $(OBJDIRS)/*.o) to fix that.
$(OBJDIRS)/*.o is going to expand into ../dir1/build/obj ../dir2/build/obj ../dir3/build/obj/*.o. Which, you'll notice, isn't what you want. So you need to use $(addsuffix /*.o,$(OBJDIRS)) or another substitution to generate the list of wildcard patterns you want.
Related
We are using make utility in windows to build our project. The version of make is "GNU Make 3.81". I need to understand how our project is built and so have added additional log lines like below which is working as expected --
$(warning Entering componentsWin32.mak )
Additionally I need to find the current directory and the list of files in that directory, for the first one, this is working--
$(warning Entering componentsWin32.make $(CURDIR))
To print the list of files in a directory I tried this but it did-not work --
$(warning Entering componentsWin32.make $(DIR))
Is it possible using $(SHELL...some command) or any other way? Any pointers to this would be helpful.
The function $(wildcard [path string]) will evaluate to a list of files which are desginated by path string: the path string may be written as a glob, so e.g.
$(wildcard $(CURDIR)/src/*.c)
will evaluate to a list of all C files, given that there is a subdirectory src under your current directory with *.c files in it.
You can even pass an arbitrary number of such path expressions:
$(wildcard $(CURDIR)/src/*.c $(MY_INCLUDE_DIR)/*.h)
Obviously, spaces in path names are not allowed.
I have a directory with a bunch of subdirectories. Each subdirectory contains a traj.dat file. I want to use a Makefile to make sure that the file traj.dat gets converted to a different format, and the output file is printed in the same subdirectory as the original file.
Therefore, if I wanted to specify the names of the subdirectories, I could just use:
subdir1/traj.dat.xyz: subdir1/traj.dat
my_convert subdir1/traj.dat subdir1/traj.dat.xyz
subdir2/traj.dat.xyz: subdir2/traj.dat
my_convert subdir2/traj.dat subdir2/traj.dat.xyz
and so on.
How can I get the above result FOR ALL the subdirectories containing a traj.dat file, regardless of their name, without having to list them explicitly?
Cheers!
Assuming you're using GNU make, try:
DATFILES := $(shell find . -name traj.dat)
OUTFILES := $(addsuffix .xyz,$(DATFILES))
all: $(OUTFILES)
%.dat.xyz : %.dat
my_convert $< $#
You weren't really clear what you mean by "subdirectories"; if you just mean immediate subdirectories you can use this instead of the shell function, which is more efficient (and works on Windows):
DATFILES := $(wildcard */traj.dat)
Before I start, I'll mention that I'm not using GNU Make in this case for building a C/C++ project.
Makefile:
DEST_DIR = build/
SRC_DIR = src/
$(SRC_DIR)a/ : $(SOMETHING_ELSE)
$(DO_SOMETHING_TO_GENERATE_A_DIR)
$(DEST_DIR)% : $(SRC_DIR)%
cp -r $^ $#
ALL_DEPS += <SOMETHING>
... more code which appends to ALL_DEPS ...
.PHONY: all
all : $(ALL_DEPS)
I've got some files not generated via Make rules in $(SRC_DIR). (For the sake of this example, let's say there's a directory $(SRC_DIR)b/ and a file $(SRC_DIR)c .)
I want to append to ALL_DEPS all targets which represent files or directories in $(DEST_DIR) so that "make all" will run all of the available $(DEST_DIR)% rules.
I thought to do something like this:
ALL_DEPS += $(addprefix $(DEST_DIR),$(notdir $(wildcard $(SRC_DIR)*)))
But of course, that doesn't catch anything that hasn't yet been made. (i.e. it doesn't append $(DEST_DIR)a/ to the list because $(SRC_DIR)a/ doesn't yet exist when the $(wildcard ...) invocation is evaluated and the shell doesn't include it in the results returned by the $(wildcard ...) invocation.)
So, rather than a function which finds all (currently-existing) files matching a pattern, I need one which finds all targets matching a pattern. Then, I could do something like this:
ALL_DEPS += $(addprefix $(DEST_DIR),$(notdir $(targetwildcard $(SRC_DIR)*)))
If it matters any, I've got much of the GNU Make code split across multiple files and included by a "master" Makefile. The ALL_DEPS variable is appended to in any of these files which has something to add to it. This is in an attempt to keep the build process modular as opposed to dropping it all in one monster Makefile.
I'm definitely still learning GNU Make, so it's not unlikely that I'm missing something fairly obvious. If I'm just going about this all wrong, please let me know.
Thanks!
It is simply not possible to do what you're trying to do; you're trying to get make to recognise something that doesn't exist.
This is part of the reason why, in general, wildcards are bad (the other being that you can end up including stuff you didn't mean to). The right thing to do here is to explicitly create a list of source files (ls -1 | sed -e 's/\(.*\)/sources+=\1/' > dir.mk) and perform the patsubst transformation on that list.
If you have additional files that are generate as part of the build, then you can append them to that list and their rules will be found as you'd expect.
In my Makefile I need to get a list of all directories present in some other directory.
To get a list of all directories in the same folder as my Makefile I use:
DIRECTORIES = $(wildcard */)
all:
echo $(DIRECTORIES)
which works fine, and gives me the desired list. However if I want to have a list of all directories in another directory using
DIRECTORIES = $(wildcard ../Test/*/)
all:
echo $(DIRECTORIES)
I get a list of ALL files (with paths) in that directory, including .h and .cpp files.
Any suggestions why this happens and how to fix it? Other solutions to obtain the list are also welcome.
Use sort and dir functions together with wildcard:
DIRECTORY = $(sort $(dir $(wildcard ../Test/*/)))
From GNU make manual:
$(dir names...)
Extracts the directory-part of each file name in names. The directory-part of the file name is everything up through (and including) the last slash in it. If the file name contains no slash, the directory part is the string ‘./’.
$(sort list)
Sorts the words of list in lexical order, removing duplicate words. The output is a list of words separated by single spaces.
Also look at the second and the third method in this article: Automatically Creating a List of Directories
Try:
$(shell find <directory> -maxdepth 1 -type d)
which will give you the list of directories inside a given directory without going into subdirectories. You may need to clean that list up since it will include . and ./ before every directory listed.
Use:
$(wildcard ../Test/*/.)
This works fine.
I would like to use a single Makefile to generate targets in hundreds of subdirectories. Each subdirectory is a date/time stamp like this: 20120119_153957, which matches the following pattern ????????_??????. There are no other subdirectories that match this pattern.
One target I would like to generate is called ????????_??????/graph.pdf. I have a script called make_graph that will make the graph given the subdirectory name. But I'm not sure how to write a Makefile that will automatically glob all of the subdirectores and generate these targets programmatically.
For example, the code SUBDIRS:=????????_?????? seems to correctly glob all of the subdirectories. I can check with this rule:
.PHONY: print
print:
echo $(SUBDIRS)
However this variable assignment
TARGETS:=$(SUBDIRS:%=%/graph.pdf)
does not seem to do what I expect and assign lots and lots of targets. Instead the following rule just prints one target.
.PHONY: print
print:
echo $(TARGETS)
It is very confusing that SUBDIRS should have the correct subdirectories but TARGET only has one file.
In your example glob matching is performed by the shell.
GNU Make has the built-in wildcard function, which you can use as follows:
SUBDIRS := $(wildcard ????????_??????)
Now you can use this variable to construct a list of targets:
.PHONY : all
all : $(SUBDIRS:%=%/graph.pdf)
%/graph.pdf : # list prerequisites here.
# recipe to make '$#' in directory '$(#D)' from '$^'.
See also: pattern rules, automatic variables.