GNU Make - Dependencies on non program code - c

A requirement for a program I am writing is that it must be able to trust a configuration file. To accomplish this, I am using several kinds of hashing algorithms to generate a hash of the file at compile time, this produces a header with the hashes as constants.
Dependencies for this are pretty straight forward, my program depends on config_hash.h, which has a target that produces it.
The makefile looks something like this :
config_hash.h:
$(SH) genhash config/config_file.cfg > $(srcdir)/config_hash.h
$(PROGRAM): config_hash.h $(PROGRAM_DEPS)
$(CC) ... ... ...
I'm using the -M option to gcc, which is great for dealing with dependencies. If my header changes, my program is rebuilt.
My problem is, I need to be able to tell if the config file has changed, so that config_hash.h is re-generated. I'm not quite sure how explain that kind of dependency to GNU make.
I've tried listing config/config_file.cfg as a dependency for config_hash.h, and providing a .PHONY target for config_file.cfg without success. Obviously, I can't rely on the -M switch to gcc to help me here, since the config file is not a part of any object code.
Any suggestions? Unfortunately, I can't post much of the Makefile, or I would have just posted the whole thing.

Declaring the file in .PHONY is wrong. Any dependency listed there will not be checked in the filesystem. Just list it as a dependency for the hash header and go from there.

What happened when you added config/config_file.cfg to the dependancies of config_hash.h, and why wasn't it what you expected?
A rule like
config_hash.h:config/config_file.cfg
$(SH) genhash $< > $#
would regenerate config_hash.h if config/config_file.cfg was more recent. Your gcc generated dependancies would then recompile anything depending on config_hash.h.
The $# variable is the target, using this ensures you are creating the file you asked for (In your question, if srcdir is defined the rule says it will generate ./config_hash.h, but will actually create ./$(srcdir)/config_hash.h). Similarly $< and $^ give the first and all prerequisites respectively.
I'm assuming you have a makefile like
CPPFLAGS+=-MMD -MP
all:
# etc.
config_hash.h:config/config_file.cfg
$(SH) genhash $< > $#
%.d %.o:%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $*.o $<
%.d %.o:%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $*.o $<
-include $(wildcard *.d) /dev/null

Related

Makefile: "ld: can't link with a main executable file" in C

I am trying to compile two c files, calutil.c and calutil.h into one executable. Here is my makefile:
CC = gcc
CFLAGS = -Wall -std=c11 -DNDEBUG
all: caltool
caltool: calutil.o caltool.o
$(CC) $(CFLAGS) calutil.o caltool.o
caltool.o: caltool.c
$(CC) $(CFLAGS) caltool.c -o caltool.o
calutil.o: calutil.c
$(CC) $(CFLAGS) -c calutil.c -o calutil.o
clean:
rm -rf *.o *.out
calutil.c has no main, while caltool.c has a main. I get the error
ld: can't link with a main executable file when I make. What is the cause of this?
The main problem is that some your recipe for linkage is missing the output file, and that your compilation is missing -c.
In case you're using GNU make, the following Makefile would be sufficient to do what you want to do:
CFLAGS:=-Wall -std=c11
CPPFLAGS:=-DNDEBUG
.PHONY: all
all: caltool
caltool: caltool.o calutil.o
.PHONY: clean
clean::
$(RM) *.o
Explanation:
When you're not using target-specific variables, you should use := instead of = to assign variables so that they're expanded at assignment and not at evaluation.
When your Makefile grows and you split it, you might want to have multiple targets called clean which all would be executed. In that case use clean:: instead of clean:.
There's a predefined variable to call rm, it is $(RM) and it includes the -f flag to prevent the Makefile from failing in case one or more of the files to be removed do not exist in the first place.
The pattern for clean should be *.[adios] (that's really easy to remember, adios is Spanish for goodbye) so that it removes intermediate archives (.a when you build your own static libraries), dependency files (.d), preprocessor output (.i) and assembler files (.s) in case you use -save-temps to see what the compiler is doing.
GNU make has built-in rules to compile and link, see http://git.savannah.gnu.org/cgit/make.git/tree/default.c?id=3.81
The built-in rule for compilation calls $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $< so you don't need to write your own rule.
The built-in rule for linkage calls $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $#
Targets which are not files themselves should be declared .PHONY to prevent confusion when a user creates a file with the same name, like all or clean.
I do not see how any of your commands would create a file matching the glob pattern *.out, so I removed that part of the clean rule.
Flags for the preprocessor should go into CPPFLAGS instead of CFLAGS. Preprocessor flags typically are all those -D and -I flags and would also be passed to other tools that use a C preprocessor in the same project, like splint or PC-Lint.
When the Makefile is run, it is looking how to make all, and it finds that for all it has to make caltool. For caltool it finds that it has to first make calutil.o and caltool.o. When it tries to make calutil.o and caltool.o, it finds that it can make them from calutil.c and caltool.c and will do so. Then it will link caltool.o and calutil.o into caltool.
From your naming I guessed that it's caltool.c that contains the main() function. It is helpful to place the object which contains main() first once you use static link libraries.
Edit: Here's some more magic for you. I assume that you have a header file calutil.h which is included by caltool.c to access extern symbols provided by calutil.c. You want to rebuild all objects that depend on these header files. In this case, add the following lines to your Makefile:
CPPFLAGS+=-MMD
-include caltool.d calutil.d
In order to not have the list of objects multiple times, you could add a variable objects like this:
objects:=caltool.o calutil.o
You would then build the application with this rule:
caltool: $(objects)
And include the dependency files like this:
-include $(objects:.o=.d)
In case you keep your working tree "clean", i.e. do not "pollute" it with "alien" code, i.e. you always want to include all .c files in your project, you can change the definition of objects as follows:
sources:=$(wildcard *.c)
objects:=$(sources:.c=.o)
In case you wonder why it is CPPFLAGS (uppercase) but objects (lowercase): it is common to use uppercase for all variables which configure the recipes of rules and control the built-in behavior of make, tools built on top of it, and classic environment variables, and lowercase variables for everything else.
I just removed the .o files from the directory, and edited my makefile to add -c to the caltool.o line.

Makefile for C Program

I am trying to use this Makefile for a C Program. Could you please share with me a way how I can understand the Make utility better? I am trying the following:
# stack/Makefile
CC := gcc
CFLAGS += -std=c99
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -g
VPATH = main src
all: bin/main.exe clean run
bin/main.exe: bin/main.o bin/stack.o
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
bin/main.o: main.c
bin/stack.o: stack.c stack.h
bin/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
demo:
../bin/main.exe
clean:
rm -f bin/*.o
run:
bin/main.exe
.PHONY: all clean run
And I getting this message:
gcc -std=c99 -Wall -Wextra -g -c -o bin/main.o main.c
error: unable to open output file 'bin/main.o': 'No such file or directory'
1 error generated.
make: *** [bin/main.o] Error 1
The error stems from the fact that your Makefile wants to
generate the executable and object files in subdirectory bin but it
contains no rule to ensure that bin exists when it is
needed. As #JonathanLeffler comments, you can solve that
just by manually creating bin yourself.
But it is often desired that a Makefile itself will ensure
that a subdirectory, or some other resource, exists when it
is needed, and you probably assumed that the pattern-rule
bin/%.o: %.c
would create bin as needed. It won't.
Your Makefile can ensure the existence of bin if you
amend it like this:
Somewhere below the all rule, add a new target:
bin:
mkdir -p $#
This is to make the bin subdirectory if it doesn't exist.
Then change the rule:
bin/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
to:
bin/%.o: %.c | bin
$(CC) $(CFLAGS) -c -o $# $<
The additional | bin is an example of an order-only prequisite
It means: If any of the targets (the bin/%.o things) needs to be remade from any of preceding prequisites (the ones before |, i.e. the %.c
things), then bin must be made first. So, as soon as anything needs to be made in bin, bin will be made first.
There is another more basic flaw in your Makefile. all is dependent on clean, so every time you successfully build
your program the object files are deleted. I understand that you intend this, but it entirely
defeats the purpose of make, which is to avoid the need to rebuild everything (object files, executables) every
time by instead just rebuilding those things that have become out-of-date with respect to their prerequisites.
So all should not depend on clean, and then an object file will be recompiled only if it needs to
be recompiled, i.e. is older than the corresponding source file. If and when you want to clean out the
object files, run make clean.
Finally, your demo rule:
demo:
../bin/main.exe
is inconsistent with the others. The others assume that the bin where the executable
is put is in the current directory. The demo rule assumes it is in the parent of
the current directory. If you correct the demo rule then it will be identical to
the run rule, so it is superfluous, but if it were not superfluous then it should
be added it to the .PHONY targets.
The best way to learn the proper way to use makefiles is to read the manual. Also, you can Google for some simple tutorials.

Makefile dependencies on multiple files

I have created a Makefile for unit tests which uses GCC with arguments to create profiling files (gcno) during compiling. Here's a similified part of it where compiling and linking takes place:
UTEXE = $(UTOBJSDIR)\$(UTUNIT).exe
UTOBJS = $(UTUUTSRC:.c=.o) $(UTUTSRC:.c=.o) $(UTCSRC:.c=.o)
UTOBJSFULL = $(addprefix $(UTOBJSDIR)\,$(UTOBJS))
UTOBJSGCNO = $(addprefix $(UTOBJSDIR)\,$(UTOBJS:.o=.gcno))
$(UTOBJS): %.o: %.c $(UTMAKEDEP)
$(call report,Compiling $(*F).c)
$(MKDEP) $(MKDFLAGS) -o.o -f$(UTOBJSDIR)\$(*F).dep $(subst /,\,$<)
$(CC) -c $(CFLAGS) $(subst /,\,$<) -o $(UTOBJSDIR)/$#
$(UTOBJSGCNO): $(UTOBJS) $(UTMAKEDEP)
utbuild: $(UTEXE) $(UTOBJSGCNO) $(UTOBJS) $(UTMAKEDEP)
$(UTEXE): $(UTOBJSGCNO) $(UTOBJS) $(UTMAKEDEP)
$(call report,Linking to $(UTUNIT).exe)
$(LINK) $(UTOBJSFULL) $(LNKFLAGS) -o $(UTEXE)
It compiles all the object and profile files and links together a binary. However when i delete some profile file (gcno) and call "utbuild" again it won't re-compile to restore the .gcno file. It tries to do linking again because gcno is a prequisite to it, but it wont do the compiling.
I don't know how to name this case so couldn't find solution from internet. Basically one recipe creates two files and i don't know how to write the rule that re-run's recipe even when only one file needs to re-created.
I would appreciate some links or hints.
thanks for all the comments. I've tried no-op ";" and ":=" with same outcome.
I think i need to take one step back and explain why i asked this question. It's not just about deleting or not-deleting gcno files manually, it's about general understanding how to write such a Makefile which restores any missing or out-of-date file. My Makefile has similar cases in few places and it's using parallel build so when some file goes missing it gives lot of weird errors. Usually it's solved by "clean" and "all", but i'd like the Makefile to be perfect and handle the missing file issues nicely.
As the example above is not so clear without all the rest of the Makefile then i made a new simple test.
hello.c
#include <stdio.h>
int main()
{
printf("Hello world\n");
}
Makefile
CCDIR = C:\tools\MinGW
CCBINDIR = $(CCDIR)\bin
CCINCDIR = $(CCDIR)\include;$(CCDIR)\lib\gcc\mingw32\4.8.1\include
CCLIBDIR = $(CCDIR)\lib;$(CCDIR)\lib\gcc\mingw32\4.8.1
# Overcome "missing dll file" messages on Windows
CC = set PATH=%PATH%;$(CCBINDIR)& $(CCBINDIR)\gcc.exe
LINK = set PATH=%PATH%;$(CCBINDIR)& $(CCBINDIR)\gcc.exe
# Compile and link for code coverage
CFLAGS = -fprofile-arcs -ftest-coverage -g3 -O0 $(addprefix -I,$(CCINCDIR))
LNKFLAGS = -fprofile-arcs -ftest-coverage -static -static-libgcc $(addprefix -L,$(CCLIBDIR))
OBJECTS = hello.o
EXE = hello.exe
$(OBJECTS): %.o: %.c
$(CC) -c $(CFLAGS) $(subst /,\,$<) -o $#
$(EXE): $(OBJECTS)
$(LINK) $(OBJECTS) $(LNKFLAGS) -o $(EXE)
build: $(EXE)
"make build" creates following files:
hello.o
hello.gcno
hello.exe
Now if i delete the "hello.gcno" and run build again it tells me:
mingw32-make: Nothing to be done for 'build'.
The goal is to update Makefile so that the make re-creates the "hello.gcno". It would probably re-create "hello.o" and "hello.exe" also during that process but that's not a problem.
Edit:
Just to be clear: in real Makefile i really-really need the .gcno files. It's not just an additional information or something which to avoid or do optionally. The Makefile builds the unit test executables, runs them and executes gcov to generate code coverage information and gcovr creates a report of all the .gcov files. If .gcno file is missing it won't work. Also - as it's parallel build then dependencies shall be absolutely correct to avoid some process starting earlier and it's tricky because coverage report has dependencies coming from two "branches" - .gcno files from compile stage and .gcda files from execute stage. So that's why i need it to be correct.
your only option here is this :
(if you can change the rule)
$(EXE): $(OBJECTS)
$(LINK) $(OBJECTS) $(LNKFLAGS) -o $(EXE)
to this:
%.exe %.gnco: $(OBJECTS)
$(LINK) $(OBJECTS) $(LNKFLAGS) -o $(EXE)
$(GENERATE_GNCO) $<
Here is a very simple solution of one thing dependig on two other things
compile:./src/main.c ./src/error.c
gcc ./src/error.c ./src/main.c -o ./exe/calc
run : ./exe/calc
./exe/calc
The correct answer in my opinion, is, don't delete any .gcno files by themselves. If you have to "clean", use make clean, but don't just go about deleting files.
The "build" is a state machine, with all the files constituting a "state". Don't corrupt the state!
Some people say, one should be able to delete arbitrary files and the build should recover. My answer is, what about if you corrupt some .o file by hand, say, add some 0's and 1's, making it unusable (thank you user3629249 for pointing that needs to be clarified, that I am talking about corruption, not intentional editing). Should the build also recover from that? Obviously no - no build system in the world will recover if you touch the .o file this way. Then why allow deleting a file, but not allow modifying it?? Where do you draw the line?
Simply put, any corruption should not be allowed. Use make clean only, or better yet, write your Makefile properly, so you never need to clean period.
The whole Makefile has a number of problems, here is how it should look like (I am assuming this is on Windows/DOS):
.SUFFIXES:
UTEXE := $(UTOBJSDIR)\$(UTUNIT).exe
UTOBJSFULL := $(addprefix $(UTOBJSDIR)\,$(subst /,\, $(UTUUTSRC:.c=.o) $(UTUTSRC:.c=.o) $(UTCSRC:.c=.o)))
UTOBJSGCNO := $(UTOBJSFULL:.o=.gcno)
.PHONY: utbuild all
all: utbuild
utbuild: $(UTEXE) $(UTOBJSGCNO) $(UTMAKEDEP)
$(UTOBJSGCNO): %.gcno: %.o $(UTMAKEDEP) ;
.SECONDARY: %\.
%\.: Makefile
mkdir $*
.SECONDEXPANSION:
$(UTOBJSFULL): $(UTOBJSDIR)\%.o: %.c $(UTMAKEDEP) | $$(#D)\.
$(call report,Compiling $<)
$(MKDEP) $(MKDFLAGS) -o.o -f$(UTOBJSDIR)\$(*F).dep $<
$(CC) -c $(CFLAGS) $< -o $#
$(UTEXE): $(UTOBJSFULL) $(UTMAKEDEP) | $$(#D)\.
$(call report,Linking to $(#F))
$(LINK) $(UTOBJSFULL) $(LNKFLAGS) -o $#

No rule to make something.o even though %.o is defined

I'm new to the forum, so I hope I'm doing things right.
I'm writing from scratch a Makefile for a C project. It was working at some point, then I tried to improve it a little (including separate folders), and I got the well-known error "No rule to make target "obj/autresFonctions.o", needed for "CUR"". Or similar, since it's not in english and I translated.
That seems quite weird since the rule I'm expecting to work is using %.o and should match anyhting. Thus I don't think it could be a typo.
Here is the Makefile :
EXE=prgm
CC=gcc
SRC_DIR=src
OBJ_DIR=obj
INCLUDE_DIR=include
_FICHIERS_H = autresFonctions.h calculPrealable.h constantes.h fonctionsAnnexes.h fonctionBoucles.h lectureFichiers.h main.h
FICHIERS_H = $(patsubst %, $(INCLUDE_DIR)/%, $(_FICHIERS_H))
_OBJ = autresFonctions.o calculPrealable.o fonctionsAnnexes.o fonctionsBoucles.o lectureFichiers.o main.o
OBJ = $(patsubst %, $(OBJ_DIR)/%, $(_OBJ))
FLAGS=-Wall -Wextra
CUR: $(OBJ)
$(CC) -o $(EXE) $^
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(FICHIERS_H)
$(CC) $(FLAGS) -c -o $# $<
clean:
rm $(OBJ) $(EXE)
I'm assuming it's the same for the others .o, because I also tried switching the first two .o in _OBJ , and I got the same error with calculPrealable.o
I'm just typing "make" when compiling, in order to get CUR, the main target. I'm located in the main directory, which contains include/ (with the .h), src/ (with the .c) and obj/ (empty).
EDIT : I forgot to say, but I'm using the usual GNU make.
The pattern rule only matches if ALL of the rule matches. It's not enough to just match the target: make must also be able to find (or make) the prerequisite pattern(s) and all other prerequisites listed in the rule.
If one thing doesn't match, then the rule doesn't match.
You can use make -d to see what files make is trying to build, and see which one doesn't exist and causes the rule to fail.
PS. This is all assuming you're using GNU make, which you don't say specifically.

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