My Makefile looks as follows:
test:
make clean
make test2
test2: CXX=g++
test2: all
CPP_FILES := $(wildcard tmp/*.cpp)
OBJ := $(CPP_FILES:.cpp=.o)
all: ${OBJ}
${CXX} ${OBJ} ${LIB_PATH} ${LIBS} ${CXX_FLAGS} -o output.exe
%.o: %.cpp
${CXX} ${CXX_FLAGS} ${INCLUDE_PATH} -c $< -o $#
All the .o files can (and should) be build in parallel. This is working if I execute "make -j" but it fails if I limit the number of processes to some fixed number (say 4) via "make -j4". This will result in the following message:
make[1]: warning: jobserver unavailable: using -j1. Add `+' to parent make rule.
Can someone please point me to my mistake? Why is "make -j" working while "make -j4" gives this error message?
Thanks!
Please read the documentation for recursive calls in GNU make. Essentially, you need to call $(MAKE) or ${MAKE} instead of plain make or at least prefix the line in the recipe with + so that the sub-make can properly communicate with the parent make. This is particularly useful when you ask for job control.
Related
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.
I am trying to write a makefile in a subdirectory of my eclipse makefile project.
MyProject \
test.cpp
Build\
Makefile
I am also trying to create a generic makefile. I am having trouble defining the targets since the build is not happening in the same directory as the source.
CC = g++
CC_FLAGS = -g3
EXEC = test
SOURCEDIR = ..
SOURCES = $(shell find $(SOURCEDIR) -name '*.c' -o -name '*.cpp')
OBJECTS = $(addsuffix .o,$(subst ../,,$(SOURCES)))
.DEFAULT_GOAL = all
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $#
.PHONY: clean
clean:
rm -f $(EXEC) $(OBJECTS)
.PHONY: all
all: $(EXEC)
Right now when I build I get the error...
make all
make: *** No rule to make target 'test.cpp.o', needed by 'test'. Stop.
Can anyone tell me why this is not working or recommend a better approach.
If you change your dependency from object to source as follows:
%.cpp.o: $(SOURCEDIR)/%.cpp
it seems to work.
In general I would prefer to NOT do anything in a build dir, because I personally expect a build dir is a temporary dir which can be removed completely for distribution which is not the case if the Makefile resists there. But this is a matter of taste.
Also I do not prefer to use all c/cpp you find as objects/sources in the make process. If you need to add files for different variants in your projects, you enter a nightmare to change all these things later.
And also as a hint: Typically objects are <basename>.o and not <basename>.cpp.o
And another one:
Users expect that the clean target also remove the executable. If not, you will never see a rebuild by simply do make clean; make, because the executable is in place and all dependencies are fulfilled.
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.
In my Makefile I'm trying to specify, that I want to save the compiled executable file to /dvoram64/ folder. Before, when I tried to save it diretly to / everything worked all right, but now I get this message after calling make run:
ubuntu#pa2:~/Project$ make run
Makefile:37: warning: overriding commands for target `dvoram64/main'
Makefile:34: warning: ignoring old commands for target `dvoram64/main'
make: Circular dvoram64/main <- dvoram64/main dependency dropped.
mkdir -p dvoram64
g++ -Wall -pedantic -Wno-long-long -O0 -ggdb -g -c src/main.cpp -o dvoram64/main
./dvoram64/main
make: execvp: ./dvoram64/main: Permission denied
make: *** [run] Error 127
My Makefile looks like this:
#macros
CC=g++
CCFLAGS=-Wall -pedantic -Wno-long-long -O0 -ggdb -g
LBFLAGS=-lncurses -pthread
Remove=rm -rf
Objects=dvoram64/main
Doxygen=Doxyfile
RUN=./dvoram64/main
CPATH=objects/
#generates final binary and documentation
all: $(Objects) $(Doxygen)
make compile
make doc
#build into final binary
compile: $(RUN)
#run program
run: $(RUN)
$(RUN)
clean:
$(Remove) doc/
$(Remove) dvoram64
#generate documentation in '<login>/doc' folder
doc: $(Doxygen) src/*
( cd src | doxygen $(Doxygen))
#rules to make objects ----------------------------------------------------------------------------------
$(RUN): $(Objects)
$(CC) $(CCFLAGS) $(Objects) -o $(RUN) $(LBFLAGS)
dvoram64/main: src/main.cpp
mkdir -p dvoram64
$(CC) $(CCFLAGS) -c src/main.cpp -o dvoram64/main
Could anybody tell me, what causes that and how to fix it?
You have several problems. First:
RUN=./dvoram64/main
$(RUN): $(Objects)
$(CC) $(CCFLAGS) $(Objects) -o $(RUN) $(LBFLAGS)
dvoram64/main: src/main.cpp
mkdir -p dvoram64
$(CC) $(CCFLAGS) -c src/main.cpp -o dvoram64/main
You have two rules for the same target(dvoram64/main). Which do you want to use? Why do you have two? Remove one of them.
Next:
Objects=dvoram64/main
RUN=./dvoram64/main
$(RUN): $(Objects)
...
You have two variables for (essentially) the same thing, which is untidy but not illegal. But You make one the prerequisite of the other. A thing cannot be it's own prerequisite, and Make must correct the error for you. You should rethink this.
Next:
RUN=./dvoram64/main
run: $(RUN)
$(RUN)
dvoram64/main: src/main.cpp
mkdir -p dvoram64
$(CC) $(CCFLAGS) -c src/main.cpp -o dvoram64/main
You have lost track of whether dvoram64/main should be an object file or an executable file. You have two rules to build it; one builds an executable, the other an object. You name it main, which sounds like an executable file, but you put that name in a variable called Objects. And in the end you build an object file and try to execute it.
You can save yourself some trouble by keeping the makefile as free of redundancy as possible. And when the big target fails, try the little targets one at a time to narrow nown the scope of the problem.
This is confusing. I have my Makefile:
OBJECTS =
INCLUDE_BUILD_PATH = /Users/wen/Projects/include
# Change compilation settings here
COMPILE = g++
override COMPILE_FLAGS += -O2
# Change linker/compiler specific settings here
LD_FLAGS :=
CC_FLAGS := -c -I$(INCLUDE_BUILD_PATH)/bigint
# Add source extensions here
SRC_EXT = cpp cc
# Add header dependencies here
HEADERS = $(wildcard *.hpp) $(wildcard $(INCLUDE_BUILD_PATH)/*/*.hh)
# Add source files here
CC_FILES = $(wildcard *.cpp) $(wildcard $(INCLUDE_BUILD_PATH)/*/*.cc)
CC_O_BUFFER = $(CC_FILES)
CC_O_BUFFER := $(CC_O_BUFFER:.cpp=.o)
CC_O_BUFFER := $(CC_O_BUFFER:.cc=.o)
OBJECTS = $(CC_O_BUFFER)
# Change .exe name here
EXE_NAME = maketest
# Link object files
$(EXE_NAME): $(OBJECTS)
$(COMPILE) $(COMPILE_FLAGS) $(LD_FLAGS) -o $# $^
# Build source files
define compile_rule
%.o : %.$1
$$(COMPILE) $$(COMPILE_FLAGS) $$(CC_FLAGS) -o $$# $$<
endef
$(foreach EXT,$(SRC_EXT),$(eval $(call compile_rule,$(EXT))))
# Clean
clean:
rm -f $(OBJECTS) $(EXE_NAME)
# Debug Build
debug:
#echo "Rerun with COMPILE_FLAGS=-D_DEBUG"
# Print variables
print:
#echo $(CC_FILES)
#echo $(OBJECTS)
#echo $(HEADERS)
it compiled successfully at first, but then it stopped for no reason and this was the output:
Yoshi-Air:maketest wen$ make
c++ -c -o maketest.o maketest.cpp
maketest.cpp:4:10: fatal error: 'BigIntegerLibrary.hh' file not found
#include "BigIntegerLibrary.hh"
^
1 error generated.
the problem was, I didn't even tell it to use "c++" in the Makefile but "g++" instead. Also, when I cleared CC_FLAGS the -c was still there. It's like Make's having a mind of it's own.
If I use make print to print out my variables it seems to be all right:
maketest.cpp /Users/wen/Projects/include/bigint/BigInteger.cc /Users/wen/Projects/include/bigint/BigIntegerAlgorithms.cc /Users/wen/Projects/include/bigint/BigIntegerUtils.cc /Users/wen/Projects/include/bigint/BigUnsigned.cc /Users/wen/Projects/include/bigint/BigUnsignedInABase.cc
maketest.o /Users/wen/Projects/include/bigint/BigInteger.o /Users/wen/Projects/include/bigint/BigIntegerAlgorithms.o /Users/wen/Projects/include/bigint/BigIntegerUtils.o /Users/wen/Projects/include/bigint/BigUnsigned.o /Users/wen/Projects/include/bigint/BigUnsignedInABase.o
maketest.hpp /Users/wen/Projects/include/bigint/BigInteger.hh /Users/wen/Projects/include/bigint/BigIntegerAlgorithms.hh /Users/wen/Projects/include/bigint/BigIntegerLibrary.hh /Users/wen/Projects/include/bigint/BigIntegerUtils.hh /Users/wen/Projects/include/bigint/BigUnsigned.hh /Users/wen/Projects/include/bigint/BigUnsignedInABase.hh /Users/wen/Projects/include/bigint/NumberlikeArray.hh
Any help or advice will be appreciated. Thanks!
Update
I updated my print to print the expected execution of compile:
print:
#echo $(CC_FILES)
#echo $(OBJECTS)
#echo $(HEADERS)
#echo "Compiles with:"
#echo $(COMPILE) $(COMPILE_FLAGS) $(LD_FLAGS) $(CC_FLAGS)
Result:
maketest.cpp /Users/wen/Projects/include/bigint/BigInteger.cc /Users/wen/Projects/include/bigint/BigIntegerAlgorithms.cc /Users/wen/Projects/include/bigint/BigIntegerUtils.cc /Users/wen/Projects/include/bigint/BigUnsigned.cc /Users/wen/Projects/include/bigint/BigUnsignedInABase.cc
maketest.o /Users/wen/Projects/include/bigint/BigInteger.o /Users/wen/Projects/include/bigint/BigIntegerAlgorithms.o /Users/wen/Projects/include/bigint/BigIntegerUtils.o /Users/wen/Projects/include/bigint/BigUnsigned.o /Users/wen/Projects/include/bigint/BigUnsignedInABase.o
maketest.hpp /Users/wen/Projects/include/bigint/BigInteger.hh /Users/wen/Projects/include/bigint/BigIntegerAlgorithms.hh /Users/wen/Projects/include/bigint/BigIntegerLibrary.hh /Users/wen/Projects/include/bigint/BigIntegerUtils.hh /Users/wen/Projects/include/bigint/BigUnsigned.hh /Users/wen/Projects/include/bigint/BigUnsignedInABase.hh /Users/wen/Projects/include/bigint/NumberlikeArray.hh
Yoshi-Air:maketest wen$ make print
maketest.cpp /Users/wen/Projects/include/bigint/BigInteger.cc /Users/wen/Projects/include/bigint/BigIntegerAlgorithms.cc /Users/wen/Projects/include/bigint/BigIntegerUtils.cc /Users/wen/Projects/include/bigint/BigUnsigned.cc /Users/wen/Projects/include/bigint/BigUnsignedInABase.cc
maketest.o /Users/wen/Projects/include/bigint/BigInteger.o /Users/wen/Projects/include/bigint/BigIntegerAlgorithms.o /Users/wen/Projects/include/bigint/BigIntegerUtils.o /Users/wen/Projects/include/bigint/BigUnsigned.o /Users/wen/Projects/include/bigint/BigUnsignedInABase.o
maketest.hpp /Users/wen/Projects/include/bigint/BigInteger.hh /Users/wen/Projects/include/bigint/BigIntegerAlgorithms.hh /Users/wen/Projects/include/bigint/BigIntegerLibrary.hh /Users/wen/Projects/include/bigint/BigIntegerUtils.hh /Users/wen/Projects/include/bigint/BigUnsigned.hh /Users/wen/Projects/include/bigint/BigUnsignedInABase.hh /Users/wen/Projects/include/bigint/NumberlikeArray.hh
Compiles with:
g++ -O2 -c -I/Users/wen/Projects/include/bigint
That proves that make knows what I wanted, but when it builds it's completely different: c++ instead of g++?!
Update 2:
c++ invokes clang, installed on my system.
Solution by Alex B:
But from the compilation command line it looks like Make is trying to
use the implicit suffix rule, and ignores your pattern rule.
I tried .SUFFIXES: and yes, it reported a no-rule found. Thanks, I will go and consult the manual.
As I stated in the comment, it works in my environment (Mac OSX, GNU Make 3.81), so the issue may be that the makefile you've posted is incomplete or you are using a different version of Make.
But from the compilation command line it looks like Make is trying to use the implicit suffix rule, and ignores your pattern rule.
You can tell Make to ignore default rules by specifying an empty list of suffixes, so you can debug your issue further.
.SUFFIXES: