Makefile to generate a binary file for each source file - makefile

I have the following structure in my project.
/
src/
bin/
Makefile
In src directory there will be multiple src files (each has a main function). I need to write makefile such that when I run
make program1
It should search for program1.c in src folder and compile the executable as program1* in bin folder.
I have came across this question How can Makefile use separate directories for source code and binaries?
But, it seems that I need to manually enter all program names into PROG variable.
I just need to supply binary name with make and it should do the compilation for that respective src file?

Okay, after a bit of experimentation with my Makefile. I finally got the solution for my problem.
Current Build System
CC = gcc
CFLAGS = -g -Wall
SRC = ./src/
BIN = ./bin/
%: $(SRC)%.c
$(CC) $(CFLAGS) $< -o $(BIN)$#
.PHONY: clean
clean:
rm $(BIN)*

Related

Calling subdir.mk from Makefile with multiple code directories

Below is the folder structure for my code.
This is a very small example to understand the concept of multiple makefiles based on which I have to create makefile for bigger code structure.
work
├── code
| |
| └── main.h and test.h files here
│ └── main.c and test.c files here
| └── subdir.mk
|
├── _Build/
│ └── Makefile here
I am keeping both Makefile and subdir.mk files to be very basic and simple to grasp the concept.
Below is the code for subdir.mk
#subdir.mk
#============================================
test.o : test.c test.h
#echo Building test.c ...
gcc -Werror -Wall -c test.c -o test.o
main.o : main.c main.h test.h
#echo Building main.c ...
gcc -Werror -Wall -c main.c -o main.o
#============================================
Below is the code for main file ... Makefile
#Makefile
#============================================
include ../code/subdir.mk
main : ../code/main.o ..code/test.o
#echo Building ...
make subdir.mk # <--- What is the correct way to perform this code
#echo Linking files ...
gcc -Llib ../code/main.o ../code/test.o -lm -o main
clean:
rm -rv ../code/*.o
#============================================
The error I am getting is
make: *** No rule to make target 'test.c', needed by 'test.o'. Stop.
In subdir.mk I am trying to generate object files.
In Makefile I am trying to link the object files generated in subdir.mk
The way I am trying to execute is correct way or some different steps are followed when we have multiple subdir.mk and main Makefile.
Share your valuable comments please.
You cannot both include the subdir.mk file and also invoke it recursively.
You need to decide whether you want to use non-recursive make (which means you'd use include) or recursive make (which means you'd run a sub-make command).
If you want to use non-recursive make then your subdir.mk makefile needs to be prepared to be run when the current working directory is different than the directory that the subdir.mk file appears in.
If you want to use recursive make then you need a separate rule to build the objects, and you should not include subdirs.mk. Something like this:
main : ../code/main.o ..code/test.o
#echo Linking files ...
gcc -Llib ../code/main.o ../code/test.o -lm -o main
../code/main.o ..code/test.o : subdir ;
subdir:
#echo Building ...
cd ../code && $(MAKE) -f subdir.mk
.PHONY: subdir
Be sure to include the semicolon after the subdir in the .o rule.
When invoking sub-makes you should always use the $(MAKE) variable, never use the literal string make.
You will probably be better off having your subdir.mk build a single library out of the objects rather than having to repeat all the object files in multiple places. Then replace the list of object files in this makefile with the library.
Contrary to Andreas's assertion, this will not always rebuild main. It will only be rebuilt when one of the object files was changed.
subdir.mk has to use paths relative to the main makefile. E.g.
../code/test.o : ../code/test.c ../code/test.h
...
What you need is a recipe for creating the object files. In Makefile you'll need to remove include ../code/subdir.mk and add something like this:
.PHONY: ../code/main.o ..code/test.o
../code/main.o ..code/test.o:
$(MAKE) -C ../code/ -f subdir.mk $(#F)
When you build target main, make sees you need the object files. Then make find the above recipe for creating the object files and so runs it.
Having them .PHONY is because the top Makefile can´t tell whether or not they´re up to date. Without it the object files would never be rebuilt. This has the unfortunate consequence that main will always be rebuilt, even if subdir.mk determines the object files were indeed up to date. The solution is either to have it all in a single make (can still split into files and include), or change to a build tool that can get it right.

Makefile pattern to compile all source files to executables

I want my makefile to identify and build every source file in the directory.
Both .f files and their executables exists in the current directory. All source files are short, independent pieces (no linking to each other). I want executables to be named the same as the source files sans .f (foo.f -> foo)
The following does not work:
FC=gfortran
% :: %.f
${FC} -Wall $< -o $#
When I run Make I get
make: *** No targets. Stop.
How can I get make to do what I want?
The following makefile does what I want:
FC=gfortran
FFLAGS=-Wall
SRC = $(wildcard *.f)
EXE = $(SRC:.f=)
all : $(EXE)

Makefile: compiling several unit test *.out files into a single test executable (C++)

Please forgive me if this is a repeat question. I am fairly new to writing Makefiles, and so I was not really sure how to find what I am looking for.
I am getting acquainted with Boost.Test and am writing unit tests on a file-per-file basis.
This is my directory structure:
- cpp
- sim
- Makefile
- bin
- src
- ExampleClass.cpp
- tests
- Makefile
- bin
- src
-ExampleClass_T.cpp
Essentially, I would like to write individual *.cpp test case files using Boost, as displayed above.
Here is the content of my tests/Makefile:
CC = g++
CPPFLAGS = -g -v -Wall -I$(ODIR_TEST) -I$(SDIR_TEST) \
-I$(SDIR) -I$(ODIR) -I$(BOOST_ROOT)
ODIR_TEST = ./bin
SDIR_TEST = ./src
ODIR = ../sim/bin
SDIR = ../sim/src
%.out : $(SDIR_TEST)/%.cpp
$(CC) $(CPPFLAGS) -o $< $#
executing make generates a No targets. Stop. error message. Any ideas as to why make thinks there is no target? Wouldn't %.out act as the target here, or can a wildcard not act in that manner?
I recognize that in the Makefile above, I am attempting to generate a *.out file for each *.cpp file; in addition, I would like to generate a final executable that is a culmination of all generated *.out files. Is this possible, or am I approaching this incorrectly?
Any other advice or Makefile best practices, especially with regards to test automation, would be highly appreciated.
I have seemed to have found a workaround, though it can likely be optimized.
PROG = main
CC = g++
CPPFLAGS = -g -Wall -I$(ODIR_TEST) -I$(SDIR_TEST) \
-I$(SDIR) -I$(ODIR) -I$(BOOST_ROOT)
ODIR_TEST = ./bin
SDIR_TEST = ./src
OUTDIR = ./execs
ODIR = ../sim/bin
SDIR = ../sim/src
TEST_EXEC_NAMES = $(notdir $(basename $(wildcard $(SDIR_TEST)/*.cpp)))
# default rule (main.cpp)
$(OUTDIR)/$(PROG) : $(SDIR_TEST)/main.cpp $(TEST_EXEC_NAMES)
$(CC) $(CPPFLAGS) -o $# $<
% : $(SDIR_TEST)/%.cpp
$(CC) $(CPPFLAGS) -o $(OUTDIR)/$# $<
I specify a default target in my first rule. I include $(TEST_EXEC_NAMES) as a prereq to make sure that all of my individual test executables are built using the pattern rule.
Specifying my executable filenames from their .cpp counterparts is done with a series of function calls (wildcard, basename, and notdir).
Again, this is surely not the fastest way I could accomplish my task, but it has gotten me onto compilation errors.

How to compile files that reside in different directory in Makefile?

I have seen this questions asked before but was not able to decipher those answers.
Lets say I reside in working directory, lets call it proj and this proj directory contains src folder which contains all the *.cpp files. I want to compile those file staying on the proj directory because in future I will be creating bin directory and placing the *.o and binary in bin.
So my proj directory currently contains : Makefile and src
What I have done so far is :
SOURCE = src
# This gives the path to the proj directory
CURRENT_DIR = $(shell pwd)
# This gives list of all the *.cpp files
SRC = $(shell cd $(SOURCE) && echo *.cpp)
# Here all the name of the files stored in SRC are converted from *.cpp to *.o
OBJS = $(SRC:.cpp=.o)
.PHONY: all
all: $(TARGE)
# use the content of SRC to compile
$(TARGET): $(OBJS)
$(info $(OBJS))
$(OBJS): $(SRC)
$(CC) $(FLAGS) -c $?
When I try to run the make command it says
make: *** No rule to make target 'xxx.cpp', needed by 'xxx.o'. Stop
Now I know what it is trying to say. It gives error because although it knows the name of the file, since the file is not in the current directory makefile does not know about src folder and hence have no clue about the *.cpp files.
So my question is: Is there any macros or trick to use in makefile to make sure makefile see the xxx.cpp in src folder while staying in the current directory( I don't want to specify the folder by hand here)?

Makefile with Fortran - src and bin directories

I'm having some trouble understanding how to design my makefile to build my project the way I want to. Specifically, I can't figure out how to keep all source files in a src directory, while putting all binaries in a bin directory except the linked executable, which goes in the project root.
This is my makefile:
# Compiler options
FC := mpif90
FFLAGS := -O3 -g -Wall -Warray-bounds -ffixed-line-length-none -fbounds-check
VPATH := src
BINDIR := bin
# Define file extensions
.SUFFIXES:
.SUFFIXES: .f .o .mod
# All modules
OBJS := $(BINDIR)/ratecoeffs.o $(BINDIR)/interpolation.o $(BINDIR)/io.o $(BINDIR)/eedf.o $(BINDIR)/single_particle.o $(BINDIR)/physics.o $(BINDIR)/random.o $(BINDIR)/mpi.o $(BINDIR)/precision.o $(BINDIR)/populations.o
# Build rules
all: runner | $(BINDIR)
$(BINDIR):
mkdir -p $(BINDIR)
$(BINDIR)/%.o: $(VPATH)/%.f | $(BINDIR)
$(FC) $(FFLAGS) -c $^ -o $#
runner: $(OBJS)
clean:
#rm -rf $(BINDIR)
Running make builds everything allright - it finds all source files in src and puts all .o files in bin - but the module files (.mod) that are generated by the compiler are put in the project root instead of in the bin directory. I realize I could just specify a rule to place them there, but that messes with the build order, and will sometimes break the build.
What is the "correct" way to get this behavior?
And yes, I've looked at autotools and automake, but I've never used them before and they seem to be overkill for this project. As I couldn't find any good tutorials on how they work (no, I didn't like the tutorial on gnu.org) I'd prefer if I could avoid having to learn this tool just to get this work...
Assuming your underlying Fortran compiler is gfortran, use the -J command line option.
$(FC) $(FFLAGS) -c $^ -o $# -J$(BINDIR)
With an eye to the future, you may be better off creating a MODDIR or similar variable, that you use instead of BINDIR. Object code (*.o) and mod files have different roles to play in later compilation and linking steps - in larger projects they are often kept separate.
It would be probably more in the sense of the make system to change into the obj-directory and do the compilation from there. Via the VPATH option you can let make to find your source files automatically. You could easily call your makefile recursively from the right directory. Below you find a trivial example which would be straightforward to adapt to your case. Please note, that it only works with GNU make.
ifeq (1,$(RECURSED))
VPATH = $(SRCDIR)
########################################################################
# Project specific makefile
########################################################################
FC = gfortran
FCOPTS =
LN = $(FC)
LNOPTS =
OBJS = accuracy.o eqsolver.o io.o linsolve.o
linsolve: $(OBJS)
$(LN) $(LNOPTS) -o $# $^
%.o: %.f90
$(FC) $(FCOPTS) -c $<
.PHONY: clean realclean
clean:
rm -f *.mod *.o
realclean: clean
rm -f linsolve
accuracy.o:
eqsolver.o: accuracy.o
io.o: accuracy.o
linsolve.o: accuracy.o eqsolver.o io.o
else
########################################################################
# Recusive invokation
########################################################################
BUILDDIR = _build
LOCALGOALS = $(BUILDDIR) distclean
RECURSIVEGOALS = $(filter-out $(LOCALGOALS), $(MAKECMDGOALS))
.PHONY: all $(RECURSIVE_GOALS) distclean
all $(RECURSIVEGOALS): $(BUILDDIR)
+$(MAKE) -C $(BUILDDIR) -f $(CURDIR)/GNUmakefile SRCDIR=$(CURDIR) \
RECURSED=1 $(RECURSIVEGOALS)
$(BUILDDIR):
mkdir $(BUILDDIR)
distclean:
rm -rf $(BUILDDIR)
endif
The principle is simple:
In the first part you write your normal makefile, as if you would create the object files in the source directory. However, additionally you add the VPATH option to make sure the source files are found (as make will be in the directory BUILDDIR when this part of the makefile is processed).
In the second part (which is executed first, when the variable RECURSED is not set yet), you change to the BUILDIR directory and invoke your makefile from there. You pass some helper variables (e.g. the current directory) and all make goals, apart of those, which must be executed from outside BUILDDIR (e.g. distclean and the one creating BUILDDIR itself). The rules for those goals you specify also in the second part.

Resources