Makefile syntax using -o and -c in c++ - c++

It's been a while since I've done a makefile. I have inherited some code that is built with the following line in a makefile
$(CC) $(FLAGS) -c -o $*.o $*.cpp
Why would you use -c and -o in the same line. Doesn't the -c make it so that you build the objects without linking?
EDIT Here is the complete makefile, now I get an error saying cpp.cpp No such file or directory
.SUFFIXES: .o .cpp
CC=g++
MAIN_OBJS = \
main.o \
f1.o \
f2.o \
all:
$(CC) -c -o $*.o $*.cpp
$(CC) $(MAIN_OBJS) -o final
Shouldn't the $*.cpp find all the .cpp files in my current path (and they are there)

As you say, -c means make object files without linking.
-o means you want to override the default output file name and specify your own. So -o $.o means the output file name would be the same as the input file name but with .o on the end.
You might do this if you were planning to have this Makefile rule usable with a number of different compilers, some of which might have a different default output file name for object files.
The man page for gcc describes -o like this:
-o file
Place output in file file. This applies regardless to whatever sort of output is being produced, whether it be an executable file, an
object file, an assembler file or preprocessed C code. If -o is not
specified, the default is to put an executable file in a.out, the
object file for source.suffix in source.o, its assembler file in
source.s, a precompiled header file in source.suffix.gch, and all
preprocessed C source on standard output.

Yes, what you said makes sense.
As we know,-c will compile the source files and produce the assembly files.
After that, we normally use -o to link all those assembly files and produce a executable file.
What follows -o is the name of the output executable file.
And if the -c and -o are used in the same line, it means the output assembly file produced by -c is named what follows -o.

Related

How to write makefile for a target that includes a header file?

I have two files "create-exercise.cpp" and "exercise.hpp". I want to write a makefile to use gnu++17 and g++ to compile them. exercise.hpp is included in create-exercise.cpp. I only want to get a binary out of create-exercise.cpp. the command I would use is g++ -std=gnu++17 create-exercise.cpp -o create-exercise and it works well. I tried using the following in a make file.
CXXFLAGS=-Wall -std=gnu++17
create-exercise: create-exercise.cpp exercise.hpp
but that generated the following g++ -Wall -std=gnu++17 create-exercise.cpp exercise.hpp -o create-exercise I don't want exercise.hpp to be included in the compilation command. I also tried to use the following instead.
CXXFLAGS=-Wall -std=gnu++17
create-exercise.o: create-exercise.cpp exercise.hpp
That generated g++ -Wall -std=gnu++17 -c -o create-exercise.o create-exercise.cpp. I don't want the -c flag. because when I try to run create-exercise.o that results in permission denied error. I tried the following as well:
CXXFLAGS=-Wall -std=gnu++17
create-exercise.o: create-exercise.cpp exercise.hpp
$(CXX) $(CXXFLAGS) create-exercise.cpp -o create-exercise.o
but when I edit exercise.hpp make says 'create-exercise.o' is up to date. and doesn't recompile it. what should I do?
The rule to write in your makefile would be:
create-exercise.o: exercise.hpp
This is a rule without a recipe, and it simply adds one more prerequisite (exercise.hpp) to the target create-exercise.o, i.e., whenever exercise.hpp changes, create-exercise.o should be rebuilt.
However, the problem when providing that rule is that GNU Make assumes create-exercise.o is an object file generated from a C source file when building create-exercise. Therefore, it doesn't link the C++ library but the C library instead, that's why you are having the liking error of undefined reference to std::cout.
GNU Make has the following implicit rule for generating an executable from a C++ source file:
%: %.cpp
# commands to execute (built-in):
$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $#
You can use that rule's recipe to build create-exercise from creating-exercise.o and still treat creating-exercise.o as an object file that was generated from a C++ source file:
create-exercise: create-exercise.o
$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $#
The whole makefile would be then:
CXXFLAGS = -Wall -std=gnu++17
create-exercise: create-exercise.o
$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $#
create-exercise.o: exercise.hpp
The target create-exercise also becomes the default goal because it's the first rule in the makefile. It's the target to build if you don't specify any to make.
You can do this:
CXXFLAGS = -Wall -std=gnu++17
create-exercise: create-exercise.o
$(LINK.cpp) $^ $(LDLIBS) -o $#
create-exercise.o: exercise.hpp
This says: build create-exercise from the object file create-exercise.o, if it's changed. And it says rebuild create-exercise.o if the header file exercise.hpp changes; it's not right to modify or rebuild a source file if a header changes. It's the object file that depends on the header.
Make has a number of built in rules. Among them are rules that know how to link a program but unfortunately that assumes your object files were built from C files, so if you're using C++ you have to create a specific recipe. But you can still use GNU make's default variables.
It also knows how to build a .o file from a .cpp file on its own: you don't need to write that recipe.
I am not sure, but maybe try to include the .hpp file instead of compiling it with the other file. You can do so by using g++ *.cpp -I *.hpp -o output
Try it out and let me know if it works for you.

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.

Makefiles: specific 'no input files', automatic variables

I'm new to makefiles, and they puzzle me. I have the following folder hierarchy:
A folder named lib contains tow folders: include (with file mylib.h) and src (with file mylib.cpp). It also contains a Makefile, which, for some reason, gives me an error.
The full makefile is:
CFLAGS = -Wall -fPIC
OBJECTS = mylib.o
all: libmine.so
libmine.so: $(OBJECTS)
g++ -shared $(CFLAGS) \
-o libmine.so \
$(OBJECTS)
%.o: src/%.cpp include/%.h
g++ $(CFLAGS) \
-I include \
-o %.o \
-c src/%.cpp
clean:
rm src/*.o
rm libmine.so
The error is
mr209#Quantum:~/Desktop/hw1/lib$ make
g++ -Wall -fPIC \
-I include \
-o %.o \
-c src/%.cpp
g++: error: src/%.cpp: No such file or directory
g++: fatal error: no input files
compilation terminated.
make: *** [mylib.o] Error 4
But the file is present. Thus, make is doing weird things, causing it not to be able to find the .cpp file.
In order to make libmine.so, g++ will have to do something with mylib.o, and for a generic .o file I have written some lines of code.
Here is what I was thinking: in order to make libmine.so, g++ will have to do something with mylib.o. Thus, in lib, a file named mylib.o has to appear. Using the generic %.0 rule, this file is made from mylib.cpp in src and mylib.h in include (hence the first line of the %.o rule). The file is made using g++, which has to look in include for additional headers, produces mylib.o as output, and compiles src/mylib.cpp, but -c guarantees that a .o file is produced.
Obviously, something goes wrong, and I am unable to figure out what. Only 2 days ago have I learned what Makefiles are and why one should learn how to deal with them, so I'm not that much of an expert.
Your build target %.o is miswritten. You can't use the % in the command section, so the names of the destination file and dependent file won't ever match.
The proper change is to do the following:
%.o: src/%.cpp include/%.h
g++ $(CFLAGS) \
-I include \
-o $# \
-c src/$(#:%.o=%.cpp)
Just to explain the changes, the -o needs the target file, which is pretty much always written as $# in Makefiles, as that's the name of the target.
Secondly, the source file needs to be defined in terms of the target, the operator in question is a pattern replacement operator $(#:%.o=%.cpp), so what that does is take the target - which will match a filename of <blah>.o, then it pattern match replaces .o with .cpp.
So in the case of the target mylib.o, the variable $# is mylib.o, and the result of doing $(#:%.o=%.cpp) is to turn mylib.o into mylib.cpp. As a result it is the expected file that is being compiled, and the expected target is build.
Rules using a % pattern in them are what are referred to as implicit rules, and are used to reduce the complexity of the code being written - if you had a pile of files that shared the target pattern: blah.o: src/blah.cpp src/blah.h, then you use the implicit rule to only have to write the target once, then you need to write the commands in terms of the target.
You must do a variable before put it in g++
like :
FT_C= $(src/%.cpp)
FT_O=$(FT_C:.c=.o)
and
g++ $(CFLAGS) -I include -o $(FT_O) -c $(FT_C)
and don't put your .h in compilation '-I' are here for it.
Look this example if you want understand what i mean:
https://github.com/emericspiroux/wolf3d/blob/master/libft/Makefile

My C++ makefile can not create object file for each .cpp code

My makefile compiles our C++ code without any problems but it can not create object files.
How do I need to modify this file in order to create the object file for each .cpp file?
Is there any problem if I proceed without creating an object file for each .cpp file ?
My makefile looks like this:
engine:main.cpp correlation.cpp correlation.h matcher.cpp matcher.h scheduler.cpp scheduler.h parser.cpp parser.h cache_manager.cpp cache_manager.h init.cpp init.h db_manager.cpp db_manager.h
g++ -o engine main.cpp correlation.cpp correlation.h matcher.cpp matcher.h scheduler.cpp scheduler.h parser.cpp parser.h cache_manager.cpp cache_manager.h init.cpp init.h db_manager.cpp db_manager.h -lpthread -lboost_regex -I/usr/include -ggdb \
-I/usr/include/oracle/11.1/client \
-L$(ORACLE_HOME)/lib -lclntsh -locci
clean:
rm -f engine
There's no problem if you skip naming object files. They'll still be created behind the scenes though.
The advantage of specifically creating object files is that you'll save time recompiling, since make will be able to skip any object file it doesn't have to recreate (since it's up-to-date; something that won't work with temporary files as they're deleted).
The easiest way to get this working is by using a special placeholder syntax in your makefile:
%.o: %.cpp
g++ -c -o $# $< $(YOUR_OTHER_PARAMS)
In this example you define a generic recipe for any file ending in .o to requiring a file with the same name ending in .cpp. $# is a special macro that will expand to the current output file, while $< will include the current input file.
In a similar way you may define macros for other files as well:
%.png: %.bmp
myinmageconverter -png $< $#
You can still name specific recipes, e.g. for cases where one specific file needs additional or different parameters. Just name it in your makefile as usual. The placeholder syntax will only try to match otherwise unmatched targets.
If you'd like to mention some generic or precompiled header, you can still include it (just like any other dependency):
%.o: %.cpp common.hpp
g++ -c -o $# $< $(YOUR_OTHER_PARAMS)
For the actual executable, you can then just define your components as usual, i.e. your example could look like this:
engine: main.o correlation.o matcher.o scheduler.o ...
g++ -o engine main.o correlation. matcher.o ...
%.o: %.cpp
g++ -c -o $# $< -lpthread -lboost_regex -I/usr/include -ggdb ...

Adding dependency on a non-compiled file in a Makefile

I have the following code generation scheme:
The original file is *.c.macro
It is processed by a special program that generates the *.c file. The program uses external XML files mentioned in the original .c.macro file. Somthing along this line:
macroprocess foo.c.macro -o foo.c
Then the *.c file is compiled to *.o normally
What I want to do is to make the .c file dependant on the XML files. So that if the XML changes, macroprocessing is automatically redone when 'make' command is invoked.
I can modify the code of the macroprocessor so that it would generate a list of all XMLs and write it somewhere, but I have no idea how to incorporate it into a makefile. Apparently I would need to play with 'include' command in the makefile, but usually it's employed to add dependencies on actual code like .h files.
If you can get your macroprocess to write a dependency file (e.g. *.xmldep) for each *.c.macro file you can do:
-include $(C_MACRO:.c.macro=.xmldep)
where $(C_MACRO) is a variable that contains your *.c.macro files.
The - in front will ensure that the first time, the make will not fail when it cannot locate the dependency files.
You can add foo.xml as a dependency of foo.c and use a filter command to get only the %.c.macro file as arguments for macroprocess.
Something like this:
# Basic targets
all: foo
foo: foo.o
gcc -o $# $^
foo.o: foo.c
gcc -o $# -c $<
# Special target with filter
foo.c: foo.c.macro
macroprocess -o $# $(filter %.c.macro,#^)
# Adding foo.xml as a dependency of foo.c
foo.c: foo.xml
.PHONY: all foo