I'm triying to write a makefile that can take any amount of sources dirs and create their object files in a tidy way. I found this post that tries more or less the same, I'm at the point that the object dirs are created correctly. But getting the make: *** No rule to make target error when triying to create the objects.
This is my makefile at the moment
INCLUDES = -I includes/ \
-I mlx
EXECPT_DIRS = /mlx
OBJDIR = objs
SRCDIR = src
SRCDIRS := $(shell find . -name '*.c' -exec dirname {} \;| uniq | sed 's/\/$(SRCDIR)//g' | sed 's/\$(EXECPT_DIRS)//g' | cut -d . -f 2)
SRCS := $(shell find $(SRCDIR) -name '*.c')
OBJS := $(patsubst $(SRCDIR)%.c,$(OBJDIR)%.o, $(SRCS))
#############################################
#.SILENT:
all: $(NAME)
$(NAME) : buildtree $(OBJS)
$(CC) $(OBJS) $(CFLAGS) $(INCLUDES) libraries/*
$(OBJDIR)%.o: $(SRCDIR)%.c
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $#
clean:
rm -rf $(OBJDIR)
fclean: clean
$(RM) $(NAME)
re: fclean all
buildtree:
#$(call mk_dir)
define mk_dir
mkdir -p $(OBJDIR)/; \
for dir in $(SRCDIRS); \
do \
mkdir -p $(OBJDIR)/$$dir; \
done
endef
.PHONY: all clean fclean re bonus ext
My tree before make
looks like this:
├── includes
├── libraries
├── mlx
│ └── man
│ └── man3
└── src
├── 42lib
└── cub3d
after
.
├── includes
├── libraries
├── mlx
│ └── man
│ └── man3
├── objs
│ ├── 42lib
│ └── cub3d
└── src
├── 42lib
└── cub3d
I did manage to get the object created using this makefile from the post:
APP = Hello
SRCDIR = Sources
OBJDIR = Objects
SRCS := $(shell find $(SRCDIR) -name '*.c')
SRCDIRS := $(shell find . -name '*.c' -exec dirname {} \; | uniq)
OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(SRCS))
CFLAGS = -Wall -pedantic -ansi
LDFLAGS =
all: $(APP)
$(APP) : buildrepo $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $#
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) $(APP)
buildrepo:
#$(call make-repo)
define make-repo
for dir in $(SRCDIRS); \
do \
mkdir -p $(OBJDIR)/$$dir; \
done
endef
But the objects got created in the objs/src/dir instead of objs/dir and it relinked too.
Some help with the relink would be really appreciated :)
Related
I have the following makefile:
CPP_COMPILER = g++
CPP_COMPILER_FLAGS = -g -O0 -Wall -Wextra -Wpedantic -Wconversion -std=c++17
EXECUTABLE_NAME = mainDebug
CPP_COMPILER_CALL = $(CPP_COMPILER) $(CPP_COMPILER_FLAGS)
INCLUDE_DIR = include
SOURCE_DIR = src1
BUILD_DIR = build
CPP_SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
CPP_OBJECTS = $(patsubst $(SOURCE_DIR)/%.cpp, $(BUILD_DIR)/%.o, $(CPP_SOURCES))
build: $(BUILD_DIR)/$(EXECUTABLE_NAME)
TARGET_DEPS = $(CPP_OBJECTS)
$(BUILD_DIR)/$(EXECUTABLE_NAME): $(TARGET_DEPS)
$(CPP_COMPILER_CALL) $^ -o $#
execute:
.$(BUILD_DIR)/$(EXECUTABLE_NAME)
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(CPP_COMPILER_CALL) -I $(INCLUDE_DIR) -c $< -o $#
clean:
rm -rf $(BUILD_DIR)/*.o $(BUILD_DIR)/$(EXECUTABLE_NAME)
And the following folder structure:
.
├── build
├── include
│ ├── mylib.h
│ └── test.h
├── Makefile
├── src1
│ ├── main.cc
│ └── mylib.cc
└── src2
└── test.cc
This works correctly with src1 but when adding src2 to SOURCE_DIR,
SOURCE_DIR = src1\
src2
I get the following error:
/usr/bin/ld: cannot find src1: file format not recognized
collect2: error: ld returned 1 exit status
make: *** [Makefile:22: build/mainDebug] Error 1
What am I doing wrong here ?
Look at how you use SOURCE_DIR:
SOURCE_DIR = src1
...
CPP_SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
CPP_OBJECTS = $(patsubst $(SOURCE_DIR)/%.cpp, $(BUILD_DIR)/%.o, $(CPP_SOURCES))
...
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(CPP_COMPILER_CALL) -I $(INCLUDE_DIR) -c $< -o $#
After you define it, you use it three times, each time as a single directory name. You cannot simply add a second name to the variable and expect Make to iterate properly over the list.
First, use addsuffix to get the right pattern for wildcard:
CPP_SOURCES = $(wildcard $(addsuffix /*.cpp,$(SOURCE_DIR)))
Then use CPP_SOURCES instead of SOURCE_DIR:
CPP_OBJECTS = $(patsubst %.cpp, $(BUILD_DIR)/%.o, $(notdir $(CPP_SOURCES)))
Then use vpath to find the sources:
vpath %.cpp $(SOURCE_DIR)
$(BUILD_DIR)/%.o: %.cpp
$(CPP_COMPILER_CALL) -I $(INCLUDE_DIR) -c $< -o $#
I've been looking into building cpp applications with make and looking at various sources online. While it works, I'm trying to build my object files and place those into a particular directory rather then have them go into the same src/ as my source files. Ideally, I would like them to go into the OUT_O_DIR location, but they're being generated and placed in the src/, which I don't want.
I want a structure like this:
.
|- Makefile
|- include/
| |- *.h
|- src/
| |- *.c
|- output/
| |- App
|- obj/
| |- *.o
My make version:
GNU Make 4.1
Built for x86_64-pc-linux-gnu
My Makefile:
OUT_O_DIR := $(OUT_DIR)/obj
PROJ = hello
SOURCE = $(wildcard src/*.cpp)
INC = $(wildcard include/*.h)
OBJS = $(SOURCE:.cpp=.o)
CFLAGS = -I include
CC = g++
.PHONY: directories
all : directories $(OUT_DIR)$(PROJ)
directories: $(OUT_DIR)
$(OUT_DIR)$(PROJ) : $(OBJS)
$(CC) -o $# $(OBJS)
.cpp.o: $(INC)
#echo $#
$(CC) -c $(CFLAGS) $< -o $#
clean :
rm -rf $(OUT_DIR)
$(OUT_DIR):
mkdir -p $(OUT_DIR)
The '.cpp.o' does not extend to cover multiple folders. Two options
Modify OBJS and rule to build object.
#OBJS = $(SOURCE:.cpp=.o)
OBJS = $(SOURCE:src/%.cpp=$(OUT_O_DIR)/%.o)
...
#.cpp.o: $(INC)
${OUT_O_DIR}/%.o: src/%.cpp $(INC)
$(CC) -c $(CFLAGS) $< -o $#
Or use vpath to specify the .cpp files are in src
#OBJS = $(SOURCE:.cpp=.o)
OBJS = $(SOURCE:src/%.cpp=$(OUT_O_DIR)/%.o)
vpath %.cpp src
${OUT_O_DIR}/%.o: %.cpp $(INC)
$(CC) -c $(CFLAGS) $< -o $#
I have a project that I am trying to create a Makefile for. The folder structure looks like this:
|-- bin
|-- build
|-- Makefile
|-- src
| |-- some_files.cpp
| |-- some_files.h
| |-- ForestFactory
| |-- MMParSet
| |-- century
| |-- century_carbon.cpp
| |-- century_carbon.h
| `-- grass
`-- src_multithread
|-- __history
and I have tried to use this reference to create a Makefile.
The Makefile I have is
CC := g++
SRCDIR := src
BUILDDIR := build
TARGETDIR := bin
INSTALLBINDIR := /usr/local/bin
TARGET := bin/formind
# CPP files
SOURCES := $(shell find $(SRCDIR) -type f -name *.cpp)
# remove the src path and add the build path and the .o extension
OBJECTS := $(addprefix $(BUILDDIR)/,$(patsubst %.cpp,%.o,$(notdir $(SOURCES))))
CFLAGS := -std=c++11 -stdlib=libc++
INC := -I/usr/local/include -I $(SRCDIR) -I $(SRCDIR)/century -I $(SRCDIR)/grass -I $(SRCDIR)/MMParSet -I $(SRCDIR)/ForestFactory
$(TARGET): $(OBJECTS)
#mkdir -p $(TARGETDIR)
#echo " Linking..."
#echo " $(CC) $^ -o $(TARGET)"
$(CC) $^ -o $(TARGET)
$(BUILDDIR)/%.o: $(SRCDIR)/%.cpp
#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)
.PHONY: clean
When I try to make I get the following error message:
make: *** No rule to make target `build/century_carbon.o', needed by `bin/formind'. Stop.
The source files come from a nested set of subdirectories inside src. My understanding was that the OBJECTS variable should contain the complete paths of the final object files, so that I have something like
$SOURCES = src/century/century_carbon.cpp ... src/for_branching.cpp ... src/grass/grass_log.cpp ...
$OBJECTS = build/century_carbon.o ... build/for_branching.o ... build/grass_log.o ...
Is there something wrong in the way I wrote the compilation rules?
The problem is with the nested source directory century. If you add to the makefile:
info:
#echo " Info..."
#echo " SOURCES = $(SOURCES)"
#echo " OBJECTS = $(OBJECTS)"
then make info gives:
Info...
SOURCES = src/century/century_carbon.cpp src/some_files.cpp
OBJECTS = build/century_carbon.o build/some_files.o
This check shows that your construction of these macros is ok. And it also shows, as you report, that make will then tell us:
make: *** No rule to make target 'build/century_carbon.o', needed by 'bin/formind'. Stop.
If you add an additional rule, with the directory century specified:
$(BUILDDIR)/%.o: $(SRCDIR)/century/%.cpp
#mkdir -p $(BUILDDIR)
$(CC) $(CFLAGS) $(INC) -c -o $# $<
then your build will proceed.
An alternative solution is to use VPATH. Add the line:
VPATH = src:src/century
and also remove $(SRCDIR)/ from your rule, which now becomes:
$(BUILDDIR)/%.o: %.cpp
#mkdir -p $(BUILDDIR)
$(CC) $(CFLAGS) $(INC) -c -o $# $<
Update: The above answer could be improved in two ways:
Use vpath rather than VPATH, for more precise control of the searches.
Automatically generate the argument for vpath / VPATH.
This is suprisingly simple: just replace my hard-coded VPATH line with:
vpath %.cpp $(sort $(dir $(SOURCES)))
I have the following directory structure for a C++ project:
.
├── bin
├── build
├── include
│ ├── dir1
│ │ ├── file1.hpp
│ │ └── file2.hpp
│ ├── dir2
│ │ ├── file3.hpp
│ │ └── file4.hpp
│ └── third_party
│ └── catch.hpp
├── Makefile
├── src
│ ├── dir1
│ │ ├── file1.cpp
│ │ └── file2.cpp
│ └── dir2
│ ├── file3.cpp
│ └── file4.cpp
└── test
├── dir1
│ ├── file1.test.cpp
│ └── file2.test.cpp
└── dir2
├── file3.test.cpp
└── file4.test.cpp
How can I write the Makefile to compile the code in src and test directories and obtain the object files in the build directory and the binaries in the bin directory, maintaining the same directory structure within them, without having to name every file and its dependency explicitly? Would it be better to use multiple Makefiles in each dir* within src and test?
My Makefile currently looks like this: (it's probably nonsensical, sorry about that!)
binaries_dir = bin
build_dir = build
sources_dir = src
include_dir = include
compile_flags = -std=c++14 -Wall
binaries := $(wildcard *.out)
objects := $(wildcard *.o)
sources := $(wildcard *.cpp)
headers := $(wildcard *.hpp)
objects: $(sources)
g++ $(compile_flags) -c $(sources_dir)/$(sources) -I $(include_dir)
binaries: $(objects)
for object in $(objects); do
g++ $(compile_flags) -o $(binaries_dir)/ $(build_dir)/$object
done
I don't think this is fool proof but I think it pretty much does what you are after. You should study up on building Makefiles because it this turns out not to quite fit your needs, how are you going to fix it?
CXX := g++
RM := rm -f
MD := mkdir -p
# don't change, this is for dependencies
CXXFLAGS += -MMD -MP
# add compiler flags here
CXXFLAGS += -std=c++14 -pedantic-errors
CXXFLAGS += -Wall -Wextra
CXXFLAGS += -g3 -O0
# add external includes here
CPPFLAGS += -Iinclude
# add library flags here
LDFLAGS +=
DIRS := $(patsubst src/%, %, $(wildcard src/*))
DIRS += $(patsubst test/%, %, $(wildcard test/*))
PROG_SOURCES := $(wildcard src/*/*.cpp)
TEST_SOURCES := $(wildcard test/*/*.cpp)
OBJECTS := $(patsubst src/%.cpp, build/%.o, $(PROG_SOURCES))
OBJECTS += $(patsubst test/%.cpp, build/%.o, $(TEST_SOURCES))
EXECUTABLES := $(patsubst src/%.cpp, bin/%, $(PROG_SOURCES))
EXECUTABLES += $(patsubst test/%.cpp, bin/%, $(TEST_SOURCES))
DEPENDENCIES := $(patsubst src/%.cpp, build/%.d, $(PROG_SOURCES))
DEPENDENCIES += $(patsubst test/%.cpp, build/%.d, $(TEST_SOURCES))
all: dirs $(EXECUTABLES)
build/%.o: src/%.cpp
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $# $<
build/%.o: test/%.cpp
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $# $<
bin/%: build/%.o
$(CXX) $(CXXFLAGS) -o $# $< $(LDFLAGS)
-include $(DEPENDENCIES)
clean:
#echo Removing build files
#$(RM) $(EXECUTABLES) $(OBJECTS) $(DEPENDENCIES)
dirs:
#$(MD) $(patsubst %, build/%, $(DIRS)) $(patsubst %, bin/%, $(DIRS))
.PHONY: show dirs
You might find some inspiration from this: https://github.com/jschmerge/DasBuild
Based on this link, I created a Autotools-based build system that accepts Qt UI and RSC files without the need to call QMAKE.
I however wish to separate the source, headers and ui-files into folders in the the following fashion:
${srcdir}
├── Makefile.am
├── main.cc
├── include
│ └── mainwidget.h
├── src
│ └── mainwidget.cc
└── ui
└── mainwidget.ui
And have the build directory ordered in the following way
${builddir}
├── include
│ └── ui_mainwidget.h
├── Makefile
├── main.o
├── mainwidget.o
└── moc_mainwidget.o
My Makefile.am currently looks like this:
moc_%.cc: %.h
#MOC# -o$# $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(MOC_CPPFLAGS) $<
ui_%.h: %.ui
#UIC# -o $# $<
qrc_%.cc: %.qrc
#RCC# -o $# $<
bin_PROGRAMS = qthello
BUILT_SOURCES = ui_mainwidget.h
qthello_CXXFLAGS = -I$(srcdir)/include -I$(builddir)/include
qthello_CPPFLAGS = $(QT_CPPFLAGS)
qthello_LDFLAGS = $(QT_LDFLAGS)
qthello_LDADD = $(QT_LIBS)
qthello_SOURCES = \
moc_mainwidget.cc \
mainwidget.cc \
main.cc
Which works fine if the ui-class files are located in $(srcdir), but simply moving them to the desired directories and changing the expected lines in the Makefile.am does not yeld the desired result. That is, doing these changes does not work:
BUILT_SOURCES = include/ui_mainwidget.h
[ ... ]
qthello_SOURCES = \
src/moc_mainwidget.cc \
src/mainwidget.cc \
main.cc
It occurs to me that some changes have to be made to the build rules to ensure that the include, src, ui -directories exist in $(builddir), and that the correct input files are passed. I am however inexperienced in writing such build rules and google does not seem to have the answer.
Are there any easy portable ways of achieving this?
So I did eventually find a solution to this thanks to this post.
Following is the final Makefile.am
moc_%.cc: ../include/%.h
$(MKDIR_P) $(#D)
#MOC# -o$# $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(MOC_CPPFLAGS) $<
ui_%.h: ../ui/%.ui
$(MKDIR_P) $(#D)
#UIC# -o $# $<
qrc_%.cc: %.qrc
$(MKDIR_P) $(#D)
#RCC# -o $# $<
clean-local:
rm -rf ui/ include/
bin_PROGRAMS = qthello
BUILT_SOURCES = \
include/ui_mainwidget.h
qthello_CXXFLAGS = \
-I$(srcdir)/include \
-I$(builddir)/include
qthello_CPPFLAGS = $(QT_CPPFLAGS)
qthello_LFLAGS = $(QT_LDFLAGS)
qthello_LDADD = $(QT_LIBS)
qthello_SOURCES = \
ui/moc_mainwidget.cc \
src/mainwidget.cc \
main.cc
Keep in mind that AC_PROG_MKDIR_P must be added to configure.ax.