Makefile misses a rule which looks to be available - linux

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.

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 $^

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.

How can I makefile with this

My program comprises sharedmemory.c sharedmemory.h semaphore.c semaphore.h sumprime.c, now I want to compile in Linux an executable file named sumprime
sumprime.c code calls some methods that are declared in sharedmemory.h semaphore.h and implemented in sharedmemory.c semaphore.c
My makefile is like this:
HEADERFILES = semaphore.h sharedmemory.h
SOURCEFILES = sumprime.c semaphore.c sharedmemory.c
OBJFILES = sumprime.o semaphore.o sharedmemory.o
DISTFILES = $(HEADERFILES) $(SOURCEFILES) Makefile
DISTFOLDER = lab5
HANDIN = ${DISTFOLDER}.tar.bz2
DEST=sumprime
CCFLAG=
.PHONY: all clean pack
all: $(DEST)
$(DEST): sumprime.o
gcc sumprime.o -o $(DEST)
sumprime.o: $(HEADERFILES) $(SOURCEFILES)
gcc -c $(HEADERFILES) $(SOURCEFILES) -o sumprime.o
clean:
pack:
#echo [PACK] Preparing for packaging...
#rm -fr ${DISTFOLDER} ${HANDIN}
#mkdir ${DISTFOLDER}
#echo [PACK] Copying solution files
#for file in ${DISTFILES}; do\
cp -f $$file ${DISTFOLDER};\
echo \>\>\> $$file;\
done;
#echo [PACK] Creating ${HANDIN}...
#tar cjf ${HANDIN} ${DISTFOLDER}
#rm -fr ${DISTFOLDER}
#echo [PACK] Done!
I tried multiple ways in vain after searching. Please help me with this
As gcc should tell you, you cannot use -c with multiple input files, so
gcc -c $(HEADERFILES) $(SOURCEFILES) -o sumprime.o
does not work.
Fortunately, it also isn't necessary; in fact, you don't need special rules for the .o files because the built-in rules work quite well. This is particularly the case because the name of the output binary corresponds with one of the object files (sumprime.o; see "Linking a single object file" behind the link).
I would use something like
#!/usr/bin/make -f
CC = gcc
CPPFLAGS = -MD
CFLAGS = -O2 -g
LDFLAGS =
LDLIBS =
TARGET = sumprime
HEADERFILES = semaphore.h sharedmemory.h
SOURCEFILES = sumprime.c semaphore.c sharedmemory.c
DISTFOLDER = lab5
DISTFILES = $(HEADERFILES) $(SOURCEFILES) Makefile
HANDIN = $(DISTFOLDER).tar.bz2
OBJFILES = $(SOURCEFILES:.c=.o)
DEPFILES = $(OBJFILES:.o=.d)
all: $(TARGET)
$(TARGET): $(OBJFILES)
clean:
rm -f $(TARGET) $(OBJFILES)
distclean: clean
rm -f $(DEPFILES) $(HANDIN)
pack: dist
dist: $(HANDIN)
$(HANDIN): $(DISTFILES)
#echo [DIST] Preparing for packaging...
#rm -f $#
#tar cjf $# --transform 's,^,$(DISTFOLDER)/,' $+
#echo [DIST] Done!
.PHONY: all clean distclean dist pack
-include $(DEPFILES)
Obviously, this requires some explanation.
Explanation
Implicit rules
I mentioned these above: make predefines a number of rules that often just Do The Right Thing™; we can make them do most of our work. In fact, the shortest Makefile you could use to build your program is
sumprime: sumprime.o semaphore.o sharedmemory.o
This uses an implicit rule to build the .o files and an implicit recipe to build sumprime. Note that there are variables that influence the behavior of implicit rules; behind the link above is a list of such rules that includes their recipes, and in them the names of the variables they use. Since we're compiling C code, the ones we're interested in are:
CPPFLAGS = -MD # C preprocessor flags, such as -Ipath -DMACRO=definition
CFLAGS = -O2 -g # C compiler flags
LDFLAGS = # linker flags, such as -Lpath
LDLIBS = # linked libraries, such as -lpthread (Alternatively:
# LOADLIBES, but this is less usual)
Pattern substitution
The lines
OBJFILES = $(SOURCEFILES:.c=.o)
DEPFILES = $(OBJFILES:.o=.d)
use pattern substitution to generate a list of .o files from a list of .c files, and .d from .o. We'll use .d files for dependency tracking.
Dependency tracking
This is perhaps the most complex part, but it's not that bad.
One of the practical problems with the minimal Makefile is that it doesn't know about #includes. If sumprime.c includes semaphore.h and semaphore.h is changed, we would really like sumprime.c to be rebuilt. Fortunately, gcc has a mechanism to facilitate this that we invoke with
CPPFLAGS = -MD
When given this option, the preprocessor generates a .d file corresponding to the input .c it was given (i.e., if sumprime.c is compiled, sumprime.d is generated) that contains a make-compatible list of dependencies of the source file. For example, I expect a sumprime.d that looks something like
sumprime.c: semaphore.h sharedmemory.h
Then, with
-include $(DEPFILES)
make is instructed to include these files into its code if they exist. This means that make always knows the dependencies of source files as they were during the last build (!). That it lags one behind is not a problem because a change in the dependencies requires a change in one of the files that a target depended on last time, and that no dependencies are pulled in the first time is not a problem because the first time everything has to be built anyway.
And so we get dependency tracking with a minimum of fuss.
Packing with GNU tar
The
pack: dist
dist: $(HANDIN)
$(HANDIN): $(DISTFILES)
#echo [DIST] Preparing for distaging...
#rm -f $#
#tar cjf $# --transform 's,^,$(DISTFOLDER)/,' $+
#echo [DIST] Done!
rule requires GNU tar, but if it is available, its --transform option makes for a much nicer dist rule, as you can see. I took the liberty of changing it to that. Of course, if you prefer, you can still use your old way.
Side note: It is more usual to call what you called the pack rule dist. There is no technical reason for this, it's just a convention; people expect make dist. With this code, both names work.

makefile with multiple dependencies for a single file

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.

Requesting makefile writing tips

build: source1.c source2.c header.h lib.so
gcc source1.c source2.c -shared lib.so -o exec.bin
exec.bin: source1.o source.o
source1.o: source1.c
gcc source1.c -c -o source1.o
source2.o: source2.c
gcc source2.c -c -o source2.o
clean:
rm exec.bin source1.o source2.o
I have some instructions to make this Makefile which depends on those 4 source files to compile a program(the program context is irrelevant).
It also has to create the object files and compile only if modifications were made.
The code above is what I managed to write. I'm new at this and I can't seem to find out the problem is.
Generally, your prerequisites are messed up. You want to declare the prerequisites for the targets that need them. You also want each recipe to build exactly the target that you wrote in the makefile.
For example, you have a rule with a target build, but it creates an output file named exec.bin. That's not right: if the recipe creates a file named exec.bin then the target should be named exec.bin. If you want to have a pretend rule like build then you should declare it to be phony.
Also, you have header.h as a prerequisite of build. Even leaving aside the target name, do you re-link the objects when a header file changes? Not directly. You recompile source files when a header file changes. So the header file should be a prerequisite of the object file, not the executable.
Lastly, your life is much simpler if you leverage the built-in rules. You can rewrite your makefile like this:
CC = gcc
SRC = source1.c source2.c
LIB = lib.so
OBJ = $(SRC:%.c=%.o)
.PHONY: build
build: exec.bin
exec.bin: $(OBJ)
$(CC) $(OBJ) $(LIB) -o $#
$(OBJ): header.h
clean:
rm -f exec.bin $(OBJ)
We aren't defining rules on how to build object files from source files, because make already has built-in rules that will do that for us.
ETA:
If you can't use the built-in rules, then create your own pattern rule. For example:
XOBJ = $(SRC:%.c=%.xo)
%.xo : %.c
<whatever command>
$(XOBJ): header.h
Here's a tip for writing new Makefiles: don't do it. There are better tools available. For example, CMake is a very usable tool which generates Makefiles from a more legible language (unfortunately not a standard language like Python, but otherwise it's pretty nice).
CMake will automatically generate "clean" and "help" and other targets, plus more features you don't yet know you need (like optimized builds).
Here's something to get you started (name this file CMakeLists.txt):
add_library(foo SHARED source1.c source2.c)
add_executable(exec source3.c)
target_link_libraries(exec foo)

Resources