How to refresh/update a variable in Makefile? - c

I have this Makefile:
CFLAGS = -ffreestanding -O2 -nostdlib -lgcc
BUILD_DIR = ../build
BIN = $(BUILD_DIR)/os.bin
LINKER_SCRIPT = linker.ld
OBJ_FILES := $(shell find $(BUILD_DIR) -iname '*.o')
.PHONY: all
all:
#make -C boot
#make -C kernel
$(CC) -T $(LINKER_SCRIPT) -o $(BIN) $(CFLAGS) $(OBJ_FILES)
After compiling (doing make in boot and kernel directories) there should be files with .o extension, however OBJ_FILES is empty. Only after calling make again OBJ_FILES contains the .o files paths which are needed to link. So my question is how do I update OBJ_FILES after compiling in the boot and kernel directories, because OBJ_FILES doesn't update/refresh.

Let's say you have following structure:
.
|-- Makefile
|-- boot
| |-- Makefile
| |-- boot.c
| `-- boot.h
|-- kernel
| |-- Makefile
| |-- kernel.c
| `-- kernel.h
`-- main.c
and your Makefile looks like this
location = $(CURDIR)
OBJ_FILES = $(shell find $(location) -name '*.o')
all: make_common
gcc -o main main.c $(OBJ_FILES)
make_common:
#make -C boot
#make -C kernel
clean:
-rm boot/boot.o
-rm kernel/kernel.o
Your source code is quite simple:
> cat boot/boot.h
int boot();
> cat boot/boot.c
int boot() {
return 1;
}
> cat kernel/kernel.h
int kernel();
> cat kernel/kernel.c
int kernel() {
return 2;
}
> cat main.c
#include "boot/boot.h"
#include "kernel/kernel.h"
int main() {
int result = boot() + kernel();
return 0;
}
"inner" Makefiles contain
> cat boot/Makefile
all:
gcc -c boot.c
> cat kernel/Makefile
all:
gcc -c kernel.c
you will get what you are looking for
> make clean
rm boot/boot.o
rm: boot/boot.o: No such file or directory
make: [clean] Error 1 (ignored)
rm kernel/kernel.o
rm: kernel/kernel.o: No such file or directory
make: [clean] Error 1 (ignored)
> make
gcc -c boot.c
gcc -c kernel.c
gcc -o main main.c ..../boot/boot.o ..../kernel/kernel.o
VAR = val
Expanded when the variable is used.

So my question is how do I update OBJ_FILES after compiling in the boot and kernel directories, because OBJ_FILES doesn't update/refresh.
OBJ_FILES variable won't change its value once make started executing the rules.
See 3.7 How make Reads a Makefile for full details:
GNU make does its work in two distinct phases. During the first phase it reads all the makefiles, included makefiles, etc. and internalizes all the variables and their values and implicit and explicit rules, and builds a dependency graph of all the targets and their prerequisites. During the second phase, make uses this internalized data to determine which targets need to be updated and run the recipes necessary to update them.
It’s important to understand this two-phase approach because it has a direct impact on how variable and function expansion happens; this is often a source of some confusion when writing makefiles.
What you can do instead is restart make once it built kernel and boot:
all: $(BIN)
$(BIN) : $(OBJ_FILES)
$(CC) -T $(LINKER_SCRIPT) -o $# $(CFLAGS) $(OBJ_FILES)
Makefile :
#$(MAKE) -C boot
#$(MAKE) -C kernel
touch $# # <---- Causes the Makefile to be re-read.
.PHONY: all

Related

Makefile that handles subdirectories and puts object files in a object folder tree

I have a question about Makefiles with subdirectories:
I have a program with the structure
---src
|
|-> main.c
|-> morestuff.c
|-> [...]
|-> builtins -> builtin.c
-> builtin2.c
---obj
---inc
Now what I want to do is: I want to run make such that I create object files in my object directory (order structure not necessarily needed) and that I (obviously) create an executable.
I am able to do that without the subdirectories, but my pattern rules break, once I try to include the subdirectories...
My current approach (without subdirectories) looks something like this:
NAME = minishell
SRC_DIR = src/
OBJ_DIR = obj/
INC_DIR = inc/
LIBFT_DIR = libft/
LIBFT_EXEC = libft.a
CC = gcc
CFLAGS = -Wall -Werror -Wextra -g
# place all source files here
SRC = $(SRC_DIR)main.c \
$(SRC_DIR)builtin1.c \
$(SRC_DIR)builtin2.c \
[...]
# takes all named source files and converts them to .o files in the /obj directory
OBJ = $(SRC:$(SRC_DIR)%.c=$(OBJ_DIR)%.o)
# prevents rules from being considered as files
.PHONY: all clean fclean re
all: $(NAME)
# creates subdirectory /obj
$(OBJ_DIR):
#mkdir $#
#echo "Creating object directory..."
# makes sure to make a /obj dir before compiling .o files
$(OBJ): | $(OBJ_DIR)
$(OBJ): $(OBJ_DIR)%.o: $(SRC_DIR)%.c
$(CC) $(CFLAGS) -c $< -o $#
# compiles all object files and builds executable file 'minishell' -> ADJUST READLINE FOR LINUX!
$(NAME): $(OBJ)
#echo "Compiling libft..."
$(MAKE) -C libft
#echo "Compiling $(NAME)..."
$(CC) $(CFLAGS) $^ $(LIBFT_DIR)$(LIBFT_EXEC) -L $(HOME)/goinfre/.brew/opt/readline/lib/ -lreadline -o $#
#echo "SUCCESSFULLY CREATED MINISHELL!"
So how can I scale that up to handle subdirectories?
I know I could make Makefiles in subdirectories, but this is not worth the effort since there aren't a lot of files in there...
Instead of just creating the object directory before compiling, you should create the object file directory tree prior to compiling each file:
$(OBJ_DIR)%.o: $(SRC_DIR)%.c
#mkdir -p $(dir $#)
$(CC) $(CFLAGS) -c $< -o $#
$(dir $#) is a GNU make extension. You can use #mkdir -p `dirname $#` for portability to other make flavors.

avr-gcc undefined reference to function in linked object file

I have some code for handling all uart related functions and operations in a .h/.c pair that I usually include in my project. I have a makefile that compiles all of my .c files into .o files then links them all to one executable. For some reason, one of my projects using this pair compiles fine but the other gives this error:
obj/fiveax.o: In function `fiveax_init':
fiveax.c:(.text+0x10): undefined reference to `uart_init'
collect2: error: ld returned 1 exit status
when trying to link to the exectutable after compiling all the .o files. I have included my makefile below, it is the same for both projects with the only difference being the appname.
Makefile
########################################################################
####################### Makefile Template ##############################
########################################################################
# Compiler settings - Can be customized.
CC = avr-gcc
CXXFLAGS = -mmcu=atmega2560 -D BUILD=1
LDFLAGS = -Iinclude -Ilibs/FreeRTOS/include -Llibs/FreeRTOS -lfreertos
DEV = /dev/ttyUSB0
AVRCONF = -C/etc/avrdude.conf
AVRLOAD = $(AVRCONF) -v -patmega2560 -carduino -P$(DEV) -b57600 -D -Uflash:w:bin/$(APPNAME).hex:i
# Makefile settings - Can be customized.
APPNAME = FiveAx
EXT = .c
SRCDIR = src
OBJDIR = obj
INCDIR = include
DEPDIR = dep
############## Do not change anything from here downwards! #############
SRC = $(wildcard $(SRCDIR)/*$(EXT))
OBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)/%.o)
DEP = $(OBJ:$(OBJDIR)/%.o=$(DEPDIR)/%.d)
# UNIX-based OS variables & settings
RM = rm
DELOBJ = $(OBJ)
# Windows OS variables & settings
DEL = del
EXE = .exe
WDELOBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)\\%.o)
########################################################################
####################### Targets beginning here #########################
########################################################################
all: bin $(APPNAME)
# Builds the app
$(APPNAME): $(OBJ)
$(CC) $(CXXFLAGS) -o bin/$#.elf $^ $(LDFLAGS)
avr-objcopy -j .text -j .data -O ihex bin/$(APPNAME).elf bin/$(APPNAME).hex
bin:
mkdir -p $#
# Creates the dependecy rules
$(DEPDIR)/%.d: $(SRCDIR)/%$(EXT)
#$(CPP) $(CFLAGS) $< -MM -MT $(#:$(DEPDIR)/%.d=$(OBJDIR)/%.o) >$# $(LDFLAGS)
# Includes all .h files
-include $(DEP)
# Building rule for .o files and its .c/.cpp in combination with all .h
$(OBJDIR)/%.o: $(SRCDIR)/%$(EXT)
$(CC) $(CXXFLAGS) -o $# -c $< $(LDFLAGS)
load: bin $(APPNAME)
avrdude $(AVRLOAD)
################### Cleaning rules for Unix-based OS ###################
# Cleans complete project
.PHONY: clean
clean:
$(RM) -r $(DELOBJ) $(DEP) bin
# Cleans only all files with the extension .d
.PHONY: cleandep
cleandep:
$(RM) $(DEP)
edit: I have included the header file for uart.h in the source file.
edit: I was asked for the output of the makefile
avr-gcc -mmcu=atmega2560 -D BUILD=1 -Iinclude -Ilibs/FreeRTOS/include -o obj/uart.o -c src/uart.c -Llibs/FreeRTOS -lfreertos
avr-gcc -mmcu=atmega2560 -D BUILD=1 -Iinclude -Ilibs/FreeRTOS/include -o obj/servo.o -c src/servo.c -Llibs/FreeRTOS -lfreertos
avr-gcc -mmcu=atmega2560 -D BUILD=1 -Iinclude -Ilibs/FreeRTOS/include -o obj/main.o -c src/main.c -Llibs/FreeRTOS -lfreertos
avr-gcc -mmcu=atmega2560 -D BUILD=1 -Iinclude -Ilibs/FreeRTOS/include -o obj/fiveax.o -c src/fiveax.c -Llibs/FreeRTOS -lfreertos
avr-gcc -mmcu=atmega2560 -D BUILD=1 -Iinclude -Ilibs/FreeRTOS/include -o bin/FiveAx.elf obj/uart.o obj/servo.o obj/main.o obj/fiveax.o
obj/fiveax.o: In function `fiveax_init':
fiveax.c:(.text+0x10): undefined reference to `uart_init'
collect2: error: ld returned 1 exit status
make: *** [Makefile:41: FiveAx] Error 1
It's impossible to read the information requested because it's not formatted as a code block so all the lines run together. Please use the live preview feature of the SO question editor to check that the content you're adding is readable, to save the sanity of the people trying to help you.
The link line appears to be this:
avr-gcc -mmcu=atmega2560 -D BUILD=1 -Iinclude -Ilibs/FreeRTOS/include -o bin/FiveAx.elf obj/uart.o obj/servo.o obj/main.o obj/fiveax.o
Here we can see that the library -lfreertos is not present, and also that all the object files come at the end after the flags. I don't see how this could have happened given the makefile you show above:
CXXFLAGS = -mmcu=atmega2560 -D BUILD=1
LDFLAGS = -Iinclude -Ilibs/FreeRTOS/include -Llibs/FreeRTOS -lfreertos
$(CC) $(CXXFLAGS) -o bin/$#.elf $^ $(LDFLAGS)
so it seems that the make output here doesn't match the makefile you've shown us. Are you sure you're using that makefile?

Compiling all C files and creating executable with Makefile

I have a C project, which has the following file structure:
Makefile
src
|-utils
| |--vic.c
| |--vic.h
|-mod
| |--type.c
| |--type.h
|-bb.c
|-bb.h
|-main.c
So, at the root directory I have the actual Makefile and the src directory, which includes the source files. Inside the src directory there are multiple .c and .h files along with the main.c file, and there are other directories which also contain other .c and .h files. Please note that the above shown file structure is kept short for brevity. I want to create a Makefile that will automatically compile everything and generate an executable main program, and also delete the object files generated during the compilation. Currently, I have something like this:
CC=gcc
CFLAGS=
RM=rm -rf
OUT=main
SRC=src
OBJ=obj
SOURCES=$(wildcard $(SRC)/*.c)
OBJECTS=$(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
all: build
build: $(OBJECTS)
$(CC) $(CFLAGS) $^ -o $#
$(RM) $(OBJ)
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -I$(SRC) -c $< -o $#
debug: CFLAGS+=-DDEBUG
debug: build
.PHONY: clean
clean:
$(RM) $(OBJ) $(OUT)
But that doesn't seem to work as expected, as when I issue make command, it returns the following error message:
Assembler messages: Fatal error: can't create obj/main.o: No such file
or directory
Any ideas how to achieve what I want?
It seems you rm -rf obj/ after each step, but there's no mkdir -p obj/ to replace it.
Since GNU make will, itself, remove intermediate targets, I don't see why you would do $(RM) $(OBJ), but your %.o target could have a line like
mkdir -p "$(shell dirname "$#")"
… to ensure that the destination directory exists.
PS: your output is named build rather than main because that's the name you gave it …

Make error when trying to create *.o

I'm at my wits end here because of this extremely stupid error I'm getting from my makefile.
I finally gave up stripped the makefile down to just two lines:
%.o: %.c
gcc -c -o $# $< -I../inc
Command: make . The output:
make: *** No targets. Stop.
The spaces at the beginning are real tabs instead of spaces. The c files are in the same directory. If instead of %.o I give, say, file1.o and file1.c instead of %.c, all is well (file1.o gets created). I see plenty of examples on the 'net that use the % operator, though. If I include a clean: target, it is promptly found, like so:
%.o: %.c
gcc -c -o $# $< -I../inc
clean:
echo "this is clean!"
Command: make . The output:
echo "this is clean!"
this is clean!
Please help me out here as I'm totally clueless about what's wrong with my targets. In the second sample (the one with clean target), I guess the clean target is found and acted upon as the first one is 'invalid' somehow.
Looks like you forgot to write a target. You have just written rules of how to compile, but not what to do with those objects. I mean, I miss something like:
my_executable_file: *.o
gcc -o my_executable_file *.o
EDIT:
What is set before is true, you need a target. But as you want only to compile, your target should be something like:
OBJECTS = file.o #and whatever objects you need, as a list separated by commas
And then your target:
my_objects: $(OBJECTS)
So putting it all together:
OBJECTS = file.o #and whatever objects you need, as a list separated by commas
my_objects: $(OBJECTS)
%.o: %.c
gcc -c -o $# $< -I../inc
Below is the Makefile that will enable to any number of targets to compile
OBJ := file.o
all: $(OBJ)
%.o: %.c
gcc -c -o $# $< -I../inc
clean:
echo "this is clean!"
Here, OBJ will be the list of the files that you want to compile , like here it is file.c
Add the file name you want to compile to OBJ, when make is called it will build the target all first which depends on the OBJ.
To build OBJ the gcc command is used.
When an explicit target is not given to make, then the first (non-pattern?) target in the Makefile is used. In the case above, it is the clean target.
I see your intention to make only .o files (can be needed for creation of libraries).
You can modify your Makefile to build only .o files or build only executable by using the same Makefile
For the below directory structure (using tree command)
# tree .
.
|-- include
| `-- head.h
|-- Makefile
|-- obj
`-- src
`-- main.c
Makefile
# GNU Makefile #
# Some Variables #
CC := gcc
RM := rm
MV := mv
# Phony Targets #
.PHONY: clean
.PHONY: move
# Path for Source, Object and Include #
SRC_PATH := ./src/
OBJ_PATH := ./obj/
INCLUDE_PATH := ./include/
# Source and Object File Names #
SRC := $(SRC_PATH)main.c
OBJ := $(SRC:c=o) # Substitutes all SRC but with .c as .o (main.c becomes main.o) #
# Executable Name #
TARGET := exe
# Building Binary - use 'make' #
binary: $(TARGET) move
$(TARGET): $(OBJ)
$(CC) -o $(TARGET) $^
# Building only Object Files - use 'make object_only' #
object_only : $(OBJ) move
$(OBJ): $(SRC)
$(CC) -c -o $# $< -I $(INCLUDE_PATH)
# This rule is for moving .o files to ./obj directory (More Organised) #
move:
$(MV) $(SRC_PATH)*.o $(OBJ_PATH)
# For Cleaning - use 'make clean' #
clean:
echo "Cleaning Up!"
$(RM) -rfv $(TARGET) $(OBJ_PATH)*.o $(SRC_PATH)*.o # Delete .o and executable #
Execution:
To build only object files use
$ make object_only
To build object files and executable, use
$ make

Makefile for building multiple applications linking a previous built library

I think to organize my project as follows:
my_project
|--src
|--include
|--test
The core files reside in the directories src and include, whereas the different test applications of the core are within test directory (multiple *.c containing each a main() function). The core should be build as static library which will be linked to all applications).
How to write a basic Makefile to match these requirements? I already googled and found the following website providing a Makefile template for building an executable 1 . How can this Makefile be extended for my needs?
If you think my project organization is bad or you have a better idea, let me know!
Any help is appreciated!
Thanks, Jonas
You haven't said where you want the library to go, so I'll assume it should go into src/ where the objects already go.
src/libcore.a: $(OBJECTS)
$(AR) -cvq $# $^
It looks as if the makefile you have will build test/testfoo.o from test/testfoo.c so I'll assume that that works. And you haven't said where you want the executable tests (e.g. testfoo) to go, so I'll put them in test/.
test/%: test/%.o src/libcore.a
$(CC) -o $# $< -Lsrc -lcore
EDIT:
If you want Make to build all of the tests by default, then you should have this before any other rule in the makefile:
TESTS := $(patsubst %.c,%,$(wildcard test/*.c))
all: $(TESTS)
There is a small project called dotmk which turns the creation of a Makefile very easy.
Here is the link:
https://github.com/swrh/dotmk
You just have to run the install script and create the Makefile like the examples
my Makefile now looks as follows:
SHELL = /bin/sh
CC = gcc
AR = ar
CFLAGS = -std=gnu99 -Iinclude -pedantic -Wall -Wextra -march=native -ggdb3
DEBUGFLAGS = -O0 -D _DEBUG
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
PROFILEFLAGS = -pg
ARFLAGS = -cvq
# core and test common includes
COMMON_INC = include/definitions.h include/debug.h
# core stuff
CORE_LIB = lib/libcore.a
CORE_SRC = $(shell echo src/*.c)
CORE_INC = $(shell echo include/*.h)
CORE_OBJ = $(CORE_SRC:.c=.o)
CORE_PUB_INC =
# test stuff
TEST_SERVER = test/server/server
TEST_SERVER_SRC = $(shell echo test/server/*.c)
TEST_SERVER_INC = $(shell echo test/server/*.h)
TEST_SERVER_OBJ = $(TEST_SERVER_SRC:.c=.o)
TEST_CLIENT = test/client/client
TEST_CLIENT_SRC = $(shell echo test/client/*.c)
TEST_CLIENT_INC = $(shell echo test/client/*.h)
TEST_CLIENT_OBJ = $(TEST_CLIENT_SRC:.c=.o)
all: $(CORE_LIB) $(TEST_SERVER) $(TEST_CLIENT)
core: $(CORE_LIB)
server: core $(TEST_SERVER)
client: core $(TEST_CLIENT)
$(CORE_LIB): $(CORE_OBJ)
$(AR) -cvq $# $^
$(TEST_SERVER): $(TEST_SERVER_OBJ)
$(CC) $(CFLAGS) -o $# $< -Llib -lcore
$(TEST_CLIENT): $(TEST_CLIENT_OBJ)
$(CC) $(CFLAGS) -o $# $< -Llib -lcore
debug: CFLAGS += $(DEBUGFLAGS)
debug: all
profile: CFLAGS += $(PROFILEFLAGS)
profile: all
release: CFLAGS += $(RELEASEFLAGS)
release: all
.PHONY : clean depend
clean:
-rm -f $(CORE_LIB) $(CORE_OBJ)
-rm -f $(TEST_SERVER) $(TEST_SERVER_OBJ)
-rm -f $(TEST_CLIENT) $(TEST_CLIENT_OBJ)
-rm -f gmon.out
depend:
#makedepend -- $(CFLAGS) -- $(CORE_SRC) $(TEST_SERVER_SRC) $(TEST_CLIENT_SRC)
I still have some problems:
- make creates the lib, the server and client test app. If I know modify one of the source files of the core (lib), make builds the lib newly, but not the server and client apps. Do I have a dependency problem?
- make or make all should build by default as DEBUG, whereas release and profile build a release, or profile version respectively.
I wonder, what is wrong in my makefile.
Thanks again!

Resources