gcc cant find definitions of stdio.h funcs and identities when gcc is executed by GNU Make

132 Views Asked by At

I'm learning how GNU Make and makefile works.
I have a small project with 7 *.c and *.h files and a main.c file.


here's the makefile:

CC = "gcc"
CFLAGS = "-std=c11"

#PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
# the PATH variable is set after I got the error. But adding this didnt change the result

src := src/lib
bin := bin

project:        $(bin)/aaa.o $(bin)/bbb.o $(bin)/ccc.o $(bin)/ddd.o $(bin)/eee.o $(bin)/fff.o $(bin)/main.o
                $(CC) $(CFLAGS) $(bin)/aaa.o $(bin)/bbb.o $(bin)/ccc.o $(bin)/ddd.o $(bin)/eee.o $(bin)/fff.o $(bin)/main.o -o $(bin)/project


$(bin)/aaa.o:   $(src)/aaa.c $(src)/ddd.h
                $(CC) $(CFLAGS) -c $(src)/aaa.c

$(bin)/bbb.o:   $(src)/bbb.c $(src)/aaa.h $(src)/bbb.h $(src)/ddd.h $(src)/fff.h
                $(CC) $(CFLAGS) -c $(src)/bbb.c

$(bin)/ccc.o:   $(src)/ccc.c $(src)/aaa.h $(src)/fff.h
                $(CC) $(CFLAGS) -c $(src)/ccc.c


# ... (and so on for all other .o files


clean:          
                rm $(bin)/*

#includes in files

aaa.c

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include "aaa.h"
#include "ddd.h"

bbb.c

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "aaa.h"
#include "bbb.h"
#include "ddd.h"
#include "fff.h"

ccc.c

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>

#include "aaa.h"
#include "fff.h"

when ran, It gave me this error:

"gcc" "-std=c11" -c src/lib/aaa.c
src/lib/aaa.c: In function ‘init_fileSize’:
src/lib/aaa.c:103:14: warning: implicit declaration of function ‘fileno’ [-Wimplicit-function-declaration]
  103 |     if((fd = fileno(arg->srcstream)) == -1)
      |              ^~~~~~
"gcc" "-std=c11" -c src/lib/bbb.c
"gcc" "-std=c11" -c src/lib/ccc.c
src/lib/ccc.c: In function ‘closeProgram’:
src/lib/ccc.c:10:15: error: ‘STDIN_FILENO’ undeclared (first use in this function)
   10 |     tcsetattr(STDIN_FILENO, TCSANOW, &(trml->termios_default));
      |               ^~~~~~~~~~~~
src/lib/ccc.c:10:15: note: each undeclared identifier is reported only once for each function it appears in
make: *** [makefile:19: bin/ccc.o] Error 1

from the error message, I conclude that the gcc couldn't find the definitions for functions and other identities declared in standard headers like stdio.h.

How to solve this issue?

2

There are 2 best solutions below

1
Harith On BEST ANSWER

These preprocessor symbols and functions are not a part of Standard C. They are defined in the POSIX standard.

On program startup, the integer file descriptors associated with the streams stdin, stdout, and stderr are 0, 1, and 2, respectively. The preprocessor symbols STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are defined with these values in <unistd.h>.

So you're missing:

#include <unistd.h>

for the macros.

And fileno(3) (declared in stdio.h), requires a feature test macro to be defined:

/* Before including any headers, define this at the top. */
#define _POSIX_C_SOURCE 200819L

/* Now include the headers. */

Alternatively, you could replace -std=cXX with -std=gnuXX, and that will include all sorts of extensions to the language.

0
John Bollinger On

from the error message, I conclude that the gcc couldn't find the definitions for functions and other identities declared in standard headers like stdio.h.

Yes, but that's different from not being able to find stdio.h itself. If it couldn't find the header then it would have also emitted a diagnostic about that.

The first issue is here:

CFLAGS = "-std=c11"

That tells the compiler to use the syntax and semantics of C11, without enabling any syntactic or semantic extensions to that version of the C language. It also tells the compiler to default to not enabling any standard library extensions. Everything in the standard library that has to do with integer file handles falls in the latter category, including in particular the fileno() function and the STDIN_FILENO macro.

Additionally, stdio.h is not the documented location for for the STDIN_FILENO macro. It is possible that you will still get that from stdio.h if the appropriate features are enabled, but the (POSIX) standard location for that macro is header unistd.h. This entire header is an extension.

In source files that you want to compile with the -std=c11 option and also want to access these library features, you need to define the appropriate feature-test macro(s), at the beginning, before any #include directives. And you should include the headers documented to provide any particular features you need, rather than relying on obtaining them from an undocumented source. For example,

#define _POSIX_C_SOURCE 200809L

// ...

#include <stdio.h>
#include <unistd.h>

// ...

.