Multiple compile modes in makefile - c++

I want to use a single make file to generate a project in multiple modes, and then each mode in a "normal" and "debug" mode, ie:
I have the following files (ofc more in reality, but this will serve to show my point):
kernel/core/main.cpp
kernel/processor/Processor.cpp
kernel/processor/x86/Processor.cpp
kernel/processor/x86_common/Processor.cpp
kernel/processor/x64/Processor.cpp
And i want to be able to use my makefile in the following ways:
make x86
(compiles all files except "kernel/processor/x64/Processor.cpp")
(enables the pre-processor directives X86 & X86_COMMON)
And,
make x86debug
(compiles all files except "kernel/processor/x64/Processor.cpp")
(enables the pre-processor directives X86 & X86_COMMON & DEBUG)
(puts "-g -ggdb" infront of all gcc/g++/as arguments)
And so on.
Currently i have the following makefile, which while it works, only lets me compile in x86-debug mode and now that i am porting my software to other platforms I wish to be able to specify what mode to build in.
CC = i586-elf-g++
CFLAGS = -g -ggdb -ffreestanding -Wall -Wextra -fno-exceptions -fno-rtti -std=gnu++11 -Isrc/system/include -DX86 -DX86_COMMON
LD = i586-elf-gcc
LDFLAGS = -g -ggdb -ffreestanding -O2 -nostdlib -lgcc
AS = i586-elf-as
ASFLAGS = -g -ggdb
OBJECTS = src/system/kernel/core/main.o
ALL_OBJECTS = $(OBJECTS) $(X86_OBJECTS)
X86COMMON_OBJECTS = src/system/kernel/core/processor/x86_common/Processor.o
X86_OBJECTS = $(X86COMMON_OBJECTS) src/system/kernel/core/processor/x86/boot.o
X86_LINKER = src/system/kernel/core/processor/x86/link.ld
X86_OUTPUT = bin/kernel_x86.bin
.PHONY: clean
clean: $(ALL_OBJECTS)
rm $(ALL_OBJECTS)
.PHONY: all
all: $(X86_OUTPUT)
$(X86_OUTPUT): $(X86_LINKER) $(OBJECTS) $(X86_OBJECTS)
$(LD) $(LDFLAGS) -T $(X86_LINKER) $^ -o $#
%.o: %.cpp
$(CC) $(CFLAGS) -c $< -o $#
%.o: %.asm
$(AS) $(ASFLAGS) $< -o $#
As you can probably tell, im not an expert with make so any help/ideas would be appreciated.

Remove -g from CFLAGS and LDFLAGS, and add the following PHONY:
.PHONY: x86_debug
x86_debug: CFLAGS += -g
x86_debug: LDFLAGS += -g
x86_debug: $(X86_OUTPUT)
To compile in normal mode: make.
To compile in debug mode: make x86_debug
It may not do exactly what you're expecting, but it's easy to modify

Related

How to recompile only what changed in makefile with automatically finds .cpp files?

I wrote the following makefile, which successfully compiles all the .cpp in the current folder into a static library.
The clean_library target is used because if I try to compile and there is already the .a file, the compilation stops with the following error:
ar: libbackend.a is a fat file (use libtool(1) or lipo(1) and ar(1) on it)
ar: libbackend.a: Inappropriate file type or format
make: *** [libbackend] Error 1
I would like to speed up the compilation compiling only those .cpp which change. Currently all the .o files are recreated each time.
I can achieve this removing the -arch part and removing the dependency clean_library.
How can I achieve the same behaviour without that?
A workaround is to create a target which builds for a single architecture and call the target which build for all the architectures only when needed/when the work is finished.
CC = g++
FLAGS = -g -std=c++14 -Wall -Wextra -O0 #debug
# FLAGS = -std=c++14 -Ofast # release
SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o)
OUT = my_library
$(OUT): $(OBJS)
ar rcs $(OUT).a $^
# libtool -static -o $(OUT).a $^ #other possibilty
%.o: %.cpp Makefile #clean_library
$(CC) $(FLAGS) -c $< -o $# -arch x86_64 -arch i386
.PHONY: clean clean_library
clean: clean_library
rm -rf *.o
clean_library:
rm -rf $(OUT).a
Your question is not very clear about what you want to do. Is your goal to compile the same code multiple times in different ways?
You cannot have exactly the same targets compiled different ways, and still only have the modified files updated: make cannot know which way a pre-existing object file was compiled. When make starts up and sees a foo.o file, was it compiled for debug? Release? There's no way to know, so this can't work. You have to recompile everything to be sure.
What people do to work around this is name the output from the different types of compilation differently. The most common way to do this is to use a subdirectory: put all the files compiled for debug in the debug subdirectory and all the files compiled for release in the release subdirectory. So your makefile would look something like this:
CC = g++
debug_FLAGS = -g -std=c++14 -Wall -Wextra -O0
release_FLAGS = -std=c++14 -Ofast
SRCS := $(wildcard *.cpp)
OBJS := $(SRCS:.cpp=.o)
OUT := my_library.a
all: debug/$(OUT) release/$(OUT)
%/$(OUT):
ar rcs $# $^
# libtool -static -o $# $^ #other possibilty
debug/$(OUT): $(addprefix debug/,$(OBJS))
debug/%.o: %.cpp Makefile | debug
$(CC) $(debug_FLAGS) -c $< -o $# -arch x86_64 -arch i386
release/$(OUT): $(addprefix release/,$(OBJS))
release/%.o: %.cpp Makefile | release
$(CC) $(release_FLAGS) -c $< -o $# -arch x86_64 -arch i386
debug release:
mkdir -p $#
clean:
rm -rf debug release
.PHONY: debug release clean
If you want to have lots of different options it might be worthwhile to get even more fancy but for just two you probably don't need to go to the extra effort.

seems I keep missing the idea of "target" and "rules"

tried to make a own makefile using alias
keep getting " make: *** No rule to make target g++', needed byrelease'. Stop."
PROGRAMS = stl
CPP = g++
CPPFLAGS = -Wall -ansi -pedantic -std=c++98
DEBUG_FLAGS = -g -DDEBUG -UNDEBUG
RELEASE_FLAGS = -O3 -UDEBUG -DNDEBUG
TEST_NAME = test$(PROGRAMS).out
DBG_TEST_NAME = test$(PROGRAMS).dbg.out
all: release debug
release: $(CPP) $(CPPFLAGS) $(RELEASE_FLAGS) $(PROGRAMS).cpp -o $(TEST_NAME)
debug: $(CPP) $(CPPFLAGS) $(DEBUG_FLAGS) $(PROGRAMS).cpp -o $(DBG_TEST_NAME)
clean:
rm -rvf *.o *.a *.out *dbg.out $(PROGRAMS)
The code for a target should be on a separate line, indented by a tab.
A rule in a makefile is:
target: dependencies
commands-for-rule
So in your case, something like e.g.
debug: $(PROGRAMS).cpp
$(CPP) $(CPPFLAGS) $(DEBUG_FLAGS) $(PROGRAMS).cpp -o $(DBG_TEST_NAME)
This makes the debug target depend on $(PROGRAMS).cpp, so the rule will always be executed if $(PROGRAMS).cpp is modified.

Creating files breaks -DDEBUG flag in Makefile for C++

In my Makefile I am using the -DDEBUG Flag for debugging which works fine (compiles and right output) in the following minimal example:
# Makefile
all : debug
CXX = g++
CXXFLAGS = -std=c++11 -Werror -Wall -Wextra -Wno-unused-value
SOURCES = main.cpp vector.cpp
OBJECTS = $(subst .cpp,.o, $(SOURCES))
debug: $(OBJECTS)
$(CXX) $(CXXFLAGS) -DDEBUG -o Program $(OBJECTS)
./Program
clean:
rm *.o Program
.PHONY: clean debug
But when i copy all project-files into the Folder the Debug-Flag wont be set (tested with #ifdef DEBUG and cout). I am adding the following files:
ind.hpp ind.cpp debug.hpp debug.cpp
I first thought debug.* could be the problem, but ".PHONY: clean debug" didn't help.
In the Makefile change this:
debug: $(OBJECTS)
$(CXX) $(CXXFLAGS) -DDEBUG -o Program $(OBJECTS)
to:
debug: $(SOURCES)
$(CXX) $(CXXFLAGS) -DDEBUG -o Program $(SOURCES)
The reason being that in the rule to build debug target you are just linking the object files and not compiling with -DDEBUG. With this change you should be able to compile with -DDEBUG flag.

Compiler options selective application

can compiler options be applied selectively on my files?
I want some files to be covered by some option but not the other files.
Guessing that you might be using Make files:
This should get you started: Note how -fopenmp gets added just for source2.c
CC=gcc
SRC=source1.c source2.c
OBJ=$(patsubst %.c,%.o,$(SRC))
EXE=source1.exe
FLAGS= -g -O2
source2.o: FLAGS+=-fopenmp
all: $(EXE)
$(EXE): $(OBJ)
$(CC) -o $# $^ $(FLAGS)
%.o: %.c
$(CC) -c -o $# $^ $(FLAGS)
clean:
rm $(EXE)$
Output of make -Bsn:
gcc -o source1.o source1.c -g -O2
gcc -o source2.o source2.c -g -O2 -fopenmp
gcc -o source1 source1.o source2.o -g -O2
Of course. You invoke the compiler, and you can tell it what you want.
Some tools may add some restrictions; Visual Studio, as far as I know, only allows specifying options at the project level. But that's an artificial restriction of the tool (and I'm sure there are ways around it—I just don't know them).

Writing a makefile to use -D_GLIBCXX_DEBUG in debug build

I have a makefile that can be reduced to this:
OBJS = obj1.o obj2.o
FLAGS = -Wall -Wextra -Werror -pedantic-errors -fno-rtti -std=c++0x
DEBUG_FLAGS = -ggdb -O0 -fstack-protector-all -D_GLIBCXX_DEBUG
RELEASE_FLAGS = -O3
release: $(OBJS)
g++ $(FLAGS) $(RELEASE_FLAGS) $(OBJS)
debug: $(OBJS)
g++ $(FLAGS) $(DEBUG_FLAGS) $(OBJS)
obj1.o: obj1.cpp
g++ -c $(FLAGS) obj1.cpp
obj2.o: obj2.cpp
g++ -c $(FLAGS) obj2.cpp
The problem is that all or none of the files must be built with the -D_GLIBCXX_DEBUG flag. I don't know how to do this without writing two entries for every compilation unit, like
obj1_release.o: obj1.cpp
g++ -c $(FLAGS) $(RELEASE_FLAGS) obj1.cpp
obj1_debug.o: obj1.cpp
g++ -c $(FLAGS) $(DEBUG_FLAGS) obj1.cpp
How can I make the -D_GLIBCXX_DEBUG flag (and the other debug flags) take effect for all compilation units only when the user types make debug without writing two entries for every CU? (And vice versa; the release flags need to take effect on all CUs when the user types make release.)
I apologise if this is the basics of writing Makefiles, I don't know much about them.
You are looking for pattern rules: something like this should do what you want. Note that this cannot be made to work correctly unless the debug and release versions of the program are given different names.
OBJS := obj1 obj2 obj3
R_OBJS := $(OBJS:=_r.o)
D_OBJS := $(OBJS:=_d.o)
all: prog_r prog_d
release: prog_r
debug: prog_d
prog_r: $(R_OBJS)
$(CXX) $(CXXFLAGS) $(RELEASE_FLAGS) $(LDFLAGS) $^ $(LIBS) -o $#
prog_d: $(D_OBJS)
$(CXX) $(CXXFLAGS) $(DEBUG_FLAGS) $(LDFLAGS) $^ $(LIBS) -o $#
%_r.o: %.cc
$(CXX) $(CXXFLAGS) $(RELEASE_FLAGS) -c $< -o $#
%_d.o: %.cc
$(CXX) $(CXXFLAGS) $(DEBUG_FLAGS) -c $< -o $#
# header files
obj1_d.o obj1_r.o: foo.h bar.h
obj2_d.o obj2_r.o: quux.h
# ... etc ...
There is a pretty straightforward way to select compilation flags based on the type of the build in Makefiles.
In addition to that you may like to ensure that debug build only links debug object files and same for release (i.e. no mixing debug and release object files). To achieve that compile object into different directories depending on the build type.
This might help : http://sunsite.ualberta.ca/Documentation/Gnu/make-3.79/html_chapter/make_7.html
You could check the first argument (debug/release) and set the CFLAGS accordingly.
HTH.