Makefile - move object files - makefile

After a bit of searching, I've managed to throw together the following Makefile:
CC = gcc
CFLAGS = -c -Wall
LDFLAGS =
SOURCEFILES = main.c
SOURCES = src/$(SOURCEFILES)
OBJECTS = $(SOURCES:.c=.o)
EXECUTABLE = netsim
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.c.o:
$(CC) $(CFLAGS) $< -o $#
clean:
rm -rf netsim $(OBJECTS)
I would like to be able to move my object files into another directory, but have been struggling with getting that to work. What am I missing?

The trick is to not move your objects.
You should build it and use it from where they are built.
For example you have the following directory structure:
$ tree .
├── Makefile
├── include
│   └── common_head.h
├── obj
└── src
├── foo.c
└── main.c
Manual execution:
$ gcc -o ./obj/foo.o -c ./src/foo.c -I ./include # Build Object #
$ gcc -o ./obj/main.o -c ./src/main.c -I ./include
$ gcc -o exe ./obj/foo.o ./obj/main.o # Build Executable #
Makefile to simulate the above
C_FLAGS := -g -Wall -Wextra
CC := gcc
RM := rm
LINKFLAGS := -lanylibrary
.PHONY: $(TARGET)
.PHONY: clean
VPATH:= ./src/ ./obj/ ./include/
# Path for .c , .h and .o Files
SRC_PATH := ./src/
OBJ_PATH := ./obj/
INC_PATH := -I ./include
# Executable Name
TARGET := exe
# Files to compile
OBJ1 := foo.o \
main.o
OBJ := $(patsubst %,$(OBJ_PATH)%,$(OBJ1))
# Build .o first
$(OBJ_PATH)%.o: $(SRC_PATH)%.c
#echo [CC] $<
#$(CC) $(C_FLAGS) -o $# -c $< $(INC_PATH)
# Build final Binary
$(TARGET): $(OBJ)
#echo [INFO] Creating Binary Executable [$(TARGET)]
#$(CC) -o $# $^ $(LINKFLAGS)
# Clean all the object files and the binary
clean:
#echo "[Cleaning]"
#$(RM) -rfv $(OBJ_PATH)*
#$(RM) -rfv $(TARGET)
So when you do a Make
$ make -B
[CC] src/foo.c
[CC] src/main.c
[INFO] Creating Binary Executable [exe]
To see a dry-run use make -n
$ make clean ; make -n
g++ -g -Wall -Wextra -o obj/foo.o -c src/foo.c -I ./include
g++ -g -Wall -Wextra -o obj/main.o -c src/main.c -I ./include
g++ -o exe obj/foo.o obj/main.o -lanylibrary
So after building your directory structure should look like this.
$ tree .
├── Makefile
├── exe
├── include
│   └── common_head.h
├── obj
│   ├── foo.o
│   └── main.o
└── src
├── foo.c
└── main.c
So from my previous answer.
You don't have to use any PHONY move and also no objects are recreated unnecessarily.

Something like this?
SOURCES = src/main.c
OBJECTS = obj/main.o
...
obj/%.o: src/%.c
$(CC) $(CFLAGS) $< -o $#
Once that's working, you can add further tricks, like this:
OBJECTS = $(patsubst src/%.c, obj/%.o, $(SOURCES)

Related

Write generic Makefile rule for subdirectories

I have a project with a directory tree that looks like this:
.
├── modules
│   ├── mod1
│   │   └── mod1.f90
│   ├── mod2
│   │   └── mod2.f90
│   └── mod.f90
└── src
└── main.f90
├── bin
└── Makefile
main.f90 uses all the modules found in modules and in the 'submodules' that are mod1/ and mod2/.
A simple Makefile I can write to compile the project is something like:
F90 = gfortran
FLAGS = -g -I$(BINDIR)
MODFLAGS = -J$(BINDIR)
BINDIR = bin
SRCDIR = src
MODDIR = modules
SMODDIR = $(dir $(wildcard $(MODDIR)/*/.))
MODFILES = $(wildcard $(MODDIR)/*f90)
MODOBJ = $(join $(addsuffix $(MODFROMBIN)/, $(dir $(MODFILES))), \
$(notdir $(MODFILES:.f90=.o)))
SMODFILES = $(foreach smoddir, $(SMODDIR), $(wildcard $(smoddir)*f90))
SMODOBJ = $(join $(addsuffix $(SMODFROMBIN)/, $(dir $(SMODFILES))), \
$(notdir $(SMODFILES:.f90=.o)))
SRCFILES = $(wildcard $(SRCDIR)/*f90)
SRCOBJ = $(join $(addsuffix $(SRCFROMBIN)/, $(dir $(SRCFILES))), \
$(notdir $(SRCFILES:.f90=.o)))
ALLOBJ = $(MODOBJ) $(SMODOBJ) $(SRCOBJ)
BINOBJ = $(addprefix $(BINDIR)/, $(sort $(notdir $(ALLOBJ))))
all: main
$(MODDIR)/../bin/%.o: $(MODDIR)/%.f90
$(F90) $(FLAGS) -c $^ -o $# $(MODFLAGS)
modules/mod1/../../bin/%.o: modules/mod1/%.f90
$(F90) $(FLAGS) -c $^ -o $# $(MODFLAGS)
modules/mod2/../../bin/%.o: modules/mod2/%.f90
$(F90) $(FLAGS) -c $^ -o $# $(MODFLAGS)
$(SRCDIR)/../bin/%.o: $(SRCDIR)/%.f90
$(F90) $(FLAGS) -c $^ -o $#
main: $(ALLOBJ)
$(F90) $(FLAGS) -o ./bin/main $(BINOBJ)
clean:
#rm bin/*.o bin/*.mod
But now I want to write a generic rule to be able to compile all modules located in directories that are inside modules directory (the code I am working on have more than two submodules and I am not willing to write as many rules as I have subdirectories).
My first try was to write something like this:
$(SMODDIR)/../../%.o: $(SMODDIR)/%.f90
$(F90) $(FLAGS) -c $^ -o $# $(MODFLAGS)
but it fails; from what I understand, it will put all the subdirectories paths and I would actually end up with a rule that would looks like this:
modules/mod1/../../bin/ modules/mod2/../../bin/%.o: modules/mod1/ modules/mod2/%.f90
that indeed looks funny.
As shown in the original Makefile, it is possible to retrieve specificaly with
SMODDIR = $(dir $(wildcard $(MODDIR)/*/.))
SMODFILES = $(foreach smoddir, $(SMODDIR), $(wildcard $(smoddir)*f90))
so I guess it may be possible to use something similar to have more generic rules. I couldn't see however how to use such a syntax to write a rule that makes sense.
Any help would be appreciated!
You have two choices to avoid writing lots of rules.
One is, you can use VPATH and put all your source directories in it, something like this:
VPATH := $(MODDIR) $(SMODDIR) $(SRCDIR)
$(BINDIR)/%.o: %.f90
$(F90) $(FLAGS) -c $< -o $# $(MODFLAGS)
Or you can put all your object files into equivalent subdirectories of $(BINDIR), something like this:
MODOBJ = $(MODFILES:%.f90=$(BINDIR)/%.o)
SMODOBJ = $(SMODFILES:%.f90=$(BINDIR)/%.o)
SRCOBJ = $(SRCFILES:%.f90=$(BINDIR)/%.o)
$(BINDIR)/%.o: %.f90
#mkdir -p $(#D)
$(F90) $(FLAGS) -c $< -o $# $(MODFLAGS)

C++ Makefile path include and src directory makefile

I'm trying to create a Makefile for my C++ project, which has the following structure:
root
├── include/
| └──external
| └── stb_image.h
│ └── all .h files here
├── src/
| └── main.cpp
│ └── all .cpp files here
└── Makefile
To compile this project, I'm trying to use the Makefile proposed in this answer, which is for gcc, but I have added CC:=g++ so it should work (I think):
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
EXE := $(BIN_DIR)/color
SRC := $(wildcard $(SRC_DIR)/*.cpp)
OBJ := $(SRC:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
CPPFLAGS := -Iinclude -MMD -MP
CFLAGS := -g -std=c++2a -Wall
LDFLAGS := -Llib
LDLIBS := -lpthread
CC := g++
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
But when running make I obtain a very long error which I do not understand. I do not know if this error comes from having main.cpp without a main.h.
I need this makefile because I want to separate the declarations and the implementations of my project. Before doing that, I had everything done in headers files and I could compile my project with the following command:
g++ -g -std=c++2a -Wall -Isrc/include -o bin/color.exe src/main.cc -lpthread
Any idea what am I doing wrong? I still do not know a lot about Makefiles, so maybe I'm doing something weird.

Circular dependency dropped in makefile

I am having problems with my makefile
It looks like this
name = project-name
testfiles = $(wildcard tst/*.cxx)
sourcefiles = $(wildcard src/*.cpp)
headerfiles = $(wildcard inc/*.hpp)
tests = $(testfiles:%=%.o)
sources = $(sourcefiles:%=%.o)
headers = $(headerfiles:%=%.gch)
location = /usr/local/include
flags = -Iinc -std=c++17 -pedantic -Wall
all: $(name)
%/:
mkdir -p $#
clean:
rm -f $(tests) $(sources) $(headers) $(name) test
install: $(name)
install $^ $(location)/$<
run-%: %
./$<
test: $(tests)
g++ -o $# $^
$(name): $(sources)
g++ -o $# $^
pch: $(headers)
%.gch: %
g++ -o $# $< $(flags)
tst/catch.cxx.o: tst/catch.cxx inc/catchmain.hpp.gch
g++ -o $# -c $< $(flags)
tst/receive.cxx.o: tst/receive.cxx inc/catchtest.hpp.gch inc/server.hpp.gch
g++ -o $# -c $< $(flags)
src/server.cpp.o: src/server.cpp inc/server.hpp.gch inc/iostream.hpp.gch
g++ -o $# -c $< $(flags)
My folder structure is like this (image attached)
.
├── inc
│ ├── catchmain.hpp
│ ├── catchtest.hpp
│ ├── iostream.hpp
│ └── server.hpp
├── makefile
├── src
│ └── server.cpp
└── tst
├── catch.cxx
└── receive.cxx
And when I run
make test
It shows that it dropped a circular dependency.
I don't see what might cause that.
# The output of `make test`
make: Circular tst/catch.cxx <- tst/catch.cxx.o dependency dropped.
g++ -o inc/catchmain.hpp.gch inc/catchmain.hpp -Iinc -std=c++17 -pedantic -Wall
g++ -o tst/catch.cxx.o -c tst/catch.cxx -Iinc -std=c++17 -pedantic -Wall
make: Circular tst/receive.cxx <- tst/receive.cxx.o dependency dropped.
g++ -o inc/catchtest.hpp.gch inc/catchtest.hpp -Iinc -std=c++17 -pedantic -Wall
g++ -o inc/server.hpp.gch inc/server.hpp -Iinc -std=c++17 -pedantic -Wall
g++ -o tst/receive.cxx.o -c tst/receive.cxx -Iinc -std=c++17 -pedantic -Wall
g++ -o test tst/catch.cxx.o tst/receive.cxx.o
You had Circular dependency because
%: %.o
is a gnu make implicit rule
I just changed the extension from cxx to cpp and everything works without any errors. Weird

Getting Make to automatically detect changes in protocol buffers

I want Make to automatically compile protos when I update them, here is what I've got so far:
TARGET=main
BIN_DIR=bin
SRC_DIR=src
OBJ_DIR=obj
PROTO_DIR=protos/
PROTO_COMPILE_DIR=src/$(PROTO_DIR)
CC = g++
CFLAGS = -Wall -std=c++17 -ggdb -pipe -I.
LINKER = g++
LFLAGS = $(CFLAGS) -lprotobuf
SOURCES = $(wildcard src/*.cc) \
$(wildcard src/protos/*.cc) \
$(wildcard src/db_handler/*.cc)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.cc=$(OBJ_DIR)/%.o)
$(BIN_DIR)/$(TARGET): proto $(OBJECTS)
#mkdir -p $(BIN_DIR)/
$(LINKER) $(OBJECTS) $(LFLAGS) -o $#
$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.cc
#mkdir -p obj/ obj/protos obj/db_handler
$(CC) $(CFLAGS) -c $< -o $#
.PHONY: proto
proto:
#printf "Compiling protos...\n"
#cd $(PROTO_DIR) && protoc * --grpc_out=../$(PROTO_COMPILE_DIR)\
--cpp_out=../$(PROTO_COMPILE_DIR)\
--plugin=protoc-gen-grpc="/usr/local/bin/grpc_cpp_plugin"\
&& cd ../
It successfully compiles protos; but, it does so every time, even if there are no changes in files. How can I prevent this and compile protos only if protos change?
Edit: Added project structure
├── LICENSE
├── makefile
├── protos
│   ├── client.proto
│   └── person.proto
├── README.md
└── src
├── db_handler
│   ├── db_handler.cc
│   └── db_handler.h
├── main.cc
└── protos
├── client.grpc.pb.cc
├── client.grpc.pb.h
├── client.pb.cc
├── client.pb.h
├── person.grpc.pb.cc
├── person.grpc.pb.h
├── person.pb.cc
└── person.pb.h
You want to add the source files of the protocol buffers to the right (the prerequisites) of the rule that cares about them. This is how Make understands and tracks their time stamps.
By adding the files to the prerequisites, Make will understand that this is the rule which cares about those source files.
PROTO_SOURCES := $(wildcard $(PROTO_DIR)/*.proto)
PROTOS := $(patsubst $(PROTO_DIR)/%.proto,$(PROTO_COMPILE_DIR)/%.cc,$(PROTO_SOURCES))
$(PROTOS): $(PROTO_SOURCES)
#printf "Compiling protos...\n"
#cd $(PROTO_DIR) && protoc * --grpc_out=../$(PROTO_COMPILE_DIR)\
--cpp_out=../$(PROTO_COMPILE_DIR)\
--plugin=protoc-gen-grpc="/usr/local/bin/grpc_cpp_plugin"
However, this $(PROTOS) : $(PROTO_SOURCES) is not good if you use parallel builds; because, Make will try to run the command once for each output file. So, make will run N instances of the command at the same time, which means they may clobber each other.
In order to know the fully correct solution you need to provide more information (for those not familiar with protoc). Is it a requirement that you invoke protoc once with all inputs? Or is it valid to run protoc individually on each input .proto file to get its output? Then you can write a pattern rule that generates one file at a time.
Note 1: As to your other attempt, if you use .PHONY to mark the rule then Make will rebuild the rule every time weather it needs to or not.
Note 2: You don't need the cd .. at the end of the second instruction, since it is run in a sub shell.
Thanks to #FiddlingBits I managed to figure out how to do it correctly
TARGET=main
BIN_DIR=bin
SRC_DIR=src
OBJ_DIR=obj
PROTO_DIR=protos/
PROTO_COMPILE_DIR=src/$(PROTO_DIR)
rm = rm -f
CC = g++
CFLAGS = -Wall -std=c++17 -ggdb -pipe -I.
LINKER = g++
LFLAGS = $(CFLAGS) -lprotobuf
SOURCES = $(wildcard src/*.cc) \
$(wildcard src/protos/*.cc) \
$(wildcard src/db_handler/*.cc)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.cc=$(OBJ_DIR)/%.o)
PROTOS := $($(PROTO_DIR)/%.proto=$(PROTO_COMPILE_DIR)/%.cc)
$(BIN_DIR)/$(TARGET): $(PROTOS) $(OBJECTS)
echo $(PROTOS)
#mkdir -p $(BIN_DIR)/
$(LINKER) $(OBJECTS) $(LFLAGS) -o $#
$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.cc
#mkdir -p obj/ obj/protos obj/db_handler
$(CC) $(CFLAGS) -c $< -o $#
$(PROTOS):
#printf "Compiling protos...\n"
#cd $(PROTO_DIR) && protoc * --grpc_out=../$(PROTO_COMPILE_DIR)\
--cpp_out=../$(PROTO_COMPILE_DIR)\
--plugin=protoc-gen-grpc="/usr/local/bin/grpc_cpp_plugin"\
&& cd ../
.PHONY: clean
clean:
#$(rm) -r $(OBJ_DIR)/*
#$(rm) -r $(BIN_DIR)/*
#printf "Cleanup complete!\n"

Generic Makefile build directory error

I have the following directory structure for a dummy C project.
.
├── inc
│   ├── getmsg.c
│   └── getmsg.h
├── makefile
└── src
└── main.c
My current generic Makefile is below,
TARGET = main
# finds all .c files, inc/getmsg.c src/main.c
SOURCES := $(shell find * -name *.c)
# converts all .c files to .o files, inc/getmsg.o src/main.o
OBJECTS := $(SOURCES:.c=.o)
# directories that contain .h files for gcc -I flag, inc/
HEADERS := $(dir $(shell find * -name *.h))
CC = gcc
CFLAGS = -Wall -std=c99 -iquote "$(HEADERS)"
all: $(TARGET)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
$(TARGET): $(OBJECTS)
$(CC) -o $# $^
clean:
rm -rf $(shell find * -name *.o) $(TARGET)
This all compiles fine however it just dumps the .o files into the same directory as its corresponding .c file.
What I would like to do is have all object files put into a build directory. To do this I change the OBJECTS to OBJECTS := $(patsubst %,build/%,$(notdir $(SOURCES:.c=.o))) which lists the files build/getmsg.o build/main.o. Then I set the %.o target to build/%.o: %.c.
This however returns No rule to make target 'build/getmsg.o'. So the make file is unable to build the .o files. What am I missing here?
Try changing
%.o: %.c
to
build/%.o: %.c

Resources