Writing a makefile for ARM project - gcc

My project structure looks like:
.
├── build
├── src
| ├── rbpi
| | └── gpio.h
| ├── boot.c
| ├── boot.s
| └── kernel.c
└── linker.ld
This is a simple raspberry pi kernel that makes a LED blink!
I currently use a simple bat file with the following content to build it:
arm-none-eabi-gcc -g -O0 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 -nostartfiles -Wl,-T,linker.ld src/kernel.c src/boot.c src/boot.s -o build/kernel.elf
arm-none-eabi-objcopy build/kernel.elf -O binary build/kernel7.img
Since I will add more files to this project, I would have to append every file to my "buildscript".
If possible, I'd like to use a makefile.
How should my makefile look like if I want the following "rules"?
Before compilation, clean all *.elf and *.img files from the build directory.
Compile all *.c and *.s files from the src directory.
Output the kernel.elf file into the build directory.
Use the linker script linker.ld.
After compilation, run objcopy to generate a binary file.

A typical Makefile may look like... Wait there's a documentation about GNU Make here with a nice simple Makefile:
http://www.gnu.org/software/make/manual/make.html#Simple-Makefile
So for you a simple one to start may be:
SRC := $(wildcard src/*.c src/*.s)
CFLAGS := -g -O0 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 -nostartfiles -Wl,-T,linker.ld
all: build/kernel.img
build/kernel.elf: $(SRC)
arm-none-eabi-gcc $(CFLAGS) $(SRC) -o $#
%.img: %.elf
arm-none-eabi-objcopy $< -O binary $#
clean:
rm -f build/*.elf build/*.img
(Be carefull, recipes have to start with a tab, not four spaces like here, it's important for make to understand your file, so copying-pasting won't work.)
You don't actually need to remove elf and img files before compiling, that's the GNU Make role to know if it has to rebuild or not according to file modification times.
Here it is, working:
$ tree
.
├── build
├── Makefile
└── src
├── boot.c
├── boot.s
└── kernel.c
$ make
arm-none-eabi-gcc -g -O0 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 -nostartfiles -Wl,-T,linker.ld src/boot.c src/kernel.c src/boot.s -o build/kernel.elf
arm-none-eabi-objcopy build/kernel.elf -O binary build/kernel.img
$ tree
.
├── build
│   ├── kernel.elf
│   └── kernel.img
├── Makefile
└── src
├── boot.c
├── boot.s
└── kernel.c
$ make
make: Nothing to be done for 'all'.
$ touch src/boot.c # If I touch a file, make will have to rebuild evrything:
$ make
arm-none-eabi-gcc -g -O0 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 -nostartfiles -Wl,-T,linker.ld src/boot.c src/kernel.c src/boot.s -o build/kernel.elf
arm-none-eabi-objcopy build/kernel.elf -O binary build/kernel.img
You should really take a look at the documentation which is really nice: http://www.gnu.org/software/make/manual/make.html you won't be able to ask on stackoverflow for any modification you'll need to do on your makefile, starting from this "bootstrap makefile" you should be able to modify it to learn step by step, with the documentation as a reference.

Related

Makefile non-recursive method issues

I am trying to build using Makefile below code structure using non-recursive method as per the guidance I received in
link description
work
├── code
| |
| └── main.h and test.h files here
│ └── main.c and test.c files here
| └── subdir.mk
|
├── _Build/
│ └── Makefile here
Below is the Makefile
-include ../code/subdir.mk
all : target_file
target_file : ../code/main.o ../code/test.o
#echo Building ...
#echo Linking files ...
gcc -Llib ../code/main.o ../code/test.o -lm -o target_file
clean:
rm -rv ../code/*.o
Below is the subdir.mk file
../code/test.o : ../code/test.c ../code/test.h
#echo Building test.c ...
gcc -Werror -Wall -c ../code/test.c -o ../code/test.o
../code/main.o : ../code/main.c ../code/main.h ../code/test.h
#echo Building main.c ...
gcc -Werror -Wall -c ../code/main.c -o ../code/main.o
The output I am getting while running make command is below
Building test.c ...
gcc -Werror -Wall -c ../code/test.c -o ../code/test.o
There is no error I am getting nor main.o is getting generated. Also in Makefile the linking command is not executed.
That's likely because make by default builds the first target it encounters. Since you include the subdir.mk before your all : target_file line, the first target named in subdir.mk is built, and nothing else. Solution: place the subdir.mk inclusion last, e.g. near the end.

Getting Make to automatically detect changes in protocol buffers

I want Make to automatically compile protos when I update them, here is what I've got so far:
TARGET=main
BIN_DIR=bin
SRC_DIR=src
OBJ_DIR=obj
PROTO_DIR=protos/
PROTO_COMPILE_DIR=src/$(PROTO_DIR)
CC = g++
CFLAGS = -Wall -std=c++17 -ggdb -pipe -I.
LINKER = g++
LFLAGS = $(CFLAGS) -lprotobuf
SOURCES = $(wildcard src/*.cc) \
$(wildcard src/protos/*.cc) \
$(wildcard src/db_handler/*.cc)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.cc=$(OBJ_DIR)/%.o)
$(BIN_DIR)/$(TARGET): proto $(OBJECTS)
#mkdir -p $(BIN_DIR)/
$(LINKER) $(OBJECTS) $(LFLAGS) -o $#
$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.cc
#mkdir -p obj/ obj/protos obj/db_handler
$(CC) $(CFLAGS) -c $< -o $#
.PHONY: proto
proto:
#printf "Compiling protos...\n"
#cd $(PROTO_DIR) && protoc * --grpc_out=../$(PROTO_COMPILE_DIR)\
--cpp_out=../$(PROTO_COMPILE_DIR)\
--plugin=protoc-gen-grpc="/usr/local/bin/grpc_cpp_plugin"\
&& cd ../
It successfully compiles protos; but, it does so every time, even if there are no changes in files. How can I prevent this and compile protos only if protos change?
Edit: Added project structure
├── LICENSE
├── makefile
├── protos
│   ├── client.proto
│   └── person.proto
├── README.md
└── src
├── db_handler
│   ├── db_handler.cc
│   └── db_handler.h
├── main.cc
└── protos
├── client.grpc.pb.cc
├── client.grpc.pb.h
├── client.pb.cc
├── client.pb.h
├── person.grpc.pb.cc
├── person.grpc.pb.h
├── person.pb.cc
└── person.pb.h
You want to add the source files of the protocol buffers to the right (the prerequisites) of the rule that cares about them. This is how Make understands and tracks their time stamps.
By adding the files to the prerequisites, Make will understand that this is the rule which cares about those source files.
PROTO_SOURCES := $(wildcard $(PROTO_DIR)/*.proto)
PROTOS := $(patsubst $(PROTO_DIR)/%.proto,$(PROTO_COMPILE_DIR)/%.cc,$(PROTO_SOURCES))
$(PROTOS): $(PROTO_SOURCES)
#printf "Compiling protos...\n"
#cd $(PROTO_DIR) && protoc * --grpc_out=../$(PROTO_COMPILE_DIR)\
--cpp_out=../$(PROTO_COMPILE_DIR)\
--plugin=protoc-gen-grpc="/usr/local/bin/grpc_cpp_plugin"
However, this $(PROTOS) : $(PROTO_SOURCES) is not good if you use parallel builds; because, Make will try to run the command once for each output file. So, make will run N instances of the command at the same time, which means they may clobber each other.
In order to know the fully correct solution you need to provide more information (for those not familiar with protoc). Is it a requirement that you invoke protoc once with all inputs? Or is it valid to run protoc individually on each input .proto file to get its output? Then you can write a pattern rule that generates one file at a time.
Note 1: As to your other attempt, if you use .PHONY to mark the rule then Make will rebuild the rule every time weather it needs to or not.
Note 2: You don't need the cd .. at the end of the second instruction, since it is run in a sub shell.
Thanks to #FiddlingBits I managed to figure out how to do it correctly
TARGET=main
BIN_DIR=bin
SRC_DIR=src
OBJ_DIR=obj
PROTO_DIR=protos/
PROTO_COMPILE_DIR=src/$(PROTO_DIR)
rm = rm -f
CC = g++
CFLAGS = -Wall -std=c++17 -ggdb -pipe -I.
LINKER = g++
LFLAGS = $(CFLAGS) -lprotobuf
SOURCES = $(wildcard src/*.cc) \
$(wildcard src/protos/*.cc) \
$(wildcard src/db_handler/*.cc)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.cc=$(OBJ_DIR)/%.o)
PROTOS := $($(PROTO_DIR)/%.proto=$(PROTO_COMPILE_DIR)/%.cc)
$(BIN_DIR)/$(TARGET): $(PROTOS) $(OBJECTS)
echo $(PROTOS)
#mkdir -p $(BIN_DIR)/
$(LINKER) $(OBJECTS) $(LFLAGS) -o $#
$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.cc
#mkdir -p obj/ obj/protos obj/db_handler
$(CC) $(CFLAGS) -c $< -o $#
$(PROTOS):
#printf "Compiling protos...\n"
#cd $(PROTO_DIR) && protoc * --grpc_out=../$(PROTO_COMPILE_DIR)\
--cpp_out=../$(PROTO_COMPILE_DIR)\
--plugin=protoc-gen-grpc="/usr/local/bin/grpc_cpp_plugin"\
&& cd ../
.PHONY: clean
clean:
#$(rm) -r $(OBJ_DIR)/*
#$(rm) -r $(BIN_DIR)/*
#printf "Cleanup complete!\n"

Failing to link to SFML libraries using Makefile even though it works as a one liner

Here is my directory structure :
.
├── a.out
├── assets
│   └── ...
├── build
│   ├── apps
│   └── objects
├── include
│   └── engine
│   └── Class.h
├── Makefile
└── src
├── engine
│   └── Class.cpp
└── program.cpp
I can compile program.cpp into a.out using the following command :
g++ src/engine/*.cpp src/program.cpp -Iinclude/ -L/usr/lib -lstdc++ -lm -lsfml-graphics -lsfml-window -lsfml-system -Wall
While this works, this project is likely to grow and obviously making a serious Makefile would be preferable to direct compiling with a one liner. So I've used a Makefile format that I've used many times before, and that works perfectly fine but I've never linked it to outside libraries in the past. Here is the Makefile I'm using :
CXX := -g++
CXXFLAGS := -std=gnu++0x -g -Wall
LDFLAGS := -L/usr/lib -lstdc++ -lm -lsfml-graphics -lsfml-window -lsfml-system
BUILD := ./build
OBJ_DIR := $(BUILD)/objects
APP_DIR := $(BUILD)/apps
TARGET := program
INCLUDE := -Iinclude/
SRC := $(wildcard src/engine/*.cpp) $(wildcard src/*.cpp)
OBJECTS := $(SRC:%.cpp=$(OBJ_DIR)/%.o)
all: build $(APP_DIR)/$(TARGET)
$(OBJ_DIR)/%.o: %.cpp
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) $(INCLUDE) -o $# -c $<
$(APP_DIR)/$(TARGET): $(OBJECTS)
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) $(INCLUDE) $(LDFLAGS) -o $(APP_DIR)/$(TARGET) $(OBJECTS)
.PHONY: all build clean debug release
build:
#mkdir -p $(APP_DIR)
#mkdir -p $(OBJ_DIR)
debug: CXXFLAGS += -DDEBUG -g
debug: all
release: CXXFLAGS += -O2
release: all
clean:
-#rm -rvf $(OBJ_DIR)/*
-#rm -rvf $(APP_DIR)/*
However, this leads to compilation errors, in the form of undefined references to SFML methods :
./build/objects/src/engine/Class.o: In function `Class::draw()':
/dir/Class.cpp:60: undefined reference to `sf::RenderTarget::getView() const'
I'm confused as to why this happens given that the one liner above compiles fine. The Makefile also works just fine if I remove all references to SFML from my code. Were the added LDFLAGS not enough even though they're all that's needed to make my one liner link to SFML ? If so, what else is needed ?
From gcc link options
-llibrary
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.
So put the libraries (-l<lib_1> ... -l<lib_x>) last on the line, after your object files.

Makefile: explicit entry works, wildcard % not working

I have this rule in my makefile, but make didn't find it:
$(BUILDDIR)%.o : $(BUILDDIR)%.bin
#echo
$(OBJCOPY) -I binary -O elf32-avr --redefine-sym _binary_$*_bin_start=$* --redefine-sym _binary_$*_bin_end=$*_end $< $#
If I make it explicit, make will use them (called for build/rom1.o and build/rom2.o; BUILDDIR=build/)
$(BUILDDIR)rom1.o : $(BUILDDIR)rom1.bin
#echo
$(OBJCOPY) -I binary -O elf32-avr --redefine-sym _binary_rom1_bin_start=rom1 --redefine-sym _binary_rom1_bin_end=rom1_end $< $#
$(BUILDDIR)rom2.o : $(BUILDDIR)rom2.bin
#echo
$(OBJCOPY) -I binary -O elf32-avr --redefine-sym _binary_rom2_bin_start=rom2 --redefine-sym _binary_rom2_bin_end=rom2_end $< $#
Does anyone has a hint whats wrong with the wildcard in my first try?
Edit:
The version of make is 4.1 running on Ubuntu 16.04.
This is the error message from make when trying to run with the wildcard:
make: *** No rule to make target 'build/rom1.o', needed by 'build/rom1.elf'. Stop.
Let's simplify the problem…
If this is your file structure…
.
├── Makefile
└── build
├── rom1.bin
└── rom2.bin
and this is your Makefile…
BUILDDIR := build/
$(BUILDDIR)%.o: $(BUILDDIR)%.bin
touch $#
and you run $ make build/rom{1,2}.o, your resulting file structure will be…
.
├── Makefile
└── build
├── rom1.bin
├── rom1.o
├── rom2.bin
└── rom2.o

Using GNU Make with subdirectories

I was wondering what different approaches of using Make in a project with subdirectories exist, and what are their advantages/drawbacks, but could never see a good summary or cookbook.
I have seen in my researches mainly the "recursive" and "single makefile" approaches, but are there others ?
I also assume that there is not only one "recursive" or "single makefile" approaches but several, so could somebody sum it up ?
For my particular case, I would like a directory architecture looking like this:
.
├── build
│   ├── *.d
│   ├── *.o
| ├── subdir1
| │ ├── *.d
| │ └── *.o
| └── subdir2
| ├── *.d
| ├── *.o
| └── subdir3
| ├── *.d
| └── *.o
├── include
│   ├── *.h
│   └── *.h
├── Makefile
└── src
├── *.c
├── *.h
├── subdir1
│   ├── *.c
│   └── *.h
└── subdir2
├── *.c
├── *.h
└── subdir3
├── *.c
└── *.h
Which solution should I choose ? Possibly one which would allow source files with the same name ?
Your project setup is really basic, so should be your Makefile:
SRC_DIR := src
BLD_DIR := build
SRC := $(shell find $(SRC_DIR) -name "*.c")
OBJ := $(SRC:$(SRC_DIR)/%.c=$(BLD_DIR)/%.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD -MP # enable auto-dependency generation
CFLAGS := -Wall -W -pedantic
.PHONY: all clean
all: $(OBJ)
clean:
$(RM) -r $(BLD_DIR)
.SECONDEXPANSION:
$(BLD_DIR)/%.o: $(SRC_DIR)/%.c | $$(#D)/ # First check that the destination directory exists
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
%/:
mkdir -p $* # -p flag necessary for recursive directory creation
ifeq "$(MAKECMDGOALS)" ""
-include $(DEP)
endif
The idea here is to list source files recursively using the find command, to supply make with the appropriate pattern rule to compile in the right place and pass the right preprocessor file to your compiler to enable auto-dependency generation.
Tested with GNU Make 4.1 under Windows 8.1 with the GIT Bash shell and the following directory structure:
.
├── Makefile
└── src
├── test.c
├── test1.c
└── subdir1
└── test.c
After reading Recursive Make Considered Harmful, I figured a quite simple and modular way to achieve this, by having files in all subdirectories that would include each other and be included in the main makefile:
CXX := gcc
SRCDIR := src
OBJDIR := build
# These lines are needed to set immediate evaluation for
# these variables, instead of deferred evaluation which is unsuitable.
SRCS :=
SUBDIRS :=
CFLAGS :=
LDFLAGS :=
include $(SRCDIR)/module.mk
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
SRCS := $(addprefix $(SRCDIR)/, $(SRCS))
DEPS := $(OBJS:.o=.d)
TMPS := $(OBJS) $(OBJS:.o=.d)
CFLAGS += -MD
debug: CFLAGS += -g -g3 -ggdb
CFLAGS += $(addprefix -I./$(SRCDIR)/, $(SUBDIRS))
LDFLAGS += -lsomelib
debug: LDFLAGS += -g -g3 -ggdb
NAME := yolo
all: $(NAME)
debug: re
-include $(DEPS)
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(NAME): $(OBJS)
#$(CXX) $(OBJS) -o $(NAME) $(LDFLAGS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
#mkdir -p $(OBJDIR)
#for dir in $(SUBDIRS); \
do \
mkdir -p $(OBJDIR)/$$dir; \
done
clean:
rm -rf $(TMPS)
fclean: clean
rm -rf $(NAME)
rm -rf $(OBJDIR)
re: fclean all
.PHONY: all clean fclean re
And in every subdirectory, a module.mk file (I could have named it anything, but this seemde cool).
For src:
SRCS := main.c file1.c file2.c
SUBDIRS += subdir1 subdir2
include $(SRCDIR)/subdir1/module.mk
include $(SRCDIR)/subdir2/module.mk
For a level 1 subdirectory:
THIS_DIR_L0 := subdir1
MOD_SRC := file3.c file4.c
SRCS += $(addprefix $(THIS_DIR_L0)/, $(MOD_SRC))
SUBDIRS += $(THIS_DIR_L0)/subdir3
include $(SRCDIR)/$(THIS_DIR_L0)/subdir3/module.mk
And for a level 2 subdir (one deeper):
THIS_DIR_L1 := subdir3
MOD_SRC := file5.c file6.c
SRCS += $(addprefix $(THIS_DIR_L0)/$(THIS_DIR_L1)/, $(MOD_SRC))
And so on...
This is quite simple to set up, I find it very modular and it does not use recursive makefiles. It would not be complicated to make librairies and stuff inside your directory structure either.
Anybody having a better idea please tell me.

Resources