Makefile : Multiple targets in dedicated folders - makefile

I'm struggling with the make language and haven't been yet able to reach my goal.
I have the following folder structure.
/sources/src => *.c
/sources/inc => *.h
/build => makefile
/build/target1/addsrc => *.c & *.h
/build/target2/addsrc => *.c & *.h
I want to compile both target using the command make or any target separately using one of the commands make target1 or make target2. Each target uses the same sources located in the sources folder, adds additional sources located its own addsrc folder and applies different compilation flags. The makefile should create the following directories and files:
/build/target1/objects => *.o
/build/target1 => mylib.so
/build/target2/objects => *.o
/build/target2 => mylib.so
I tried with the following makefile:
targets=target1 target2
TARGET=$(dir $#)
DIR_OBJ = $(TARGET)objects
DIR_BIN = $(TARGET)
BIN = mylib.so
DIR_SRC = ../sources/src
DIR_ADDSRC_LOC = ./$(TARGET)addsrc
INCLUDES = -I./$(TARGET)addsrc -I../sources/inc
SRC := $(notdir $(wildcard $(DIR_SRC)/*.c))
ifneq ($(DIR_ADDSRC_LOC),)
SRCLOC := $(notdir $(wildcard $(DIR_ADDSRC_LOC)/*.c))
endif
SRCS = $(SRC) $(SRCLOC)
OBJ = $(SRCS:%.c=$(DIR_OBJ)/%.o)
CFLAGS = -fPIC
LFLAGS = -shared -lm -Wl,--start-group -Wl,--no-undefined
all : $(targets)
$(targets): % : %/init %/$(BIN)
$(targets:%=%/init):
#if [ ! -d $(DIR_OBJ) ]; then \mkdir -p $(DIR_OBJ); fi;
#if [ ! -d $(DIR_BIN) ]; then \mkdir -p $(DIR_BIN); fi;
$(targets:%=%/$(BIN)): $(OBJ)
gcc $(OBJ) $(LFLAGS) -o $#
$(DIR_OBJ)/%.o: %.c
gcc $(INCLUDES) $(CFLAGS) -c $< -o $#
This works for the directory initialisation for each target. However, the rest is absolutely not working. I spent hours to have it working but without any success. Any help would be appreciated. Thanks !
Note: I haven't worked yet on the target dependency regarding the compilation flags.

As you have the gnu-make tag let's use GNU make:
targets := target1 target2
BIN := mylib.so
DIR_SRC := ../sources/src
DIR_INC := ../sources/inc
SRC := $(wildcard $(DIR_SRC)/*.c)
OBJ := $(patsubst $(DIR_SRC)/%.c,%.o,$(SRC))
CFLAGS := -fPIC -I$(DIR_INC)
LDFLAGS := -shared -Wl,--start-group -Wl,--no-undefined
LDLIBS := -lm
.PHONY: all $(targets) clean
all: $(addsuffix /$(BIN),$(targets))
clean:
rm -rf $(addsuffix /objects,$(targets)) $(addsuffix /$(BIN),$(targets))
$(targets): %: %/$(BIN)
%.o:
$(CC) $(CFLAGS) -c $< -o $#
$(addsuffix /objects,$(targets)):
\mkdir -p $#
# $1: target
define target_rule
$1-LSRC := $$(wildcard $1/addsrc/*.c)
$1-LOBJ := $$(patsubst $1/addsrc/%.c,$1/objects/%.o,$$($1-LSRC))
$1-GOBJ := $$(addprefix $1/objects/,$$(OBJ))
$1-OBJ := $$($1-LOBJ) $$($1-GOBJ)
$$($(1)-LOBJ): $1/objects/%.o: $1/addsrc/%.c
$$($(1)-GOBJ): $1/objects/%.o: $$(DIR_SRC)/%.c
$$($1-OBJ): CFLAGS += -I./$1/addsrc
$$($1-OBJ): | $1/objects
$1/$$(BIN): $$($1-OBJ)
$$(CC) $$(CFLAGS) $$(LDFLAGS) -o $$# $$^ $$(LDLIBS)
endef
$(foreach t,$(targets),$(eval $(call target_rule,$t)))
This makes use of GNU make specific features, especially the foreach-eval-call. It also uses order-only prerequisites for the directories, and the the standard make variables (LDFLAGS, CC, LDLIBS...) instead of the ones you were using.
Dependencies in the header files are not expressed because you do not explain what they should be. Adapt.
Demo:
$ tree
.
├── build
│   ├── makefile
│   ├── target1
│   │   └── addsrc
│   │   └── c.c
│   └── target2
└── sources
├── inc
│   ├── a.h
│   └── b.h
└── src
├── a.c
└── b.c
7 directories, 6 files
$ cd build
$ make
\mkdir -p target1/objects
\mkdir -p target2/objects
cc -fPIC -I../sources/inc -I./target1/addsrc -c target1/addsrc/c.c -o target1/objects/c.o
cc -fPIC -I../sources/inc -I./target1/addsrc -c ../sources/src/a.c -o target1/objects/a.o
cc -fPIC -I../sources/inc -I./target1/addsrc -c ../sources/src/b.c -o target1/objects/b.o
cc -fPIC -I../sources/inc -I./target2/addsrc -c ../sources/src/a.c -o target2/objects/a.o
cc -fPIC -I../sources/inc -I./target2/addsrc -c ../sources/src/b.c -o target2/objects/b.o
cc -fPIC -I../sources/inc -shared -o target1/mylib.so target1/objects/c.o target1/objects/a.o target1/objects/b.o -lm
cc -fPIC -I../sources/inc -shared -o target2/mylib.so target2/objects/a.o target2/objects/b.o -lm
$ make clean
rm -rf target1/objects target2/objects target1/mylib.so target2/mylib.so
$ make target1
\mkdir -p target1/objects
cc -fPIC -I../sources/inc -I./target1/addsrc -c target1/addsrc/c.c -o target1/objects/c.o
cc -fPIC -I../sources/inc -I./target1/addsrc -c ../sources/src/a.c -o target1/objects/a.o
cc -fPIC -I../sources/inc -I./target1/addsrc -c ../sources/src/b.c -o target1/objects/b.o
cc -fPIC -I../sources/inc -shared -o target1/mylib.so target1/objects/c.o target1/objects/a.o target1/objects/b.o -lm
$ make target2
\mkdir -p target2/objects
cc -fPIC -I../sources/inc -I./target2/addsrc -c ../sources/src/a.c -o target2/objects/a.o
cc -fPIC -I../sources/inc -I./target2/addsrc -c ../sources/src/b.c -o target2/objects/b.o
cc -fPIC -I../sources/inc -shared -o target2/mylib.so target2/objects/a.o target2/objects/b.o -lm

Related

makefile error: “make: *** No rule to make target …”

I'm trying to use GCC (linux) with a makefile to compile my project.
I get the following error
"No rule to make target 'output/src/main.o', needed by 'test'. Stop."
This is the makefile:
COMPILE_PREX ?=
CC = $(COMPILE_PREX)gcc
SOURCE = $(wildcard src/*.c)
OBJS = $(addprefix ./output/, $(patsubst %.c, %.o, $(SOURCE)))
INCLUDES = -I ./src
CFLAGS += -O2 -Wall -g
LDFLAGS += -lpthread
TARGET = test
$(TARGET): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $(TARGET)
%.o: %.c
#mkdir -p ./output
$(CC) $(CFLAGS) $(INCLUDES) -o $(addprefix ./output/, $#) -c $<
clean:
rm -rf ./output
This should work. Note the use of mkdir $(#D) to create output directories as needed.
COMPILE_PREX ?=
CC = $(COMPILE_PREX)gcc
SOURCE = $(wildcard src/*.c)
OBJS = $(addprefix output/, $(patsubst %.c, %.o, $(SOURCE)))
INCLUDES = -I src
CFLAGS += -O2 -Wall -g
LDFLAGS += -lpthread
TARGET = test
$(TARGET): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $(TARGET)
output/%.o: %.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) $(INCLUDES) -o $# -c $<
clean:
rm -rf output
Running it here with make clean test:
rm -rf output
gcc -O2 -Wall -g -I src -o output/src/hello.o -c src/hello.c
gcc output/src/hello.o -lpthread -o test

makefile with 2 executables, how?

My project is organized like this :
src/plateau.c plateau.h tuile.c tuile.h main.c
tests/tests.c
obj/
bin/
I'm trying to do a makefile with 2 executables. I can't figure out why it doesn't works.
The makefile with one executable only works fine, it looks like this :
CC = gcc -Wall -Wextra -ansi
SRCDIR = src
OBJDIR = obj
BINDIR = bin
DOXYGEN = doxygen
all: honshu
honshu: $(OBJDIR)/main.o $(OBJDIR)/plateau.o $(OBJDIR)/tuile.o
$(CC) $(OBJDIR)/main.o $(OBJDIR)/plateau.o $(OBJDIR)/tuile.o -o honshu
$(OBJDIR)/plateau.o: $(SRCDIR)/plateau.c $(SRCDIR)/plateau.h
$(CC) -c $(SRCDIR)/plateau.c -o $(OBJDIR)/plateau.o
$(OBJDIR)/tuile.o: $(SRCDIR)/tuile.c $(SRCDIR)/tuile.h
$(CC) -c $(SRCDIR)/tuile.c -o $(OBJDIR)/tuile.o
$(OBJDIR)/main.o: $(SRCDIR)/main.c
$(CC) -c -I src $(SRCDIR)/main.c $# -lm
doxygen:
$(DOXYGEN) -g
$(DOXYGEN) Doxyfile
clean:
rm *.o
rm honshu
And with two executables, I tried like this :
CC = gcc -Wall -Wextra -ansi
SRCDIR = src
OBJDIR = obj
BINDIR = bin
DOXYGEN = doxygen
all: honshu tests
honshu: $(OBJDIR)/main.o $(OBJDIR)/plateau.o $(OBJDIR)/tuile.o
$(CC) $(OBJDIR)/main.o $(OBJDIR)/plateau.o $(OBJDIR)/tuile.o -o honshu
tests: $(OBJDIR)/test_honshu.o $(OBJDIR)/plateau.o $(OBJDIR)/tuile.o
$(CC) $(OBJDIR)/test_honshu.o $(OBJDIR)/plateau.o $(OBJDIR)/tuile.o -o tests
$(OBJDIR)/plateau.o: $(SRCDIR)/plateau.c $(SRCDIR)/plateau.h
$(CC) -c $(SRCDIR)/plateau.c -o $(OBJDIR)/plateau.o
$(OBJDIR)/tuile.o: $(SRCDIR)/tuile.c $(SRCDIR)/tuile.h
$(CC) -c $(SRCDIR)/tuile.c -o $(OBJDIR)/tuile.o
$(OBJDIR)/main.o: $(SRCDIR)/main.c
$(CC) -c -I src $(SRCDIR)/main.c $# -lm
$(OBJDIR)/test_honshu.o: $(SRCDIR)/test_honshu.c
$(CC) -c -I src $(SRCDIR)/test_honshu.c $# -lm
doxygen:
$(DOXYGEN) -g
$(DOXYGEN) Doxyfile
clean:
rm *.o
rm honshu
But I have the following message "no rules to make "src/test_honshu.c", necessary for "obj.test_honshu.o", do you have an idea ? Thanks !

Not able to include a library in makefile

I am kind of new in the use of make.
I have a library written in C which is in the folder folder1
Where these files are there is also a makefile which is the following:
PREFIX ?= /usr/local
CC = gcc
AR = ar
CFLAGS = -std=gnu99 -fPIC -Wall -Wno-unused-parameter -Wno-unused-function -I. -O4
APRILTAG_SRCS := $(shell ls *.c common/*.c)
APRILTAG_HEADERS := $(shell ls *.h common/*.h /usr/include/flycapture/*.h)
APRILTAG_OBJS := $(APRILTAG_SRCS:%.c=%.o)
TARGETS := libapriltag.a libapriltag.so
.PHONY: all
all: $(TARGETS)
#$(MAKE) -C example all
.PHONY: install
install: libapriltag.so
#chmod +x install.sh
#./install.sh $(PREFIX)/lib libapriltag.so
#./install.sh $(PREFIX)/include/apriltag $(APRILTAG_HEADERS)
#sed 's:^prefix=$$:prefix=$(PREFIX):' < apriltag.pc.in > apriltag.pc
#./install.sh $(PREFIX)/lib/pkgconfig apriltag.pc
#rm apriltag.pc
#ldconfig
libapriltag.a: $(APRILTAG_OBJS)
#echo " [$#]"
#$(AR) -cq $# $(APRILTAG_OBJS)
libapriltag.so: $(APRILTAG_OBJS)
#echo " [$#]"
#$(CC) -fPIC -shared -o $# $^
%.o: %.c
#echo " $#"
#$(CC) -o $# -c $< $(CFLAGS)
.PHONY: clean
clean:
#rm -rf *.o common/*.o $(TARGETS)
#$(MAKE) -C example clean
Then, in the folder example I have some example which I can just run by giving the following command in the terminal:
./opencv_demo
or
./apriltag_demo
In this folder example I have another makefile which is the following:
CC = gcc
CXX = g++
CPPFLAGS = -I..
CFLAGS = -std=gnu99 -Wall -Wno-unused-parameter -Wno-unused-function -O4
CXXFLAGS = -Wall -O4
LDFLAGS = -Lusr/include/flycapture -lpthread -lm
INC_DIR = /usr/include/flycapture
TARGETS := apriltag_demo opencv_demo
.PHONY: all
all: apriltag_demo opencv_demo
apriltag_demo: apriltag_demo.o ../libapriltag.a
#echo " [$#]"
#$(CC) -o $# $^ $(LDFLAGS)
opencv_demo: opencv_demo.o ../libapriltag.a /usr/include/flycapture/Error.h
#echo " [$#]"
#$(CXX) -o $# $^ $(LDFLAGS) `pkg-config --libs opencv`
%.o: %.c
#echo " $#"
#$(CC) -o $# -c $< $(CFLAGS) $(CPPFLAGS)
%.o: %.cc
#echo " $#"
#$(CXX) -o $# -c $< $(CXXFLAGS) $(CPPFLAGS)
.PHONY: clean
clean:
#rm -rf *.o $(TARGETS)
If I do make in the folder1 I get the following error:
opencv_demo.o: In function `main':
opencv_demo.cc:(.text.startup+0x24e): undefined reference to `FlyCapture2::Error::Error()'
opencv_demo.cc:(.text.startup+0x2a7): undefined reference to `FlyCapture2::Error::~Error()'
opencv_demo.cc:(.text.startup+0x11a0): undefined reference to `FlyCapture2::Error::~Error()'
collect2: error: ld returned 1 exit status
make[1]: *** [opencv_demo] Error 1
make[1]: Leaving directory `/home/fschiano/Repositories/apriltag2/example'
make: *** [all] Error 2
If I am not wrong this error tells me that I did not include a library.
In the file opencv_demo.cc I did:
#include "flycapture/FlyCapture2.h"
#include "flycapture/Error.h"
using namespace FlyCapture2;
Headers which are in /usr/include/flycapture a folder which contains all the headers needed for what I need in the file opencv_demo.cc.
I don't know why it is not working, someone is able to help me?
I think I should write in the makefile where to search for the libraries but I don't know how.
I tried to write the following things in the makefile separately but they are not working :
LDFLAGS = -Lusr/include/flycapture -lpthread -lm
INC_DIR = /usr/include/flycapture
DEPS = $(INC_DIR)/Error.h

I want to generate objects in subdirectory by makefile

How to specify a subdirectory for the generated .o files, e.g. objsdir, for this code in the make file
cc = gcc
CFLAGS = -o6 -Wall
LIBS = -lm
SOURCES = main.c\
extra.c
OBJECTS = $(SOURCES: .c = .o)
.c.o :; $(cc) -c $(CFLAGS) $<
all : $(OBJECT)
$(cc) -o ...
Actually this is a part of the mkefile code.
I usually use something like this:
cc=gcc
SOURCES=main.c extra.c
OBJECTS=$(patsubst %.c, objsdir/%.o, $(SOURCES))
objsdir/%.o: %.c
echo $^
all: $(OBJECTS)
echo $(OBJECTS)
I actually use this Makefile in general
CC := g++ # This is the main compiler
SRCDIR := src
BUILDDIR := build
TARGETDIR :=bin/
TARGET := pddlcrate
DATADIR := data
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -g # -Wall
#LIB := -pthread -lmongoclient -L lib -lboost_thread-mt -lboost_filesystem-
mt -lboost_system-mt
INC := -I include
$(TARGET): $(OBJECTS)
#echo " Linking..."
#echo " $(CC) $^ -o $(TARGETDIR)$(TARGET) $(LIB)"; $(CC) $^ -o
$(TARGETDIR)$(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
#echo " $(CC) $(CFLAGS) $(INC) -c -o $# $<"; $(CC) $(CFLAGS) $(INC) -c - o $# $<
clean:
#echo " Cleaning...";
#echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)
for any c++ project with this tree structure
$ tree .
├── Makefile
├── bin
>exefile
├── include
> *.h files
├── obj
> *.o files
├── src
>*.cpp

Automatic dependency processing in Makefile

I have a simple makefile.
IDIR =./include
CC=gcc
CFLAGS=-I$(IDIR)
SRCDIR = ./src
ODIR=obj
LDIR =./lib
LIBS=-lm
SRC = hellomake hellofunc
OBJ = ${SRC:%=$(ODIR)/%.o}
_DEPS = hellomake.h
DEPS = ${_DEPS:%=$(IDIR)/%}
$(ODIR)/%.o: $(SRCDIR)/%.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ hellomake
What I don't like about this Makefile is that the dependency generation.
.c.o
Is it possible to teach make file that the .c is in src directory, and .o is in obj directory to make this simple one?
.c.o:
$(CC) -c -o $# $< $(CFLAGS)
header dependency
Is it possible to teach make file that all the c files are recompiled automatically when header files that the c file contains is changed?
Preliminaries
Generating dependencies
gcc's -MM -MG can be used to create the dependencies: gcc -MM -MG src/hellofunc.c -I./include will create hellofunc.o: src/hellofunc.c include/hellomake.h. However, we need to include the .d file itself into the .d file, so we use sed to achieve that goal.
gcc -MM -MG src/hellofunc.c -I./include | sed -e 's#^\(.*\)\.o:#\1.d \1.o:#'
The results will be as follows:
hellofunc.d hellofunc.o: src/hellofunc.c include/hellomake.h
When we want to change the content to include the different directory location, we can modify the sed script.
gcc -MM -MG src/hellofunc.c -I./include | sed -e 's#^\(.*\)\.o:#obj/\1.d obj/\1.o:#'
The results will be as follows:
obj/hellofunc.d obj/hellofunc.o: src/hellofunc.c include/hellomake.h
include
-include $(DEPS) will include the files in DEPS directory, the - in front of the include teaches the make to ignore when the directories does not exits.
Pattern matching and replacement
We can substitute any pattern (%) or pattern that ends with c (%.c) as follows:
OBJDIRS := $(patsubst %, $(OBJDIR)/%, $(MODULES))
OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(SRCS))
We also can have shorthand form.
DEPS := $(OBJS:.o=.d)
filter
We can select only some of the files with filter, this is an example:
OBJ := $(patsubst %.c, %.o, $(filter %.c, $(SRC)))
Method 1
In this method, we specify the dependency (.d depends on .c), and include the created dependency file with include.
.PHONY: clean depend
CC := gcc
CXX := g++
LD := g++
CP := cp
PROG := hellomake
MODULES := src
OBJDIR := obj
default: $(PROG)
OPTFLAGS := -g -O
CFLAGS += -Wall -Wno-unused-function $(OPTFLAGS) $(patsubst %, -I%, $(MODULES))
GARBAGE := core core.* *.stackdump ./tags $(PROG)
include $(patsubst %, %/module.make, $(MODULES))
OBJ := \
$(patsubst %.c, %.o, $(filter %.c, $(SRC)))
DEP := $(OBJ:.o=.d)
# implicit rules
%.d: %.c
./depends.sh $(CC) `dirname $*.c` $(CFLAGS) $*.c > $#
-include $(DEP)
# Actual targets
depend: $(DEP)
clean:
rm -rf $(PROG) $(OBJ) $(GARBAGE) $(DEP) depends
$(PROG): $(OBJ)
$(LD) -o $# $^ $(LIBS)
Each module should contain the make file (module.make) to specify what files are included in the SRC variable.
`SRC += src/hellofunc.c \
src/hellomake.c`.
This is the script to generate the dependency file:
#!/bin/sh
#echo "## Got: $*"
CC="$1"
DIR="$2"
shift 2
case "$DIR" in
"" | ".")
$CC -MM -MG "$#" | sed -e 's#^\(.*\)\.o:#\1.d \1.o:#'
;;
*)
$CC -MM -MG "$#" | sed -e "s#^\(.*\)\.o:#$DIR/\1.d $DIR/\1.o:#"
;;
esac
This method is simple, but the object files and dependency files are created in the same src directory with these statements.
SRC += src/hellofunc.c src/hellomake.c
OBJ := $(patsubst %.c, %.o, $(filter %.c, $(SRC)))
DEP := $(OBJ:.o=.d)
Method 2
This method creates the object directory, and puts all the generated (intermediate) files into the directory.
It enlists all the modules to specify the actions both for object file and dependency file generation.
In the example, we have only one module, but with multiple modules, we need to duplicate the statements.
obj/src/%.o: src/%.c
$(CC) -c $< -o $# $(CFLAGS)
obj/src/%.d: src/%.c
gcc -MM -MG $< $(CFLAGS) | sed -e 's#^\(.*\)\.o:#obj/src/\1.d obj/src/\1.o:#' > $#
This is the makefile:
.SUFFIX = .o .c
.PHONY: clean
CC := gcc
LD := gcc
PROG := hellomake
OBJDIR = obj
MODULES := src
SRCS := src/hellofunc.c src/hellomake.c
OBJDIRS := $(patsubst %, $(OBJDIR)/%, $(MODULES))
OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(SRCS))
DEPS := $(OBJS:.o=.d)
default: $(PROG)
CFLAGS += -Wall -Wno-unused-function $(OPTFLAGS) $(patsubst %, -I%, $(MODULES))
CXXFLAGS += $(CFLAGS)
obj/src/%.o: src/%.c
$(CC) -c $< -o $# $(CFLAGS)
$(PROG): $(OBJDIRS) $(OBJS)
$(LD) $(filter %.o, $^) -o $(PROG)
-include $(DEPS)
obj/src/%.d: src/%.c
gcc -MM -MG $< $(CFLAGS) | sed -e 's#^\(.*\)\.o:#obj/src/\1.d obj/src/\1.o:#' > $#
depend: $(DEPS)
GARBAGE := core core.* *.stackdump ./tags $(PROG)
clean:
rm -rf $(PROG) obj/*
$(OBJDIRS):
mkdir -p $#
References
Create directories when generating object files in gcc
How to place object files in separate subdirectory
make deleting dependency files
http://scottmcpeak.com/autodepend/autodepend.html
IDIR = ./include
CC = gcc
CFLAGS = -I$(IDIR)
SRCDIR = src
ODIR = obj
LDIR = ./lib
LIBS = -lm
SRC = hellomake hellofunc
OBJ = ${SRC:%=$(ODIR)/%.o}
_DEPS = hellomake.h
DEPS = ${_DEPS:%=$(IDIR)/%}
%.o: ../$(SRCDIR)/%.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ) $(DEPS)
gcc -o $# $^ $(CFLAGS) $(LIBS)

Resources