Why do we specify header files for targets in Makefile? - c

I'm trying to understand Makefile. I understand the hole concept of the dependency tree, but why do we include .h files for the .o targets that include certain header file. Here is an example:
// main.c
#include <stdio.h>
#include "math.h"
int main() {
printf("%d\n", magic_number);
printf("%d\n", square(5));
}
// foo.h
const int magic_number = 10;
int square(int);
// foo.c
int square(int value) {
return value*value;
}
# -*- Makefile -*-
all: main
main: main.o foo.o
gcc main.o foo.o -o main
main.o: main.c #foo.h <-----------
gcc -c main.c
foo.o: foo.c
gcc -c foo.c
I commented the part out where I would add the header file. Because that's my question, why does it have to be there? I did some testing and added some more const int variables to the header. Just looking at the Makefile (with commented out foo.h) it would only recompile the main.c file. There it would then access a variable from the header. So why does it look into the header file even thought it's not in the Makefile?

Makefiles track dependencies - in this case it is an explicit dependency.
Specifying that main.o depends on both main.c and foo.h means that any time either file changes, main.o will be rebuilt.
If you didn't have that explicit dependency chain, then you could change foo.h in a way which renders main.c uncompilable, but Make wouldn't know about it so would not rebuild it when it should.

There are tons of ways that a header file can change in such a way that a source file doesn't need to also change, but yet the program is malformed if the source file is not rebuilt. Here's one simple example: say we have this source:
// foo.h
struct foo {
int f;
};
int getfoo(const struct foo* f);
// foo.c
#include "foo.h"
int getfoo(const struct foo* f)
{
return f->f;
}
// main.c
#include "foo.h"
int main()
{
struct foo f = {1};
return getfoo(&f);
}
You compile everything and all is well. Now suppose you modify foo.h like this:
// foo.h
struct foo {
const char* val; // added value
int f;
};
int getfoo(const struct foo* f);
And you modify main.c like this:
// main.c
#include "foo.h"
int main()
{
struct foo f = {"hello", 1};
return getfoo(&f);
}
Now you run make and since you've modified main.c it is recompiled, but since you haven't modified foo.c it is not recompiled.
Now your program will certainly return a bogus value since foo.o thinks that the structure it was passed contains just a single integer, but the structure it was really passed from main() actually has a pointer plus an integer.

Related

Variable in file 2 is not accessible in file 1

My file1.c is as follows
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("x = %d\n", x);
return 0;
}
And file2.c is as follows
int x = 12;
When I compile both files with gcc -std=c17 file1.c file2.c, I get the error.
error: ‘x’ undeclared (first use in this function)
Now, in my file2.c, x is a global variable. So, even if I don't declare it in file1.c, it should be seen in file1.c. So, why am I getting this error ?
x is a global variable. So, even if I don't declare it in file1.c, it
should be seen in file1.c. So, why am I getting this error ?
No, code in file1.c does not know anything about code in the file2.c. Global variables are visible only in one compilation unit (ie file).
In file1.c you need to add (before main)
extern int x;
This declaration will tell the compiler that somewhere in the project there is a definition of the variable x having the type int
#include <stdio.h>
extern int x;
int main(int argc, char *argv[])
{
printf("x = %d\n", x);
return 0;
}
Like #0___________ said above you need to declare the symbol x so my answer is just spelling it out in a bit more detail. It is customary to move declarations into a file2.h file so it's easy to reference in multiple places (especially if there is more than one symbol):
#ifndef FILE2_H
#define FILE2_H
extern int x;
#endif
Then modify file1.c and file2.c to include it:
#include <stdio.h>
#include "file2.h"
int main() {
printf("x = %d\n", x);
return 0;
}
#include "file2.h"
int x = 12;
Finally, you compile (-std=c17 makes not difference in this sample) and link the two files. Subsequently execute the binary::
$ gcc -std=c17 file1.c file2.c && ./a.out
x = 12
If you prefer a Makefile:
.PHONY: all clean
CFLAGS = -std=c17
all: a.out
clean:
rm -f a.out file1.o file2.o
a.out: file1.o file2.o
$(CC) $^ -o $#
file1.o: file2.h
file2.o: file2.h
and it's then:
$ make && ./a.out
x = 12

linking with wrap directive for unit testing can be used to redefine a subroutine?

I'm using Cmocka to write a unit testing suite for a shared object written in C, but I'm having some issue. Since I cannot share the source code, I have written a minimum "not-working" example to show what is the issue:
my program is composed 5 files: foo.c, foo.h bar.c bar.h main.c.
bar.* files define a bar() function, which simply returns the argument multiplied by 2
foo.* files declare a foo() function that uses the bar() function defined by bar.h
main.c contains a simple cmocka test and a __wrap_bar()
function, returning the argument multiplied by 3.
I compile the program by producing a libfootest.so object (foo+bar) and then I link this object with main.o passing the -Wl,--wrap=bar flag to the compiler. In this configuration libfootest is the module under test and main is the tester program. I expect the __wrap__bar to be called (failing the test), but the standard bar() is called(test is passed). How can I solve this problem? Below you find all the code I'm using.
bar.c:
#include "bar.h"
int bar(int val) {
return val*2;
}
bar.h:
int bar(int val);
foo.h:
#include <stdio.h>
int foo(int val);
foo.c:
#include "foo.h"
#include "bar.h"
int foo(int val) {
int ret;
ret = bar(val);
printf("RET: %d", ret);
return ret;
}
main.c:
#include <stdio.h>
//required include for CMOCKA
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <cmocka.h>
//library under test
#include "foo.h"
int __wrap_bar(int val) {
return 3*val;
}
static void test_foo(void **state) {
int ret = foo(5);
assert_int_equal(ret, 10);
}
int main (int argc, char** argv) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_foo),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
Makefile:
CMOCKA_LIB_DIR=../../cmocka-1.1.5/build/src
CXXFLAGS+=-g -Og -fPIC
CFLAGS+=-g -Og -std=c99 -fPIC
CC=gcc
CXX=g++
all: main.o ./libfootest.so
gcc -o linux-test -g -L. -L$(CMOCKA_LIB_DIR) $(filter %.o, $^) -lcmocka -lfootest -Wl,-rpath=. -Wall -Wl,--wrap=bar -Wl,-rpath=$(CMOCKA_LIB_DIR)
./libfootest.so: foo.o bar.o
$(CC) -shared -o $# -g $^ -pedantic -Wall
clean:
rm -f *.o
rm -f *.so
The problem is your build of the library. You don't create a link library as commonly done, with separated modules. Instead you link all given modules and place the resulting single module in the target library.
That's why the linker resolved the call to bar() already, and it is no longer unresolved when linking the test program.
The option --wrap works only for unresolved references between modules.
The solution is to build the library from separated modules. Use the tool ar for this:
ar r libfootest.a foo.o bar.o

C - Makefile compiles after header file changes, but changes dont take effect

I have 3 files in this program, lab4.c, functions.h, functions.c
The lab4.c calls a function multiply(), whose prototype is in functions.h and is defined in functions.c. Multiply then used multiple other functions from functions.c. The only includes I have for this is in lab4.c including functions.h, do I need more? The problem I am having is described below
lab4:
#include <stdio.h>
#include <stdlib.h>
#include "functions.h"
int main(void) {
...
}
functions.h:
#ifndef FUNCTIONS
#define FUNCTIONS
void divideByPowerOf2(unsigned int* a, int power);
void multiplyByPowerOf2(unsigned int* a, int power);
...
#endif /* FUNCTIONS */
functions.c:
void divideByPowerOf2(unsigned int* a, int power){
*a >>= power;
}
void multiplyByPowerOf2(unsigned int* a, int power){
*a <<= power;
}
...
Currently, my makefile looks like this:
Makefile:
#Makefile
all: lab4
lab4: lab4.o functions.o functions.h
gcc -Wall -o lab4 lab4.o functions.o
lab4.0: lab4.c
gcc -c lab4.c
functions.o: functions.c
gcc -c functions.c
now this will recompile when I change the header file, but the changes dont actually take effect. For example, if I change the header file to
#ifndef FUNCTIONS
#define FUNCTIONS
void divideByPowerOf2(unsigned int* a, int power);
//void multiplyByPowerOf2(unsigned int* a, int power);
...
#endif /* FUNCTIONS */
the program still works just fine. Im assuming I may have messed up linking the files with includes and everything, as that usually confuses me. For example, does functions.c need to refer to anything? and does functions.h need any kind of reference to the .c files? How do I get this to work properly so that if I change the header file, it recompiles and actually uses the new header
Thanks for any help!
First, there's a typo here:
lab4.0: lab4.c
should be
lab4.o: lab4.c
then, your function.h should be on the source => object dependency lines, not on the object => executable line, else, if you change the .h file, it just re-links without rebuilding the .o files: it changes nothing.
Moreover, it's good to use -Wall, but you have to use it when you compile your files, not when you link the executable, or you'll miss the actual compilation warnings (-Wall during the link phase only is pretty useless).
For instance, the -Wall flag would show you that commenting a prototype generates an "implicit declaration" warning (which can lead to an improper call/return values of a function). It's even more effective with -Werror, which turns warnings into errors, so you cannot ignore warnings.
Here's how your makefile should look like:
all: lab4
CFLAGS = -Wall
lab4: lab4.o functions.o
gcc -o lab4 lab4.o functions.o
lab4.o: lab4.c functions.h
gcc $(CFLAGS) -c lab4.c
functions.o: functions.c functions.h
gcc $(CFLAGS) -c functions.c
note that if you only have 2 source files and they're small enough, you could even not use the make file by just running:
gcc -Wall -o lab4 lab4.c functions.c
in a script. That's not adapted if you have too many / big source files, because it rebuilds everything everytime.

extern declaration and global scope

I'm wondering why is this code compiles and run. I thought that if a variable is declared as static (in global scope) it will be accessible only within the file it is declared.
functions.h
static int x = 10;
main.c
#include <stdio.h>
#include "functions.h"
extern int x;
int main()
{
printf("%d", x);
}
Technically, it is indeed declared within the main.c, as this includes the functions.h. If it was a sparate compilation module, you'd be right.
But I'd have suspected that within the same compilation unit extern and staticwould collide with each other. At least it would be worth a warning.
The preprocessor takes the text in functions.h and copies it as is into main.c
After preprocessing (and before compilation) your main.c looks as follows:
#include <stdio.h>
static int x = 10;
extern int x;
int main()
{
printf("%d", x);
}
You will have linker problems if functions.h is included into a second source file, and you try to link both object files into one executable.
when you are including functions.h in main.c , you are actually copy content of function.h in main.c so your final code become something like :
#include <stdio.h>
static int x = 10;
extern int x;
int main()
{
printf("%d", x);
}
So your extern line is redundant.
you can achieve what you want by this
remove #include "functions.h" from main.c
compile function.h using g++ -c function.h
compile main.c using g++ -c main.c
then build g++ function.o main.o -o out
third line would not compile because of static int .

Is this correct usage of weakref?

I want to allow the redefinition of a function in a .c file that is already defined in a header file. According to GCC manual on the weakref attribute:
The effect is equivalent to moving all references to the alias to a separate translation unit, renaming the alias to the aliased symbol, declaring it as weak, compiling the two separate translation units and performing a reloadable link on them.
Which sounds like exactly what I want to do.
However, the following example does not compile with error:
tpp.c:18:13: error: redefinition of ‘foo’
tpp.c:6:13: note: previous definition of ‘foo’ was here
#include <sys/types.h>
#include <stdio.h>
/* this will be in a header file */
static void foo(void) __attribute__ ((weakref ("_foo")));
static void _foo(void)
{
printf("default foo\n");
}
/* in a .c file #including the header mentioned above */
#define CUSTOM_FOO
#ifdef CUSTOM_FOO
static void foo(void)
{
printf("user defined foo.\n");
}
#endif
int main(int argc, char **argv)
{
printf("calling foo.\n");
foo();
}
Am I using this correctly? What am I missing?
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
As far as I understand that you need to define that function as extern.
Then it work for me as follows:
user#horst:$ cat weakref.c
#include <sys/types.h>
#include <stdio.h>
/* this will be in a header file */
extern void foo(void) __attribute__ ((weak, alias ("_foo")));
void _foo(void)
{
printf("default foo\n");
}
int main(int argc, char **argv)
{
printf("calling foo.\n");
foo();
}
user#horst:$ gcc weakref.c
user#horst:$ ./a.out
calling foo.
default foo
user#horst:$ cat weakrefUser.c
#include <stdio.h>
/* in a .c file #including the header mentioned above */
#define CUSTOM_FOO
#ifdef CUSTOM_FOO
void foo(void)
{
printf("user defined foo.\n");
}
#endif
user#horst:$ gcc -c weakrefUser.c
user#horst:$ gcc -c weakref.c
user#horst:$ gcc weakref.o weakrefUser.o
user#horst:$ ./a.out
calling foo.
user defined foo.
Note1: It does not work with static functions, for the weak attribute, it need to be global.
Note2: Weak symbols are "only" supported for ELF targets.
Since I wanted to use weak or weakref, and the existing answer seemed incomplete, I decided to write up the options, and try to explain.
There are apparently three basic options:
Use weakref. In this case, you write a static definition of a different name referencing the name you want, and it may or may not be null. You need to test the function before calling it. In this case, the alias option must be included either explicitly or as a parameter on weakref.
Use weak without alias. In this case, things are simple and public. Again, it may or may not be null, and you must test it before calling it.
Use weak and alias. In this case, the call and the declared alias must (apparently) be in the same source file. In this case, there is always a definition for the symbol, so you don't need to test for it. If there is an external definition of the name, you will get that in leiu of the alias.
In C++, when providing an alias name, the name must be the mangled form. (This was relevant to me, not to OP.)
My test sources are:
cat weakref.c :
#include <stdio.h>
static void fooref(void) __attribute__((weakref("foo")));
int main(int argc, char **argv)
{
if (fooref) {
printf("calling foo.\n");
fooref();
} else {
printf("no foo to call. (do something default-ish)\n");
}
}
cat weak.c :
#include <stdio.h>
#include "header.h"
int main(int argc, char **argv)
{
if (foo) {
printf("calling foo.\n");
foo();
} else {
printf("no foo to call. (do something default-ish)\n");
}
}
cat weakalias.c :
#include <stdio.h>
#include "header.h"
extern void foo(void) __attribute__ ((weak, alias ("defaultfoo")));
void defaultfoo(void)
{
printf("default foo\n");
}
int main(int argc, char **argv)
{
printf("calling foo.\n");
foo();
}
cat header.h :
extern void foo(void) __attribute__ ((weak));
cat Makefile :
EXES = weakref weakreffoo weakalias weakaliasfoo weak weakfoo
all : ${EXES}
clean :
-rm ${EXES} *.o
weakref : weakref.o
gcc -o $# $^
weakreffoo : weakref.o foo.o
gcc -o $# $^
weakalias : weakalias.o header.h
gcc -o $# $^
weakaliasfoo : weakalias.o foo.o header.h
gcc -o $# $^
weak : weak.o header.h
gcc -o $# $^
weakfoo : weak.o foo.o header.h
gcc -o $# $^
cat foo.c :
#include <sys/types.h>
#include <stdio.h>
void foo(void)
{
printf("custom foo\n");
}
My output reads:
$ ./weakref
no foo to call. (do something default-ish)
$ ./weakreffoo
calling foo.
custom foo
$ ./weak
no foo to call. (do something default-ish)
$ ./weakfoo
calling foo.
custom foo
$ ./weakalias
calling foo.
default foo
$ ./weakaliasfoo
calling foo.
custom foo
$
I initially decided on weakref, but am now leaning towards weak.

Resources