Multi target makefile with subfolders - c

My project has the following structure:
\---Project
+ Makefile
|
+---source
| +---target1
| | t1_lib.c
| | t1_main.c
| |
| +---target2
| | t2_lib.c
| | t2_main.c
| |
| \---common
| common_lib.c
|
+---headers
+---target1
| t1_lib.h
|
+---target2
| t2_lib.h
|
\---common
common_lib.h
I am trying to write a makefile which allows me to run 'make target1' or 'make target2' and compile target1 source code with common source code or compile target2 source code with common source code respectively.
In my project, target1 is call 'ue' and target2 is call 'enb'.
This is what I have in my current makefile:
# Author: j0lama
# COMPILER
CC = gcc
#FLAGS
CFLAGS = -c -Wall -ansi -g -std=c99 -D_DEBUG
#LIB FLAGS
LIBFLAGS = -lgc -rdynamic -lcrypto -lpthread
#LINK FLAGS
LINKFLAGS = -lsctp
# PATHS
UE_SOURCE_DIRECTORY = source/ue/
UE_INCLUDE_DIRECTORY = headers/ue/
ENB_SOURCE_DIRECTORY = source/enb/
ENB_INCLUDE_DIRECTORY = headers/enb/
COMMON_SRC_DIRECTORY = source/common/
COMMON_HDR_DIRECTORY = headers/common/
OBJECT_DIRECTORY = objects/
BUILD_DIRECTORY = build/
COMMON_CFILES= $(wildcard $(COMMON_SRC_DIRECTORY)*.c)
COMMON_OBJECTS= $(patsubst $(COMMON_SRC_DIRECTORY)%.c, $(OBJECT_DIRECTORY)%.o, $(COMMON_CFILES))
CFILES = $(COMMON_CFILES)
OBJECTS = $(COMMON_OBJECTS)
all: clean ue enb
ue: setup_ue $(OBJECT_DIRECTORY) $(TARGET) ue_emulator
enb: setup_enb $(OBJECT_DIRECTORY) $(TARGET) enb_emulator
setup_ue:
$(eval CFILES += $(wildcard $(UE_SOURCE_DIRECTORY)*.c))
$(eval OBJECTS += $(patsubst $(UE_SOURCE_DIRECTORY)%.c, $(OBJECT_DIRECTORY)%.o, $(wildcard $(UE_SOURCE_DIRECTORY)*.c)))
$(eval INCLUDE_DIRECTORY = $(UE_INCLUDE_DIRECTORY))
setup_enb:
$(eval CFILES += $(wildcard $(ENB_SOURCE_DIRECTORY)*.c))
$(eval OBJECTS += $(patsubst $(ENB_SOURCE_DIRECTORY)%.c, $(OBJECT_DIRECTORY)%.o, $(wildcard $(ENB_SOURCE_DIRECTORY)*.c)))
$(eval INCLUDE_DIRECTORY = $(ENB_INCLUDE_DIRECTORY))
$(OBJECT_DIRECTORY):
#mkdir $(OBJECT_DIRECTORY)
#echo "Building objects directory..."
ue_emulator: $(OBJECTS)
#echo "Building $#..."
#$(CC) $(OBJECTS) $(LIBFLAGS) $(LINKFLAGS) -o $#
enb_emulator: $(OBJECTS)
#echo "Building $#..."
#$(CC) $(OBJECTS) $(LIBFLAGS) $(LINKFLAGS) -o $#
$(OBJECT_DIRECTORY)%.o: $(SOURCE_DIRECTORY)%.c $(COMMON_SRC_DIRECTORY)%.c
#echo "Building $#..."
#$(CC) -I $(COMMON_HDR_DIRECTORY) -I $(INCLUDE_DIRECTORY) $(CFLAGS) $(LIBFLAGS) $< -o $#
.PHONY: clean
clean:
#echo "Removing objects files"
#rm -rf $(OBJECT_DIRECTORY) $(TARGET)
Somehow this makefile does not compile any file.

Related

riscv64-linux-gnu-ld: undefined reference to `fseek'

Recently,I met with this problem under vmware ubuntu 22.04:
riscv64-linux-gnu-ld: loader.c:(.text.naive_uload+0x4c): undefined reference to fseek' riscv64-linux-gnu-ld: loader.c:(.text.naive_uload+0x78): undefined reference to fread'
riscv64-linux-gnu-ld: loader.c:(.text.naive_uload+0xbc): undefined reference to fseek' riscv64-linux-gnu-ld: loader.c:(.text.naive_uload+0xe0): undefined reference to fread'
I was using crossing compiler
My makefile is:
# Makefile for AbstractMachine Kernels and Libraries
### *Get a more readable version of this Makefile* by `make html` (requires python-markdown)
html:
cat Makefile | sed 's/^\([^#]\)/ \1/g' | markdown_py > Makefile.html
.PHONY: html
## 1. Basic Setup and Checks
### Default to create a bare-metal kernel image
ifeq ($(MAKECMDGOALS),)
MAKECMDGOALS = image
.DEFAULT_GOAL = image
endif
### Override checks when `make clean/clean-all/html`
ifeq ($(findstring $(MAKECMDGOALS),clean|clean-all|html),)
### Print build info message
$(info # Building $(NAME)-$(MAKECMDGOALS) [$(ARCH)])
### Check: environment variable `$AM_HOME` looks sane
ifeq ($(wildcard $(AM_HOME)/am/include/am.h),)
$(error $$AM_HOME must be an AbstractMachine repo)
endif
### Check: environment variable `$ARCH` must be in the supported list
ARCHS = $(basename $(notdir $(shell ls $(AM_HOME)/scripts/*.mk)))
ifeq ($(filter $(ARCHS), $(ARCH)), )
$(error Expected $$ARCH in {$(ARCHS)}, Got "$(ARCH)")
endif
### Extract instruction set architecture (`ISA`) and platform from `$ARCH`. Example: `ARCH=x86_64-qemu -> ISA=x86_64; PLATFORM=qemu`
ARCH_SPLIT = $(subst -, ,$(ARCH))
ISA = $(word 1,$(ARCH_SPLIT))
PLATFORM = $(word 2,$(ARCH_SPLIT))
### Check if there is something to build
ifeq ($(flavor SRCS), undefined)
$(error Nothing to build)
endif
### Checks end here
endif
## 2. General Compilation Targets
### Create the destination directory (`build/$ARCH`)
WORK_DIR = $(shell pwd)
DST_DIR = $(WORK_DIR)/build/$(ARCH)
$(shell mkdir -p $(DST_DIR))
### Compilation targets (a binary image or archive)
IMAGE_REL = build/$(NAME)-$(ARCH)
IMAGE = $(abspath $(IMAGE_REL))
ARCHIVE = $(WORK_DIR)/build/$(NAME)-$(ARCH).a
### Collect the files to be linked: object files (`.o`) and libraries (`.a`)
OBJS = $(addprefix $(DST_DIR)/, $(addsuffix .o, $(basename $(SRCS))))
LIBS := $(sort $(LIBS) am klib) # lazy evaluation ("=") causes infinite recursions
LINKAGE = $(OBJS) \
$(addsuffix -$(ARCH).a, $(join \
$(addsuffix /build/, $(addprefix $(AM_HOME)/, $(LIBS))), \
$(LIBS) ))
## 3. General Compilation Flags
### (Cross) compilers, e.g., mips-linux-gnu-g++
AS = $(CROSS_COMPILE)gcc
CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
READELF = $(CROSS_COMPILE)readelf
### Compilation flags
INC_PATH += $(WORK_DIR)/include $(addsuffix /include/, $(addprefix $(AM_HOME)/, $(LIBS)))
INCFLAGS += $(addprefix -I, $(INC_PATH))
CFLAGS += -O2 -MMD -Wall -Werror $(INCFLAGS) \
-D__ISA__=\"$(ISA)\" -D__ISA_$(shell echo $(ISA) | tr a-z A-Z)__ \
-D__ARCH__=$(ARCH) -D__ARCH_$(shell echo $(ARCH) | tr a-z A-Z | tr - _) \
-D__PLATFORM__=$(PLATFORM) -D__PLATFORM_$(shell echo $(PLATFORM) | tr a-z A-Z | tr - _) \
-DARCH_H=\"arch/$(ARCH).h\" \
-fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector \
-Wno-main -U_FORTIFY_SOURCE
CXXFLAGS += $(CFLAGS) -ffreestanding -fno-rtti -fno-exceptions
ASFLAGS += -MMD $(INCFLAGS)
LDFLAGS += -z noexecstack
## 4. Arch-Specific Configurations
### Paste in arch-specific configurations (e.g., from `scripts/x86_64-qemu.mk`)
-include $(AM_HOME)/scripts/$(ARCH).mk
### Fall back to native gcc/binutils if there is no cross compiler
ifeq ($(wildcard $(shell which $(CC))),)
$(info # $(CC) not found; fall back to default gcc and binutils)
CROSS_COMPILE :=
endif
## 5. Compilation Rules
### Rule (compile): a single `.c` -> `.o` (gcc)
$(DST_DIR)/%.o: %.c
#mkdir -p $(dir $#) && echo + CC $<
#$(CC) -std=gnu11 $(CFLAGS) -c -o $# $(realpath $<)
### Rule (compile): a single `.cc` -> `.o` (g++)
$(DST_DIR)/%.o: %.cc
#mkdir -p $(dir $#) && echo + CXX $<
#$(CXX) -std=c++17 $(CXXFLAGS) -c -o $# $(realpath $<)
### Rule (compile): a single `.cpp` -> `.o` (g++)
$(DST_DIR)/%.o: %.cpp
#mkdir -p $(dir $#) && echo + CXX $<
#$(CXX) -std=c++17 $(CXXFLAGS) -c -o $# $(realpath $<)
### Rule (compile): a single `.S` -> `.o` (gcc, which preprocesses and calls as)
$(DST_DIR)/%.o: %.S
#mkdir -p $(dir $#) && echo + AS $<
#$(AS) $(ASFLAGS) -c -o $# $(realpath $<)
### Rule (recursive make): build a dependent library (am, klib, ...)
$(LIBS): %:
#$(MAKE) -s -C $(AM_HOME)/$* archive
### Rule (link): objects (`*.o`) and libraries (`*.a`) -> `IMAGE.elf`, the final ELF binary to be packed into image (ld)
$(IMAGE).elf: $(OBJS) am $(LIBS)
#echo + LD "->" $(IMAGE_REL).elf
#$(LD) $(LDFLAGS) -o $(IMAGE).elf --start-group $(LINKAGE) --end-group
### Rule (archive): objects (`*.o`) -> `ARCHIVE.a` (ar)
$(ARCHIVE): $(OBJS)
#echo + AR "->" $(shell realpath $# --relative-to .)
#ar rcs $(ARCHIVE) $(OBJS)
### Rule (`#include` dependencies): paste in `.d` files generated by gcc on `-MMD`
-include $(addprefix $(DST_DIR)/, $(addsuffix .d, $(basename $(SRCS))))
## 6. Miscellaneous
### Build order control
image: image-dep
archive: $(ARCHIVE)
image-dep: $(OBJS) am $(LIBS)
#echo \# Creating image [$(ARCH)]
.PHONY: image image-dep archive run $(LIBS)
### Clean a single project (remove `build/`)
clean:
rm -rf Makefile.html $(WORK_DIR)/build/
.PHONY: clean
### Clean all sub-projects within depth 2 (and ignore errors)
CLEAN_ALL = $(dir $(shell find . -mindepth 2 -name Makefile))
clean-all: $(CLEAN_ALL) clean
$(CLEAN_ALL):
-#$(MAKE) -s -C $# clean
.PHONY: clean-all $(CLEAN_ALL)
#HAS_NAVY = 1
RAMDISK_FILE = build/ramdisk.img
NAME = nanos-lite
SRCS = $(shell find -L ./src/ -name "*.c" -o -name "*.cpp" -o -name "*.S")
include $(AM_HOME)/Makefile
ifeq ($(ARCH),native)
ISA = am_native
else
INC_PATH += include $(NAVY_HOME)/libs/libc/include
endif
./src/resources.S: $(RAMDISK_FILE)
#touch $#
ifeq ($(HAS_NAVY),)
files = $(RAMDISK_FILE) src/files.h src/syscall.h
# create an empty file if it does not exist
$(foreach f,$(files),$(if $(wildcard $f),, $(shell touch $f)))
else
ifeq ($(wildcard $(NAVY_HOME)/libs/libos/src/syscall.h),)
$(error $$NAVY_HOME must be a Navy-apps repo)
endif
update:
$(MAKE) -s -C $(NAVY_HOME) ISA=$(ISA) ramdisk
#ln -sf $(NAVY_HOME)/build/ramdisk.img $(RAMDISK_FILE)
#ln -sf $(NAVY_HOME)/build/ramdisk.h src/files.h
#ln -sf $(NAVY_HOME)/libs/libos/src/syscall.h src/syscall.h
.PHONY: update
endif
I was fully unaware of what was happening.Who can help me,please!!!
Solve the cross compile link error

How can I make my Makefile build to the obj/ folder, not the src/ folder?

I am extending an old school project, and I have the Makefile the course staff made for us. I have reorganized the directory structure of the project like this.
+-----obj
|
+-----src
| |
| +-Makefile
| +-allocator.h
| +-debug_break.h
| +-rbtree_clrs.c
| +-rbtree_linked.c
| +-rbtree_stack.c
| +-rbtree_topdown.c
| +-rbtree_unified.c
| +-segment.c
| +-segment.h
| +-test_harness.c
| +-my_optional_program.c
|
+------scripts
The Makefile currently prepends the heap allocators I wrote (files starting with rbtree_) with either test_ or my_optional_program and puts them in the same directory as the Makefile. I can then run my different heap allocator implementations on the scripts in the scripts folder. Instead, I want this:
+-----obj
| +-my_optional_program_rbtree_clrs
| +-my_optional_program_rbtree_linked
| +-my_optional_program_rbtree_stack
| +-my_optional_program_rbtree_topdown
| +-my_optional_program_rbtree_unified
| +-test_rbtree_clrs
| +-test_rbtree_linked
| +-test_rbtree_stack
| +-test_rbtree_topdown
| +-test_rbtree_unified
|
+-----src
| |
| +-Makefile
| +-allocator.h
| +-debug_break.h
| +-rbtree_clrs.c
| +-rbtree_linked.c
| +-rbtree_stack.c
| +-rbtree_topdown.c
| +-rbtree_unified.c
| +-segment.c
| +-segment.h
| +-test_harness.c
| +-my_optional_program.c
|
+------scripts
What do I need to add or change in the Makefile so that it will build to the obj/ folder?
# They had us try different optimization levels here (-O0, -O2, etc).
rbtree_clrs.o: CFLAGS += -O0
rbtree_unified.o: CFLAGS += -O0
rbtree_linked.o: CFLAGS += -O0
rbtree_stack.o: CFLAGS += -O0
rbtree_topdown.o: CFLAGS += -O0
ALLOCATORS = rbtree_clrs rbtree_unified rbtree_stack rbtree_linked rbtree_topdown
PROGRAMS = $(ALLOCATORS:%=test_%)
MY_PROGRAMS = $(ALLOCATORS:%=my_optional_program_%)
all:: $(PROGRAMS) $(MY_PROGRAMS)
# I had to use gcc-11 on mac to be able to build this project.
UNAME := $(shell uname)
ifeq ($(UNAME),Darwin)
CC = gcc-11
else
CC = gcc
endif
CFLAGS = -g3 -std=gnu99 -Wall $$warnflags -fcf-protection=none -fno-pic -no-pie
export warnflags = -Wfloat-equal -Wtype-limits -Wpointer-arith -Wlogical-op -Wshadow -Winit-self -fno-diagnostics-show-option
LDFLAGS =
LDLIBS =
$(PROGRAMS): test_%:%.o segment.c test_harness.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(MY_PROGRAMS): my_optional_program_%:my_optional_program.c %.o segment.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean::
rm -f $(PROGRAMS) $(MY_PROGRAMS) *.o callgrind.out.*
.PHONY: clean all
.INTERMEDIATE: $(ALLOCATORS:%=%.o)
Update: This Makefile has solved the issue. I took Renaud Pacalet's Makefile (thanks!) and adjusted the paths to achieve the desired result. It seems not going up one level in the directories was an issue. Then I had to add the path I wanted to the ALLOCATORS in the PROGRAMS variable. I have no idea if this is how it should be done but it worked. I can update this if there is a better way.
SRCDIR = ../src
OBJDIR = ../obj
SRC := $(wildcard $(SRCDIR)/*.c)
OBJ := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o,$(SRC))
# They had us try different optimization levels here (-O0, -O2, etc).
$(filter $(OBJDIR)/rbtree_%.o,$(OBJ)): CFLAGS += -O0
ALLOCATORS = rbtree_clrs rbtree_unified rbtree_stack rbtree_linked rbtree_topdown
PROGRAMS = $(addprefix $(OBJDIR)/test_,$(ALLOCATORS))
MY_PROGRAMS = $(addprefix $(OBJDIR)/my_optional_program_,$(ALLOCATORS))
all:: $(PROGRAMS) $(MY_PROGRAMS)
# I had to use gcc-11 on mac to be able to build this project.
UNAME := $(shell uname)
ifeq ($(UNAME),Darwin)
CC = gcc-11
else
CC = gcc
endif
CFLAGS = -g3 -std=gnu99 -Wall $$warnflags -fcf-protection=none -fno-pic -no-pie
export warnflags = -Wfloat-equal -Wtype-limits -Wpointer-arith -Wlogical-op -Wshadow -Winit-self -fno-diagnostics-show-option
LDFLAGS =
LDLIBS =
$(OBJ): $(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c -o $# $<
$(PROGRAMS): $(OBJDIR)/test_%: $(OBJDIR)/%.o segment.c test_harness.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(MY_PROGRAMS): $(OBJDIR)/my_optional_program_%: my_optional_program.c $(OBJDIR)/%.o segment.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean::
rm -f $(PROGRAMS) $(MY_PROGRAMS) $(OBJ) callgrind.out.*
You don't have a compilation rule so make uses its implicit rule for compilation which puts the object files in the same directory as the source files.
Simply add a rule of your own and rework a bit all references to object files:
OBJDIR := ../obj
SRC := $(wildcard *.c)
OBJ := $(patsubst %.c,$(OBJDIR)/%.o,$(SRC))
# They had us try different optimization levels here (-O0, -O2, etc).
$(filter $(OBJDIR)/rbtree_%.o,$(OBJ)): CFLAGS += -O0
ALLOCATORS = rbtree_clrs rbtree_unified rbtree_stack rbtree_linked rbtree_topdown
PROGRAMS = $(ALLOCATORS:%=$(OBJDIR)/test_%)
MY_PROGRAMS = $(ALLOCATORS:%=$(OBJDIR)/my_optional_program_%)
all:: $(PROGRAMS) $(MY_PROGRAMS)
# I had to use gcc-11 on mac to be able to build this project.
UNAME := $(shell uname)
ifeq ($(UNAME),Darwin)
CC = gcc-11
else
CC = gcc
endif
CFLAGS = -g3 -std=gnu99 -Wall $$warnflags -fcf-protection=none -fno-pic -no-pie
export warnflags = -Wfloat-equal -Wtype-limits -Wpointer-arith -Wlogical-op -Wshadow -Winit-self -fno-diagnostics-show-option
LDFLAGS =
LDLIBS =
$(OBJ): $(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -c -o '$#' '$<'
$(PROGRAMS): $(OBJDIR)/test_%: $(OBJDIR)/%.o segment.c test_harness.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(MY_PROGRAMS): $(OBJDIR)/my_optional_program_%: my_optional_program.c $(OBJDIR)/%.o segment.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean::
rm -f $(PROGRAMS) $(MY_PROGRAMS) $(OBJ) callgrind.out.*
Note that you should also manage the dependencies between object and header files (which the above does not, just like the original version). If it's simple enough you'll easily modify the proposed Makefile. Else consider reading this very interesting post about Auto-Dependency Generation by the current GNU make main maintainer.

dyld: Library not loaded when Linked in makefile

Hi I know there is some other posts with the same title, but they are not in the same context. So: I have a library named mlx and the library file is named libmlx.dylib: when I try to compile it with a simple main using gcc main.c libmlx.dylib it compiles well and the lib is working, but when I try to compile it with my project using my makefile the compilation doesn't throw any error but when I launch the program I get this error message:
dyld: Library not loaded: libmlx.dylib
Referenced from: /Users/leo/Documents/42-cursus/so_long/./so_long
Reason: image not found
[1] 8313 abort ./so_long
Here is my makefile:
SHELL = /bin/sh
NAME = so_long
.SUFFIXES = .c .o .h .dylib
SRCDIR = src
INCDIR = inc
LIBDIR = lib
OBJDIR = .obj
SRC = $(addsuffix $(word 1, $(.SUFFIXES)),\
$(addprefix exception/,\
exception\
bad_alloc\
invalid_arguments\
invalid_map\
runtime_error)\
$(addprefix parsing/,\
get_map)\
$(addprefix rendering/,\
render_map)\
$(addprefix utils/,\
init_image\
make_color)\
$(addprefix cleaning/,\
mlx_clear)\
$(addprefix get_next_line/,\
get_next_line\
get_next_line_utils)\
main)
INC = $(addsuffix $(word 3, $(.SUFFIXES)),\
get_next_line\
mlx\
exception\
so_long)
LIB = mlx\
ft
OBJ = $(SRC:$(word 1, $(.SUFFIXES))=$(word 2, $(.SUFFIXES)))
CC = gcc
CFLAGS = -Wall -Wextra -Werror -I $(INCDIR)
LCFLAGS = $(addprefix -L, $(LIBDIR)) $(addprefix -l, $(lib))
#### COLORS ####
KNRM = \x1B[0m
KRED = \x1B[31m
KGRN = \x1B[32m
KYEL = \x1B[33m
KBLU = \x1B[34m
KMAG = \x1B[35m
KCYN = \x1B[36m
KWHT = \x1B[37m
######################
all: $(OBJDIR) $(NAME)
#printf "$(KGRN)\`$(NAME)\` is up to date.\n$(KNRM)"
$(OBJDIR):
#printf "$(KYEL)➤ "
mkdir -p $#/exception $#/parsing $#/rendering $#/utils $#/cleaning $#/get_next_line
#printf "$(KNRM)"
$(NAME): $(addprefix $(OBJDIR)/, $(OBJ))
#printf "$(KCYN)[ Linking ]\n➤ "
$(CC) $(CFLAGS) $^ -o $# $(LCFLAGS)
#printf "$(KNRM)"
$(OBJDIR)/%$(word 2, $(.SUFFIXES)): $(SRCDIR)/%$(word 1, $(.SUFFIXES)) $(addprefix $(INCDIR)/, $(INC))
#printf "$(KMAG)[ Compiling ]\n➤ "
$(CC) $(CFLAGS) -c $< -o $#
#printf "$(KNRM)"
clean:
#printf "$(KRED)➤ "
rm -rf $(OBJDIR)
#printf "$(KNRM)"
fclean: clean
#printf "$(KRED)➤ "
rm -f $(NAME)
#printf "$(KNRM)"
re: fclean all
I'm linking it with the flags -L $(LIBDIR) -lmlx. What did I do wrong ?
I found that for dynamic libraries you need to have the .dylib in the same directory as your target, I let the post in case some people face the same problem.

Make-File: compile multiple SRC-Folders to single OBJ-Folder

I got a project hierarchy that looks like this:
+Makefile
+---src
| main.c
| ...
| +---block
| | air.c
| | ...
| |
| +---entity
| | esc.c
| | esc.h
| | ...
| |
| \---world
| \---gen
| noise.c
| ...
| xyz.c
| ...
\---obj
main.o
air.o
esc.o
noise.o
xyz.o
...
I want to compile all the .c files in the hierarchy into one obj folder using make.
So far I got:
UNAME_S = $(shell uname -s)
CC = clang
CFLAGS = -std=c11 -O3 -g -Wall -Wextra -Wpedantic -Wstrict-aliasing
CFLAGS += -Wno-pointer-arith -Wno-newline-eof -Wno-unused-parameter -Wno-gnu-statement-expression
CFLAGS += -Wno-gnu-compound-literal-initializer -Wno-gnu-zero-variadic-macro-arguments
CFLAGS += -Ilib/cglm/include -Ilib/glad/include -Ilib/glfw/include -Ilib/stb -Ilib/noise -fbracket-depth=1024
LDFLAGS = lib/glad/src/glad.o lib/cglm/libcglm.a lib/glfw/src/libglfw3.a lib/noise/libnoise.a -lm
# GLFW required frameworks on OSX
ifeq ($(UNAME_S), Darwin)
LDFLAGS += -framework OpenGL -framework IOKit -framework CoreVideo -framework Cocoa
endif
ifeq ($(UNAME_S), Linux)
LDFLAGS += -ldl -lpthread
endif
OBJ_DIR = obj
SRC = $(wildcard src/**/*.c) $(wildcard src/*.c) $(wildcard src/**/**/*.c) $(wildcard src/**/**/**/*.c)
OBJ = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(notdir $(basename $(SRC)))))
SRC_DIRS = $(sort $(dir $(SRC)))
BIN = bin
.PHONY: all clean
all: dirs libs game
libs:
cd lib/cglm && cmake . -DCGLM_STATIC=ON && make
cd lib/glad && $(CC) -o src/glad.o -Iinclude -c src/glad.c
cd lib/glfw && cmake . && make
cd lib/noise && make
dirs:
mkdir -p ./$(BIN) ./$(OBJ_DIR)
run: all
$(BIN)/game
game: $(OBJ)
$(CC) -o $(BIN)/game $^ $(LDFLAGS)
$(OBJ_DIR)/%.o: src/%.c
$(CC) -o $# -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/block/%.c
$(CC) -o $# -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/entity/%.c
$(CC) -o $# -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/gfx/%.c
$(CC) -o $# -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/ui/%.c
$(CC) -o $# -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/util/%.c
$(CC) -o $# -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/world/%.c
$(CC) -o $# -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/world/gen/%.c
$(CC) -o $# -c $< $(CFLAGS)
clean:
rm -rf $(BIN) $(OBJ_DIR)
Is there any way to get this done in a more efficient way? Especially the $(OBJ_DIR)/%.o cases?
Variable $(SRC_DIRS) stores all src folders
Variable $(SRC) stores all .c files with their paths
Variable $(OBJ) stores all .o file paths and names
The best way to do this is using VPATH.
For example:
SRC := $(wildcard src/*/*.c) $(wildcard src/*.c) $(wildcard src/*/*/*.c) $(wildcard src/*/*/*/*.c)
OBJ := $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(notdir $(basename $(SRC)))))
SRC_DIRS := $(sort $(dir $(SRC)))
VPATH := $(SRC_DIRS)
...
$(OBJ_DIR)/%.o: %.c
$(CC) -o $# -c $< $(CFLAGS)
You just need the one pattern rule.

clang makefile "ar: no archive members specified"

I refactor some C code and I try to compile it as a lib on clang on mac instead of gcc on linux.
First of all if I just run make command I got an error at the first file compile:
+++ Compiling [sys_msg.c]
clang: error: unsupported argument '-adhlns=../../src/sys_msg.lst' to option 'Wa,'
So I remove the -Wa,-adhlns=$(<:.c=.lst) option that create this error.
After that everything seems to compile but the assembly of the last .a file fail, and I don't understand why.
Here is my make output :
+++ Creation of [../../hal/stub/obj]
+++ Dependencies of [hal.c]
+++ Dependencies of [target.c]
+++ Dependencies of [robus.c]
+++ Dependencies of [reception.c]
+++ Dependencies of [sys_msg.c]
+++ Compiling [sys_msg.c]
+++ Compiling [reception.c]
+++ Compiling [robus.c]
+++ Compiling [target.c]
+++ Compiling [hal.c]
ar -rv ../../hal/stub/libstub.a
ar: no archive members specified
usage: ar -d [-TLsv] archive file ...
ar -m [-TLsv] archive file ...
ar -m [-abiTLsv] position archive file ...
ar -p [-TLsv] archive [file ...]
ar -q [-cTLsv] archive file ...
ar -r [-cuTLsv] archive file ...
ar -r [-abciuTLsv] position archive file ...
ar -t [-TLsv] archive [file ...]
ar -x [-ouTLsv] archive [file ...]
make: *** [../../hal/stub/libstub.a] Error 1
Here is my makefile:
# make all = Make software and program
# make clean = Clean out built project files.
# make program = Download the hex file to the device, using avrdude. Please
# customize the avrdude settings below first!
# make docs = compile with doxygen the code documentation
# Maximum I2C speed (HZ)
SCLFREQ = 400000
#-------------------------------------------------------------------------------
# Tools
#-------------------------------------------------------------------------------
# Set DEBUG variable for once if not coming from command line
ifndef DEBUG
DEBUG = 0
endif
# Tool suffix when cross-compiling
CROSS_COMPILE ?=
# Compilation tools
CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
SIZE = $(CROSS_COMPILE)size
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
SIZE = $(CROSS_COMPILE)size
GDB = $(CROSS_COMPILE)gdb
NM = $(CROSS_COMPILE)nm
ROOT_PATH = ../..
HAL_PATH = $(ROOT_PATH)/hal/$(BOARD)
DOC_PATH = $(ROOT_PATH)/../extra/Docs
# Doxygen configuration file name
DOXYFILE = $(ROOT_PATH)/../extra/.Doxyfile
OBJ_PATH = $(HAL_PATH)/obj
OUTPUT_NAME = lib$(BOARD)
OUTPUT_FILE_PATH = $(HAL_PATH)/$(OUTPUT_NAME).a
#|---------------------------------------------------------------------------------------|
#| Source files |
#|---------------------------------------------------------------------------------------|
include ../sources.mk
#|---------------------------------------------------------------------------------------|
#| Extract file names and path |
#|---------------------------------------------------------------------------------------|
PROJ_ASRCS = $(filter %.s,$(foreach file,$(SOURCES),$(file)))
PROJ_ASRCS += $(filter %.S,$(foreach file,$(SOURCES),$(file)))
PROJ_CSRCS = $(filter %.c,$(foreach file,$(SOURCES),$(file)))
PROJ_CPPSRCS = $(filter %.cpp,$(foreach file,$(SOURCES),$(file)))
#|---------------------------------------------------------------------------------------|
#| Set important path variables |
#|---------------------------------------------------------------------------------------|
VPATH = $(foreach path,$(sort $(foreach file,$(SOURCES),$(dir $(file)))),$(path) :)
INC_PATH = $(INCLUDES)
LIB_PATH = -L$(dir $(RESOURCES_LINKER))
#|---------------------------------------------------------------------------------------|
#| Options for compiler binaries |
#|---------------------------------------------------------------------------------------|
COMMON_FLAGS = \
-g -O$(OPT) \
-funsigned-char -fpack-struct -fshort-enums \
-Wall -Wstrict-prototypes \
-DMCU=$(MCU) \
-DMAINCLOCK=$(MAINCLOCK) \
-DSCLFREQ=$(SCLFREQ) \
$(INCLUDES)
ifeq ($(CROSS_COMPILE),avr-)
COMMON_FLAGS += -mmcu=$(MCU)
ASFLAGS = -mmcu=$(MCU)
endif
CFLAGS += $(COMMON_FLAGS) -std=gnu99
CPPFLAGS = $(COMMON_FLAGS) -std=gnu++11 -fno-rtti -fno-exceptions
ASFLAGS += -Wa,-adhlns=$(<:.S=.lst),-gstabs -I. -x assembler-with-cpp
LDFLAGS = -Wl,-Map=$(BOARD).map,--cref
#|---------------------------------------------------------------------------------------|
#| Define targets |
#|---------------------------------------------------------------------------------------|
#AOBJS += $(patsubst %.S,%.o,$(PROJ_ASRCS))
AOBJS = $(patsubst %.s,%.o,$(addprefix $(OBJ_PATH)/, $(notdir $(PROJ_ASRCS))))
COBJS = $(patsubst %.c,%.o,$(addprefix $(OBJ_PATH)/, $(notdir $(PROJ_CSRCS))))
CPPOBJS = $(patsubst %.cpp,%.o,$(addprefix $(OBJ_PATH)/, $(notdir $(PROJ_CPPSRCS))))
.PHONY: all clean print_info packaging
all: $(OUTPUT_FILE_PATH)
print_info:
#echo DEFAULT_GOAL ---------------------------------------------------------------------------------
#echo $(.DEFAULT_GOAL)
#echo VPATH ---------------------------------------------------------------------------------
#echo $(VPATH)
#echo SOURCES -------------------------------------------------------------------------------
#echo $(SOURCES)
# #echo PROJ_ASRCS ----------------------------------------------------------------------------
# #echo $(PROJ_ASRCS)
# #echo AOBJS ---------------------------------------------------------------------------------
# #echo $(AOBJS)
#echo PROJ_CSRCS ----------------------------------------------------------------------------
#echo $(PROJ_CSRCS)
#echo COBJS ---------------------------------------------------------------------------------
#echo $(COBJS)
#echo PROJ_CPPSRCS --------------------------------------------------------------------------
#echo $(PROJ_CPPSRCS)
#echo CPPOBJS -------------------------------------------------------------------------------
#echo $(CPPOBJS)
#echo ---------------------------------------------------------------------------------------
#echo $(CURDIR)
#echo $(OUTPUT_FILE_PATH)
#echo ---------------------------------------------------------------------------------------
$(OUTPUT_FILE_PATH): $(OBJ_PATH) ../rules.mk ../sources.mk $(HAL_PATH)/Makefile $(AOBJS) $(COBJS) $(CPPOBJS)
$(AR) -rv $(OUTPUT_FILE_PATH) $(AOBJS)
$(AR) -rv $(OUTPUT_FILE_PATH) $(COBJS)
$(AR) -rv $(OUTPUT_FILE_PATH) $(CPPOBJS)
$(NM) $(OUTPUT_FILE_PATH) > $(HAL_PATH)/$(OUTPUT_NAME)_symbols.txt
#|---------------------------------------------------------------------------------------|
#| Compile or assemble |
#|---------------------------------------------------------------------------------------|
$(AOBJS): $(OBJ_PATH)/%.o: %.s
#echo +++ Assembling [$(notdir $<)]
#$(AS) $(AFLAGS) $< -o $#
$(AOBJS): $(OBJ_PATH)/%.o: %.S
#echo +++ Assembling [$(notdir $<)]
#$(AS) $(AFLAGS) $< -o $#
$(COBJS): $(OBJ_PATH)/%.o: %.c
#echo +++ Compiling [$(notdir $<)]
#$(CC) $(CFLAGS) -c $< -o $#
$(CPPOBJS): $(OBJ_PATH)/%.o: %.cpp
#echo +++ Compiling [$(notdir $<)]
#$(CC) $(CPPFLAGS) -c $< -o $#
#|---------------------------------------------------------------------------------------|
#| Output folder |
#|---------------------------------------------------------------------------------------|
$(OBJ_PATH):
#echo +++ Creation of [$#]
#-mkdir $(OBJ_PATH)
#|---------------------------------------------------------------------------------------|
#| Cleanup |
#|---------------------------------------------------------------------------------------|
clean:
-rm -f $(OBJ_PATH)/* $(OBJ_PATH)/*.*
-rmdir $(OBJ_PATH)
-rm -f $(OUTPUT_FILE_PATH)
-rm -f $(HAL_PATH)/$(OUTPUT_NAME)_symbols.txt
-rm -rf $(DOC_PATH)
#|---------------------------------------------------------------------------------------|
#| Dependencies |
#|---------------------------------------------------------------------------------------|
$(OBJ_PATH)/%.d: %.s $(OBJ_PATH)
#echo +++ Dependencies of [$(notdir $<)]
#$(CC) $(AFLAGS) -MM -c $< -MT $(basename $#).o -o $#
$(OBJ_PATH)/%.d: %.S $(OBJ_PATH)
#echo +++ Dependencies of [$(notdir $<)]
#$(CC) $(AFLAGS) -MM -c $< -MT $(basename $#).o -o $#
$(OBJ_PATH)/%.d: %.c $(OBJ_PATH)
#echo +++ Dependencies of [$(notdir $<)]
#$(CC) $(CFLAGS) -MM -c $< -MT $(basename $#).o -o $#
$(OBJ_PATH)/%.d: %.cpp $(OBJ_PATH)
#echo +++ Dependencies of [$(notdir $<)]
#$(CC) $(CPPFLAGS) -MM -c $< -MT $(basename $#).o -o $#
#|---------------------------------------------------------------------------------------|
#| Include dependencies, if existing |
#| Little trick to avoid dependencies build for some rules when useless |
#| CAUTION: this won't work as expected with 'make clean all' |
#|---------------------------------------------------------------------------------------|
DEP_EXCLUDE_RULES := clean print_info
ifeq (,$(findstring $(MAKECMDGOALS), $(DEP_EXCLUDE_RULES)))
-include $(AOBJS:%.o=%.d)
-include $(COBJS:%.o=%.d)
-include $(CPPOBJS:%.o=%.d)
endif
#|---------------------------------------------------------------------------------------|
#| Module packaging for Arduino IDE Board Manager |
#|---------------------------------------------------------------------------------------|
packaging: $(OUTPUT_FILE_PATH)
docs: ( cat $(DOXYFILE) ; echo "OUTPUT_DIRECTORY = $(DOC_PATH)" ; echo "INPUT = $(DOC_SOURCES)" ) | doxygen -
# doxygen $(DOXYFILE)
%.d:
Why clang raise me this?
Thank's to #MadScientist
I understand why I have this error, if I print things on my make I got :
$make print_info
DEFAULT_GOAL ---------------------------------------------------------------------------------
all
VPATH ---------------------------------------------------------------------------------
../../hal/stub/ : ../../src/ :
SOURCES -------------------------------------------------------------------------------
../../src/sys_msg.c ../../src/reception.c ../../src/robus.c ../../src/target.c ../../hal/stub/hal.c
PROJ_ASRCS ----------------------------------------------------------------------------
AOBJS ---------------------------------------------------------------------------------
PROJ_CSRCS ----------------------------------------------------------------------------
../../src/sys_msg.c ../../src/reception.c ../../src/robus.c ../../src/target.c ../../hal/stub/hal.c
COBJS ---------------------------------------------------------------------------------
../../hal/stub/obj/sys_msg.o ../../hal/stub/obj/reception.o ../../hal/stub/obj/robus.o ../../hal/stub/obj/target.o ../../hal/stub/obj/hal.o
PROJ_CPPSRCS --------------------------------------------------------------------------
CPPOBJS -------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
/Users/nico/Documents/pollen/Robus/robus/hal/stub
../../hal/stub/libstub.a
---------------------------------------------------------------------------------------
My mistake come for the for this part of my makefile :
PROJ_ASRCS = $(filter %.s,$(foreach file,$(SOURCES),$(file)))
PROJ_ASRCS += $(filter %.S,$(foreach file,$(SOURCES),$(file)))
I don't want to include all .o because I do multiple compilation, I just want to list the needed files.
I have the same compilation process than ExperimentalCore-sam project.
How can I do that?
I can only assume that the variable AOBJS is empty. Following back along where it's created, I can only assume that means that there are no .s or .S files listed in your SOURCES variable.
Why don't you run a single invocation of $(AR) and just use the $^ automatic variable and filter out .o files, rather than three different invocations of the $(AR) command?
$(AR) -rv $(OUTPUT_FILE_PATH) $(filter %.o,$^)
EDIT To be clear I'm suggesting you change your output target rule to this:
$(OUTPUT_FILE_PATH): $(OBJ_PATH) ../rules.mk ../sources.mk $(HAL_PATH)/Makefile $(AOBJS) $(COBJS) $(CPPOBJS)
$(AR) -rv $(OUTPUT_FILE_PATH) $(filter %.o,$^)
$(NM) $(OUTPUT_FILE_PATH) > $(HAL_PATH)/$(OUTPUT_NAME)_symbols.txt
Or, if you wanted to be more idiomatically correct:
$(OUTPUT_FILE_PATH): $(OBJ_PATH) ../rules.mk ../sources.mk $(HAL_PATH)/Makefile $(AOBJS) $(COBJS) $(CPPOBJS)
$(AR) -rv $# $(filter %.o,$^)
$(NM) $# > $(HAL_PATH)/$(OUTPUT_NAME)_symbols.txt
As above I'd definitely remove $(OBJ_PATH) from the prerequisites list.
I understand the difference between GCC and Clang.
With GCC if you run an ar command with no archive members specified, he just skip the step.
Clang raise an error in this case and stop the build.
To patch it I just check if my list is empty or not :
$(OUTPUT_FILE_PATH): $(OBJ_PATH) ../rules.mk ../sources.mk $(HAL_PATH)/Makefile $(AOBJS) $(COBJS) $(CPPOBJS)
ifneq ($(strip $(AOBJS)),)
$(AR) -rv $(OUTPUT_FILE_PATH) $(AOBJS)
endif
ifneq ($(strip $(COBJS)),)
$(AR) -rv $(OUTPUT_FILE_PATH) $(COBJS)
endif
ifneq ($(strip $(CPPOBJS)),)
$(AR) -rv $(OUTPUT_FILE_PATH) $(CPPOBJS)
endif

Resources