makefile with multiple dependencies for a single file - linux

I have a makefile similar to the following:
SRCS = a.c b.cpp
OBJS = objs/a.o objs/b.o
all: $(OBJS)
objs/%.o: %.c
gcc -c $< -o $#
objs/%.o: %.cpp
gcc -c $< -o $#
It seems to work. But I don't really understand why.
Why doesn't it try to generate a.cpp and b.c?
as I read it : a.cpp is a prerequisite for objs/a.o and it should try to generate it. And because it doesn't find a matching rule for it - it should fail
Where am I wrong?
P.S - I execute my makefile using -r -R to avoid builtin rules

Make does not combine the prerequisite lists of different pattern rules.
When Make is looking for a way to build objs/a.o, it finds that the first pattern rule matches the target, and the prerequisite (a.c) exists. The second pattern rule matches the target, but the prerequisite (a.cpp) does not exist and cannot be built, so Make uses the first rule. Likewise, Make chooses the second rule over the first when looking for a way to build objs/b.o.

Make would try to generate a.cpp and b.c if these files depended on something else. However it is not the case here, these two files are leaves in the dependency tree, so Make has no reason to try to generate them.

Related

Getting dependencies of a shared library that could be located at any folder

I'm creating a Rules.make file, similar to Linux's 2.0 version, which contains all kinds of targets - including .so files. My goal is to then only need to make minimalistic Makefiles like so:
include $(DIR_TOP)/Rules.make
in the directories that contain any source files I need compiled. The rules also enable me to create targets like so in the "main" Makefile:
something: something_else lib.so
, so that something_else is done first, and then lib.so is built.
Everything has been going smoothly, until I decided to add dependencies to the aforementioned shared library target. I figured something like the following would do the trick:
${DIR_OUT}/%.so: $(shell find $(dir $#) -name *.o)
$(CC) $(CFLAGS) -o $# $(CLIBS) -shared $^
However, to my demise, $(dir $#) apparently expands to $(dir ${DIR_OUT}/%.so), which then results in simply ${DIR_OUT}, which is exactly not what I need. DIR_OUT is simply the top-level directory string, but the target may be invoked from any sub-directories, or simply like target: $(DIR_OUT)/path/to/lib.so. I was hoping that % could match not only file names, but also any directories (which it does), and then have that expanded to $# once it's already decided what the full path is. Doesn't work like that. With this solution, not only the object files I need are included in the building process, but also any other object files that are there in the output folder, and that then produces errors of kind multiple definition of x y z etc.
Is there any other way to get the list of dependencies for the shared library I want to build? Ideally a purely Makefile based solution, but if there isn't one, I'm fond of some bash scripting too.
The solution turns out to be secondary expansion:
.SECONDEXPANSION:
${DIR_OUT}/%.so: $$(shell find $$(dir $$#) -name *.o)
$(CC) $(CFLAGS) -o $# $(CLIBS) -shared $^

Primitive makefile failure for compiling

I am trying to learn makefile, but I fail badly.
One example (which is very primitive) but I should understand it to go ahead is this one
f90_simple: f1.o
gfortran f1.o
mv a.out f90_simple
f90_simple.o: f1.f90
gfortran -c f1.f90
it does not work, and I get this error
I get this error
make: *** No rule to make target `f1.o', needed by `f90_simple'. Stop.
could you please advise me?
thanks
Your first rule says that before f90_simple can be built, the target f1.o must be built.
But there's no rule in your makefile that tells make how to build the target f1.o, and make can't find any built-in rule that can build it (based on the source files make has available), so it prints that error.
You do have a rule that tells make how to build a target f90_simple.o... but that's not the target make is looking for. Most likely you want your makefile to either be:
f90_simple: f1.o
gfortran $^
mv a.out $#
f1.o: f1.f90
gfortran -o $# -c $<
or else:
f90_simple: f90_simple.o
gfortran $^
mv a.out $#
f90_simple.o: f1.f90
gfortran -o $# -c $<
but you can't mix and match them, or make doesn't know what to do.
I think you would really benefit from reading at least the introductory chapters in The GNU Make Manual.

Makefile: compiling several objects with single target

I have several c++ objects that I'd like to compile using a single target. If possible I'll make a variable in the makefile that list all the object files and then have a single target that compiles them all.
Following this question I have the following "Makefile" so far:
#### Directories and flags
ifndef $(DIR_MAIN)
DIR_MAIN=../..
endif
DIR_EXE=$(DIR_MAIN)
DIR_SRC=$(DIR_MAIN)/src/Analyse_MC
DIR_MISC_SRC=$(DIR_MAIN)/src/Misc
DIR_BLD=$(DIR_MAIN)/build/Analyse_MC
DIR_MISC_BLD=$(DIR_MAIN)/build/Misc
COMP=g++
COMPILE_FLAGS= -std=c++11 -O3 -lstdc++ `pkg-config --cflags eigen3` -msse2 -I${DIR_MISC_SRC}
LINK_FLAGS= -O3 -fopenmp -lgsl -lgslcblas -lm -lhdf5_cpp -lhdf5
OBSERVABLE_OBJECTS=g_decomp_IP_orthog_sphere.o g_decomp_LS_orthog_sphere.o g_decomp_IP_disk.o g_decomp_LS_disk.o find_rank.o eigenvectors.o GramSchmidt.o diagonal_Hamiltonian.o mean_log_WF.o energy.o JK_EP_overlap.o overlap.o geo_mean_eigstate_overlap.o eigstate_overlap.o pair_corr_bins.o
#### Compile all
all: setup observables $(DIR_EXE)/Analyse_MC
setup:
#mkdir -p $(DIR_BLD)
#### Compile observable objects
observables: $(addsuffix -stamp,$(OBSERVABLE_OBJECTS))
%.-stamp : %.o
${COMP} -c -o $# $<
However when running make I get the following:
make: *** No rule to make target `g_decomp_IP_orthog_sphere.o-stamp', needed by `observables'. Stop.
So I've misunderstood something.
If possible I'd also like each of the objects to be updated with changes in .h-files with the name of the object in addition to some common .h-files for all of the objects. Is this possible?
Or do I have to / is it recommended to write a separate target for each object?
EDIT:
Some info about the variables:
DIR_MAIN is defined the way it is because usually this makefile will be called from another makefile which defines DIR_MAIN from its directory using pwd; but ut can also be called on its own from its own directory.
DIR_MISC_SRC points to some header files necessary for the files in DIR_SRC.
DIR_BLD and DIR_MISC_BLD will contain the corresponding resulting object files.
The error message does show you what you've done wrong, but a bit obliquely:
make: *** No rule to make target g_decomp_IP_orthog_sphere.o-stamp, needed by observables. Stop.
Your rule to make stamp files is:
%.-stamp: %.o
You probably wanted that to be
%.o-stamp: %.o
Compiling %.o to %.o-stamp looks very strange to begin with - probably you just want
observables: $(OBSERVABLE_OBJECTS)
.PHONY: observables
Stamp files are sometimes useful for actions you want to perform once but have no output file. For compilation, the object file is the output file, and that's all that make requires.
If possible I'd also like each of the objects to be updated with changes in .h-files with the name of the object in addition to some common .h-files for all of the objects. Is this possible?
That's a whole nother question in itself - you want to search for "makefile auto-dependency generation" for starting points.

Makefile misses a rule which looks to be available

I have the following Makefile which I want to use to build a project serial.c in Linux which lies in the current directory, but which uses C++ libraries from inside src and include, which should be build into a directory obj, keeping all the files clear and separated.
#define some paths
DHOME = ${HOME}/Serial
SRC = ${DHOME}/src
INCLUDE = ${DHOME}/include
BIN = ${DHOME}/bin
OBJ = ${DHOME}/obj
# compiler
CFLAGS = -I$(INCLUDE)
CXX = g++ -g ${INCLUDE}
MAKE = ${CXX} -O -Wall -fPIC -c
$(OBJ)/%.o: $(SRC)/%.cc
$(MAKE) $(CFLAGS) $< -o ${OBJ}/$#
serial: $(OBJ)/%.o
${CXX} -o $# $#.c $< $(CFLAGS)
.PHONY: clean
clean:
#rm -f serial $(OBJ)/*.o
The error message when trying make serial or just make is
make: *** No rule to make target `/home/alex/Serial/obj/%.o', needed by `serial'. Stop.
But when looking at the Makefile it seem I have specified this rule (the rule above the serial rule). I probably missed something basical. Maybe there is a better way to handle such a project and to have the different pieces clearly separated in directories?
Thanks,
Alex
The problem is your rule:
serial: $(OBJ)/%.o
Since there is no % in the TARGET of this rule, this is not a pattern rule. So it looks for a file named /home/alex/Serial/obj/%.o (literally) which doesn't exist and can't be made.
You need to have serial depend on a list of actual object file names. Then the pattern rule $(OBJ)/%.o: $(SRC)/%.cc can match each of those and will be used to compile it.
edit
If you want to generate that list automatically, you can use a glob rule on your sourcefiles, and then a pattern replacement to generate the object files:
SOURCES = $(wildcard $(SRC)/*.cc)
OBJECTS = $(SOURCES:$(SRC)/%.cc=$(OBJ)/%.o)
Pattern matching rules act on targets.
You do not supply a list of targets to be built so the pattern matching does not work as you assume it does.
Pattern matching is not constructed to work as a wildcard on the command line. You can not ask make to look for targets, you have to supply them.
So, if serial depends on some specific .o files, you need to supply these. The easiest way to do that is to rewrite your rule:
serial: $(OBJ)/foo.o $(OBJ)/bar.o $(OBJ)/fie.o
#Insert build command here, as needed
This will trigger the pattern matching as each object file is set as a target before serial can be linked.

Makefile with multiple targets

Hopefully this is a very simple question. I have a makefile pattern rule that looks like this:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
I want the makefile to build a number of .so files, so I tried to get it to build two files (radgrd_py.so and lodiso_py.so) by doing this:
radgrd_py.so lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
and then tried this:
radgrd_py.so:
lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
But in each case, it only builds the first target that I specify. If I run 'make radgrd_py.so' it works fine, I'm just not sure how to specify a list of files that need to be built so I can just run 'make'.
The usual trick is to add a 'dummy' target as the first that depends on all targets you want to build when running a plain make:
all: radgrd_py.so lodiso_py.so
It is a convention to call this target 'all' or 'default'. For extra correctness, let make know that this is not a real file by adding this line to your Makefile:
.PHONY: all
Best way is to add:
.PHONY: all
.DEFAULT: all
all: radgrd_py.so lodiso_py.so
Explanations:
make uses the first target appearing when no .DEFAULT is specified.
.PHONY informs make that the targets (a coma-separated list, in fact) don't create any file or folder.
all: as proposed by schot

Resources