Makefile: compiling several objects with single target - object

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.

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

How to ouput the static library into other directory than current?

Following is my directory structure
calculator
|
|---src
(multiply.cpp sum.cpp)
|---lib
I am building a static library calc.a using following
ar -rcs calc.a multiply.o sum.o
calc.a is builded in current directory.
I trying calc.a to be put into lib folder not in current directory (i.e. src)
I searched in internet and man page but couldn't find anything.
Any idea?
Since you are using the command line, the easiest way to write the library into the lib directory is to do it explicitly:
ar -rcs lib/libcalc.a multiply.o sum.o
Using a Makefile you can do more sophisticated things, but even then, it boils down to the same thing, e.g. adding the path to the front of the library name.
Since you asked for additional info on your comment, I add here a simple Makefile, which may be helpful to get you started:
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=src/main.cpp src/sum.cpp src/multiply.cpp
OBJECTS=$(SOURCES:.cpp=.o)
LIBRARY=lib/libcalc.a
EXECUTABLE=main
all: $(SOURCES) $(LIBRARY) $(EXECUTABLE)
$(LIBRARY): $(OBJECTS)
<tab>mkdir -p lib
<tab>ar -rcs $# $<
$(EXECUTABLE): $(OBJECTS)
<tab>$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
<tab>$(CC) $(CFLAGS) $< -o $#
clean:
<tab>rm -rf main lib/ src/*.o
Important: All <tab>s must be replaced with real tabs, as required by the Makefile syntax!
Makefiles are very very flexible, so they can be very simple and specific to your problem, or as general and/or complex to build many libraries and binaries, based on millions and millions of source code. I suggest you to search for Makefile documentation for more information.
As a final note, I also suggest you to rename your library as 'libcalc.a', since the 'lib' prefix is standard in Unix. Other similar standards apply for other environments.

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)

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.

Resources