First attempt at makefiles - c++

I am writing my first second makefile because I need to understand them before I can actually start my C++ project. Here's the files I'm trying to link:
/storage/emulated/0/cpptest/test.h
#ifndef TEST_H_DEF
#define TEST_H_DEF
class Test {
private:
int value;
public:
Test(int);
operator int();
Test operator + (Test);
};
#endif
/storage/emulated/0/cpptest/test.cpp
#include "test.h"
Test::Test(int new_value):
value(new_value) {}
Test::operator int() {
return value;
}
Test Test::operator + (Test other) {
return Test(value + int(other));
}
/storage/emulated/0/cpptest/main.cpp
#include <iostream>
#include "test.h"
int main() {
Test o1(12);
Test o2(18);
std::cout << int(o1) << '\n';
std::cout << int(o2) << '\n';
std::cout << int(o1 + o2) << std::endl;
}
And here's my attempt at a (maintainable) makefile:
CC = g++
default: test
#I'm actually using four spaces here on SO
test: main.o test.o
$(CC) -o test main.o test.o
#my issue starts here: what does main.o depends on? My guess is main.cpp only (which is really /storage/emulated...main.cpp)
main.o: main.cpp
$(CC) -o main.o /storage/emulated/0/cpptest/main.cpp
#same with test.o
test.o: test.cpp
$(CC) -o test.o /storage/emulated/0/cpptest/test.cpp
And then? Am I fine now? How do I handle the issue of test.h being updated without make knowing about it?
Also did I get the usage of .h and .cpp files right while writing my files?

gcc can generate dependencies for you. So rather than manually typing out what all dependencies your source files have (which will inevitably be wrong or incomplete), use the compiler:
default: test
.PHONY : default
compiler := g++
objects := main.o test.o
depends := $(objects:.o=.d)
# include the depends rules if they exist
-include $(depends)
# test depends on all the objects, compiled together
test : $(objects)
$(compiler) -o $# $^
# each object depends on its source file
# the recipe here will both compile the source file and generate its dependencies
%.o : %.cpp
$(compiler) -o $# -c $< -MP -MMD -MF $(#:.o=.d)
This will generate files for you named main.d and test.d which will contain makefile rules with the actual dependencies of main.cpp and test.cpp.
Whenever you're in doubt about the validity of your makefiles, it's always helpful to run make -pn and examine everything that's printed there. That will help make sure your dependencies are entirely the way they should be.
For example, the first time you compile, the *.d files won't exist, so the include $(depends) command will fail (silently because of -include), and this makefile creates a dependency graph that looks like:
You should read this as any node needs to have its recipes rerun if any of its children have been updated (I filled in default blue because it's a phony rule.). So main.o needs to be recompiled whenever main.cpp gets updated. Note that there is no dependency on test.h! This may seem like a mistake, but we have to recompile everything anyway, so we're not missing out. After we compile the first time, we'll have generated the *.d files and then we bring those into our include, and the new dependency graph looks like:
which is exactly what we want.

The dependency of test.h is for both test.cpp and main cpp:
CC = g++
default: test
test: main.o test.o
$(CC) -o test main.o test.o
main.o: main.cpp test.h
$(CC) -o main.o /storage/emulated/0/cpptest/main.cpp
test.o: test.cpp test.h
$(CC) -o test.o /storage/emulated/0/cpptest/test.cpp
The idea is that if something changes within test.h both test.o and main.o must be remade.

Related

Makefile with an Implementation and Header Files

Every question I've seen on here is dealing with much more complicated use cases than I am.
I'm in a first year programming course and just can't understand what I am doing incorrectly. When running make I just get a Circles is up to date message.
I have three files:
main.cpp => entry point for the program
CircleDriver.cpp => an implementation file
circle.h => a header file containing the header class.
main.cpp depends on CircleDriver.cpp and circle.h, CircleDriver.cpp depends on circle.h
Currently my Makefile looks like this:
Circles: main.o
g++ -std=c++11 -g -Wall main.o -o Circles
main.o: main.cpp
g++ -std=c++11 -g -Wall -c main.cpp CircleDriver.cpp
clean:
rm *.o Circles
I read that you don't need to include header files in the compile command, but adding the other .cpp file did not solve my issue.
I'm sure this is a simple issue, but about 30 minutes of Googling yielded no results.
Thank you in advance.
I usually do something like this for my Makefile:
%.o: %.cpp
g++ -c -o $# $< -std=c++11 -Wall
Circles: main.o CircleDriver.o
g++ -o $# $^ -std=c++11 -Wall
clean:
rm *.o *~
This will create object files for each .cpp file and then use the object files to make Circles.

makefile issues multiple definitions

I'm learning how to use makefile however after a few hours of research and still being stuck I just can not manage to resolve what is wrong with my makefile:
output: main.o module.o
g++ main.o module.o -o output
main.o: module.cpp module.h
g++ -c module.cpp
module.o: module.cpp module.h
g++ -c main.cpp
my main.cpp file has #include "module.cpp"
my module.cpp file has #include "module.h"
after attempting to execute my makefile i get lots of "multiple definitions of" and "undefined references"
help will be highly appreciated
p.s code in codeblocks works flawlessly, that's why i am so confused. i am using mingw32-make
You are getting "multiple definition errors" becasue you are linking module.o and main.o together but your main.cpp already includes module.cpp. Do not include module.cpp in main.cpp (i.e.: remove the #include "module.cpp directive inside main.cpp). Since main.o won't depend then on module.cpp, you should remove that prerequisite from the main.o rule as well.
Also, consider using GNU Make's automatic variables instead of hard-coded filenames and predefined variables (i.e.: CXX) instead of hard-coded commands (i.e.: g++):
output: main.o module.o
$(CXX) $^ -o $#
main.o: main.cpp module.h
$(CXX) -c $<
module.o: module.cpp module.h
$(CXX) -c $<
Or even better, rely on the predefined pattern rule for generating .o files from .cpp files:
output: main.o module.o
$(CXX) $^ -o $#
main.o: module.h
module.o: module.h
Note that failing to provide the last two lines will cause main.o and module.o to be still up-to-date (i.e.: not being rebuilt) even though module.h changes.
Thanks to implicit rules in Makefiles, this should be enough:
output: main.o module.o
g++ main.o module.o -o output
The implicit rules allows make to know how to create .o files from .cpp files.
But this could be even simpler:
output: main.o module.o
$(CXX) -o $# #^
$(CXX) is your C++ compiler, usually g++
$# is an automatic variable of the target (value before the colon)
#^ is an automatic variable of the prerequisites (values after the colon)

C/C++ project compiles with Xcode but not with gcc/g++

When compiling a little C or C++ project in terminal using gcc, g++ or make, I get these kind of errors:
/tmp/ccG1caGi.o: In function `main':
main.c:(.text+0xa): undefined reference to `display_menu'
main.c:(.text+0xf): undefined reference to `get_input'
collect2: ld returned 1 exit status
main.c:
#include "menu.h"
int main()
{
display_menu();
get_input();
return 0;
}
menu.h:
void display_menu();
int get_input();
However with Xcode I get no errors or warnings.
What could be the issue here? It's seems it's like this when I include files.
So, gcc is complaining that it doesn't know where display_menu and get_input are, what they are doing or how to link them in, and rightly so.
You probably have more sourcefiles, where those functions are defined (menu.c, perhaps?). If so, add them to your compile instruction:
gcc main.c menu.c
Alternatively, just compile into an object (waiting for the functions later) with the -c flag. This will not make an executable, but will make an object file that awaits final compilation with
gcc main.c -c # Make the main.o object
gcc menu.c main.o # Link the main.o object with a compiled menu.c
into a final executable.
Xcode, in all likelihood, knows all about all your source files, and is happy to put them all together in its compilation step. If you are doing it manually, you have to do a little more work yourself. Its not when you include files (h files, that is) but when you have multi-file sources.
Try with a basic Makefile:
CC=gcc
CFLAGS=-W -Wall
LDFLAGS=
SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)
all: myexec
myexec: $(OBJ)
#$(CC) -o $# $^ $(LDFLAGS)
%.o: %.c
#$(CC) -o $# -c $< $(CFLAGS)
.PHONY: clean
clean:
#rm -rf *.o

Linking not done in Makefile

I tried to make a Makefile using files main.cpp, factorial.cpp, hello.cpp and function.h
On typing 'make' on Linux command window, it shows:
g++ -c -o hello main.o factorial.o hello.o
g++: main.o: linker input file unused because linking not done
g++: factorial.o: linker input file unused because linking not done
g++: hello.o: linker input file unused because linking not done
I am making the Makefile for first time. Please give suggestions what can be the problem?
The Makefile contains following code->
hello: main.o factorial.o hello.o
g++ -c -o hello main.o factorial.o hello.o
main.o: main.cpp
g++ -c -o main.o main.cpp
factorial.o: factorial.cpp
g++ -c -o factorial.o factorial.cpp
hello.o: hello.cpp
g++ -c -o hello.o hello.cpp
The individual file contents if you want to see are:
1) main.cpp
#include<iostream>
#include"functions.h"
using namespace std;
int main()
{
print_hello();
cout << endl;
cout << "The factorial of 5 is " << factorial(5) << endl;
return 0;
}
2) hello.cpp
#include<iostream>
#include "functions.h"
using namespace std;
void print_hello()
{
cout << "Hello World!";
}
3) factorial.cpp
#include "functions.h"
int factorial(int n)
{
if(n!=1)
{
return(n * factorial(n-1));
}
else return 1;
}
4) function.h
void print_hello();
int factorial(int n);
The -c parameter to g++ tells it not to link:
-c Compile or assemble the source files, but do not link. The linking stage simply is not done. The ultimate output is in the form of an object file for each source file.
You definitely don't want the -c here:
hello: main.o factorial.o hello.o
g++ -c -o hello main.o factorial.o hello.o
You could also use rules and patterns to make it more generic:
SRC_DIR = ./src
OBJ_DIR = ./bin/obj
BIN_DIR = ./build/bin
# List all the sources
SRCS = A.cpp B.cpp
# Define the rule to make object file from cpp
$(OBJ_DIR)/%.o : $(SRC_DIR)/%.cpp
g++ -o $# $(INCLUDES) $(CPPFLAGS) -c $^
TARGET_BIN = $(BIN_DIR)/test
all : make_dirs $(TARGET_BIN)
$(TARGET_BIN) : $(SRCS:%.cpp=$(OBJ_DIR)/%.o)
g++ $(LDFLAGS) -o $# $^ $(LDLIBS)
make_dirs :
mkdir -p $(OBJ_DIR)
mkdir -p $(BIN_DIR)
With this approach you have several benefits:
Easy to use: you specify source files once, and you don't care about processing of each object file: the job is done by a single rule.
More maintainable: every time you need to change the compiler or linker options you do it in the single rule, not for each translation unit.
You have an error in that line:
g++ -c -o hello main.o factorial.o hello.o
man gcc says: ... the -c option says not to run the linker.
This option is used to produce objects files only. When it passed, gcc will not start linker to produce executable file or shared library.
As clear from all above answers, because of using -c in g++ -c -o hello main.o factorial.o hello.o, it is preventing from linking. After creating the object files from corresponding .cpp or .h etc files, these need to be linked. Without linking, as each file is a part of a complete program that can perform some task, nothing useful can be done as these file are dependent. So, we have to link these dependent parts to run our complete program.
One basic video tutorial for easy learning of making a Makefile in the two methods viz dependencies and pattern rules is here.
It takes example of method of dependencies and then introduce pattern rules as a better approach for making a long Makefile.
To know the difference between compilation and linking, this link can be useful.

building the same file for different targets with different options

I have one "helper" file included in two "main" files which are built into two executables with the same makefile. I have debug print statements in the helper file. I want the print statements to actually be printed in one executable, but not the other. Is there a way to do it? Right now I have the following, and I was hoping to compile with DEBUG_PRINT defined for one executable but not the other, but I don't see how.
main1.cpp:
#include "helper.h"
...
main2.cpp:
#include "helper.h"
...
helper.cpp:
#ifdef DEBUG_PRINT
cout << "here is a debug message" << endl;
#endif
Makefile:
build: main1 main2
main1: main1.o helper.o
g++ -g -o main1 main1.o helper.o
main2: main2.o helper.o
g++ -g -o main2 main2.o helper.o
%.o: %.cpp
gcc -g -c $<
You will need two different object files (main1-helper.o and main2-helper.o) and target-specific compiler flags:
main1: CXXFLAGS=-DDEBUG_PRINT
%.o: %.cpp
gcc $(CXXFLAGS) -g -o $# -c $<
Note: This leaves you with the problem of generating main1-helper.o from helper.o. There are a few ways to solve this; however, you might be more comfortable using automake from the start instead of rolling your own solutions.