Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Including header file from static library

I am making a test setup of a C static library and program. The library code, located in a subdirectory 'foo' of my project, contains the following files:

foo/foo.c:

#include <stdio.h>
void foo(void) {
    printf("something");
}

foo/foo.h:

#ifndef foo_h__
#define foo_h__
extern void foo(void);
#endif

My progam code is as follows:

test.c:

#include "foo.h"
int main() {
    foo();
    return 0;
}

I have a build script, called 'build', which contains the following:

build:

#!/bin/bash
gcc -c -Wall -Werror foo/foo.c
ar rcs libfoo.a foo.o
gcc -static -o test test.c libfoo.a # I have also tried -L. -lfoo

But when I run build, it gives me the following error:

test.c:1:17: fatal error: foo.h: No such file or directory
  #include "foo.h"
                  ^
Compilation terminated

It does, however, work when I omit the #include line, but I would prefer if I could use header files in my static libraries. What am I doing wrong, and how can I fix it?

like image 764
Ethan McTague Avatar asked Dec 26 '14 18:12

Ethan McTague


People also ask

Does static library include headers?

No. A library contains solely and only object files. Headers are not object files. Headers are not contained in libraries.

What does including a library header file mean?

Definition. Header File is the file where all the headers name are mentioned that going to be used or consumed in the main code file. On other hand Library is the file where the implementation code of each header is written down which is mentioned in the Header file. 2. File Extension.

How do you include a header file in AC source file?

You request to use a header file in your program by including it with the C preprocessing directive #include, like you have seen inclusion of stdio. h header file, which comes along with your compiler.

What is the method to include header file?

You make the declarations in a header file, then use the #include directive in every . cpp file or other header file that requires that declaration. The #include directive inserts a copy of the header file directly into the . cpp file prior to compilation.


1 Answers

Headers are not stored in libraries. Headers are stored separately from libraries. Libraries contain object files; headers are not object files. By default, standard headers on a Unix system are stored in /usr/include — you'll normally find /usr/include/stdio.h and /usr/include/string.h and /usr/include/stdlib.h, for example. By default, libraries are stored in /usr/lib (but you may also find some in /lib). Often, compilers are configured to look in some other places too. One common alternative location is under /usr/local, so /usr/local/include for headers and /usr/local/lib for libraries. Note, too, that a single library may have many headers defining the services. The default library is an example. It has the functions corresponding to those found in <stdio.h>, <string.h>, <stdlib.h> and many other headers too.

Looking at your code:

  1. If your header file is in ./foo/foo.h, then you need to write:

    #include "foo/foo.h"
    

    Or if you continue to use #include "foo.h", you need to specify where to find the header on the compiler command line with the argument:

    gcc -Ifoo -o test test.c -L. -lfoo
    

    I deliberately excluded the -static; it's only necessary when there's a choice between a static and a shared library, but you only have libfoo.a, so the linker will use that anyway.

    Note that the problem is a compilation error, not a linking error. This would be clearer if you split the program building into two steps: (1) create test.o and (2) link program:

    gcc -c -Ifoo test.c
    gcc -o test test.o -L. -lfoo
    
  2. Your header guard is faulty. You originally had (but have updated the question so this typo is no longer present):

    #ifndef foo_h__
    #define foo_h_
    

    You need:

    #ifndef foo_h__
    #define foo_h__
    

    The macro names must be the same in both lines. Note that in this case, the misspelling is mostly harmless — but on Mac OS X, clang (masquerading as gcc) did give a warning about it (though I'd spotted it before I did any compilation). In some other cases, you wouldn't get the protection that the header guards are designed to provide.

    ./foo/foo.h:1:9: warning: 'foo_h__' is used as a header guard here, followed by #define of a
          different macro [-Wheader-guard]
    #ifndef foo_h__
            ^~~~~~~
    ./foo/foo.h:2:9: note: 'foo_h_' is defined here; did you mean 'foo_h__'?
    #define foo_h_
            ^~~~~~
            foo_h__
    1 warning generated.
    

You might legitimately wonder:

  • If I need -Ifoo when compiling test.c, why wasn't it necessary when compiling foo/foo.c?

Good question!

  1. It would not have hurt the compilation of foo/foo.c
  2. GCC looks for headers in the directory where the source code of the translation unit is found (so, when compiling foo/foo.c, it looks in foo directory for headers included as #include "foo.h" anyway.
  3. The source file foo/foo.c should have included foo.h too; it is very important that it does as that is how the compiler provides the cross-checking necessary to ensure consistency. If you had written #include "foo.h", the compilation would work as described. If you wrote (in foo/foo.c) #include "foo/foo.h", then the command line for creating foo.o would have needed -I. so the header could be found.
like image 148
Jonathan Leffler Avatar answered Sep 16 '22 11:09

Jonathan Leffler