0

Sometimes we have to deal with a header file which contains inline code snippets that use macros or variables defined in previous include files. I've met such a problem while trying to make the C object file dependent on the included header files. So I looked it up on stackoverflow and found this but the poster's question is unnecessarily complex so it seems he didn't get the intended answer. So I made a simple example here.

-- main.c

#include <stdio.h>
#define ADDVAL 32
int val;
void set_val(int);
int main()
{
set_val(10);
#include "print_val.h"
return 0;
}

-- set_val.c

extern int val;
void set_val(int a)
{
val += a;
}

-- print_val.h

printf("added value = %d\n",val + ADDVAL);

Of course I can compile and run the program like this.

$cc -c main.c -o main.o
$cc -c set_val.c -o set_val.o
$cc main.o set_val.o -o main
$./main
added value = 42

Now using Makefile.. I made this Makefile.

csrcs := $(wildcard *.c)
cobjs := $(patsubst %.c, %.o, $(csrcs))
main: $(cobjs)
    cc $^ -o $@
clean:
    \rm -f *.o main

When I do make, it works just fine.

$make
cc    -c -o set_val.o set_val.c
cc    -c -o main.o main.c
cc set_val.o main.o -o main

But of course the problem is, when I modify print_val.h, it doesn't re-make main.
So I added the header file in the prerequisite list of target 'main' like below.

csrcs := $(wildcard *.c)
cobjs := $(patsubst %.c, %.o, $(csrcs))
main: $(cobjs) print_val.h
    cc $^ -o $@
clean:
    \rm -f *.o main

Now, after cleaning, if I do make, I see errors.

$ make
cc    -c -o set_val.o set_val.c
cc    -c -o main.o main.c
cc set_val.o main.o print_val.h -o main
print_val.h:1:8: error: expected declaration specifiers or ??...?? before string constant
    1 | printf("added value = %d\n",val + ADDVAL);
      |        ^~~~~~~~~~~~~~~~~~~~
print_val.h:1:29: error: unknown type name ??val??
    1 | printf("added value = %d\n",val + ADDVAL);
      |                             ^~~
make: *** [Makefile:4: main] Error 1

This header file contains execution line and this file cannot be compile by itself.
How should I handle this??

Chan Kim
  • 5,177
  • 12
  • 57
  • 112
  • The way you use your header file is *very* unusual. Why did you make it that way? What is the assignment or exercise you attempt to solve? – Some programmer dude Nov 15 '22 at 08:51
  • Does this answer your question? [Makefile (Auto-Dependency Generation)](https://stackoverflow.com/questions/8025766/makefile-auto-dependency-generation) – the busybee Nov 15 '22 at 09:01
  • @Someprogrammerdude This is quite common, if you have for example some preprocessing step that creates the file to be included. Let's say for some array initialization, or too-complex-for-manual creation of statements. -- However, I would not use the "*.h" file extension, because this is clearly no header file, but "*.c" or some other. The preprocessor does not care about file extensions. – the busybee Nov 15 '22 at 09:05
  • @thebusybee For auto-generated data (tables/arrays/etc.) I've seen it. As well as for configuration of some embedded RTOS systems. More common (in my experience) is to create actual source files that are built separately and then link with the object files. But for a simple single statement like that? I just don't see a use-case for this specific example. – Some programmer dude Nov 15 '22 at 09:22
  • @Someprogrammerdude It is just an example, and granted, an irritating one. :-D I concentrated on the actual issue, not the contents of the sources. – the busybee Nov 15 '22 at 09:26
  • @Someprogrammerdude it is a very pecuilar case provided to me and I cannot change the header files. – Chan Kim Nov 15 '22 at 11:18
  • @thebusybee I tried giving -MM or -MD with gcc but it didn't re-make main. – Chan Kim Nov 15 '22 at 11:26
  • Some programmer dude's answer is the correct one, but I found the reason print_val.h was compiled was it was the target of cc by '$^' in the recipe. So if I still leave print_val.h in the prerequisite and I change $^ to it to $(filter %.o, $^) in the recipe it also works, but is a weird method. :) – Chan Kim Nov 15 '22 at 11:37
  • It does not suffice to add these options. You need to add at least an include line to your Makefile. Please read the complete linked question and its answers. It might also help to follow the links and to understand the mechanics. Please do not insert some code snippets blindly, never. The beauty of the suggested method is its automagic. Someprogrammerdude's solution is OK and works with any compiler. But you need to maintain the lists of dependencies manually. – the busybee Nov 15 '22 at 11:45
  • @thebusybee Ok I forgot to include the .d files in the prereq. Because I'm doing something else, I'll study this auto dep method later. and the current build system is not what I made and it was given to me, more complex than the simple example. Thanks! – Chan Kim Nov 15 '22 at 11:48

1 Answers1

0

It is the main.o file which depends on the header file, not the main executable program file.

So you need to add the dependency for the object file only:

main.o: print_val.h

Just add that line at the end of the of the makefile.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621