Makefile path issues - c

I've .c files in different subfolders within main src directory, I've the problem with running Makefile, I'm new to Makefile, need hands on the Makefile to work and to create a static library.
src/math/addition/add.c (+add.h)
int add(int a, int b) {return a + b;}
src/math/subtraction/sub.c (+sub.h)
int sub(int a, int b) {return a - b;}
src/math/math.c
#include "addition/add.h"
#include "subtraction/sub.h"
Makefile (at the root of the project)
SRC=src/math/Math.c src/math/Math.h src/math/addition/add.c src/math/addition/add.h src/math/subtraction/sub.c src/math/subtraction/sub.h
INCLUDE_PATH=src/
Math: bin
ar rcs libMath.a Math.o
bin:
mkdir bin/
for dir in $(SRC); do \
cd $$dir; \
gcc -c *.c -I../; \
mv *.o ../../../bin; \
cd -; \
done
If you believe there's a better way or any lateral thinking, I'm not fixated on anything.

Makefile is good at two things: building dependency graphs and executing steps between each node in the dependency graphs.
If you have access to GNUMake (most of us do; it's pretty much the only one anyone uses), you can use VPATH to tidy up a bit. VPATH is used to tell make where it can find source files. Be careful with it, if you have multiple files with the same name under different directories.
I suggest you use something akin to the following
VPATH := src src/math src/math/addition src/math/subtraction
CFLAGS += -Isrc -Isrc/math -Isrc/mathaddition -Isrc/math/subtraction
all: libMath
libMath: bin/Math.o bin/add.o bin/sub.o
ar rcs libMath bin/Math.o bin/add.o bin/sub.o
bin/%.o: %.c %.h
Make contains a default .c -> .o rule which you can use; the %.o: %.c %.hdoes this, but also declares that all .o files, by default, depend on a .c and a .h file with the same prefix (the % part) as the object file.
I suspect your Math.o target will also depend on the addition.h and subtraction.h files; you can declare Math.o as dependent on those files using the rule Math.o: Math.c Math.h addition.h subtraction.h.
Remember to substitute the space before ar, with a tab.
You may want to change how you organize your source files and/or header files.
Usually ar produces archive files that end in .a. You may want to change that as well.
If you use make right, you can use parallel builds (make -J) to really speed up compilation time; if you use it wrong, everything is going to get slower and we'll have yet another person who starts to hate make because they don't understand it.

Makefile:
#
# Boilerplate.
#
all:
define add_target
$(info add_target($1))
$(eval $(eval_args))
$(eval $(call eval_args,$1,\
OBJDIR := $(firstword $($1.OBJDIR) ./objs/$1),\
))
$(eval $(call eval_args,$1,\
TYPE := $(firstword $($1.TYPE) binary),\
))
$(eval $(call eval_args,$1,\
objs := $(obj_from_source),
))
$(eval $1 := $($1.TARGET))
TARGETS += $($1)
PHONY_TARGETS += $1
CLEAN_TARGETS += clean_$1
.PHONY: clean_$1
clean_$1:; rm -rf $($1.OBJDIR) $($1)
.PHONY: $1
$1: $($1)
$($1): target:=$1
$($1): $($1.objs); $$(if $$(wildcard $$(#D)),,mkdir -p $$(#D) && )$$(add_target.link)
$($1.objs):; $$(if $$(wildcard $$(#D)),,mkdir -p $$(#D) && )$$(add_target.compile)
$(foreach $1.SOURCES,$($1.SOURCES),$(eval $(obj_from_source): $($1.SOURCES)))
$(info end)
endef
void :=
space := $(void) $(void)
obj_from_source = $(addprefix $($1.OBJDIR)/,$(addsuffix .o,$(basename $(notdir $($1.SOURCES)))))
eval_args = $(foreach i,2 3 4 5 6 7 8 9,$(call eval_arg,$1,$(strip $($i))))
eval_arg = $(if $2,$(info $(space)$(space)$1.$2)$(eval $1.$2))
# Link command line
add_target.link_binary = $(CC) $($(target).LDFLAGS) -o $# $^
add_target.link_lib = $(AR) rcs $# $^
add_target.link = $(add_target.link_$($(target).TYPE))
# Compile command line
add_target.compile = $(CC) -c -o $# $($(target).CFLAGS) $<
# -- Directories --
SRC_ROOT := ./src
BIN := ./bin
# Add 'math' target to the project
$(eval $(call add_target,math,\
TYPE := lib,\
TARGET := $(BIN)/math.a,\
SOURCES += ${SRC_ROOT}/math/addition/add.c\
${SRC_ROOT}/math/subtraction/sub.c\
${SRC_ROOT}/math/math.c,\
CFLAGS := -Wall -I./$(SRC_ROOT)/math,\
))
all: ${PHONY_TARGETS}
.PHONY: all
clean: | $(CLEAN_TARGETS)
.PHONY: clean
Directory structure:
$ find
.
./Makefile
./src
./src/math
./src/math/addition
./src/math/addition/add.c
./src/math/addition/add.h
./src/math/math.c
./src/math/subtraction
./src/math/subtraction/sub.c
./src/math/subtraction/sub.h
File contents:
$ find src/ -type f -exec sh -c "echo Contents of {} file:; cat {}; echo" \;
Contents of src/math/addition/add.c file:
int add(int a, int b) {return a + b;}
Contents of src/math/addition/add.h file:
int add(int a, int b);
Contents of src/math/math.c file:
#include "addition/add.h"
#include "subtraction/sub.h"
Contents of src/math/subtraction/sub.c file:
int add(int a, int b) {return a - b;}
Contents of src/math/subtraction/sub.h file:
int add(int a, int b);
Running Makefile:
$ make
add_target(math)
math.TYPE := lib
math.TARGET := ./bin/math.a
math.SOURCES += ./src/math/addition/add.c ./src/math/subtraction/sub.c ./src/math/math.c
math.CFLAGS := -Wall -I././src/math
math.OBJDIR := ./objs/math
math.TYPE := lib
math.objs := ./objs/math/add.o ./objs/math/sub.o ./objs/math/math.o
end
mkdir -p objs/math && cc -c -o objs/math/add.o -Wall -I././src/math src/math/addition/add.c
cc -c -o objs/math/sub.o -Wall -I././src/math src/math/subtraction/sub.c
cc -c -o objs/math/math.o -Wall -I././src/math src/math/math.c
mkdir -p bin && ar rcs bin/math.a objs/math/add.o objs/math/sub.o objs/math/math.o
This general purpose makefile is missing some important features, like tracking .h file dependencies, linking with static/dynamic libraries, etc. Extend it with the features you need yourself.

Related

Can't run simple printf on cortex a55

I'm trying to get started with the RK3568 controller (cortex a55)
I have a project and a makefile
I managed to output the character using registers and flashing the LED.
But if I try to output a string using printf, the program just freezes without any signs of life.
I was looking for a solution to the problem, and the main solution is to implement the _write function(int file, char *ptr, int len), which the standard printf function should use. But it doesn't help.
I tried to connect another Printf function from github and it works. I don't understand what the reason is.
I tried to call other functions from the standard library, for example strlen and it has the same behavior as printf
int _write(int file, char *ptr, int len)
{
__io_putchar('w');
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar( *ptr++ );
}
return len;
}
I am using the AArch64 bare-metal target compiler (aarch64-none-elf)
I tried using another AArch32 bare-metal target compiler (arm-none-eabi), but there are even more problems with it. He can't even build the project and throws assembler errors.
Error: selected processor does not support requested special purpose register -- `msr tpidr_el 1,xzr'
Error: ARM register expected -- `ldr x1,=_start'
and many more similar
my makefile, maybe its help
PWD := $(shell pwd)
PRJ_BUILD := $(PWD)/build
CC := aarch64-none-elf-gcc
LD := aarch64-none-elf-ld
OBJCOPY := aarch64-none-elf-objcopy
OBJDUMP := aarch64-none-elf-objdump
SRC := src/entry_point.S
SRC += src/cache.S
SRC += src/main.c
SRC += src/stub.c
SRC := $(addprefix $(PWD)/,$(SRC))
INCLUDES := .
INCLUDES += src
INCLUDES := $(addprefix -I$(PWD)/,$(INCLUDES))
CFLAGS := -c -g
#CFLAGS += -march=armv8.2-a -mcpu=cortex-a55
CFLAGS += -mcpu=cortex-a55
#-mcpu=cortex-a55 -mfloat-abi=hard
define get_library_path
$(shell dirname $(shell $(CC) $(CFLAGS) -print-file-name=$(1)))
endef
LDFLAGS += -L $(call get_library_path,libc.a)
LDFLAGS += -L $(call get_library_path,libgcc.a)
LDFLAGS += -T $(PWD)/link.lds -lgcc -lc
all: app.elf
app.elf:
$(info $(PWD))
$(info SRC:[$(SRC)])
$(info INCLUDES:[$(INCLUDES)])
cd $(PRJ_BUILD) && $(CC) $(CFLAGS) $(INCLUDES) $(SRC)
cd $(PRJ_BUILD) && \
$(LD) -o app.elf $(PRJ_BUILD)/*.o \
$(LDFLAGS) -Map app.map
cd $(PRJ_BUILD) && $(OBJCOPY) -O binary app.elf app.bin
cd $(PRJ_BUILD) && $(OBJDUMP) app.elf -dS > app.lst
clean:
cd $(PRJ_BUILD) && rm -f *.*
I would be glad to at least some advice
In the end I was able to solve this problem
I tried to do the following
I implemented the _sbrk function (get from this)
I tried to highlight heap and stack
I implemented the _write function (but did not touch _write_r [!])
I provided the implementation of the memcmp, memset, memmove, memcpy functions
In reality, item No. has the greatest impact on work.4. If you remove everything except point 4, then the code works and I can output "Hello world"!
Let me remind you that I use aarch64-none-elf-gcc
item 4 I took from here https://embeddedartistry.com/blog/2017/03/22/memset-memcpy-memcmp-and-memmove/

multiple definition of `function' error occurring on the same line as "first defined here"

error log
paging.c: In function ‘setup_paging_structures’:
paging.c:7: warning: implicit declaration of function ‘printf’
rm -f bootimg
gcc -nostdlib -static boot.o paging.o x86_desc.o i8259.o kernel.o lib.o paging.o tests.o -Ttext=0x400000 -o bootimg
paging.o: In function `setup_paging_structures':
/workdirmain/work/mp3_group_31/student-distrib/paging.c:4: multiple definition of `setup_paging_structures'
paging.o:/workdirmain/work/mp3_group_31/student-distrib/paging.c:4: first defined here
paging.o: In function `initialize_paging':
/workdirmain/work/mp3_group_31/student-distrib/paging.c:13: multiple definition of `initialize_paging'
paging.o:/workdirmain/work/mp3_group_31/student-distrib/paging.c:13: first defined here
collect2: ld returned 1 exit status
make: *** [bootimg] Error 1
Here's what my paging.h file looks like:
#ifndef _PAGING_H
#define _PAGING_H
#include "types.h"
#define TOTAL_ENTRIES 1024
extern void setup_paging_structures();
extern void initialize_paging();
#endif
Paging.c below:
#include "paging.h" //include header files
void setup_paging_structures(){
int i;
for (i = 0; i < TOTAL_ENTRIES; i++){
printf("weird");
}
return;
}
void initialize_paging(){
setup_paging_structures();
return;
}
Note, I have not called the functions yet.
The command I'm using is "sudo make" (Makefile was given to me. I'm pretty sure I'm not supposed to modify it):
# Makefile for OS project
# To build, first `make dep`, them `make`. Everything should be automatic.
# Will compile all *.c and *.S files in the current directory.
# Flags to use when compiling, preprocessing, assembling, and linking
CFLAGS+=-Wall -fno-builtin -fno-stack-protector -nostdlib
ASFLAGS+=
LDFLAGS+=-nostdlib -static
CC=gcc
#If you have any .h files in another directory, add -I<dir> to this line
CPPFLAGS+=-nostdinc -g
# This generates the list of source files
SRC=$(wildcard *.S) $(wildcard *.c) $(wildcard */*.S) $(wildcard */*.c)
# This generates the list of .o files. The order matters, boot.o must be first
OBJS=boot.o
OBJS+=$(filter-out boot.o,$(patsubst %.S,%.o,$(filter %.S,$(SRC))))
OBJS+=$(patsubst %.c,%.o,$(filter %.c,$(SRC)))
bootimg: Makefile $(OBJS)
rm -f bootimg
$(CC) $(LDFLAGS) $(OBJS) -Ttext=0x400000 -o bootimg
sudo ./debug.sh
dep: Makefile.dep
Makefile.dep: $(SRC)
$(CC) -MM $(CPPFLAGS) $(SRC) > $#
.PHONY: clean
clean:
rm -f *.o */*.o Makefile.dep
ifneq ($(MAKECMDGOALS),dep)
ifneq ($(MAKECMDGOALS),clean)
include Makefile.dep
endif
endif
edit: I added updates to my post including the actual directories, the entire error log, and the contents of the Makefile I am using. This is also for a class that I'm currently taking, hence some of the things that were automatically given to me.

"make all" twice in a row doesn't return "make: Nothing to be done for 'all'."

I've noticed a lot of questions about people having the message "make: Nothing to be done for 'all'.", however my problem is the opposite.
Here is my makefile:
#################
## VARIABLES ##
#################
# Environment
OS := $(shell uname)
# Output
NAME := libft.a
DYNAMIC_NAME := ${NAME:a=so}
# Compiler
CC := gcc
ifneq ($(OS), Linux)
FLAGS += -Wall -Wextra -Werror
endif
DYN_FLAG := -shared
HEADERS := -I ./includes/
O_FLAG := -O2
# Directories
ADDITIONAL_FUNCTIONS = $(addprefix ./additional_functions/, $(ADDITIONAL))
BONUS_FUNCTIONS = $(addprefix ./bonus_functions/, $(BONUS))
LIBC_FUNCTIONS = $(addprefix ./libc_functions/, $(LIBC))
PERSONAL_FUNCTIONS = $(addprefix ./personal_functions/, $(PERSONAL))
DYN_OBJDIR = dyn_build/
OBJDIR := build/
# Sources
ADDITIONAL += ft_itoa.c
ADDITIONAL += ft_memalloc.c ft_memdel.c
ADDITIONAL += ft_putchar.c ft_putchar_fd.c
ADDITIONAL += ft_putendl.c ft_putendl_fd.c
ADDITIONAL += ft_putnbr.c ft_putnbr_fd.c
ADDITIONAL += ft_putstr.c ft_putstr_fd.c
ADDITIONAL += ft_strclr.c ft_strdel.c
ADDITIONAL += ft_strnew.c ft_strjoin.c
ADDITIONAL += ft_strequ.c ft_strnequ.c
ADDITIONAL += ft_striter.c ft_striteri.c
ADDITIONAL += ft_strmap.c ft_strmapi.c
ADDITIONAL += ft_strsplit.c ft_strsub.c ft_strtrim.c
BONUS += ft_lstadd.c ft_lstnew.c
BONUS += ft_lstdel.c ft_lstdelone.c
BONUS += ft_lstiter.c ft_lstmap.c
LIBC += ft_atoi.c
LIBC += ft_isalnum.c ft_isalpha.c ft_isascii.c
LIBC += ft_isdigit.c ft_isprint.c
LIBC += ft_memcpy.c ft_memccpy.c ft_memchr.c ft_memcmp.c
LIBC += ft_bzero.c ft_memmove.c ft_memset.c
LIBC += ft_strcat.c ft_strlcat.c ft_strncat.c
LIBC += ft_strchr.c ft_strrchr.c
LIBC += ft_strcmp.c ft_strncmp.c
LIBC += ft_strcpy.c ft_strncpy.c ft_strdup.c
LIBC += ft_strlen.c
LIBC += ft_strstr.c ft_strnstr.c
LIBC += ft_tolower.c ft_toupper.c
PERSONAL += ft_intlen.c
PERSONAL += ft_invert.c ft_islower.c ft_isupper.c
PERSONAL += ft_lstgetnode.c ft_lstsize.c
PERSONAL += ft_kill.c ft_putuchar.c ft_putuchar_fd.c
PERSONAL += ft_strrev.c ft_strrevcpy.c
PERSONAL += get_next_line.c
DYN_OBJECTS = $(patsubst %.c,$(DYN_OBJDIR)%.o,$(SRCS))
OBJECTS = $(patsubst %.c,$(OBJDIR)%.o,$(SRCS))
SRCS += $(ADDITIONAL_FUNCTIONS)
SRCS += $(BONUS_FUNCTIONS)
SRCS += $(LIBC_FUNCTIONS)
SRCS += $(PERSONAL_FUNCTIONS)
#################
## RULES ##
#################
all: $(NAME)
$(NAME): $(OBJECTS)
#ar rcs $# $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(SRCS)))
ranlib $#
#echo "Static library created."
$(OBJECTS): | $(OBJDIR)
$(OBJDIR):
#mkdir -p $#
$(OBJDIR)%.o: %.c
$(CC) $(FLAGS) $(O_FLAG) -c $< $(HEADERS) -o $(OBJDIR)$(notdir $#)
$(DYN_OBJECTS): | $(DYN_OBJDIR)
$(DYN_OBJDIR):
#mkdir -p $#
$(DYN_OBJDIR)%.o: %.c
$(CC) $(FLAGS) $(O_FLAG) -c $< $(HEADERS) -fpic -o $(DYN_OBJDIR)$(notdir $#)
clean:
#/bin/rm -rfv $(OBJDIR)
#/bin/rm -rfv $(DYN_OBJDIR)
fclean: clean
#/bin/rm -fv $(NAME)
#/bin/rm -fv $(DYNAMIC_NAME)
re: fclean all
so: $(DYN_OBJECTS)
#$(CC) $(DYN_FLAG) -o $(DYNAMIC_NAME) $(patsubst %.c,$(DYN_OBJDIR)%.o,$(notdir $(SRCS)))
#echo "Dynamic library created."
.PHONY: all build clean dynbuild fclean re so
The makefile works perfectly fine. It takes every .c in the different directories, creates an object directory, build/ if the library is static and dyn_build/ if it is dynamic, put the object files inside said directory and compile the library from them.
My issue is that if I run make twice in a row, nothing should be done the second time as the object files and the library are still there and up to date. But, somehow doing make twice in a row results in the second make repeating the operation.
What is causing this and is there a way to fix it?
Your problem can be reduced to this:
ADDITIONAL += ft_strsplit.c
BONUS += ft_lstadd.c
ADDITIONAL_FUNCTIONS = $(addprefix ./add/, $(ADDITIONAL))
BONUS_FUNCTIONS = $(addprefix ./bonus/, $(BONUS))
SRCS += $(ADDITIONAL_FUNCTIONS)
SRCS += $(BONUS_FUNCTIONS)
OBJECTS = $(patsubst %.c,./build/%.o,$(SRCS))
# OBJECTS contains ./build/./add/ft_strsplit.o and ./build/./bonus/ft_lstadd.o
all: $(OBJECTS)
$(OBJDIR)%.o: %.c
$(CC) ...
So Make runs the last rule with e.g. build/./add/ft_strsplit.o as the target, and add/ft_strsplit.c as the prerequisite. The question is how to write the recipe so as to build build/ft_strsplit.o.
As #user657267 has pointed out, it is a mistake to have a (non-PHONY) rule that does not build a file whose name is the target of the rule. So let's first ask Make for the files we actually want:
ADDITIONAL += ft_strsplit.c
BONUS += ft_lstadd.c
SRCS += $(ADDITIONAL)
SRCS += $(BONUS)
OBJECTS = $(patsubst %.c,./build/%.o,$(SRCS))
# OBJECTS contains ./build/ft_strsplit.o and ./build/ft_lstadd.o
So far so good, but now how can Make find the sources? When we ask Make to build ./build/ft_strsplit.o, how can it know where ft_strsplit.c is?
We use vpath:
vpath %.c add bonus
Now the makefile works correctly. And to write that vpath line automatically, we can just pull the directory names out of the assignments:
# Directories
ADDITIONAL_DIR := ./additional_functions
BONUS_DIR := ./bonus_functions
...
ADDITIONAL_FUNCTIONS = $(addprefix $(ADDITIONAL_DIR)/, $(ADDITIONAL))
BONUS_FUNCTIONS = $(addprefix $(BONUS_DIR)/, $(BONUS))
...
vpath %.c $(ADDITIONAL_DIR)
vpath %.c $(BONUS_DIR)
...

Makefile with multiple files always builds everything

I am writing a Makefile which compiles a number of C files, some in the same directory as the Makefile and others in parent directories (must be there for historic reasons). I want to put all *.o files in a single directory (objdir in my case). This seems to work, but for some reason, this Makefile always builds everything, even if nothing has changed. Where am I going wrong in my rules/dependecies?
UPDATE: I've distilled my Makefile and sources down to the bare minimum (see below for source file contents. To be clear, this does compile and link. The problem is that it does the compilation and linking every time I run make, even if nothing has changed. This is not typical make behavior.
Makefile contents:
CC = gcc
CFLAGS = -g -Wall -Werror -I..
SRCS = main.c ../a.c
OBJS = $(patsubst %.c, objdir/%.o, $(SRCS))
LN_OBJS = $(patsubst %.c, objdir/%.o, $(notdir $(SRCS)))
MAIN = foo
.PHONY: clean
default: objdir $(MAIN)
#echo Done
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) -o $(MAIN) $(LN_OBJS )
objdir/%.o: %.c
$(CC) $(CFLAGS) -c $< -o objdir/$(notdir $#)
objdir:
#mkdir -p objdir
clean:
#$(RM) -rf objdir $(FDP) $(DK)
main.c contents
#include "stdlib.h"
#include "stdio.h"
#include "a.h"
int main(int argc, char**argv)
{
printf("Hello\n");
a();
}
../a.c contents
#include <stdio.h>
void a()
{
printf("Hi from a\n");
}
../a.h contents
#ifndef __a__
#define __a__
void a();
#endif
Your rule for objdir/%.o: is expanded to objdir/../a.o: ../a.c, but you then go and create objdir/$(notdir $#), violating rule 2 of the Rules of Makefiles.
One way to fix this is with vpath (also note that objdir should be a (order-only) dependency of the objects):
SRCS = main.c a.c
vpath %.c ../
# [...]
objdir/%.o: %.c | objdir
$(CC) $(CFLAGS) -c $< -o $#

use define to generate Makefile rule with eval function

I want to generate rules in Makefile like this for many PROG
CC = gcc
LD = gcc
CFLAGS = -g
LDFLAGS = -g
PROGS = test1 test2
SRCS_test1 = test1.c
SRCS_test2 = test2.c
$(foreach prog, $(PROGS), $(eval OBJS_$(prog) = $(SRCS_$(prog):%.c=%.o)))
.PHONY: all clean
all: $(PROGS)
define PROG_template
$(1): $$(OBJS_$$(1))
#echo ------------------
#echo $(1)
#echo $$(OBJS_test1) $$(OBJS_test2)
#echo $$(OBJS_$(1))
#echo $$^
#echo -----------------
$$(LD) $$(LDFLAGS) -o $$# $$^
endef
$(foreach prog, $(PROGS), $(eval $(call PROG_template, $(prog))))
%.o: %.c
#echo compiling $#
$(CC) $(CFLAGS) -c -o $# $<
clean:
rm -f $(OBJS_test1) $(OBJS_test2) $(PROGS)
the output like this
------------------
test1
test1.o test2.o
-----------------
gcc -g -o test1
gcc prompt no input file.
what's wrong with my Makefile?
Thanks at first.
Sorry, My English is poor.
You have two errors. The first is just a typo; this line:
$(1): $$(OBJS_$$(1))
should be:
$(1): $$(OBJS_$(1))
(note removing unwanted $ in the second $(1).
The second error is more subtle: you have to be careful about whitespace when you are invoking functions in make. When you leave whitespace in arguments to call, for example, it can get embedded into the argument. So here:
$(foreach prog, $(PROGS), $(eval $(call PROG_template, $(prog))))
^
That space is being used verbatim as part of the argument, so '$1' is equivalent to ' test1', not just 'test1'. You can debug eval operations by replacing the eval with info to see what make sees:
$(foreach prog, $(PROGS), $(info $(call PROG_template, $(prog))))
will show you:
test1: $(OBJS_ test1)
note the extra space.
Remove extra whitespace and it'll work:
$(foreach prog, $(PROGS), $(eval $(call PROG_template,$(prog))))
^^

Resources