Make implicit rules with GCC: Redirecting *.o - c

I am trying to get make to do the following with an implicit rule:
obj/lsabase.o : inc/lsabase.h lsabase.c
cc -c lsabase.c && mv lsabase.o obj
I searched for ways to redirect the output of "cc -c .." with compiler options, but didn't find any here.
Also the implicit rule defined for compiling from source to object only lets you use $(CPPFLAGS) and $(CFLAGS).
Does anybody know how to trick make into using this (mv lsabase.o obj) in an implicit rule, so I can put all *.o files in a seperate directory?

obj/lsabase.o : inc/lsabase.h lsabase.c
cc -I"inc" -c lsabase.c -o obj/lsabase.o

I would
avoid doing the mv manually but rather telling gcc to put in the obj dir
let gcc handle the dependencies (by creating .d files)
and here is what I usually do when all my .c files are in a subdir and I want to compile all of them in a parallel dir obj (that I can easily remove):
default: my_code
#add subdirs
DIRS := $(shell find src -type d)
#add include directives for subdirs
CFLAGS += $(DIRS:%=-I%)
#collect all c files
SRCS := $(shell find src/* -name \*.c)
OBJS := $(addprefix obj/, $(SRCS:.c=.o))
DEPS := $(addprefix obj/, $(SRCS:.c=.d))
# this generates a dependency file for every .c
obj/%.d: %.c
# mkdir -p "$(#D)"
# echo "Checking dependencies for $<"
# create and modify dependecy file .d to take into account the location obj (sed magical)
# gcc $(CFLAGS) -MM $< 2>/dev/null | sed -e "s#\(^.*\)\.o:#obj/$(shell dirname $<)/\1.d obj/$(shell dirname $<)/\1.o:#" > $#
#this compiles
obj/%.o : %.c
gcc $(CFLAGS) -c $< -o $#
#this creates the executable
my_code: $(OBJS)
gcc $(OBJS) -o $# $(LDFLAGS)
# this does the magic
-include $(DEPS)
clean:
rm -rf obj
If you're new to Make, this might seem difficult, but it's really powerful once you get through.

you can write the makefile rule this way:
obj/lsabase.o : lsabase.c inc/lsabase.h
<tab>cc $(CFLAGS) -c $< -o $# -Iinc/.
where, in the actual makefile, the <tab> would be replaced with an actual tab character
Notice the *.c file is first in the list of dependencies, so can use the $< shortcut
You mentioned wanting to do this for all the object files..
obj/$.o : %.c inc/%.h
<tab>cc $(CFLAGS) -c $< -o $# -Iinc/.
However, that may not be the most flexible. For maximum flexibility, suggest adding a rule to generate and include dependency files named *.d. Then using:
obj/$.o : %.c %.d
<tab>cc $(CFLAGS) -c $< -o $# -Iinc/.

Related

Unexpected prerequisite skip in GNU Make 4.2.1

I'm trying to create a generic Makefile to use with most of my projects. It should work as follows: only rebuild and link those .o files whose .c or .h dependency has changed. The .o and .d files are stored in a separate directory called 'build'.
With the help of the official GNU Make manual and some googling I've managed to achieve the desired behavior except for one thing: when I run make re I get the error:
Assembler messages: Fatal error: can't create build/ft_build_buffer.o: No such file or directory — the reason for this is that the 'build' directory only gets created whenever the .d files are generated, but for some reason the re rule simply skips this step and goes on to compile .o files straight away! Note: if I run make clean && make fclean && make all (which should be the exact same thing) everything works fine.
A few other things: I've tried using the -MMD option to generate dependencies on the fly but on my machine that causes the .d files to only contain .c dependencies. Of course I could just make all .c files depend on all .h files but that seems like a very sloppy solution.
Feel free to share any other advice/improvements that will make this file more clean and readable, thanks! :)
# Define the C compiler to use.
CC := gcc
# Define any compile-time flags.
CFLAGS := -I./include -Wall -Wextra -Werror -g
#CFLAGS := -I./include -march=native -O2 -pipe
# Define the executable file.
BIN := ft_hexdump
# Define build directory.
BUILD_DIR := build
# Define source files directory.
SRC_DIR := src
# Define the C source files.
SRCS := $(wildcard $(SRC_DIR)/*.c)
# Define the C object files.
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
# Define the prerequisite files.
DEPS := $(OBJS:%.o=%.d)
.PHONY: all clean fclean re
.DELETE_ON_ERROR:
all: $(BIN)
-include $(DEPS)
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
$(BUILD_DIR)/%.o: $(BUILD_DIR)/%.d
$(CC) $(CFLAGS) -c $(SRC_DIR)/$*.c -o $#
$(BUILD_DIR)/%.d: $(SRC_DIR)/%.c
#mkdir -p $(#D)
#set -e; rm -f $#; \
$(CC) $(CFLAGS) $(INCLUDE) -MM $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
clean:
-rm -rf $(BUILD_DIR)
fclean: clean
-rm -f $(BIN)
re: fclean all
Here is the modified working version as suggested by #M.M
# Define the C compiler to use.
CC := gcc
# Define any compile-time flags.
CFLAGS := -I./include -Wall -Wextra -Werror -g
#CFLAGS := -I./include -march=native -O2 -pipe
# Define the executable file.
BIN := ft_hexdump
# Define build directory.
BUILD_DIR := build
# Define source files directory.
SRC_DIR := src
# Define the C source files.
SRCS := $(wildcard $(SRC_DIR)/*.c)
# Define the C object files.
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
# Define the prerequisite files.
DEPS := $(OBJS:%.o=%.d)
.PHONY: all clean fclean re
.DELETE_ON_ERROR:
all: $(BIN)
-include $(DEPS)
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) -MMD -c $(SRC_DIR)/$*.c -o $#
clean:
-rm -rf $(BUILD_DIR)
fclean: clean
-rm -f $(BIN)
re:
$(MAKE) fclean
$(MAKE) all

makefile, compile list of sources stuck on first file

I have a very extrange problem.
I'm working with makefile and Eclipse to compile a program for an AVR microcontroller. The basic idea is to create a project handled by a makefile, and everything works well if I only have one (1) source file, but if I add more than one source file, just the first file is compiled as many time as objects (.o files) I want to create.
I think is better with the example below:
This is a snipet of my makefile:
PROJ_DIR = /home/namontoy/workspace-AVR/exampleBitCloudMakefile
SDK_ROOT = /opt/cross/avr
LIST_PATH = $(CONFIG_NAME)/List
EXE_PATH = $(CONFIG_NAME)/Exe
OBJ_PATH = $(CONFIG_NAME)/Obj
# Create list of sources and list objects
SRCS := $(shell find . -type f -name '*.c')
OBJECTS := $(SRCS:.c=.o)
# Second for to create list of sources and objects
#SOURCES=$(wildcard $(SRCS)/*.c)
#OBJECTS_AUX=$(patsubst %.c, %.o, $(SOURCES))
#OBJECTS = $(subst $(PROJ_DIR),$(OBJ_PATH), $(OBJECTS_AUX))
directories:
#echo
#echo $(MSG_MKDIR) $#
#"mkdir" -p $(LIST_PATH)
#"mkdir" -p $(EXE_PATH)
#"mkdir" -p $(OBJ_PATH)
# Compile: create object files from C source files.
$(OBJECTS) : $(SRCS) directories
#echo
#echo $(MSG_BUILDING) $< # print message of begining build
#echo srcs: $(SRCS) # print list of sources
#echo objects: $(OBJECTS) # print list of objects
#echo '$$< is "$<"' # print file to be compiled
#echo '$$# is "$#"' # print name of object file
$(CC) $(CFLAGS) $< -o $#
#echo $(MSG_FINISH_BUILDING) $< # print message of finished build
On the terminal, make prints:
Building file: dummyFile.c
srcs: ./dummyFile.c ./LearningInterrupt_Main.c
objects: ./dummyFile.o ./LearningInterrupt_Main.o
$< is "dummyFile.c"
$# is "dummyFile.o"
avr-gcc -g -c -O1 -std=gnu99 -Wall -mmcu=atmega328p -fshort-enums -funsigned-char -funsigned-bitfields -fpack-struct -Wstrict-prototypes -Wa,-adhlns=dummyFile.lst -I/opt/cross/avr/avr/include -I/opt/cross/avr/lib/gcc/avr/4.8.3/include -I/opt/cross/avr/lib/gcc/avr/4.8.3/include-fixed -I/home/namontoy/workspace-AVR/exampleBitCloudMakefile/headers -I/home/namontoy/workspace-AVR/exampleBitCloudMakefile/ dummyFile.c -o dummyFile.o
Finished building: dummyFile.c
Building file: dummyFile.c
srcs: ./dummyFile.c ./LearningInterrupt_Main.c
objects: ./dummyFile.o ./LearningInterrupt_Main.o
$< is "dummyFile.c"
$# is "LearningInterrupt_Main.o"
avr-gcc -g -c -O1 -std=gnu99 -Wall -mmcu=atmega328p -fshort-enums -funsigned-char -funsigned-bitfields -fpack-struct -Wstrict-prototypes -Wa,-adhlns=dummyFile.lst -I/opt/cross/avr/avr/include -I/opt/cross/avr/lib/gcc/avr/4.8.3/include -I/opt/cross/avr/lib/gcc/avr/4.8.3/include-fixed -I/home/namontoy/workspace-AVR/exampleBitCloudMakefile/headers -I/home/namontoy/workspace-AVR/exampleBitCloudMakefile/ dummyFile.c -o LearningInterrupt_Main.o
Finished building: dummyFile.c
So, as you can see, make read all sources files and objects, but when the second object file is going to be created, make didn't run over the list of sources, it stucks on the first source file.
Any ideas or suggestions?
Thanks in advance,
namontoy.
Here:
$(OBJECTS) : $(SRCS) directories
...
$(CC) $(CFLAGS) $< -o $#
You make every object depend on all sources. And the automatic variable $< takes the first prerequisite, which will be the first source file in the list, no matter what you're trying to build.
Try a pattern rule:
%.o : %.c directories
#echo compiling $< to produce $#
$(CC) $(CFLAGS) $< -o $#
Solved by :
%.o: %.f90
$(FC) $< $(INC) $(LIB) $(FLAGS) -o $(addprefix $(BINDIR)/, $(notdir $#))

Adding a library to my makefile

I have set up a makefile that takes the sources main.c, word.c, and trim.c
I also used a library which is called linkedList.a, however even after adding it it does not build as I keep getting undefined references to functions within linkedlist.
The following is my makefile code:
SHELL = /bin/sh
SRCDIR = .
CC = gcc
YACC = bison -y
CDEBUG = -g
COMPLIANCE_FLAGS =
CFLAGS = $(COMPLIANCE_FLAGS) $(CDEBUG) -I. -I$(SRCDIR)
LDFLAGS = -g
LIBRARY_FILES = linkedList.a
linkedList.a: $(LIBRARY_FILES).o
$(RM) -f $(output)
$(AR) cr $(output) $(inputs)
ranlib $(output)
############################################################################################################
# List your sources here.
SOURCES = main.c word.c trim.c
############################################################################################################
############################################################################################################
# list the name of your output program here.
EXECUTABLE = wordCounter
############################################################################################################
# Create the names of the object files (each .c file becomes a .o file)
OBJS = $(patsubst %.c, %.o, $(SOURCES))
include $(SOURCES:.c=.d)
all : $(OBJS) $(EXECUTABLE)
$(EXECUTABLE) : $(OBJS)
$(CC) -o $(EXECUTABLE) $(OBJS)
%.o : %.c #Defines how to translate a single c file into an object file.
echo compiling $<
echo $(CC) $(CFLAGS) -c $<
$(CC) $(CFLAGS) -E $< > $<.preout
$(CC) $(CFLAGS) -S $<
$(CC) $(CFLAGS) -c $<
echo done compiling $<
%.d : %.c #Defines how to generate the dependencies for the given files. -M gcc option generates dependencies.
#set -e; rm -f $#; \
$(CC) $(COMPLIANCE_FLAGS ) -M $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
clean : # Delete any and all artifacts from the build. The only thing which is kept is the source code.
rm -f *.o
rm -f *.preout
rm -f *.s
rm -f *.S
rm -f *d
rm -f $(EXECUTABLE)
I feel I added the proper items in the proper places. My best guess is that my library_files is somehow wrong?
Your $(EXECUTABLE) rule doesn't mention the library, it just tries to link main.o, word.o and trim.o. So we must rewrite that rule.
First try this from the command line (because we can't do something with Make until we know how to do it without Make):
gcc -o wordCounter main.o word.o trim.o -L. -llinkedList
If this works, then we can write the rule:
$(EXECUTABLE) : $(OBJS) linkedList.a
$(CC) -o $# $(OBJS) -L. -llinkedList
If it doesn't, we'll have to tweak it a little. And some further refinements are possible, once we have the makefile working.
The "all:" line needs enhancement and, yes, LIBRARY_FILES needs changing/splitting. You have an OBJS variable for the executable, but nothing similar for the library. Actually, a bit more to do, as follows ...
(1) Currently, you have one library, but let's go for two:
LIBRARY_FILES += lib1.a
LIBRARY_FILES += lib2.a
(2) We now need two variables, similar to your OBJS, but one for each library:
LIBOBJS1 += abc.o def.o
LIBOBJS2 += ghi.o jkl.o
(3) We now need two rules, one for each library, similar to your rule for your library, but different [Note that most modern "ar" programs do their own ranlib--YMMV]:
lib1.a: $(LIBOBJS1)
ar crv $# $(LIBOBJS1)
lib2.a: $(LIBOBJS2)
ar crv $# $(LIBOBJS2)
(4) Now, change the rule for the executable itself:$(EXECUTABLE): $(OBJS) $(LIBRARY_FILES)
$(CC) -o $(EXECUTABLE) $(OBJS) $(LIBRARY_FILES)
(5) Now, we need to change the "all:" line. With the other rule changes, this can be simplified to:all: $(EXECUTABLE)
(6) Now add a command to the "clean:" target, either: rm -f *.a
Or: rm -f $(LIBRARY_FILES)
(7) Note that care must be taken so that LIBOBJS1/LIBOBJS2 don't overlap with SOURCES/OBJS. That is, you have to decide which sources build the libraries and which ones are strictly for the executable. I think you'll be fine on this, but I didn't see anything that spelled which .c/.o files you wanted to build your library from.
(8) All the build rules should probably be moved down the file after all the symbol definitions

Compiling a list of files with many directories

i've been banging my head over this issue today.
I have many c files in many directories. They all need to be compiled and linked to a library.
Here is a hypothetical layout of the files:
main_dir/
thing1/
thing1.c
thing2/
thing2.c
thing3/
thing3.c
MakeFile
I have a makefile that "finds" these files and generates the necessary objects, however, the same c file is always used as the input.
This is what the Makefile looks like (the contents of each file are a function each that uses puts()):
C=gcc
CFLAGS=-Wall -g
OBJDIR=obj
SRC=$(shell find src/ -type f -name "*.c")
SRC_DIRS=$(shell find src/ -type f -name "*.c" -exec dirname {} \; | uniq)
OBJS=$(SRC:%.c=${OBJDIR}/%.o)
$(OBJS) : $(SRC)
#echo Compiling : $<
$(C) -c $(CFLAGS) -o $# $<
clean:
rm -fv $(OBJS) thingy.a
folders:
$(call build_dirs)
all: folders $(OBJS)
ar -r -o thingy.a $(OBJS)
define build_dirs
for dir in $(SRC_DIRS); do \
mkdir -pv $(OBJDIR)/$$dir; \
done
endef
The output from making:
for dir in src/thing1 src/thing2 src/thing3; do mkdir -pv obj/$dir; done
Compiling : src/thing1/thing1.c
gcc -c -Wall -g -o obj/src/thing1/thing1.o src/thing1/thing1.c
Compiling : src/thing1/thing1.c
gcc -c -Wall -g -o obj/src/thing2/thing2.o src/thing1/thing1.c
Compiling : src/thing1/thing1.c
gcc -c -Wall -g -o obj/src/thing3/thing3.o src/thing1/thing1.c
ar -r -o thingy.a obj/src/thing1/thing1.o obj/src/thing2/thing2.o obj/src/thing3/thing3.o
ar: creating thingy.a
I'm very certain the problem is my use of $(SRC) in
$(OBJS) : $(SRC)
However, I just don't know what to do.
Anybody with MakeFu that could help?
Your $(OBJS) seems to be setup correctly, therefore the following should work (instead of $(OBJ) : $(SRC) target):
$(OBJDIR)/%.o : %.c
#echo Compiling : $<
$(C) -c $(CFLAGS) -o $# $<
You're right about the $(OBJS) rule being the problem.
Look at the variables: (SRC) is src/thing1/thing1.c src/thing2/thing2.c src/thing3/thing3.c, and $(OBJS) is obj/src/thing1/thing1.o obj/src/thing2/thing2.o obj/src/thing3/thing3.o. (Are you sure you want a src directory in obj/?) Now suppose you want to build obj/src/thing2/thing2.o using this rule:
$(OBJS) : $(SRC)
#echo Compiling : $<
$(C) -c $(CFLAGS) -o $# $<
The prerequisite field ($(SRC)) expands to "src/thing1/thing1.c src/thing2/thing2.c src/thing3/thing3.c", so $< expands to "src/thing1/thing1.c". Obviously what you want in this case is "src/thing2/thing2.c", so that's what the prerequisite field should be. What you need is something like a pattern rule or static pattern rule. The trick is that you don't know the paths ahead of time, and Make doesn't handle patterns well, so we have to be deft:
$(OBJS) : $(OBJDIR)/%.o : %.c
#echo Compiling : $<
$(C) -c $(CFLAGS) -o $# $<

How can I create a Makefile for C projects with SRC, OBJ, and BIN subdirectories?

A few months ago, I came up with the following generic Makefile for school assignments:
# ------------------------------------------------
# Generic Makefile
#
# Author: yanick.rochon#gmail.com
# Date : 2010-11-05
#
# Changelog :
# 0.01 - first version
# ------------------------------------------------
# project name (generate executable with this name)
TARGET = projectname
CC = gcc -std=c99 -c
# compiling flags here
CFLAGS = -Wall -I.
LINKER = gcc -o
# linking flags here
LFLAGS = -Wall
SOURCES := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS := $(SOURCES:.c=*.o)
rm = rm -f
$(TARGET): obj
#$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
#echo "Linking complete!"
obj: $(SOURCES) $(INCLUDES)
#$(CC) $(CFLAGS) $(SOURCES)
#echo "Compilation complete!"
clean:
#$(rm) $(TARGET) $(OBJECTS)
#echo "Cleanup complete!"
This will basically compile every .c and .h file to generate .o files and the executable projectname all in the same folder.
Now, I'd like to push this a little. How can I write a Makefile to compile a C project with the following directory structure?
./
./Makefile
./src/*.c;*.h
./obj/*.o
./bin/<executable>
In other words, I'd like to have a Makefile that compiles C sources from ./src/ into ./obj/ and then link everything to create the executable in ./bin/.
I've tried to read different Makefiles, but I simply can't make them work for the project structure above; instead, the project fails to compile with all sorts of errors. Sure, I could use full blown IDE (Monodevelop, Anjuta, etc.), but I honestly prefer to stick with gEdit and the good ol' terminal.
Is there a guru who can give me a working solution, or clear information about how this can be done? Thank you!
** UPDATE (v4) **
The final solution :
# ------------------------------------------------
# Generic Makefile
#
# Author: yanick.rochon#gmail.com
# Date : 2011-08-10
#
# Changelog :
# 2010-11-05 - first version
# 2011-08-10 - added structure : sources, objects, binaries
# thanks to http://stackoverflow.com/users/128940/beta
# 2017-04-24 - changed order of linker params
# ------------------------------------------------
# project name (generate executable with this name)
TARGET = projectname
CC = gcc
# compiling flags here
CFLAGS = -std=c99 -Wall -I.
LINKER = gcc
# linking flags here
LFLAGS = -Wall -I. -lm
# change these to proper directories where each file should be
SRCDIR = src
OBJDIR = obj
BINDIR = bin
SOURCES := $(wildcard $(SRCDIR)/*.c)
INCLUDES := $(wildcard $(SRCDIR)/*.h)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
rm = rm -f
$(BINDIR)/$(TARGET): $(OBJECTS)
#$(LINKER) $(OBJECTS) $(LFLAGS) -o $#
#echo "Linking complete!"
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
#$(CC) $(CFLAGS) -c $< -o $#
#echo "Compiled "$<" successfully!"
.PHONY: clean
clean:
#$(rm) $(OBJECTS)
#echo "Cleanup complete!"
.PHONY: remove
remove: clean
#$(rm) $(BINDIR)/$(TARGET)
#echo "Executable removed!"
First, your $(OBJECTS) rule is problematic, because:
it's kind of indiscriminate, making all sources prerequisites of every object,
it often uses the wrong source (as you discovered with file1.o and file2.o)
it tries to build executables instead of stopping at objects, and
the name of the target (foo.o) is not what the rule will actually produce (obj/foo.o).
I suggest the following:
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
#echo "Compiled "$<" successfully!"
The $(TARGET) rule has the same problem that the target name does not actually describe what the rule builds. For that reason, if you type make several times, Make will rebuild the target each time, even though there is no reason to. A small change fixes that:
$(BINDIR)/$(TARGET): $(OBJECTS)
$(LINKER) $# $(LFLAGS) $(OBJECTS)
#echo "Linking complete!"
Once that's all in order, you might consider more sophisticated dependency handling; if you modify one of the header files, this makefile will not know which objects/executables must be rebuilt. But that can wait for another day.
EDIT:
Sorry, I omitted part of the $(OBJECTS) rule above; I've corrected it. (I wish I could use "strike" inside a code sample.)
You can add the -I flag to the compiler flags (CFLAGS) to indicate where the compiler should look for source files , and the -o flag to indicate where the binary should be left:
CFLAGS = -Wall -I./src
TARGETPATH = ./bin
$(TARGET): obj
#$(LINKER) $(TARGETPATH)/$(TARGET) $(LFLAGS) $(OBJECTS)
#echo "Linking complete!"
In order to drop the object files into the obj directory, use the -o option when compiling. Also, look at the $# and $< automatic variables.
For example, consider this simple Makefile
CFLAGS= -g -Wall -O3
OBJDIR= ./obj
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o )
all:$(OBJS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $(OBJDIR)/$#
Update>
By looking at your makefile, I realize you are using the -o flag. Good. Continue using it, but add a target directory variable to indicate where the output file should be written.
I have stopped writing makefiles these days, if your intention is to learn go ahead, else you have good makefile generator that comes with eclipse CDT. If you want some maintainability / multiple project support with in your build tree, have a look at the following -
https://github.com/dmoulding/boilermake I found this pretty good..!

Resources