makefile prerequisite appears older then target even if it was built afterwards - c

I am trying to add more then one file created in different directories to a static library but apparently it does not work as expected.
My makefile structure is something like this:
./src/drv/platform/AVR/
- hal
- hw
--- spi
--- uart
In hal I define a library name in $(LIB_TARGET) named libHal and all the *.o files should be archived in that library.
In hw I define another library name in $(LIB_TARGET) named libHw and all *.o files in hw/spi and hw/uart should go in that library: first the library libHw is created with the object files in hw/spi and they are never missed, then the objects in hw/uart are created and should be added to libHw.
In each subdirectory a generic makefile with suffix rules is ran that creates the object files and then should add each *.o to the library. At the end of the run I should have in another library directory(as in another location) 2 libs, libHal and libHw, libHal contains everything in hal, libHw everything in hw.
In this case the directory hw does not have any source files and looks like this:
SUBDIRS:= spi uart
LIB_TARGET = libHw.a
.PHONY: $(SUBDIRS) clean all
default: all
$(SUBDIRS)::
$(MAKE) -C $# $(MAKECMDGOALS)
all clean : $(SUBDIRS)
Each of the uart and spi subdirs hold something like this:
include $(TGT_BASE)/make/generic.mk
SRCS := uart.c
include $(TGT_BASE)/make/rules.mk
The file generic.mk only holds generic platform definitions.
The code for the generic makefile rules.mk with all the suffix rules.
.PHONY : all clean
OBJS = $(SRCS:.c=.o)
DEPS = $(OBJS:.o=.d)
LIB_TARGETT = $(LIB_DIR)/$(LIB_TARGET)
### Archive into a library file (.a)
$(LIB_DIR)/%.a: $(OBJS)
#echo $(MSG_L)
#echo 'Adding $^ to library $#'
$(AR) $(ARFLAGS) $# $^
#echo $(MSG_L)
### rule for c files
%.o: %.c
#echo $(MSG_C)
$(CC) -c $(CFLAGS) $(MODULES_INC) $(TGT_LOCAL_INCLUDES) $< -o $#
#echo $(MSG_C)
### make dependencies
%.d: %.c
#echo $(MSG_D)
$(CC) -E -MM $(CFLAGS) $(MODULES_INC) $(TGT_LOCAL_INCLUDES) $(CURDIR)/$< > $#
#echo $(MSG_D)
all: $(DEPS) $(OBJS) $(LIB_TARGETT)
clean:
$(RM) -rf *.o *.d .depend
The makefile that exists in most
Now the problem is that sometimes some of the *.o files in hw/uart are not added to the library defined in hw. Running make in debug reveals that make itself considers the prerequisites for the library to be older then the last access to the library so they are missed.
Found an implicit rule for 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
Pruning file 'uart.o'.
Finished prerequisites of target file 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
Prerequisite 'uart.o' is older than target 'F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a'.
To explain better how this goes when it works here is an example
make[7]: Entering directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart
'
-------- make c --------
avr-gcc -c -Wall -Werror -Os -mmcu=atmega328p -IF:/automata/tmp/remake//tmp/ap
p/brick -IF:/automata/tmp/remake/src/common/h -IF:/automata/tmp/remake/src/drv/p
latform/AVR/hw/spi -IF:/automata/tmp/remake/src/drv/platform/AVR/hw/uart -IF:/au
tomata/tmp/remake/src/modules/interface/cli -IF:/automata/tmp/remake/src/drv/pl
atform/AVR/hw/uart uart.c -o uart.o
-------- make c --------
------- make Lib -------
Adding uart.o to library F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/li
bHw.a
avr-ar rcs F:/automata/tmp/remake//tmp/app/brick/lib/atmega328p/libHw.a uart.o
------- make Lib -------
make[7]: Leaving directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart'
And here is an example if it when it is not working
make[7]: Entering directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart
'
-------- make c --------
avr-gcc -c -Wall -Werror -Os -mmcu=atmega328p -IF:/automata/tmp/remake//tmp/ap
p/brick -IF:/automata/tmp/remake/src/common/h -IF:/automata/tmp/remake/src/drv/p
latform/AVR/hw/spi -IF:/automata/tmp/remake/src/drv/platform/AVR/hw/uart -IF:/au
tomata/tmp/remake/src/modules/interface/cli -IF:/automata/tmp/remake/src/drv/pl
atform/AVR/hw/uart uart.c -o uart.o
-------- make c --------
make[7]: Leaving directory 'F:/automata/tmp/remake/src/drv/platform/AVR/hw/uart'
I am using make 3.82.90 and Windows 7.
So any idea how I can force make to not miss those objects? Or to see their real time of creation and properly add them to the library? Remember, sometimes they are added, but sometimes they are not.
Thank you.

When you say it always works when you run it with make all --debug=a it always works: which part of that matters? If you run make all does it always work? Or if you run make --debug=a does it always work? Or do you have to use both to make it always work?
Since you're not showing all the makefile, we can't say much. For example, how are you setting the value of OBJS? Where and how do you define the rules that build object files (or are you using make's built-in rules for that)? That information is critical. It looks like what's happening is that make is asking you to build one file but your rules build a different file, so make sees that the file it expects was not actually updated and doesn't do anything.
Also, it's very confusing that in your overview you talk about things like dir1, dir2, dir2.1, etc. but then in the error output you provide completely different paths. We can't determine how the "real" pathnames in your example match up with the pseudo-paths in your overview.
Please either use real paths everywhere, or edit your example output to use the pseudo-paths, so we can see which paths are doing what.

Related

Simplest C makefile using implicit rules

I know it is not optimal at all to rely on make's implicit rules but
my goal is to understand why they are not working in this case.
I want to write the simplest makefile one can write for a C project
without having to specify the sources.
I have tried to run make -d but the ouput is too big and verbose to
really be helpful.
I have written makefiles for some time and I believe I am familiar with how it
works. I am pretty sure I have managed to get implicit rules to work for me both
compiling and linking in the past but apparently I am forgetting something.
Here's what I have tried :
SRCS = $(wildcard *.c)
OBJS = ${SRCS:.c=.o}
NAME=exe
${NAME}: ${OBJS}
clean:
rm -rf *.o
fclean: clean
rm -rf ${NAME}
re: fclean ${NAME}
.PHONY: clean fclean re
It almost works but it doesn't link.
I am using gnu make version 4.3
Your Makefile doesn't execute the link step because there is only a very simple implicit rule for linking. From the documentation:
Linking a single object file
n is made automatically from n.o by running the C compiler to link the program. The precise recipe used is $(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS).
This rule does the right thing for a simple program with only one source file. It will also do the right thing if there are multiple object files (presumably coming from various other source files), one of which has a name matching that of the executable file. Thus,
x: y.o z.o
In other words, for your Makefile to work, NAME needs to match the basename of one of your object files.
For example, if I have your Makefile and a single source file named hello.c, I can run:
make NAME=hello
And see the result:
cc -c -o hello.o hello.c
cc hello.o -o hello

What is this variable in the Makefile?

So here is a Makefile I have been given, with comment I have added.
MF= Makefile_c #name of the makefile
CC= cc #compiler to use
CFLAGS= -g #flags to use
LFLAGS= -lm #flags to use after the thingy
EXE= hello #name to give the executable
INC= \ # ??? What's this for ???
# No user-defined include files at present - list here if required.
# name of the source file
SRC= \
hello.c
#delete default suffix
.SUFFIXES:
#define the suffixes we are interested in
.SUFFIXES: .c .o
OBJ= $(SRC:.c=.o) # names to give the object files
#The .o files depend on the .c files. Compile the object files.
.c.o:
$(CC) $(CFLAGS) -c $<
all: $(EXE) #The output is the executable
$(OBJ): $(INC) #The objects depend on whatever INC is
# The executable depends on the object files. build it from the object files.
$(EXE): $(OBJ)
$(CC) $(CFLAGS) -o $# $(OBJ) $(LFLAGS)
# ??? the object files depend on the makefile???
$(OBJ): $(MF)
# remove any old executables or object files.
clean:
rm -f $(OBJ) $(EXE) core
I am still learning about makefiles so please correct me if I have misidentified anything. The makefile works fine But I want to adapt it to work with my program that has multiple files and header files. I suspect that the variable $INC will somehow make this possible, but so far my attempts to use it have not worked.
For now I would like to understand what this makefile is trying to do, cn you tell me what $INC is for?
The makefile works fine But I want to adapt it to work with my program that has multiple files and header files. I suspect that the variable $INC will somehow make this possible
Unfortunately, no. The \ is just a line continuation, so you can write content for the variable in the next line. It's empty here. This is just a very simple (and ancient!) approach for dependencies: List them yourself. The intention is to list all files your C source file #includes there, so make will rebuild when any of these included files change.
There are much advanced patterns, gcc (and other compilers) allow to do automatic dependency information for make, but this is out of scope for this question. (*)
As for building with multiple source files, this Makefile already supports it, again using an "ancient" way, a suffix rule. It automatically considers all .c files in your directory part of your final program.
(*) As mentioned by Tormund Giantsbane in the comments, this document has nice information on the topic auf automatic dependencies

All compiled artifacts in separate directory?

I'd like to write a simple Makefile which creates all *.o, *.so, and binary files in a build directory, possibly build/.
Is there a straightforward way of doing this in a Makefile? I'm on Linux, Ubuntu 14.04.
The linked question puts all *.o artifacts in a build directory, but not the executables themselves. To be clear, I'd like to hit make and have all items compiled and stored in build/.
Assuming you use GNU make, something like:
O ?= build
OBJS := $(patsubst %.c,$(O)/%.o,$(wildcard *.c))
SOS := $(O)/<you know better than me>
EXECS := $(O)/<you know better than me>
all: $(OBJS) $(SOS) $(EXECS)
$(OBJS): $(O)/%.o: %.c
mkdir -p $(O); \
$(CC) $(CFLAGS) -c $< -o $#
$(SOS): ...
$(EXECS): ...
should be close to what you want. As I do not know which *.so and executables you want to build and how, I just indicate a possibility for the rule that builds the *.o. It should be easy to adapt to the other targets.
If you type make, the build sub-directory will be created if it does not exist. If you type make O=foo, the foo sub-directory will be created (if it does not exist) and be used instead of build.
$(OBJS): $(O)/%.o: %.c is a static pattern rule. In case it is not clear enough, the GNU make documentation will tell you everything about them.

Extend the makefile to generate a library and documentation with doxygen

I have implemented a binary tree program which includes the tree.c with the functions, the tree.h with the declarations of them and a main.c for testing.
Also, I have a makefile which is:
CC=gcc
CFLAGS=-g -Wall
DEPS = tree.h
OBJ = main.o tree.o
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
tree: $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
clean:
rm -f *.o tree
Now I want to make it generate a library not only an object file for the binary trees functions and afterwards to generate the documentation of doxygen inside the makefile. Any help would be helpful.
I know that my answer comes in a bit late, but i hope someone will benefit from this.
I have a makefile that generates Doxygen doc.
You have to twist Doxygen a tiny bit
Create the Doxygen setup file that fits Your need, then open that in an editor and remove the lines containg the following two settings (they will be added by the make file later)
INPUT
FILE_PATTERNS
add this line
#INCLUDE = doxyfile.inc
Save this file under a different name I use Doxyfile.mk
in You makefile You need a list of sources and the directories where they are located
example
SRCS = $(OBJS:.o=.c)
SRCDIRS = ./src
SRCDIRS += ./other_src
Now You can put this rule in the Makefile, it will create the file doxyfile.inc that contains the settings You removed from Doxyfile.mk.
.PHONY: all clean distclean doxy
# If makefile changes, maybe the list of sources has changed, so update doxygens list
doxyfile.inc: Makefile.mk
echo INPUT = $(SRCDIRS) > doxyfile.inc
echo FILE_PATTERNS = *.h $(SRCS) >> doxyfile.inc
doxy: doxyfile.inc $(SRCS)
doxygen.exe doxyfile.mk
Bonus: If run from inside an IDE like Eclipse the errors that Doxygen spits out becomes clickable and will jump to the bad comment.
Well, I don't really know the syntax for the doxygen command, so I'll make a generic answer:
in your Makefile, each
term: [dep]
action
is a target.
So if you add something like:
doc: $(OBJ)
doxygen with-correct-options
You will be able to generate the documentation using:
make doc
(doc being here the name of the target)
Now, if you add:
all: tree doc
#echo "Generating program and doc."
you will have the program and the documentation generated with simply invoking
make
In the end, there is an additional statment your Makefile could have use of: .PHONY. It's "A way to mark one of many targets as not directly producing files, and ensure their execution even if a file having the same name as the target exists". In other terms, it's to make sure doc, clean or all will always be executed even if files named doc, clean or all exist.
Its syntax is the following:
.PHONY: all clean doc
And is usually put at the end of the Makefile.

Why does this makefile not apply includes to all objects?

This makefile does not behave as I expect. I want it to build .o files for each .c file in the current directory and subdirectories, and put them in a static library. However, it stops applying my $(INCS) after the first or second file. When it tries to build the second .o file, I don't see the -I paths in the build line and it complains about not finding a header file therein. Names have been genericized to simplify things. I'm using cygwin on Windows XP. I'm using an ARM cross compiler that is not under the cygwin tree. I based this makefile off an answer here. There are only about two dozen .c files so the overhead of creating the dependency files this way isn't a big deal.
# Project specific options
CC = my-cross-gcc
INCS := -I. -Iinc
INCS += -Imy/inc/path
CFLAGS := -Wall -fPIC -static -cross-compiler-specific-options
OUT := bin/libmylib.a
MKDIR:=mkdir -p
### Generic C makefile items below:
# Add .d to Make's recognized suffixes.
SUFFIXES += .d
NODEPS:=clean
#Find all the C files in this directory, recursively
SOURCES:=$(shell find . -name "*.c")
#These are the dependency files
DEPFILES:=$(patsubst %.c,%.d,$(SOURCES))
OBJS:= $(patsubst %.c,%.o,$(SOURCES))
#Don't create dependencies when we're cleaning, for instance
ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
-include $(DEPFILES)
endif
#This is the rule for creating the dependency files
%.d: %.c
$(CC) $(INCS) $(CFLAGS) -MM -MT '$(patsubst %.c, %.o,$(patsubst %.c,%.o,$<))' $< > $#
#This rule does the compilation
%.o: %.c %.d %.h
$(CC) $(INCS) $(CFLAGS) -o $# -c $<
# Now create a static library
all: $(OBJS)
#$(MKDIR) bin
ar rcsvq $(OUT) $(OBJS)
clean:
rm -rf $(OBJS) $(OUT) $(DEPFILES)
Why does this makefile not apply $(INCS) when building subsequent .o files? How do I fix it? Output resembles this:
$ make all
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o firstfile.o -c firstfile.c
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o secondfile.o -c secondfile.c
my-cross-gcc -<compiler flags> -o thirdfile.o -c thirdfile.c
thirdfile.c:23:18: fatal error: myinc.h: No such file or directory
compilation terminated.
When I go to the command line and type in the gcc line to build thirdfile.o and use the -I paths, the object file is successfully built.
There are two different mechanisms for handling header files at work here:
When the compiler is trying to build foo.o from foo.c, and in foo.c it encounters #include "foo.h", it goes looking for foo.h. The -I flags tell it where to look. If it is invoked without the flags it needs to find foo.h, it will complain and die.
When Make is trying to build foo.o, and considering which rule to use, it looks at the prerequisites. The prerequisites for your rule are foo.c foo.d foo.h, so it goes looking for those prerequisites. How is it to know where foo.h is? Note that the compiler flag inside one of its commands is of no use-- it won't make any deductions about that. If it can't find (and doesn't know how to make) a prerequisite, it will reject that rule and look for another one, such as the implicit %.o rule which knows nothing about your $(INCS) variable, and that leads you to the problem described above.
If this is the problem (and you can check by looking at the locations of the headers and doing some experiments) you have a couple of options:
A) You can use the implicit rule, and it's variables. Just add INCS to CFLAGS and you'll probably get the results you want. This tells the compiler what to do, but it still leaves Make in the dark about the dependencies, so you'll probably have to double-check that your dependency handling is correct.
B) You can tell Make where to find the header files:
vpath %.h inc my/inc/path
(You may notice that this is redundant with your INCS variable, and redundancy is bad-- you can eliminate this redundancy, but I urge you to get it working first.)
I'm going to guess that you have files named firstfile.h, secondfile.h, but no file named thirdfile.h?
I would then suppose that make cannot use the rule you gave it because and can't find or build the .h file. So it decides to use the default implicit rule instead.
All I can imagine is that for "thirdfile" your depfile is somehow out-of-date or corrupt. Perhaps it is bad enough that it's confusing make into calling some other default target.

Resources