Make implicit rules and header files - c

Make's implicit rules are supposedly there to make writing Makefiles easier but, if my understanding is correct, if my C files depend on any header files, I need to write the rule, explicitly. Am I right? This seems to serioiusly lower the usefulness of implicit rules, since most C files depend on a couple of header files, so I thought perhaps there's something I'm missing.

You can autogenerate header dependencies with gcc using the following makefile snippet
SOURCES := $(wildcard *.c)
DEPS := $(SOURCES:%.c=%.d)
CFLAGS += -MMD
-include $(DEPS)
The code might need some adjustments to work with your particular ruleset.

You don't need to write the rule, only the dependencies. Example:
foo.o : foo.h bar.h
The file foo.o will still be generated by the implicit rule, but have the additional dependencies foo.h and bar.h. This dependency line can also be auto-generated by most compilers.

make is not a utility which goes and reads inside your C file and determines which header it is including. It works based on changed timestamps of files. Hence, irrespective of whether a target is dependent on a header or any other file, you need to explicitly tell make of the dependencies.
gcc can help you ease your job by generating a dependency list for you like this
main.c
#include<stdio.h>
#include"my_header.h"
int main ()
{
return 0;
}
And then,
gcc -M main.c
Now, with -M preprocessor flag, it will automatically generate a dependency list like
main.o: main.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/bits/predefs.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h \
/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
my_header.h
gcc has figured out all includes inside stdio.h too!

Related

Referencing a C code-defined macro within its makefile

I'm writing some embedded firmware using C with arm-gcc and Eclipse.
Within my code is a FW version number defined as a macro.
I want to have that version appended to the build target file automatically.
For the sake of the example, let's say this is my main.h file:
#ifndef MAIN_H__
#define MAIN_H__
#define FW_MAJOR_VERSION 1
#define FW_MINOR_VERSION 0
and the makefile:
TARGET := fw_release
OUTPUT_DIR := out
...
generate_pkg:
#gen_pkg $(OUTPUT_DIR)/$(TARGET)_pkg.zip
where gen_pkg is some script to generate a firmware update package.
This would generate a file path like this: out/fw_release_pkg.zip
Ideally, I would like something like this:
generate_pkg:
#gen_pkg $(OUTPUT_DIR)/$(TARGET)_pkg_v$(FW_MAJOR_VERSION).$(FW_MINOR_VERSION).zip
which would generate a file path like this: out/fw_release_pkg_v1.0.zip
Now I know I can define the version within the makefile and reference that within the code (basically the other way around), but that has 2 problems:
Every time I change the makefile it triggers a compilation of the entire code which takes a few minutes.
I have two separate build configurations (release and debug), each using its own makefile, and that would require me to update the two separately.
The approach I'd take would be to define the version number elements in the Makefile, and burn those in to your code using cflags.
In the Makefile:
FW_VERSION_MAJOR=1
FW_VERSION_MINOR=1
FW_VERSION_MICRO=0a
FW_VERSION = $(FW_VERSION_MAJOR).$(FW_VERSION_MINOR).$(FW_VERSION_MICRO)
CFLAGS += -DFW_VERSION_MAJOR=$(FW_VERSION_MAJOR)
CFLAGS += -DFW_VERSION_MINOR=$(FW_VERSION_MINOR)
CFLAGS += -DFW_VERSION_MICRO=$(FW_VERSION_MICRO)
debug_build:
$(CC) -DDEBUG=1 $(OBJECTS) -o $(OUTPUT)
release_build:
$(CC) -DDEBUG=0 $(OBJECTS) -o $(OUTPUT)
Then it's a fairly easy matter to burn the correct version into your debug and
non-debug pkg generation - and you only have to change the firmware version info
in one place.
Well, you'll have to parse main.h one way or another.
Assuming that you're using gcc or clang:
generate_pkg: main.h
#gen_pkg "$(OUTPUT_DIR)/$$(echo FW_MAJOR_VERSION/FW_MINOR_VERSION | $(CC) -P -E -include main.h -x c -)_pkg.zip"
If your main.h is more complicated than that, you'll have to add all your $(CFLAGS) and other default options to the $(CC) command.

Is it possible to use .d file to compile all dependent c files?

I'm new to make ifle
I want to test certain function in my main. this function inside c files which has a LOT of dependencies that I cant even track
Is it possible to use the .d file for that .c file to compile my main with it to get this function working in my small application and the .d file gets all dependencies ?
I was thinking if it is possible to do something like
mymain.o : requiredfunctions.d mymain.c
You seem to misunderstand the relationship between source files, header files, object files and executable files.
Suppose we have several functions:
void alpha();
void beta();
void gamma();
void delta();
...
Each is declared in a header file (alpha.h) and defined in a source file (alpha.c). And suppose for now that these functions are independent; they do not call each other. Compiling one of them (to produce an object file) is easy:
gcc -c beta.c -o beta.o
(The "-c c -o o" is just a coincidence. The -c means "build an object file", and the -o means "here's how to name the result".)
We also have a function void octopus() that calls all of them. We declare it in a header, octopus.h:
// octopus.h
void octopus();
and define it in a source file, octopus.c:
#include "alpha.h"
#include "beta.h"
...
#include "omega.h"
void octopus()
{
... // calls alpha(), beta(), etc.
}
Producing the object file is easy:
gcc -c octopus.c -o octopus.o
Now suppose we have a file, mymain.c, which contains main() and invokes some functions:
#include "alpha.h"
#include "beta.h"
int main()
{
alpha();
beta();
return 0;
}
Building the object file mymain.o is easy:
gcc -c mymain.c -o mymain.o
Building the executable mymain is slightly more difficult:
gcc mymain.o alpha.o beta.o -o mymain
If all of this is clear, then I can attempt to guess what you want. You want main() to call octopus(), and you want Make to build the executable for you even though you do not know the list alpha, beta,... omega, is that right?
EDIT: If you have the file octopus.d:
octopus.o: octopus.c alpha.h beta.h ... omega.h
you can turn it into the list of required object files:
alpha.o beta.o ... omega.o
by any of a number of methods. You could use sed from the command line:
sed 's/.*\.c //;s/h /o /g' octopus.d
or within a makefile you could use Make's text-manipulation functions:
OBJECTS := $(subst .h,.o,$(filter %.h, $(shell cat octopus.d)))
This is the standard way of doing it:
foo.o : foo.c foo.d
cc $< -o $# -MF $(#:.o=.d)
touch $(#:.o=.d)
touch $Q
foo.d : ;
include foo.d
Not guaranteed to work as it is, just typed in without testing, but you get the idea.
Make sure that the compiler really produces the .d file in the proper format, further options might be necessary for your compiler. Some assemblers can also produce deps in the same way as compilers.
What's happening:
We define the dep file as a secondary target. If it's missing or out
of date, the recipe will be executed.
After invoking the compiler, we touch first the dep file then the
object. This fixes two issues: some compilers can't generate deps,
and some set the dep file date to later than the object date. That
would trigger unnecessary compilations.
The empty recipe tells make that the file is generated by some
other recipe, no need to panic when it's not there.
And finally, we include the dep file.

When I compile in C I have an error of imports in header files

I got the next error when I compile my project.
./PC.h:15:12: error: unknown type name 'InstructionMemory'
PC *new_pc(InstructionMemory *memoria);
^
./PC.h:17:1: error: unknown type name 'InstructionMemory'
InstructionMemory *get_memory(PC *programCounter);
^
2 errors generated.
In file included from main.c:5:
./InstructionRegister.h:7:36: error: unknown type name 'BankRegister'
int opera(InstructionRegister *IR, BankRegister *bank);
But this don't makes me sense, I look at the files and they are headers files, so I know that you can not use #include into headers file. So I don't know what I'm doing wrong.
There is the content of my PC.h file:
typedef struct PC PC;
PC *new_pc(InstructionMemory *memoria);
int getpc(PC *programCounter);
InstructionMemory *get_memory(PC *programCounter);
char *fecth(PC *programCounter);
char *linea_actual(PC *programCounter);
I use the next makefile to compile:
CC = gcc
CFLAGS=-I
DEPS = ALU.h InstructionRegister.h Rebasing.h BankRegister.h MemoryInstruction.h ControlUnit.h PC.h
run: exect
./exect $(EX)
%.o: %.c $(DEPS)
$(CC) -c $< $(CFLAGS)
exect: ALU.c InstructionRegister.c Rebasing.c BankRegister.c MemoryInstruction.c main.c ControlUnit.c PC.c
gcc -o exect InstructionRegister.c Rebasing.c BankRegister.c MemoryInstruction.c main.c ControlUnit.c PC.c -I.
clean:
rm -f *.o
so I know that you cannot use #include into headers file.
You are mistaken. You can, and often should and want to, use several include directives in your header file.
A typical small C project (e.g. less than a hundred thousands lines of C code in total) often would have a single common header file, e.g. myheader.h, typically starting with an include guard and several system includes, so like
#ifndef MYHEADER_INCLUDED
#define MYHEADER_INCLUDED
// some system includes
#include <stdio.h>
#include <stdlib.h>
/// your type declarations
enum foo_en { /* blablabla */ };
struct bar_st { /* blablabla */ };
typedef struct bar_st Bar;
/* etc... */
/// your global functions
extern int myglobfun(int, int);
/* etc...*/
/// your global variables (have only a few of them)
extern Bar*my_bar;
/* etc... */
#endif /*MYHEADER_INCLUDED*/
This is just one possibility of organizing a project. Some people prefer to have many header files and explicitly #include system headers before some of their own headers in every of their translation units (e.g. C source files).
The advantage of having a single common header is that the Makefile is simple to code, and you might even precompile your common header. A disadvantage is that any change (e.g. adding a field in a common struct) in that header forces make to recompile everything (not a big deal for a small project).
Alternatively you could have many header files, then be sure to use include guards (in the single common header case it is actually useless but does not harm) in them, and to define a discipline regarding multiple inclusion. Often, a header file would itself include other needed header files, or else check that they have been included, e.g. with
// file "myheaderone.h"
#ifndef MYHEADERONE_INCLUDED
// check that "myotherheader.h" has been included
#ifndef MYOTHERHEADER_INCLUDED
#error myotherheader.h should have been #include-d
#endif
//// etc
Alternatively you might code #include "myotherheader.h" near the beginning of myfirstheader.h
If you have multiple headers, you need a complex Makefile and you'll rather generate the dependencies, see this. It uses some preprocessor options to gcc like -M and friends.
BTW, your Makefile is wrong. Don't hardcode cc in it (but use $(CC)). Be sure to ask GCC for all warnings & debug info (e.g. CFLAGS= -Wall -g). Learn about GNU make catalog of rules by running make -p. And your CFLAGS= -I is really wrong, you might want CFLAGS= -I. -Wall -g since -I should always be followed by a directory.
PS. If using gcc take the habit of always passing -Wall to it. Very often (and certainly in your case) you also want -Wextra (to get even more warnings; remember the compiler warnings are your friends and you should improve your code till you have none of them) and probably -g (to be able to use the -g debugger). For benchmarking purposes ask the compiler to optimize (e.g. with -O1 or -O2 -mcpu=native).
Be aware of the -H preprocessor option: it is asking gcc to show every included file. Sometimes (e.g. to debug some nasty macro) you want to see the preprocessed form of a translation unit, use gcc -C -E to get it.

C Project - How to manage a feature list?

I have multiple features that can be enabled or disabled at the build time in a project.
The current implementation uses declarations such as #define FEATURE_FOO. Whenever I need to do something related to a particular feature, I use a pre-processor directive such as #ifdef.
The features definitions are stored inside a global header file.
This approach have two drawbacks:
It requires to #include this global header in every file, before any other header.
I cannot easily disable a C file:
This is not very good:
// file: foo.c
#include <stdio.h>
#include "main_header.h"
#ifdef FEATURE_FOO
...
#endif
Because I prefer this:
// file: foo.c
#ifdef FEATURE_FOO
#include <stdio.h>
...
#endif
So, another approach to this problem is to declare all my features at the build time:
gcc -DFEATURE_FOO -c %< -o %#
What I don't like here is that I manually need to pass each feature to my compiler.
An acceptable workaround would be to read a features.list file that contains all the features. In my Makefile I will have:
DEFINES=$(shell perl -ne 'print "-DFEATURE_$1 " if /(\w+)/' features.list)
%o: %c
gcc $(DEFINES) -c %< -o $#
What better alternative can I find?
You can use gcc's option -include myheader.h.
It adds the content of myheader.h to the very beginning of the current translation unit's source.
I am using a GNU make based build process for most of my projects and although it wasn't about features so far, I used techniques that could help you here, too.
First, the idea to have a configuration file is very good, but why not just have it in make syntax and include it?
I use something like this
# default configuration
CC := gcc
DEBUG := 0
GCC32 := 0
USELTO := 1
# read local configuration
-include defaults.mk
You could use this for having a list of features, e.g. in your defaults.mk
FEATURES := foo bar baz
and then do something like
FEATUREDEFINES := $(addprefix -DFEATURE_, $(FEATURES))
There's a lot more black magic possible with GNU make when you use the $(eval ...) function -- this might be a good alternative for completely excluding a source file from compilation depending on your settings. I use this for platform-specific implementations. For example I have this included Makefile for building a binary:
P:= src
T:= csnake
csnake_SOURCES:= csnake.c utils.c game.c board.c snake.c food.c screen.c
csnake_PLATFORMSOURCES:= ticker.c
csnake_LDFLAGS:= -lm
csnake_posix_LDFLAGS:= -lcurses
csnake_dos_LDFLAGS:= -Wl,-Bstatic -lpdcurses
csnake_win32_LDFLAGS:= -static-libgcc -Wl,-Bstatic -lpdcurses \
-Wl,-Bdynamic -lwinmm
csnake_win32_RES:= res$(PSEP)csnake.rc
$(eval $(BINRULES))
My P is the current relative path in the source tree, T is the target to build and PSEP is just a helper variable containing / or \ in order to be compatible with windows. The rest should be quite self-explanatory -- for $(T)_PLATFORMSOURCES, $(BINRULES) looks in the relative path platform/$(PLATFORM)/. It works like this:
define BINRULES
BINARIES += $$(BINDIR)$$(PSEP)$(T)$$(EXE)
$(T)_SOURCES_FULL := $$(addprefix $(P)$$(PSEP),$$($(T)_SOURCES))
ifneq ($$(strip $$($(T)_PLATFORMSOURCES)),)
$(T)_SOURCES_FULL += $$(addprefix \
$(P)$$(PSEP)platform$$(PSEP)$$(PLATFORM)$$(PSEP), \
$$($(T)_PLATFORMSOURCES))
endif
[...] (... further rules ... )
endef
All these double dollars are there because $(eval ...) will expand variables -- that's desired for $(T) and $(P) but not for all the other ones, so they are protected with an extra dollar. I'm just quoting the part doing the magic for deciding which files to compile here. If you consider doing something like this, see the full example

C/C++ file before preprocessing

Is it possible to look at a c/c++ file before preprocessing? Or rather after just a half-hearted pre-processing? Basically there is a
#define <commonly_used_word> 0
in a third party library header and I want to figure out where it is. So basically, I just want the compiler to include all the headers but not the the preprocessor as such.
Your original source file is file before preprocessing.
It sounds like you want your #include directives processed, yet you want to keep macros non-substituted. Both actions are carried out by the preprocessor.
In general case it is impossible, since in C and C++ it is legal to use macros as include file names, as in
#define INCLUDE_FILE "stdio.h"
#include INCLUDE_FILE
Achieving what you want would require a preprocessor specifically designed to satisfy your request. I, for one, don't know of any such preprocessor implementation.
If you want to find where a specific macro is defined, you might try the following trick: define your own macro with the same name before including any headers, and start compilation. The compiler (the preprocessor) should complain about macro redefinition when it encounters the library definition of the same macro and point out its location to you.
There are GCC-specific -M and -MM options:
To list absolute paths of include files, use -M
Instead of outputting the result of preprocessing, output a rule
suitable for make describing the dependencies of the main source file.
The preprocessor outputs one make rule containing the object file name
for that source file, a colon, and the names of all the included
files, including those coming from -include or -imacros command line
options. gcc -M test.c
If you dont want the system includes like
#include <stdio.h>,
then use -MM Like -M but do not mention header files that are found in
system header directories, nor header files that are included,
directly or indirectly, from such a header. gcc -MM test.c
That could significantly narrow down the search area.
http://www.math-linux.com/spip.php?article263
You can tell cpp to generate the list of included files using -M option:
$ cpp -M a.c
a.o: a.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.1/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.1/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
It gives you a Makefile rule format but you could ignore that and use with any other command.
For example, you can grep for the symbol (here I'm ignoring stderr because of \ and a.o: not being a real file names -- laziness):
$ grep '#\s*define\s*BUFSIZ' $(cpp -M a.c) 2>/dev/null
/usr/include/stdio.h:# define BUFSIZ _IO_BUFSIZ
You can also use a program like ctags to find the symbol for you:
$ ctags $(cpp -M a.c)
...
$ grep BUFSIZ tags
BUFSIZ /usr/include/stdio.h 128;" d
If you know which header files contain the definition you're looking for, e.g by using find and grep as suggested, you may be able to pinpoint which one is affecting the current source file by getting gcc to print the header inclusion tree. As described in gcc's documentation, you can achieve this by using the -H option, possibly combined with -MG to eliminate normal processing.

Resources