Subdirectories and GCC problem with MakeFile - c

I'm writing a makefile for a very small personal project written in C.
My project is divided into subdirectories, but the directives for these utilme are not found even if (I think) the code is right:
TARGET = example.out
ENV = /usr/bin/env
MKDIR = mkdir
RMV = rm
CP = cp
CC = gcc
CFLAGS = -lm
BINDIR = ./bin
OBJDIR = ./obj
SRCDIR = ./src
SRCS = master.o request/request.o util/util.o # these are all .c files (./src/...)
# ---
.PHONY: build
build: prepare $(SRCS)
$(ENV) $(CC) $(addprefix $(OBJDIR)/, $(SRCS)) -o $(BINDIR)/$(TARGET)
# ---
.PHONY: prepare
prepare:
#$(ENV) $(MKDIR) -p $(BINDIR) $(OBJDIR)
#$(ENV) $(CP) data.txt $(BINDIR)/data.txt
# ---
.PHONY: clean
clean:
#$(ENV) $(RM) -rf $(BINDIR) $(OBJDIR)
# ---
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(ENV) $(CC) $(CFLAGS) -c $<
It says:
make: *** No rule to make target 'master.o', needed by 'build'. Stop.
And if I change $(OBJDIR)/%.o: $(SRCDIR)/%.c to %.o: $(SRCDIR)/%.c, it says:
make: *** No rule to make target 'request/request.o', needed by 'build'. Stop.

You have effectively no rule to create master.o from master.c.
In the following rule:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
./obj/%.o does not match master.o
And if master.c is in src (as indicated by the comment) the default rules don't match either.
So in order to match the rule, the target must be ./obj/master.o
The same goes for all the other .o files and you will run into trouble with the subdirectories. To get around that you can create the target directory in the recipe directly:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
mkdir -p $(dir $#)
$(CC) -c -o $# $(CFLAGS) $<

the default behaviour of gcc is to place the .o-file beneath the .c-file. to place it into the object file directory, you have to use an -o $# argument:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(ENV) $(CC) $(CFLAGS) -c $< -o $#
And the build rule shoud depend on $(addprefix $(OBJDIR)/, $(SRCS))
if this is what is used in the command.
build: prepare $(addprefix $(OBJDIR)/, $(SRCS))
$(ENV) $(CC) $(addprefix $(OBJDIR)/, $(SRCS)) -o $(BINDIR)/$(TARGET)

Related

Makefile: Separated sources and objects

I've been trying for some time to separate the source files of my project from the generated object files.
Indeed, I would like my project to be structured this way:
obj/
main.o
src1.o
[...]
src/
main.c
src1.c
[...]
Makefile
The Makefile I currently have is as follows:
NAME = a.out
OBJ_DIR = "obj"
SRC_DIR = "src"
MAIN_SRC = main.c
PROJ_SRC = src1.c \
src2.c \
src3.c
MAIN_OBJ = $(MAIN_SRC:%.c=%.o)
PROJ_OBJ = $(PROJ_SRC:%.c=%.o)
CC = gcc
RM = rm -rf
$(NAME): $(MAIN_OBJ) $(PROJ_OBJ)
$(CC) $(MAIN_OBJ) $(PROJ_OBJ) -o $(NAME)
all: $(NAME)
clean:
$(RM) $(MAIN_OBJ) $(PROJ_OBJ)
fclean: clean
$(RM) $(NAME)
I tried to use pattern rules, without success.
MAIN_OBJ = $(MAIN_SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
PROJ_OBJ = $(PROJ_SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
[...]
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
Does anyone have a solution to my problem?
MAIN_SRC and PROJ_OBJ do not have directory prefix, so that expressions
$(MAIN_SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
$(PROJ_SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
do not replace anything.
Fix:
MAIN_OBJ := $(MAIN_SRC:%.c=$(OBJ_DIR)/%.o)
PROJ_OBJ := $(PROJ_SRC:%.c=$(OBJ_DIR)/%.o)
And then your pattern rule should work.
You may like to have make create that $(OBJ_DIR) for you:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CC) $(CFLAGS) -c -o $# $<
$(OBJ_DIR) :
mkdir -p $#
A more advanced example for you with automatic header dependency generation.
bro!
If your project "main" 's architecture is just liking this:
main
|
|__Makefile
|__obj
|__src
|__main.c
|__src1.c
|__src2.c
[...]
Just add this to your "Makefile" to store your object out of source files directory:
# Object files
# String substituion for every C/C++ file
# e.g: ./src/src1.cpp turns into ./obj/src1.o
OBJS := $(patsubst %.c, ${OBJ_DIR}/%.o, $(notdir $(SRC_DIR)))
And just add this to your "Makefile" to compile:
# Compile: Generate object files from source files
# $# := {NAME}
# $< := THE first file
# $^ all the dependency
# C Sources
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(C_FLAGS) -c $< -o $#
END!

Makefile relink error

I am trying to get this makefile relink and not recompile unessecarily files that aren't modified. The "libft" is my library and doesnt have any errors. The error that I am having when doing
make
is :
make: *** No rule to make target `main.o', needed by `ft_printf'. Stop.
My makefile is:
NAME = ft_printf
SRC = main.c\
ft_printf.c\
parser_main.c\
utils.c\
debug_funcs.c
OBJ = $(SRC:.c=.o)
SRC_PATH = srcs/
SRC_POS = $(addprefix $(SRC_PATH),$(SRC))
INC = -I includes
LIBFT = libft/libft.a
CC = gcc
FLAGS = -Wall -Wextra -Werror
all: $(NAME)
$(NAME): $(OBJ)
$(CC) $(FLAGS) $(OBJ) -o $(NAME) $(LIBFT)
%.o: %.c
$(CC) -o $# -c $< $(FLAGS)
$(LIBFT):
make -C ./libft/
clean:
rm -f $(OBJ)
make clean -C ./libft/
fclean: clean
rm -f $(NAME)
make fclean -C ./libft/
re: fclean all
Any idea ? I can't figure it out and i think it's because %.o:%.c isn't called
Given the existence of these variables:
SRC_PATH = srcs/
SRC_POS = $(addprefix $(SRC_PATH),$(SRC))
I'm guessing that your source files actually live in srcs/ whereas you're building your object files in . So this pattern rule:
%.o: %.c
when trying to match main.o won't find a main.c since that file really is srcs/main.c. Since that pattern doesn't match, the rule itself isn't considered, and since no other rule is found, you get an error.
Instead, try:
%.o : $(SRC_PATH)/%.c
$(CC) -o $# -c $< $(FLAGS)

make: excluding main.c from rule that .o file depends on .h file

I have a C project with a bunch of source files and their headers:
one.c
one.h
two.c
two.h
I also have a main.c, but that has no .h file with it:
main.c
I have this in my Makefile:
# Use gcc to make object files from C files.
_build/%.o: %.c %.h
#mkdir -p _build
#echo
#echo Compiling $<
$(CC) $(CFLAGS) $< -o $#
This is fine for one.o and two.o. But it's no good for main.o, which does not have a main.h on which to depend. Make then throws this error.
make: *** No rule to make target `_build/main.o', needed by `all'. Stop.
How can I best treat main.c specially?
Add a separate static pattern rule
_build/%.o: %.c
#mkdir -p _build
#echo
#echo Compiling $<
$(CC) $(CFLAGS) $< -o $#
_build/one.o _build/two.o: _build/%.o: %.h
Even better, use dependency generation
OBJS := $(addprefix _build/,main.o one.o two.o)
DEPS := $(OBJS:.o=.d)
CPPFLAGS := -MMD -MP
.PHONY: all clean
all: $(OBJS)
$(OBJS): _build/%.o: %.c | _build
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
_build: ; mkdir -p $#
clean: ; $(RM) -r _build
-include $(DEPS)

Need help writing a Makefile that creates all the objective files into a new subdir

I am trying to make a Makefile for a big project.
The project structure is (I've ommitted the header files):
root/feature1/feat1.c
root/feature2/feat2.c
root/srcfile1.c
root/srcfile2.c
I wanted to start easy so I created a simpler project with the source files in the root dir.
I need to create all the object files in one directory, let's say, objdir.
The project structure of the simple project is:
root/main.c
root/word.c
By looking in other questions I have come up with this:
CC = gcc
FLAGS = -c
MKDIR_P = mkdir -p
OUT = words
OBJDIR = objdir
SRCDIR = .
_OBJS = main.o word.o
OBJS = $(patsubst %,$(OBJDIR)/%,$(_OBJS))
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) -c -o $# $<
all: directories program
directories: ${OBJDIR}
${OBJDIR}:
${MKDIR_P} ${OBJDIR}
program: $(OBJS)
$(CC) -o $# $^ $(LIBS)
clean:
rm -f $(OBJS)
When running it with make -f ./myMakefile all (changed the filename as in the same dir, there is Netbeans' Makefile), I am getting this output:
gcc -o objdir/main.o main.c
/tmp/ccatfAHu.o: In function `main':
main.c:(.text+0x15): undefined reference to `CreateWord'
main.c:(.text+0x26): undefined reference to `CreateWord'
collect2: error: ld returned 1 exit status
make: *** [objdir/main.o] Error 1
Giving the make all command, it tries to produce the targes directories and program.
The dir objdir is created and in it, there are the main.o and word.o files.
What am I doing wrong with the makefile of the simpleproject?
EDIT:
Added the -c flag at the $(OBJDIR)/%.o rule.
Removed the $(FLAGS) from $(CC) -o $# $^ $(FLAGS) $(LIBS).
Now, if we move to my project problem, I need to access all the source files from all the directories:
/repo-root
/repo-root/feature1/feat1.c
/repo-root/feature2/feat2.c
In this rule:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) -o $# $<
you're missing the -c flag. Instead of building an object file, Make is trying to build an executable named objdir/main.o, and main.c doesn't have all of the needed code. Just do this:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) -c -o $# $<
Try this
#source files to compile relative to the src dir
CSOURCE = main.c
CSOURCE += func1.c
SRCDIR = .
vpath %.c $(SRCDIR)/
CC = gcc
MKDIR_P = mkdir -p
OBJDIR = objdir
BINDIR = bindir
#list of objects
OBJS = $(addprefix $(OBJDIR)/, $(CSOURCE:.c=.o))
#output name for executable
APP = example
all: ${OBJDIR} $(OBJS) bin
#rule to create bin and objects dir
${BINDIR}:
${MKDIR_P} ${BINDIR}
${OBJDIR}:
${MKDIR_P} ${OBJDIR}
#rule to compile c files
$(OBJDIR)/%.o: %.c
$(CC) -c $< -o $#
#to create executable
bin: $(BINDIR) $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(BINDIR)/$(APP)
#to clean executable and objects
clean:
rm -rf $(OBJS) $(BINDIR) $(OBJDIR)
Updated root make file, Use this in the root/ directory
WORKDIR = $(shell pwd)
MODULES = feature1 feature2
CSOURCE = main.c
CSOURCE += func1.c
SRCDIR = .
vpath %.c $(SRCDIR)/
CC = gcc
MKDIR_P = mkdir -p
OBJDIR = $(WORKDIR)/objdir
BINDIR = $(WORKDIR)/bindir
OBJS = $(addprefix $(OBJDIR)/, $(CSOURCE:.c=.o))
APP = example
all: ${OBJDIR} modules $(OBJS) bin
modules:
for mod in $(MODULES); do \
echo "Building $$mod ....."; \
$(MAKE) -C $(WORKDIR)/$$mod all; \
done
${BINDIR}:
${MKDIR_P} ${BINDIR}
${OBJDIR}:
${MKDIR_P} ${OBJDIR}
$(OBJDIR)/%.o: %.c
$(CC) -c $< -o $#
bin: $(BINDIR) $(OBJS)
$(CC) $(CFLAGS) $(OBJDIR)/*.o -o $(BINDIR)/$(APP)
clean:
rm -rf $(OBJS) $(BINDIR) $(OBJDIR)
feature make file, use this in the root/feature1 directory and root/feature2 directory
WORKDIR = $(shell cd ..; pwd)
CSOURCE = func2.c
SRCDIR = .
vpath %.c $(SRCDIR)/
CC = gcc
MKDIR_P = mkdir -p
OBJDIR = $(WORKDIR)/objdir
OBJS = $(addprefix $(OBJDIR)/, $(CSOURCE:.c=.o))
all: ${OBJDIR} $(OBJS)
${OBJDIR}:
${MKDIR_P} ${OBJDIR}
$(OBJDIR)/%.o: %.c
$(CC) -c $< -o $#
clean:
rm -rf $(OBJS) $(OBJDIR)
When you want to add new directory say feature3, you can just add it in main makefile module list and copy the feature1 makefile to feature3 and update source file list
Hope this helps

make: *** No rule to make target

Thanks for the responses. I found that this worked — I don't know why though.
all: $(OUT)
$(OBJ_DIR)/%.o: %.c
$(CC) $(CCFLAGS) -o $# -c $< $(INCLUDES)
$(OUT): $(OBJ)
ar rcs $(OUT) $(OBJ)
cp DIMEFILEAPPSAUTH.h ../include
.PHONY: clean
Below is a makefile I have. I keep getting the error make: *** No rule to make target but cannot see what is wrong in this case. The ".c" files exist in the current directory. I'm not sure why makefile cannot see them — can you explain?
DimeFileAppsAuth/src> ls
db_get_DIMEFILEAPPSAUTH.c db_reset_query_DIMEFILEAPPSAUTH.c Makefile
db_add_DIMEFILEAPPSAUTH.c db_print_DIMEFILEAPPSAUTH.c db_update_DIMEFILEAPPSAUTH.c
db_delete_DIMEFILEAPPSAUTH.c db_reset_DIMEFILEAPPSAUTH.c
Running the make
DimeFileAppsAuth/src> make
make: *** No rule to make target `../obj/db_add_DIMEFILEAPPSAUTH.o', needed by `../lib/lib_dime_file_apps.a'. Stop.
The Makefile
# clear out all suffixes
.SUFFIXES:
# list only those we use
.SUFFIXES: .o .c
# define a suffix rule for .c -> .o
.c.o :
$(CC) $(CFLAGS) -c $<
FILE_DIVERSION=$(IMG_PROJ_HOME)/dime/basics/BasicsLink
INC_DIR =../include
LIB_DIR =../lib
OBJ_DIR =../obj
BIN_DIR =../bin
CUR_DIR = .
OUT = $(LIB_DIR)/lib_dime_file_apps.a
BIN_OUT = $(BIN_DIR)/test_run
# include directories
INCLUDES = -I$(INC_DIR) -I$(FILE_DIVERSION)/include -I$(ORACLE_HOME)/rdbms/public -I/usr/local/include
# library paths
LIBS = -L$(LIB_DIR) -ldime_direct -L$(FILE_DIVERSION)/lib -loutput_files -lquerylib -lsql_common -lsql_common -L$(ORACLE_HOME)/lib -lclntsh -L$(ORACLE_HOME)/lib `cat $(ORACLE_HOME)/lib/sysliblist` -L/usr/local/lib -lm
CC=gcc
CCFLAGS=-w -O2 -unused-variable -Wall -fPIC -c -g -rdynamic
_DEPS = DIMEFILEAPPSAUTH.h
DEPS = $(patsubst %,$(INC_DIR)/%,$(_DEPS))
_OBJ = db_add_DIMEFILEAPPSAUTH.o db_delete_DIMEFILEAPPSAUTH.o db_get_DIMEFILEAPPSAUTH.o db_get_SEQ_DIMEFILEAPPSAUTH.o db_print_DIMEFILEAPPSAUTH.o db_reset_DIMEFILEAPPSAUTH.o db_reset_query_DIMEFILEAPPSAUTH.o db_special_DIMEFILEAPPSAUTH.o db_update_DIMEFILEAPPSAUTH.o
OBJ = $(patsubst %,$(OBJ_DIR)/%,$(_OBJ))
_BIN = db_add_DIMEFILEAPPSAUTH.o db_delete_DIMEFILEAPPSAUTH.o db_get_DIMEFILEAPPSAUTH.o db_get_SEQ_DIMEFILEAPPSAUTH.o db_print_DIMEFILEAPPSAUTH.o db_reset_DIMEFILEAPPSAUTH.o db_reset_query_DIMEFILEAPPSAUTH.o db_special_DIMEFILEAPPSAUTH.o db_update_DIMEFILEAPPSAUTH.o test_this.o
BIN = $(patsubst %,$(BIN_DIR)/%,$(_BIN))
all: $(OUT)
$(OBJ_DIR)/%.o: %.c $(DEPS)
$(CC) $(CCFLAGS) -o $# $< $(INCLUDES)
$(OUT): $(OBJ)
ar rcs $(OUT) $(OBJ)
cp DIMEFILEAPPSAUTH.h ../include
exec: $(BIN) $(OUT)
$(CC) -o $(BIN_OUT) $(BIN) $(LIBS)
rm $(BIN_DIR)/*.o
.PHONY: clean
The make error occurs when it comes to this line "$(OUT): $(OBJ)". Please check whether the file named "db_add_DIMEFILEAPPSAUTH.o" exists in the directory "../obj"

Resources