Gnu Make: Strange "Multiple targets pattern" - error - c++

I have started a SDL2-project where I have a source file containing the main function which depends on several of my own header and object files which are in other folders. My directory structure is as follows
/SDL2 // Top-Level directory of all my SDL2 projects
-> /projectX // My current project
-> main.cpp
-> /obj_sdl2_ana // Directory of all self-made object files
-> ...object files
-> ...source files of object files
-> /include_sdl2_ana // Directory of all self-made header files
-> ..header files
To compile and link main.cpp against my object and header files I have written the following Makefile
TARGET = main
FILETYPE = cpp
OBJDIR = ../obj_sdl2_ana/ # Directory with self-made object files
INCDIR = ../include_sdl2_ana/ # Directory with self-made header files
IFLAGS = -I$(INCDIR)
LFLAGS = -lSDL2 -lSDL2_image # insert all necessary libraries into it
VPATH = $(OBJDIR):$(INCDIR)
ADD_RESOURCES = common_ana
ADD_INC := $(ADD_RESOURCES:%=$(INCDIR)%.hpp) # specify header files which are prerequisites
ADD_OBJ := $(ADD_RESOURCES:%=$(OBJDIR)%.o) # specify additional object files which are prerequisites
$(TARGET): $(TARGET).o $(ADD_OBJ)
g++ $(TARGET).o $(ADD_OBJ) -g3 -o $(TARGET) $(LFLAGS)
$(TARGET).o: $(TARGET).$(FILETYPE) $(ADD_INC)
g++ -c $(TARGET).$(FILETYPE) $(IFLAGS) -g3 -o $(TARGET).o $(LFLAGS)
$(ADD_OBJ): $(OBJDIR)%.o: $(OBJDIR)%.cpp $(INCDIR)%.hpp
g++ -c $< $(IFLAGS) -g3 -o $# $(LFLAGS)
I have tested this with only one object file (common_ana.o) and the corresponding header file (common_ana.hpp) but the problem is that make is tossing a "Multiple target pattern" error at the rule
$(ADD_OBJ): $(OBJDIR)%.o: $(OBJDIR)%.cpp $(INCDIR)%.hpp
g++ -c $< $(IFLAGS) -g3 -o $# $(LFLAGS)
I have absolutely no clue, why this error appears. The Gnu make manual suggests that this error appears when there is a misuse of static pattern rules. But I have triple-checked my Makefile and couldn't find anything which would justify the error message of gnu make. While I'm aware of a workaround, I would be really glad if someone could give me a hint, what I have done wrong with respect to the above static pattern rule.

Make is including the extra space before your comments, try something the following
# Directory with self-made object files
OBJDIR = ../obj_sdl2_ana/
# Directory with self-made header files
INCDIR = ../include_sdl2_ana/
IFLAGS = -I$(INCDIR)
# insert all necessary libraries into it
LFLAGS = -lSDL2 -lSDL2_image
Same applies to the other lines, it's best to avoid inline comments.

Related

Makefile not allowing me to specify directory for object files

My Makefile is located in the current working directory. I am trying to put all my object files in the directory ./bin/obj and my executable in the directory ./bin. However, when I follow the method described here: How to place object files in separate subdirectory and in several other StackOverflow questions, I'm unable to get my *.o files to be written to the desired directory; they're created in the directory containing my Makefile. Below is an excerpt from my Makefile (the dots are just rules for many more source files, omitted for brevity). Please note that the Makefile worked until I tried to change the output directory.
CXX=g++
CXXFLAGS=-O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3
LINKFLAGS=-O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3
SRC=src
BIN=bin
OBJ=$(BIN)/obj
BAREBONES=$(SRC)/universal.h $(SRC)/parameters.h
HEADERS=$(wildcard *.h)
ALLOBJS=$(OBJ)/assignDomain.o $(OBJ)/assignDomains.o ...
all: $(BIN)/ngl.x
$(OBJ)/assignDomain.o: $(BAREBONES) $(SRC)/assignDomain.cpp $(SRC)/Domain.h $(OBJ)/Domain.o $(SRC)/Kingdom.h $(OBJ)/Kingdom.o $(SRC)/Sp.h $(OBJ)/Sp.o
$(CXX) $(CXXFLAGS) -c $(SRC)/assignDomain.cpp
$(OBJ)/assignDomains.o: $(BAREBONES) $(OBJ)/assignDomain.o $(SRC)/assignDomains.cpp $(SRC)/Domain.h $(OBJ)/Domain.o $(SRC)/Kingdom.h $(SRC)/Sp.h $(OBJ)/Sp.o
$(CXX) $(CXXFLAGS) -c $(SRC)/assignDomains.cpp
#...more rules...
$(BIN)/ngl.x: $(BAREBONES) $(ALLOBJS) $(wildcard *.h)
$(CXX) $(ALLOBJS) $(LINKFLAGS) -o $(BIN)/ngl.x
#...more rules...
clean:
rm -f $(OBJ)/*.o $(OBJ)/*.gch $(BIN)/ngl.x
.phony: all clean
The output is as follows:
/usr/local/include/eigen3 -c ./src/assignDomain.cpp
g++ -O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3 -c ./src/assignDomains.cpp
g++ -O0 -march=native -std=c++11 -fopenmp -isystem /usr/local/include/eigen3 -c ./src/evict.cpp
g++ ./bin/obj/assignDomain.o ./bin/obj/assignDomains.o /usr/local/include/eigen3 -o ./bin/ngl.x
g++: error: ./bin/obj/assignDomain.o: No such file or directory
g++: error: ./bin/obj/assignDomains.o: No such file or directory
#...same error, for the other rules...
g++: fatal error: no input files
compilation terminated.
Makefile:94: recipe for target 'bin/ngl.x' failed
make: *** [bin/ngl.x] Error 1
Just to be clear: there is no built-in rule in make which knows how to compile a source file in one directory and put the object file into a different directory. If you want to do that, you have to write your own rule. When you write your own rule you have to provide the -o option: there's no way for the compiler to know that in your makefile you specified a different output directory, unless you tell it with the -o flag. The compiler doesn't parse your makefile!
You can write a pattern rule like this:
$(OBJ)/%.o : $(SRC)/%.c
$(CXX) $(CXXFLAGS) -c $< -o $#
Then you don't need any explicit rules, although you do need to define the prerequisites. Other notes about your makefile:
It's never correct to have .o files depend on other .o files.
It's never correct to have executable files depend on header files.
Object files list source and header files as prerequisites. Executable files list object files (and libraries, if you have any) as prerequisites. You should write your prerequisites like this:
$(OBJ)/assignDomain.o: $(SRC)/assignDomain.cpp $(BAREBONES) $(SRC)/Domain.h $(SRC)/Kingdom.h $(SRC)/Sp.h
$(OBJ)/assignDomains.o: $(SRC)/assignDomains.cpp $(BAREBONES) $(SRC)/Domain.h $(SRC)/Kingdom.h $(SRC)/Sp.h
...other prerequisites...
$(BIN)/ngl.x: $(ALLOBJS)
$(CXX) $^ $(LINKFLAGS) -o $#
Your explicit compilation rule is disabling Make's knowledge of how to compile files in subdirectories, and so you get exactly what your rule says, and nothing else. You don't specify an -o option, so you are not telling g++ where to put the output file; so it follows its built-in default, and simply creates a file ./a.out (!).
The most straightforward solution is to not override the built-in rules. Make already knows how to create an .o file from a .cpp file with the same base name; you only need to declare the dependencies and flags in your Makefile.
For legibility, I have refactored the shared dependencies into a separate variable.
SHAREDDEPS := $(SRC)/Domain.h $(OBJ)/Domain.o \
$(SRC)/Kingdom.h \
$(SRC)/Sp.h $(OBJ)/Sp.o
$(OBJ)/assignDomain.o: $(BAREBONES) $(SRC)/assignDomain.cpp \
$(SHAREDDEPS) $(OBJ)/Kingdom.o
# No $(CXX) anything here!
$(OBJ)/assignDomains.o: $(BAREBONES) $(OBJ)/assignDomain.o \
$(SRC)/assignDomains.cpp $(SHAREDDEPS)
# Here either!
I wrapped the dependencies across multiple lines for legibility (notice the final backslash on the first line) but you should notice that they are a single logical line, and only specify dependencies, not how to actually compile anything.
It's not clear how the depended *.o files are supposed to figure into this; my speculation, based on your explicit rules which I am removing, is that these are not actually used in compilation, and so are not actually true dependencies.

Link .h files and .c files from different directory using makefile

I'm trying to compile a program called um from a current folder with um.c
and include some external implementations. The .h files are in one directory but the .c files implementing these .h files are in a different directory. Below is my makefile. It seems that the compiler knows where to look for the .h file. However, the linker fails and produces the error:
ld: symbol(s) not found for architecture x86_64
clang: fatal error: linker command failed with exit code 1
Makefile:
# define the C compiler to use
CC = gcc
# define any compile-time flags
CFLAGS = -g -O -Wall -Wextra -Werror -Wfatal-errors -std=c99 -pedantic
# define any directories containing header files other than /usr/include
INCLUDES = -I/Users/nguyenmanhduc/Documents/C\ library/cii/include
# define library paths in addition to /usr/lib
LFLAGS = -L/Users/nguyenmanhduc/Documents/C\ library/cii/src
# define any libraries to link into executable:
LIBS = -lm
# define the C source files
SRCS = um.c
# define the C object files
OBJS = $(SRCS:.c=.o)
# define the executable file
MAIN = um
.PHONY: depend clean
all: $(MAIN)
#echo Simple compiler named um has been compiled
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $#
clean:
$(RM) *.o *~ $(MAIN)
depend: $(SRCS)
makedepend $(INCLUDES) $^
This question might seem weird because I have little experience with makefile but is there a way that I can link .h and .c files in different folders using makefile.
Thanks!
The problem here is not that your additional .c files are in different directories: it's that you didn't tell your Makefile that they exist at all!
Here's where you list the source inputs (I guess you didn't see the comment?):
# define the C source files
SRCS = um.c
Add the other .c files whose compiled .os are what you want to link.
For example:
# define the C source files
SRCS = um.c ../wot.c ../hah/lol.c
There is no hard and fast rule but, the way you've constructed this Makefile, those relative paths should resolve just fine.
You don't link .c files, you link .o files.
You appear to be stating is that some of your .c files are in a different directory.
No matter, you have to explicitly list those .c files, in your makefile, just like you are listing the .c files in the directory with the makefile. You have to compile the .c files in a different directory, and then link them, just like you're compiling and linking the .c files in the same directory as the makefile. They're not going to compile themselves.
Another approach would be to have a separate makefile in that other directory, that compiles and builds an archive library, and then in this directory link with that archive library.

Makefile with two targets and two languages

I work with C and C++ and thanks to this answer I was able to compile and run my project. Now I am writing a makefile to spare time. But things are getting complicated :
Project structure
project
makefile
client
bin
src
c
cc
java
server
...
# Directories
# CLIENT
CLIENT_BIN_DIR = /client/bin/
CLIENT_SRC_C_DIR = /client/src/c/
CLIENT_SRC_CC_DIR = /client/src/cc/
CLIENT_SRC_JAVA_DIR = /client/src/java/
# SECC
SERVER_BIN_DIR = /server/bin/
SERVER_SRC_C_DIR = /server/src/c/
SERVER_SRC_CC_DIR = /server/src/cc/
SERVER_SRC_JAVA_DIR = /server/src/java/
# Files
# CLIENT
CLIENT_BIN = ${CLIENT_BIN_DIR}client_app
CLIENT_SRC_C = ${wildcard ${CLIENT_SRC_C_DIR}*.c}
CLIENT_SRC_CC = ${wildcard ${CLIENT_SRC_CC_DIR}*.cc}
CLIENT_SRC_JAVA = ${wildcard ${CLIENT_SRC_JAVA_DIR}*.java}
# SERVER
SERVER_BIN = ${SERVER_BIN_DIR}server_app
SERVER_SRC_C = ${wildcard ${SERVER_SRC_C_DIR}*.c}
SERVER_SRC_CC = ${wildcard ${SERVER_SRC_CC_DIR}*.cc}
SERVER_SRC_JAVA = ${wildcard ${SERVER_SRC_JAVA_DIR}*.java}
# Flags
CFLAGS = -g -W -Wall
IFLAGS = -I${INC_DIR}
# Compilers
C = gcc
CC = g++
# Rules
all: ${CLIENT_BIN} ${SERVER_BIN}
${CLIENT_BIN}:
${SERVER_BIN}:
// NEED HELP HERE
Now that I have all the sources files, what should I write to the followings steps to every files :
gcc -c -o file.o file.c
g++ -c -o file.o file.cc -I/PATH_TO_C_HEADER
g++ -o APP_NAME C_O_FILES CC_O_FILES
make has built-in rules for compiling C and C++ files into object files, you can use those instead of writing your own by using the built-in flags they expect. Similarly make has a rule for building a binary from object files (as long as the binary matches one of the source files exactly).
Compiling C programs
n.o is made automatically from n.c with a recipe of the form ‘$(CC) $(CPPFLAGS) $(CFLAGS) -c’.
Compiling C++ programs
n.o is made automatically from n.cc, n.cpp, or n.C with a recipe of the form ‘$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c’. We encourage you to use the suffix ‘.cc’ for C++ source files instead of ‘.C’.
Linking a single object file
n is made automatically from n.o by running the linker (usually called ld) via the C compiler. The precise recipe used is ‘$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)’.
This rule does the right thing for a simple program with only one source file. It will also do the right thing if there are multiple object files (presumably coming from various other source files), one of which has a name matching that of the executable file. Thus,
x: y.o z.o
when x.c, y.c and z.c all exist will execute:
cc -c x.c -o x.o
cc -c y.c -o y.o
cc -c z.c -o z.o
cc x.o y.o z.o -o x
rm -f x.o
rm -f y.o
rm -f z.o
In more complicated cases, such as when there is no object file whose name derives from the executable file name, you must write an explicit recipe for linking.
Each kind of file automatically made into ‘.o’ object files will be automatically linked by using the compiler (‘$(CC)’, ‘$(FC)’ or ‘$(PC)’; the C compiler ‘$(CC)’ is used to assemble ‘.s’ files) without the ‘-c’ option. This could be done by using the ‘.o’ object files as intermediates, but it is faster to do the compiling and linking in one step, so that’s how it’s done.
So just set the right flags (as used in those rules) and add the right .o file prerequisites to your binary targets and you should be done.
If you must use make, this could help get you started (just for C files):
# CLIENT
CLIENT_BIN_DIR = client/bin/
CLIENT_SRC_C_DIR = client/src/c/
# CLIENT
CLIENT_BIN = $(CLIENT_BIN_DIR)client_app
CLIENT_SRC_C = $(wildcard $(CLIENT_SRC_C_DIR)*.c)
CLIENT_SRC_C_O = $(CLIENT_SRC_C:.c=.o)
CLIENT_SRC_C_D = $(CLIENT_SRC_C:.c=.d)
# Flags
CFLAGS = -g -W -Wall
IFLAGS = -I$(INC_DIR)
# Compilers
C = gcc
#Create header dependency files (included headers are dependencies too)
%.d: %.c
$(C) $(CFLAGS) -MM -MF $# -MT $*.o $<
#include will remake the dependency files if they need to be
-include $(CLIENT_SRC_C_D)
#O files will be created via the implicit rule
$(CLIENT_BIN): $(CLIENT_SRC_C_O)
$(C) $(CFLAGS) $(LDFLAGS) $^ -o $(#)
all: $(CLIENT_BIN)
https://www.gnu.org/software/make/manual/make.html is really helpful.
Otherwise, if you can, I recommend tup, which is easier, more flexible, faster, and more advanced than make.
# client binary depends on c and c++ .o's
$(CLIENT_BIN): $(CLIENT_SRC_C:.c=.o) $(CLIENT_SRC_CC:.cc=.o)
# server binary depends on c and c++ .o's
$(SERVER_BIN): $(SERVER_SRC_C:.c=.o) $(SERVER_SRC_CC:.cc=.o)
# example header dependency (file.cc depends on file.h and file1.h)
$(CLIENT_SRC_CC_DIR)file.o: $(CLIENT_SRC_CC_DIR)file.h $(CLIENT_SRC_CC_DIR)file1.h
GNU Make has implicit rules for compile C and C++ source files and generating the final binary, so there's no need to rewrite them.
Also, you might want to RTFM.

How do I write a smart makefile?

I'm new to linux and new to makefiles so I'm a little stumped at this point. I've been staring the make manual for an hour now and figured I would just ask:
I want to create a makefile for a relatively small project, whose source files are in proj/src/, and within subdirectories of that location. I have written a makefile at proj/makefile and want to use it to gather up all the source files, find their dependencies, and compile the result into proj/build/. Here is what I've written:
# here are my files and directories (there are also header files that are not
# listed here, but these are referred to from within the .cpp files with
# respect to the proj/src directory)
# proj/makefile
# proj/src/
# proj/src/main.cpp
# proj/src/dir1/
# proj/src/dir1/source1.cpp
# proj/src/dir2/
# proj/src/dir2/source2.cpp
# proj/build/
srcDir = src/
buildDir = build/
# This is a list of all the object files (can I get this programatically?)
objects = main.o source1.o source2.o
all: prog
# Here I want to compile all source (.cpp) files from src/ and all of its subdirectories, and to find the dependencies I want to call g++ -MM to automatically generate the list:
%.o: %.cpp
$(CXX) $(CXXFLAGS) -MM -I $(srcDir)
clean:
rm -rf *o $(buildDir)/prog
This is far from functional but I wanted to give it ago before asking. Running this gives
make: * No rule to make target main.o', needed byprog'. Stop.
So presumably my attempt at automatically writing the object files failed. If someone could give me some direction that would be great, I'm hoping that between the comments and code you can make out the intention.
EDIT: I have now tried the following:
SHELL := /bin/bash
srcDir = src
buildDir = bin
sources := $(shell find $(srcDir) -name *.cpp)
objects := $(sources:%.cpp=%.o)
-include $(sources:%.cpp=%.d)
# This is a list of all the object files (can I get this programatically?)
all: prog
prog: $(objects)
g++ $(objects) -o $(buildDir)/prog
# Here I want to compile all source (.cpp) files from src/ and all of its subdirectories, and to find the dependencies I want to call g++ -MM to automatically generate the list:
%.o: %.cpp
$(CXX) $(CXXFLAGS) -MMD -MP -c -I $(srcDir)
clean:
rm -rf *o $(buildDir)/hello
But when I run this I get the following error:
g++ -MMD -MP -I src
g++: fatal error: no input files
compilation terminated.
make: *** [src/core/Cell.o] Error 1
It wants to build main.o from main.cpp, but there is no main.cpp at the top level. You could specify the full paths of the object files, if they are to be built alongside the source files:
objects = $(srcDir)/main.o $(srcDir)/dir1/source1.o $(srcDir)/dir2/source2.o
can I get this programatically?
I do it using gnumake's shell function:
SHELL := /bin/bash
sources := $(shell find $(srcDir) -name *.cpp)
objects := $(sources:%.cpp=%.o)
to find the dependencies I want to call g++ -MM to automatically generate the list
Use -MMD to generate dependency files as well as compiling. It's also a good idea to specify -MP here - that makes sure the dependencies are correctly updated when you remove a header. Given the variables defined above, you can include the dependency files with
-include $(sources:%.cpp=%.d)

syntax error near unexpected token `newline'

After compiling some code using a Makefile I get this when I try to run it:
$ ./libbookgui.a
./libbookgui.a: line 1: syntax error near unexpected token `newline'
./libbookgui.a: line 1: `!<arch>'
The Makefile has the following contents.
INCLUDES = -I"$(FLTK)"
LIBS = -lstdc++
CXXFLAGS = $(INCLUDES) -Wall -time -O3 -DNDEBUG -Wno-deprecated
LIBFLAGS =
AR = ar
.SUFFIXES: .cpp .o
# Create a list of source files.
SOURCES = $(shell ls *.cpp)
# Create a list of object files from the source file lists.
OBJECTS = ${SOURCES:.cpp=.o}
# Create a list of targets.
TARGETS = libbookgui.a
# Build all targets by default
all: $(TARGETS)
%.a: $(OBJECTS)
$(AR) rcs $# $(OBJECTS)
# A rule to build .o file out of a .cpp file
%.o: %.cpp
$(CXX) $(CXXFLAGS) -o $# -c $<
# A rule to clean all the intermediates and targets
clean:
rm -rf $(TARGETS) $(OBJECTS) *.out *.stackdump
I see that it has the line TARGETS = libbookgui.a and the compiler doesn't return any errors it just creates the .a file.
Any ideas?
libbookgui.a is a static library (that aggregates several object files in it).
You are supposed to run executables, not libraries. Link this library into some executable and run that.
I suggest you read this article.
You need to update your post to show the changes you made to the makefile to get the link line added. Without that we can't really help you with that part of the problem.
Based on the errors my suspicion is that you're not using the right tool for linking: you're either using "gcc" (C compiler front-end) or trying to invoke the linker directly. When you link your application you should use the C++ compiler (in your case, $(CXX)). You also don't need to specify -lstdc++, since the C++ front-end will automatically add that to the link line.