Getting wrong file name while pattern matching in makefile - c++

The directory structure of my project is something like this:
|-build
|-src
|-lib
|-libfile1.hpp
|-libfile1.cpp
|-libfile2.hpp
|-libfile2.cpp
|-libfile3.hpp
|-Makefile(lib)
|-examples
|-pingpong
|-main.cpp
|-ping.cpp
|-ping.hpp
|-Makefile(ping)
My goal is to have many examples in the examples folder which all use the libfiles but are independent of each other. Hence I wanted to use separate makefiles in each of the example folders to link to objects of libfiles.
To that goal, here's makefile(lib):
SRC = .
BLD = ../../build
SOURCE = $(wildcard $(SRC)/*.cpp)
INCLUDE = $(wildcard $(SRC)/*.hpp)
OBJECT = $(patsubst %,$(BLD)/%, $(notdir $(SOURCE:.cpp=.o)))
CC = g++
#flags went here, removed for brevity
all: $(OBJECT)
$(BLD)/%.o: $(SRC)/%.cpp $(SRC)/%.hpp
mkdir -p $(dir $#)
$(CC) -c $< -o $#
.PHONY: clean
clean:
$(RM) -r $(BLD)
And here's makefile(ping), where I try to build local objects and pass the library object build pattern to makefile(lib):
TARGET = mainpingpong.out
SRC = ../../actorlib
BLD = ../../../build
LIBSOURCE = $(wildcard $(SRC)/*.cpp)
LIBINCLUDE = $(wildcard $(SRC)/*.hpp)
LIBOBJECT = $(patsubst %,$(BLD)/%, $(notdir $(LIBSOURCE:.cpp=.o)))
LOCSOURCE = $(wildcard *.cpp)
LOCINCLUDE = $(wildcard *.hpp)
LOCOBJECT = $(patsubst %,$(BLD)/%, $(notdir $(LOCSOURCE:.cpp=.o)))
CC = g++
$(TARGET) : $(LIBOBJECT) $(LOCOBJECT)
$(CC)-o $# $^
$(LOCOBJECT): $(LOCSOURCE) $(LOCINCLUDE)
mkdir -p $(dir $#)
$(CC) -c $< -o $#
$(LIBOBJECT): $(LIBSOURCE) $(LIBINCLUDE)
cd $(SRC) && $(MAKE)
.PHONY: clean
clean :
cd $(SRC) && $(MAKE) clean
The error occurs in my local file matching, where it associates both main.o and ping.o with main.cpp (everything else works fine):
mkdir -p ../../../build/
g++ -c main.cpp -o ../../../build/main.o
mkdir -p ../../../build/
g++ -c main.cpp -o ../../../build/ping.o
How do I correctly do what I'm trying to do? Should I have a different rule or target? Or is there a correct way to get the filename from the variable?
I want the .o files to end up in the same place but the executable to stay in the examples directory.

The problem is here:
$(LOCOBJECT): $(LOCSOURCE) $(LOCINCLUDE)
mkdir -p $(dir $#)
$(CC) -c $< -o $#
LOCSOURCE contains main.cpp ping.cpp, so this rule makes both source files prerequisites of each target. Whether Make is trying to build main.o or ping.o, the prerequisite list is the same: main.cpp ping.cpp ping.hpp. So the automatic variable $< always expands to main.cpp (since that is the first filename in the list).
One way to solve this is by means of a static pattern rule:
$(LOCOBJECT): $(BLD)/%.o: %.cpp $(LOCINCLUDE)
mkdir -p $(dir $#)
$(CC) -c $< -o $#
This is still imperfect, in that all local header files are prerequisites of each object from a local source. If you have a paddle.cpp and you modify ping.hpp, Make will rebuild paddle.o, even if paddle.cpp does not depend on ping.hpp in any way. This is not a serious problem, it simply means that Make will do some extra work, rebuilding things when there is no reason to. If you want to solve it, you can either write the dependencies into the makefile by hand, or use a more sophisticated method like automatic dependency generation.

Related

Makefile target with wildcard is not working

I have a simple project, whose folder structure is something like:
ls -R
.:
build include makefile src
./build:
./include:
myfunc.h
./src:
main.cpp myfunc.cpp
I want to compile the .cpp sources into .o object files, which should end into ./build folder. Using the GNUmake documentation and other sources (e.g. Proper method for wildcard targets in GNU Make), I wrote this makefile:
CXX := g++
CXXFLAGS += -I./include
CXXFLAGS += -Wall
OBJDIR := ./build
SRCDIR := ./src
PROGRAM = release
DEPS = myfunc.h
SRC = $(wildcard $(SRCDIR)/*.cpp)
OBJ = $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(SRC))
all: $(PROGRAM)
$(PROGRAM): $(OBJ)
$(CXX) $(CXXFLAGS) -o $(PROGRAM) $(OBJ)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
$(CXX) $(CXXFLAGS) -c $< -o $#
.PHONY: clean
clean:
rm $(PROGRAM) $(OBJ)
But I get the error message: make: *** No rule to make target 'build/main.o', needed by 'release'. Stop.. I tried a lot of different ways but I cannot manage to have my .o files end up in the ./build directory. Instead, everything works if I put them in the root directory of the project. I can also make it work by specifying a rule for each object file, but I'd like to avoid that. What am I missing?
(I am using GNUmake version 4.3)
The problem is here:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
$(CXX) $(CXXFLAGS) -c $< -o $#
See the $(DEPS)? That expands to myfunc.h. The compiler knows where to find that file (or would if this recipe were executed), because you've given it -I./include, but Make doesn't know where to find it (so it passes over this rule).
Add this line:
vpath %.h include
P.S. If you want to be really clean, you can add a variable:
INCDIR := ./include
CXXFLAGS += -I$(INCDIR)
vpath %.h $(INCDIR)

Echo make my Makefile relink on every Make

I'm working on a Makefile that i can use on most of my school projects.
I only did basics makefile before and never had a problem, but for this one i wanted to put some colors etc...
And it relink everytime i make it.
I think the relink come from my echos ? But i'm not sure.
Here is my makefile :
#GENERAL
CC = clang++
FLAGS = -Wall -Wextra -Werror -std=c++98
RM = rm -rf
#PROJET
EXEC = ClapTrap
#FILES
SRCS = ClapTrap.cpp main.cpp
OBJS = $(SRCS:.cpp=.o)
OBJSDIR = objects/
#REGLES
.cpp.o: $(SRCS)
mkdir -p $(OBJSDIR)
echo "$(BLUE)Compiling $^ ..$(CLEAR)"
$(CC) $(FLAGS) -c $< -o $(addprefix $(OBJSDIR), $#)
echo " $(YELLOW)$(addprefix $(OBJSDIR), $#)$(CLEAR) [$(GREEN)OK$(CLEAR)]"
all: $(EXEC)
$(EXEC): $(OBJS)
echo "$(BLUE)========================================$(CLEAR)"
echo "$(BLUE) Compiling binary file ..$(CLEAR)"
echo "$(BLUE)========================================$(CLEAR)"
$(CC) -o $(EXEC) $(addprefix $(OBJSDIR), $^) $(FLAGS)
echo "$(YELLOW)$(EXEC)$(GREEN) is now ready to use !$(CLEAR)"
clean:
#$(RM) $(OBJSDIR)
#echo "$(RED)Cleaning up..$(CLEAR)"
fclean: clean
#$(RM) $(EXEC)
#echo -n "$(RED)$(EXEC)$(CLEAR)"
re: fclean all
.PHONY: all
Thank's for reading !
EDIT :
So i removed SRCS from my .cpp.o rules dependencies, but still relinking.
Here the updated Makefile :
#FILES
SRCS = ClapTrap.cpp main.cpp
OBJS = $(SRCS:.cpp=.o)
OBJSDIR = objects
#REGLES
.cpp.o:
echo "$(BLUE)Compiling $(YELLOW)$^$(BLUE) ..$(CLEAR)"
mkdir -p $(OBJSDIR)
$(CC) $(FLAGS) -c $< -o $#
mv $# $(OBJSDIR)
echo "$(BLUE) - $(YELLOW)$#$(CLEAR) [$(GREEN)OK$(CLEAR)]"
all: $(EXEC)
$(EXEC): $(OBJS)
echo "$(BLUE)========================================$(CLEAR)"
echo "$(BLUE) Compiling binary file ..$(CLEAR)"
echo "$(BLUE)========================================$(CLEAR)"
$(CC) $(FLAGS) $(STD) $(addprefix $(OBJSDIR)/, $(OBJS)) -o $(EXEC)
echo "$(YELLOW)$(EXEC)$(GREEN) is now ready to use !$(CLEAR)"
This is wrong:
$(CC) $(FLAGS) -c $< -o $#
mv $# $(OBJSDIR)
When make runs your recipe it will put the file it expects you to build into the $# automatic variable. If your makefile builds some OTHER file, not the one it asked you to build, then the next time you run make it will see that the file it wants doesn't exist (because you didn't build it, you build some other file) and so it's always out of date.
Your rules must always build exactly the file $#, not some other file.
It's not actually possible to write a makefile that puts targets in a different directory, using suffix rules. They can only create files in the same directory. That's (one reason) why GNU make supports pattern rules which are much more flexible.
If you have to write a POSIX conforming makefile that doesn't support pattern rules, and you want to put the object files in some other directory, all you can do is write out all the targets and their rules explicitly.

Makefile: compile objects to different directory and build from there

My Makefile:
CXX = clang++
CXXFLAGS = -g -Wall -std=c++14
LDFLAGS = -lboost_system -lcrypto -lssl -lcpprest -lpthread
OBJDIR = obj
SRCDIR = .
SRC := $(shell find $(SRCDIR) -name "*.cpp")
OBJ := $(SRC:%.cpp=%.o)
APP = run
all: $(APP)
$(APP): $(OBJ)
#echo "== LINKING EXECUTABLE $(APP)"
#$(CXX) $^ $(LDFLAGS) -o $(APP)
%.o: %.cpp
#echo "COMPILING SOURCE $< INTO OBJECT $#"
#$(CXX) -c $(CXXFLAGS) $< -o $#
clean:
find . -name *.o -delete
rm -f $(APP)
Directory structure:
Makefile
sources/
directory1
...cpp
directory2
...cpp
...
main.cpp
obj/
I try to make make create *.o files in a directory obj/ and then compile the final executable from there. I tried various approaches and they fail because of the project structure that stores *.cpp files in sub-directories. Particularly, I've tried the following: https://stackoverflow.com/a/26032630/2042546
I've also tried to manipulate the command itself clang++ $< -o obj/$# but it breaks whole idea of make and it's dependency management.
If I modify OBJ via patsubstr and notdir, make becomes unable to deduce dependency of a *.o on a corresponding *.cpp by it's path, cause *.o's path loses it's directory part and becomes unable to find it's *.cpp file when executing %.o:%.cpp rule (I hope I managed to write down my thoughts correctly).
If you want objects to live in the same source directory structure but under obj, then simply change your pattern rule (and how you generate the object files). And you should create the directory first:
OBJ := $(SRC:%.cpp=$(OBJDIR)/%.o)
...
$(OBJDIR)/%.o: %.cpp
#echo "COMPILING SOURCE $< INTO OBJECT $#"
#mkdir -p '$(#D)'
#$(CXX) -c $(CXXFLAGS) $< -o $#

Single top-level makefile with source subdirectories

Firstly, apologies for my ignorance. I'm sure the answer to my question exists in one of the many existing makefile threads here. However, I have been unable to find one that concisely and clearly answers my specific question without obfuscating the answer with details that aren't relevant to my particular situation.
My code directory has a single top-level source file containing main. The rest of the source files are organised in subdirectories according to logical divisions in the system. The code contains no relative paths in the includes. This means that everything works perfectly if all the code is in a single directory using the following, simple makefile:
CC=g++
CFLAGS=-c
LDFLAGS=
SOURCES=Main.cpp Source1.cpp Source2.cpp Source3.cpp Etc.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=executable
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
Until now I have been building my code using the NetBeans IDE. This has helped preserve my make ignorance by generating some vast and overly complicated makefiles on my behalf. Now the time has come to distribute my code for public use so I'm looking to produce a makefile will enable me to distribute the code with the directory structure I have.
Can you help?
Regards,
Enthusastic Amateur.
Take a look at this:
# Source directories separated by space
# Example ./ src1/ src2/
SRCDIR = ./ src/
# Directory where object files will be placed
OBJDIR = obj/
# Include directories separated by space
# Example: include1/ include2/
INCDIR = include/
# Directory where binary file will be placed
BINDIR = bin/
# Name of the result file
TARGET = app
# Compiler
CXX = g++
# Retrive list of the source files
SRC = $(wildcard $(addsuffix *.cpp,$(SRCDIR)))
# Generate list of the object files
OBJ = $(addprefix $(OBJDIR), $(patsubst %.cpp, %.o, $(notdir $(SRC))))
VPATH = $(SRCDIR)
# Compilation flags
CXXFLAGS = -std=c++11 -pthread
$(TARGET) : $(OBJ)
#echo Linking...
#mkdir -p $(BINDIR)
#$(CXX) $(CXXFLAGS) -o $(BINDIR)$# $(OBJ)
$(OBJDIR)%.o : %.cpp
#echo Compiling $< in $#...
#mkdir -p $(OBJDIR)
#$(CXX) $(CXXFLAGS) $(addprefix -I,$(INCDIR)) -c -o $# $<
clean :
#$(RM) -r $(OBJDIR)
#$(RM) -r $(BINDIR)
Here you can provide multiple source directories.
And "everything works perfectly" as well if the code is in multiple directories, using the same makefile you already have. No changes needed.

How to build library and link it with sources with Make

I'm still quite new to make. I am trying to compile a project in which maketest.cpp and maketest.hpp rests on Users/wen/Projects/maketest with the Makefile itself. Problem is, I want to also compile and link the source files (.cc and .hh) in Users/wen/Projects/include/bigint.
# Macros
INCLUDE = -I/Users/wen/Projects/include/bigint
LIBS =
CC = g++
override FLAGS += -O2
HEADERS= $(wildcard *.hpp) $(wildcard Users/wen/Projects/include/bigint/*.hh)
# EXE Name
INSTALL = maketest
CC_FILES = %.cpp Users/wen/Projects/include/bigint/%.cc
OBJ_FILES = maketest.o $(wildcard Users/wen/Projects/include/bigint/*.o)
# Rules
$(INSTALL): $(OBJ_FILES)
$(CC) $(FLAGS) $^ -o $# $(LIBS)
%.o: $(CC_FILES) $(HEADERS)
$(CC) $(FLAGS) $(INCLUDE) -c $< -o $#
# Installation types
install: $(INSTALL)
release:
#echo "Re-run with parameter:"
#echo "FLAGS=-D_RELEASE"
debug:
#echo "Re-run with parameter:"
#echo "FLAGS=-D_DEBUG"
# Cleaning up
clean:
rm -f $(OBJ_FILES) $(INSTALL)
The code compiles maketest.cpp and links it, but not bigint.
What will be the right way to build and link the files from Users/wen/Projects/include/bigint? Many thanks!
I figured it out at the end, thank you Jay. The problem was I forgot a slash at the front of Users/wen/Projects/include/bigint, so it was not searching from root but instead the project folder. Now it works!
Try explicitly specifying one of the files from bigint in OBJ_FILES (perhaps "bigint.o" ?). I don't think your wildcard is getting what you want.