I am building a small utility library in c++, and I am adding some examples to it. The project structure looks like this:
MyLib
|__bin
|
|__include
| |__mylib.hpp
|
|__lib
|
|__examples
| |__example.cpp
|
|__src
| |__mylib.cpp
|
|__Makefile
Here is what my Makefile looks like:
LIBK = mylib
LIBS = $(LIBK).a
CXXFLAGS := -Wall -Wextra -std=c++17 -ggdb
BIN := bin
SRC := src
INCLUDE := include
LIB := lib
EXAMPLES := examples
all: lib examples
lib: $(LIB)/$(LIBK)
examples: lib $(BIN)/$(EXAMPLES)
run: clean all
clear
./$(LIB)/$(LIBK)
$(LIB)/$(LIBK): $(SRC)/*.cpp
-mkdir -p lib
$(CXX) -c $(CXXFLAGS) -I$(INCLUDE) -L$(LIB) $^ -o $#.o
ar rcs $(LIB)/lib$(LIBK).a $#.o
$(BIN)/$(EXAMPLES): $(EXAMPLES)/*.cpp
-mkdir -p bin
$(CXX) $(CXXFLAGS) -I$(INCLUDE) -L$(LIB) -l$(LIBK) $^ -o $#
clean:
-rm -rf $(BIN)/*
-rm -rf $(LIB)/*
My problem is that everything seems to look fine when I run make, but it fails when I run make -j8 with the following error.
cannot find -lmylib
collect2: error: ld returned 1 exit status
make: *** [Makefile:36: bin/examples] Error 1
make: *** Waiting for unfinished jobs....
ar rcs lib/libmylib.a lib/mylib.o
It seems like the multiple core instruction triggers both compilations at the same time, without waiting for the library to build before launching the job to build the example. I believe I had defined the dependencies correctly, but there is something obviously wrong that I don't seem to be able to find by myself.
EDIT:
Seeing that I the original Makefile is fundamentally incorrect, but no answer really provided an alternative one, I created a new one to the best of my knowledge that seems to work. Any constructive and respectful criticism is welcome.
LIBNAME := libIntegration.a
CXX := g++
BIN := bin
SRC := src
INCLUDE := include
LIB := lib
LIBRARIES := -lIntegration
EXECUTABLE := main
LIBRARY_SOURCES := $(SRC)/mxIntegration.o
EXECUTABLE_SOURCES := examples/main.o
CXXFLAGS := -Wall -Wextra -std=c++17 -ggdb -I$(INCLUDE)
all: $(BIN)/$(EXECUTABLE)
run: clean all
clear
./$(BIN)/$(EXECUTABLE)
$(LIB)/$(LIBNAME): $(LIBRARY_SOURCES)
ar rcs $# $^
$(BIN)/$(EXECUTABLE): $(LIB)/$(LIBNAME)
$(CXX) $(CXXFLAGS) -I$(INCLUDE) -L$(LIB) $(EXECUTABLE_SOURCES) -o $# $(LIBRARIES)
clean:
-rm -rf $(BIN)/*
-rm -rf $(LIB)/*
This is a super-bizarre makefile. I'm not sure why you even bother to use make at all, because you are always recompiling every source file whenever any source file changes.
But, just to deal with your specific question your error message says:
cannot find -lmylib
so clearly the example is being built before the library is done. So, let's look at the rule for building examples:
$(BIN)/$(EXAMPLES): $(EXAMPLES)/*.cpp
Here you list the source files as prerequisites of the target. But nowhere have you listed the library as a prerequisite. So, make has no idea that you need to wait for the library to be built, and you definitely haven't defined that dependency.
Related
I can compile the project just fine if I run the project by hand with g++ source/* -lSDL2 -o bin/fly_fishing. When I do run make, I get
mkdir -p bin
g++ -lSDL2 -o bin/fly_fishing
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x17): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [Makefile:20: bin/fly_fishing] Error 1
Which tells me that it's not populating from $^ for linking. So what have I missed here? Here's the makefile for reference.
SRC_DIR := source
OBJ_DIR := objects
BIN_DIR := bin
EXE := $(BIN_DIR)/fly_fishing
SRC := $(wildcard $(SRC_DIR)/*.c)
OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
CXXFLAGS := -Wall
#CFLAGS := -Wall
LDLIBS := -lSDL2a
LDFLAGS :=
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CXX) -c $(CXXFLAGS) $(CFLAGS) $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
Which tells me that it's not populating from $^ for linking.
That seems unlikely. Much more likely would be that $^ expands to nothing. Which would be the case if $(OBJ) expands to nothing. Which seems plausible because I don't see any corresponding objects being built (though perhaps you've omitted that, or they were built on a previous run). And $(OBJ) expanding to nothing implies that $(SRC) expands to nothing.
So what have I missed here?
That $(SRC) expands to nothing is not inconsistent with the data presented. I observe that the manual compilation command you present is
g++ source/* -lSDL2 -o bin/fly_fishing
That does seem to suggest that there are indeed source files in source/, but do they match the pattern source/*.c? Since you're compiling with g++, I bet not. It would be highly unconventional to name C++ source files to end with .c, and surely you would not attempt to compile C source files with a C++ compiler. I infer, then, that your source files are all named with .cpp, or maybe .cc or .C, all of which forms are conventions for C++ source names.
If all your source names follow one or another of those patterns then indeed, this ...
SRC := $(wildcard $(SRC_DIR)/*.c)
... will result in $(SRC) being empty.
For this reason I downloaded the C++ library VTK and made a local build in the build subdirectory on a OSX environment.
I would like to compile a project using this library (particularly I am using the class vtkSmartPointer) with Makefile.
Consider for example the following source code:
#include<iostream>
#include<vtkSmartPointer.h>
#include<vtkCallbackCommand.h>
int main()
{
vtkSmartPointer<vtkCallbackCommand> keypressCallback =
vtkSmartPointer<vtkCallbackCommand>::New();
std::cout<<"hello world\n";
return 0;
}
For the Makefile I started from the second answer in this post to which I aded VTK library path:
CXX = g++
# OpenCV trunk
CXXFLAGS = -std=c++11 \
-I ../VTK/Common/Core/ -I ../VTK/build/Common/Core/ -I ../VTK/build/Utilities/KWIML/ \
-I ../VTK/Utilities/KWIML/ \
-L../VTK/build/lib \
-lvtkCommon -lvtkFiltering -lvtkImaging -lvtkGraphics -lvtkGenericFiltering -lvtkIO
SOURCES := $(wildcard *.cpp)
OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: parking
clean:
$(RM) $(OBJECTS) $(DEPENDS) parking
# Linking the executable from the object files
parking: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
-include $(DEPENDS)
%.o: %.cpp Makefile
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
My environment variable DYLD_LIBRARY_PATH has the value ../cmake_bin_dir/instDir/lib:../VTK/build/lib/.
When I try to compile running make, I get the following error:
ld: library not found for -lvtkCommon
clang: error: linker command failed with exit code 1 (use -v to see invocation)
What part of the Makefile or program or step in the process is not correct?
Thank you in advance.
The current VTK library does not contain libVtkCommon.so (see package contents section https://www.archlinux.org/packages/community/x86_64/vtk/). Are you looking for libVtkCommonCore.so? If that is the case you have to change -lvtkCommon to -lvtkCommonCore in your Makefile. The same seems to be the case for some of the other included libraries.
I am trying to create a static library based on the file layout given below.
/library
Makefile
/include
.h files
/src
.cpp files
/build
.o files
/lib
.a file
When I run make all with the current code in my makefile given below it gives me the error:
make: *** No rule to make target src/%.cpp', needed bybuild/BaseGfxApp.o'. Stop.
CPP_FILES = $(wildcard src/*.cpp)
OBJ_FILES = $(addprefix build/,$(notdir $(CPP_FILES:.cpp=.o)))
CC_FLAGS = -c -Wall
all: libphoto.a
libphoto.a: $(OBJ_FILES)
ar rcs lib/$# $^
build/%.o: src/%.cpp
g++ $(CC_FLAGS) $# $<
I am fairly new to 'make' and I honestly have no clue where to go from here. I would appreciate some input or help. Thanks!
It could be that you are missing a makefile in your src/ directory.
dont put paths in the rules
%.o: %.cpp
g++ $(CC_FLAGS) $# $<
I think the main problem is you are not giving the proper path to the files you are trying to build. But also you missed some flags for g++. I think the following changes should work (not properly tested).
CPP_FILES = $(wildcard src/*.cpp)
OBJ_FILES = $(patsubst src/%.cpp,build/%.o,$(CPP_FILES))
CXXFLAGS = -Wall
all: prereqs lib/libphoto.a
lib/libphoto.a: $(OBJ_FILES)
ar rcs $# $^
build/%.o: src/%.cpp
g++ -c $(CXXFLAGS) -o $# $<
prereqs:
mkdir -p lib
mkdir -p build
.PHONY: prereqs
clean:
rm $(OBJ_FILES) lib/libphoto.a
Im currently learning how to code without an IDE and so Im learning how to write makefiles. Here is my current test-project:
\__ /CoDstructor/
|\__ Makefile
|\__ /bin/
| \__ CoDstructor.exe
|\__ /src/
| \__ /cod/
| |\__ main.cpp
| |\__ types.cpp
| \__ types.hpp
\__ /obj/
\__ /cod/
|\__ main.o
|\__ main.d
|\__ types.o
\__ types.d
I only have one single top level makefile that handles every module in the src/ directory and creates the objects and dependency files in the obj/ directory.
Here are the files:
main.cpp
#include <iostream>
#include <cod/types.hpp>
int main() {
int s;
std::cin >> s;
return lol();
}
types.hpp
#ifndef TYPES_HPP_INCLUDED
#define TYPES_HPP_INCLUDED
int lol();
#endif // TYPES_HPP_INCLUDED
types.cpp
#include <iostream>
#include <cod/types.hpp>
int lol() {
std::cout << "lol";
return 0;
}
Makefile
APP_NAME = CoDstructor
DEBUG_TARGET = debug
RELEASE_TARGET = release
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
INC_DIR = src
INCLUDE_DIRS +=
LIBRARY_DIRS +=
CXXFLAGS += -Wall
CXXFLAGS += -Werror
CXXFLAGS += -Wextra
CXXFLAGS += -pedantic
CXXFLAGS += -std=c++11
$(DEBUG_TARGET): CXXFLAGS += -g
$(RELEASE_TARGET): CXXFLAGS += -O3
LDFLAGS += -static
LDFLAGS += -static-libstdc++
LDFLAGS += -static-libgcc
$(DEBUG_TARGET): LDFLAGS += -g
$(RELEASE_TARGET): LDFLAGS +=
CPPMACROS =
$(DEBUG_TARGET): CPPMACROS += DEBUG
$(RELEASE_TARGET): CPPMACROS += NDEBUG
CXXFLAGS += $(foreach i,$(INC_DIR),$(addprefix -I,$(i)))
CXXFLAGS += $(foreach i,$(INCLUDE_DIRS),$(addprefix -I,$(i)))
CXXFLAGS += $(foreach i,$(CPPMACROS),$(addprefix -D,$(i)))
LIBS = $(foreach i,$(LIBRARY_DIRS),$(addprefix -L,$(i)))
SOURCES = $(subst ./,,$(shell find . -name *.cpp))
OBJS = $(subst $(SRC_DIR),$(OBJ_DIR),$(SOURCES:.cpp=.o))
DEPS = $(OBJS:.o=.d)
all: $(DEBUG_TARGET) clean
$(RELEASE_TARGET): $(BIN_DIR)/$(APP_NAME) clean
#echo Building release...
$(DEBUG_TARGET): $(BIN_DIR)/$(APP_NAME) clean
#echo Building debug...
$(OBJS): $(SOURCES)
#mkdir -p $(#D)
$(CXX) -MMD -MP $(CXXFLAGS) -c $< -o $#
$(BIN_DIR)/$(APP_NAME): $(OBJS)
$(CXX) $(LDFLAGS) $^ -o $# $(LIBS)
#echo $^
.PHONY: clean
clean:
#echo clean
# #-rmdir $(OBJ_DIR)
-include $(DEPS)
And here is the error:
obj/cod/types.o: In function `main':
D:\PROJECTS\CoDstructor/src/cod/main.cpp:4: multiple definition of `main'
obj/cod/main.o:D:\PROJECTS\CoDstructor/src/cod/main.cpp:4: first defined here
obj/cod/main.o:main.cpp:(.text+0x2a): undefined reference to `lol()'
obj/cod/types.o:main.cpp:(.text+0x2a): undefined reference to `lol()'
collect2.exe: error: ld returned 1 exit status
I searched for almost two days now how to resolve these errors.
For the first one (multiple definitions of main):
I already checked the OBJS variable, and it contains and links only one time the main.o. Also why says it obj/cod/types.o in the first line? There is no main in types.hpp/types.cpp.
The second error (undefined reference to lol()):
Why is the reference undefined, but gives no compiler error instead?
The third error (it rebuilds everything everytime, instead of only changed ones or instead of looking up the .d dependency files)
I am running the latest MinGW32 build (g++ 4.9.1) and latest MSYS (make).
What am I doing wrong here?
Your $(OBJS): $(SOURCES) rule is not what you think it is. As a result, you're building both main.o and types.o from the same main.cpp file ($< param in command line). Hence you have two identical files which are conflicting, while types.cpp wasn't even built.
Correct rule would be $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
Your key problem is here:
$(OBJS): $(SOURCES)
#mkdir -p $(#D)
$(CXX) -MMD -MP $(CXXFLAGS) -c $< -o $#
This rule has two problems.
You have multiple object files. The first action won't work when you go beyond having just one subdirectory under your src directory.
The second action compiles your src/cod/main.cpp twice, once into obj/cod/main.o and then into obj/cod/types.o. That's because $< is the first item in the dependency list, and that first item is src/cod/main.cpp.
The second problem is easier to fix than the first. You need a pattern rule:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) -MMD -MP $(CXXFLAGS) -c $< -o $#
Now to address the first problem. What if you have multiple source directories, each a subdirectory of your src directory? You want to make a corresponding obj subdirectory for each one of those. Also note that there's a directory you aren't making, the bin directory. The first thing to do is build a list of the directories you need to make.
MKDIRS = $(sort $(foreach i,$(OBJS),$(dir $i)))
MKDIRS += bin
Then you need a rule to make them. Let's start simply:
mkdirs:
mkdir -p $(MKDIRS)
This however is problematic. You'll get error messages from mkdir and the build will stop if any one of those directories already exists. We need to make those directories only if they don't exist. Make does provide the tools to filter that list down to only the directories that don't exist, but I'd rather not do that. To me it's better to use the shell to make some decisions:
mkdirs:
#sh -c \
'for d in $(MKDIRS); do \
if [ ! -d $$d ]; then echo mkdir -p $$d; mkdir -p $$d; fi \
done'
Now we need to add that rule as a dependency.
$(RELEASE_TARGET): mkdirs $(BIN_DIR)/$(APP_NAME)
#echo Release built
$(DEBUG_TARGET): mkdirs $(BIN_DIR)/$(APP_NAME)
#echo Debug built
Note that I've done three things to those targets.
I added the mkdirs target.
I deleted the clean target. You really don't want to do that here. It defeats the purpose of separate compilations. When you have hundreds of source files and make a change in one of them, you just want to recompile that one source file and then rebuild the executable from the hundreds of object files that already exist. Don't do a clean right after you built the executable! You can always do a make clean from the command line if you feel compelled to do so.
I changed the messages. Those messages will be issued after the dependencies have been satisfied. They'll be the last thing you see. To get messages before action starts it's easiest to build a phony target that prints the desired message.
A couple of final notes:
Note that mkdirs is a phony target (and so is all). It's best to add it to your .PHONY list, and that list is best placed up-front.
Finally, the target $(DEBUG_TARGET): mkdirs $(BIN_DIR)/$(APP_NAME) is a ticking time bomb. The same goes for $(RELEASE_TARGET). One day you'll find out about parallel make. There's no guarantee that the directories will be made before the compiler tries to compile the code. The directories won't exist, and kaboom, your make just failed. Making your makefile robust against parallel execution is a matter of a different stackexchange question.
From memory, did not check the docs, problem is this:
$(OBJS): $(SOURCES)
#mkdir -p $(#D)
$(CXX) -MMD -MP $(CXXFLAGS) -c $< -o $#
That means that every object file depends on all sources. And then the compile command uses $< which I think means the first dependency. So in effect, you compile both types.o and main.o from main.cpp (which is first of the $(SOURCES), I suppose).
One solution would be to use a pattern rule, something like:
%.o : %.c
#mkdir -p $(#D)
$(CXX) -MMD -MP $(CXXFLAGS) -c $< -o $#
Object files are already requied by your rule $(BIN_DIR)/$(APP_NAME): $(OBJS), and this pattern rule will tell make how to generate them.
I have this makefile below. While it compiles properly at the moment, I'm running into a really weird and tedious issue where I have to run make twice to compile the code.
The first time I call make, I get this error:
./src/gravity.cpp:1:31: fatal error: gravity.h: No such file or directory
compilation terminated.
I have a lot more source files added under OBJECTS = .., and that message repeats for each one of them. Of course, this would indicate that I didn't link the headers correctly, except that when I run make again, everything compiles smoothly.
An interesting observation may be that main.cpp doesn't complain about a missing gravity.h, but I'm not sure how it relates.
I have header guards on all my header files. If it helps, this is for a C++ SDL/OpenGL application.
My makefile is below. Thanks!
OUTPUT_NAME = output_file
INC_DIR = ./inc
SRC_DIR = ./src
BIN_DIR = ./bin
INCLUDES= \
-I${SRC_DIR}
SRC := $(shell find $(SRC_DIR) -name '*.cpp')
INC := $(shell find $(INC_DIR) -name '*.h')
CXX = g++
CXXFLAGS = -g -Wall -std=c++0x -I${INC_DIR} -I./lib/glm
LIBFLAGS = -lSDL -lGL -lGLU -lglut
OBJECTS = \
${BIN_DIR}/main.o \
${BIN_DIR}/gravity.o
DEPS = $(BIN_DIR)/${OUTPUT_NAME}.deps
all: ${DEPS} ${OUTPUT_NAME}
${DEPS}: ${INC} ${SRC}
#${CXX} -M ${SRC} > ${DEPS}
${OUTPUT_NAME}: ${OBJECTS}
${CXX} ${CXXFLAGS} ${OBJECTS} -o ${OUTPUT_NAME} ${LIBFLAGS}
${OBJECTS}: ${BIN_DIR}/%.o : ${SRC_DIR}/%.cpp
${CXX} ${CXXFLAGS} $< -c -o $#
force:
$(MAKE) fullclean
$(MAKE)
clean:
rm ${OBJECTS} ${OUTPUT_NAME}
fullclean:
rm ${OBJECTS} ${DEPS} ${OUTPUT_NAME}
run:
clear
./${OUTPUT_NAME}
style:
astyle --style=java --indent=spaces=4 ${SRC} ${INC}
.PHONY: all clean fullclean run style force
include $(DEPS)
The rule to build your .deps file:
${DEPS}: ${INC} ${SRC}
#${CXX} -M ${SRC} > ${DEPS}
will unconditionally create the ${DEPS} file even if the invocation of the C++ compiler fails. (It probably would have been better to have used -o.)
It is also missing the -I options which would allow it to find the header files.
As a result of the second error, it will fail when run. As a result of the first error, it will nevertheless create a .deps file. The second time you invoke make, it will not trigger the ${DEPS} rule because the .deps file is newer than any dependency.
Also, I don't understand
INCLUDES= \
-I${SRC_DIR}
It's not correct (I think: it should be INC_DIR, and it's missing ./lib/glm), and you don't use it anywhere.