Makefile, better understanding rules - c

Reading the official documentation
A prerequisite is a file that is used as input to create the target. A
target often depends on several files.
If my source file already includes the header, should I list the header in the rule?
src.c
#include <stdio.h>
#include "myheader.h"
int main()
{
printMessage();
return 0;
}
myheader.h
void printMessage()
{
printf("a message to screen\n");
}
makefile
src : src.o
cc -o src src.o
src.o : src.c
cc -c src.c
If I add myheader.h in the prerequisite it changes nothing, the same message is printed to screen. If a header is explicitly included, should it appear in the prerequisite?

The header file should be included in the dependency list.
The first time you use make to build your program, it will compile just the same whether you include myheader.h as a dependency or not. The difference is what happens when one of the files changes.
If you run make again without changing anything, it will say that "src" is up to date and won't compile anything. However, if you were to modify myheader.h and you didn't include it as a dependency, then make will say that the target is up to date. It doesn't look at the source file to see what files it includes. The make utility doesn't know anything about C or C++ source code (or any other source code). It looks only at whether the given files have changes without looking at their content.
When you include myheader.h as a dependency, if you later modify that file then running make will rebuild the program.
If you want to know all the non-system header files that a given source file depends on, you can run gcc with the -MM option. This will output a make rule listing the header dependencies of a source file.
For example, if you run gcc -MM src.c, you'll get the following output:
src.o: src.c myheader.h
You can then include that in your makefile.

Yes, you should.
The make program uses the list of files to figure out if a dependency changed and the the target should be rebuilt as a result. It needs you to specify that dependency explicitly.
It does not see the inclusion, it only sees the rules you specified. So there is a theoretical possibility that you change the header in a way that may require a re-compilation of src.o, but make will not know you did that unless you tell it to watch out.

Related

GNU gcc compiler cannot handle partial include statements

Imagine that I have a C-project in the following folder:
C:\microcontroller\stm32\myProject
I have two important folders inside myProject:
- source => here are all my .c and .h files
- build => gcc will write all the object files in here
Note: as you can see, the backward slashes indicate that this is happening on a Windows pc.
The figure below gives an overview:
I will not display my complete makefile here, because that would lead us too far. The rules inside the makefile for all .c => .o files are similar. Let us just focus on the compilation of one specific file: fileA2.c:
--------------------- COMPILATION OF FILE fileA2.c -------------------
Building ./build/folderA/fileA2.o
arm-none-eabi-gcc C:\\microcontroller\\stm32\\myProject\\source\\folderA\\fileA2.c
-o C:\\microcontroller\\stm32\\myProject\\build\\folderA\\fileA2.o
-c
-MMD
-mcpu=cortex-m7
-...
-IC:/microcontroller/stm32/myProject/source/folderA
-IC:/microcontroller/stm32/myProject/source/folderB
Notice that the gcc call ends with two include flags: one for folderA and one for folderB. This enables gcc to use any of the header files from these folders (fileA1.h, fileA2.h or fileB1.h) if fileA2.c has an import statement.
Let us now consider the source code in fileA2.c. We assume that this file needs to include fileA2.h and also fileB1.h.
/*******************************/
/* SOURCE CODE fileA2.c */
/*******************************/
// Some include statements
#include "fileA2.h"
#include "fileB1.h"
// Code
...
These include statements work perfectly. The gcc compiler retrieves the files fileA2.h and fileB1.h in the given folders. But I noticed that the following does not work:
/*******************************/
/* SOURCE CODE fileA2.c */
/*******************************/
// Some include statements
#include "fileA2.h"
#include "folderB/fileB1.h"
// Code
...
The last include statement is a 'partial path' to the file. I get the error when compiling:
fatal error: folderB/fileB1.h: No such file or directory
How can I get gcc to handle this?
PS: It is not my own habit to use 'partial paths'. But they appear a lot in the libraries from the silicon vendor of my chip, so I have to live with it.
You specify two paths to look for includes other than the current directory for the source file:
-IC:/microcontroller/stm32/myProject/source/folderA
-IC:/microcontroller/stm32/myProject/source/folderB
You get the error because neither
C:/microcontroller/stm32/myProject/source/folderA/folderB/fileB1.h nor
C:/microcontroller/stm32/myProject/source/folderB/folderB/fileB1.h exists.
To address the error, you can add the following path:
-IC:/microcontroller/stm32/myProject/source
When using double-quotes to include a header file the compiler first looks in the same directory as the current file. If the header file is not found then it continues with the standard include search paths.
So when the compiler compiles the file source/folderA/fileA2.c the first directory the compiler will look for include files is the source/folderA directory. In the first example the fileB1.h will not be found there, but since you added source/folderB to the standard search path it will be found there as source/folderB/fileB2.h.
In the second example there is no folderB/fileB1.h file on source/folderA so the compiler will search the standard search path. When it comes to source/folderB it will again try folderB/fileB2.h (i.e. source/folderB/folderB/fileB2.h) and it will still not be found, nor will it be found anywhere else.
You need to add -IC:/microcontroller/stm32/myProject/source to be able to find folderB/fileB1.h.
Apart of the two correct responses you have received before this, you have the third chance to specify the path to the file in the #include directive from the curren directory, as with
`#include "../folderB/fileB1.h"

C - How are c source files incuded without an include statement

I've taken the plunge and am learning C. It's been a pretty good but manageable learning curve coming from a scripting (php, perl) background with only a little bit of C#.
I've used the web-site "Learn C The Hard Way" and am so far grasping reasonably well (I think) but I can't understand this part of one of the exercises:
http://c.learncodethehardway.org/book/ex19.html
He created four source files - object.h, object.c, ex19.h, ex19.c
But I don't understand how the object.c file is included.
The main function is located in ex19.c, and it has the line
#include "ex19.h"
File ex19.h has the line
#include "object.h"
But object.h makes no reference to including object.c. Interestingly object.c contains the line
#include "object.h"
Is there some sort of implied include where if you include the header file, it will automatically include the c source code of the same name?
This is the job of a separate program called the linker. In C, source files need access to the header files of other C source files so that they can see information about what functions, types, and variables are defined by that second C file that the first file might want to use. Each C file is then compiled independently of the rest. The output of the compiler is an object file.
To build a final program, a second program called the linker comes in and combines all the object files together into the overall executable. This program is tasked with taking the implementations of all the different C files and cross-referencing them against one another so that each time one C file references a function or variable in a different C file, that reference can actually be made to the appropriate object.
This is why you don't need to include .c files. Once a source file has a header, it knows enough about the other file in order to use the functions it provides for the compiler to verify that it's using them correctly. The linker then handles of the job of actually making the cross-references. You can think of the compiler as a program that checks to see that if the functions are defined, then the program would work. The linker then actually checks to make sure that those functions are defined in the first place and sets up the appropriate links in the executable.
Hope this helps!
Object.c is not included.
It's compiled as it's own unit and it includes object.h
See the make file:
CFLAGS=-Wall -g
all: ex19
ex19: object.o
clean:
rm -f ex19
ex19: object.o tells you that object.o must be created before ex19 can be built, and this is picked up by default from make file as an object.c exists.
So this make file says
to build all you need ex19, to get ex19 you need object.o, and the to create object.o the makefile picks up object.o built from the object.c
From the page you reference:
make can't see anything in the file for object.o, but it does see an
object.c file, and it knows how to turn a .c into a .o, so it does
that.
The entire logic lies in the makefile and an intelligent compiler. The final binary created has an object file named as object.o which will ideally contain all the function definitions defined in object.h file. It is the linker which links the functions declared in .h file with the definition which are available in .o file.

purpose of creating DEPENDENCIES_OUTPUT file while compiling c program

gcc -MD file.c creates a dependency output file named file.d. But I dont understand the need of creating this file ( dependency file ), because when error comes while compilation, no dependency file is generated. So can anyone throw some light when he/she has used this dependency file or some usefulness of this file / feature of gcc.
The file.d file can be understand by make. You often first generate the .d files, include them into your Makefile and then compile the c-files only if one of the included headers has changed.
Don't bother about if you don't use make.
GCC documentation says:
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.

C Header Files with the same declarations but different implementations

I have two sets of header files and .c files in my project i will only ever be including one of these headers but i want the option to quickly swap the header im including. Both header files have some declarations that are exactly the same but the implementations in the .c files are different. Basically what I need is way to tell the compiler to only compile the .c file that is associated with the header im including elsewhere in my program.
You could always specify the .c or .o file that you're going to link against at compile/link time for instance
gcc -o myexe file1.c/file1.o
or
gcc -o myexe file2.c/file2.o
you could even make this a different make directive if you have a makefile if you have the same header file but 2 different implementations. I would recommend just using 1 header file and changing the underlying implementation, no point in having 2 headers with similar declarations.
If both header files are exactly the same then you don't need to maintain two header files. You can keep only one copy. Whichever code includes the header file can include this single header file only.
You can always specify which .c file you want to compile while compiling. In gcc, you can mention the C file to be compiled in the command line. In Visual Studio, you can include the correct C file.
I guess you should maintain only one header file and include that in your code. Introduce a flag to the makefile to link which implementation to be linked. You have not mentioned what are you using to build.

How to link a non-standard header file into a C compiler

I'm trying to use a non-standard header file (http://ndevilla.free.fr/gnuplot). Its used in lots of codes in various different places on my computer. Currently I have to put the header file and the object file in every folder which its needed with the preprocessor directive:
#include "gnuplot_i.h"
In the file. Is there a way by which I can put the header file in one place so I can reference it like other standard header file. Cheers.
Compile with -I<directory>
E.g.
compile with -I/usr/local/gnuplot/inc.
Also it might be worth your reading up on include paths and the difference between:
#include <include_file.h>
and
#include "include_file.h"
Linking in an object file needs to be done explicitly the same way as a C file, which means (I believe) that you need a full path. However if you archive it into a proper library then you can use -l<library name> and -L<library path> instead. E.g.
gcc -I/usr/local/gnuplot/inc -L/usr/local/gnuplot/lib -lgnuplot -o my_prog my_prog.c
Most compilers have a flag -I that lets you add a directory of your choosing to the search path for include files.

Resources