Search code examples
cgcclinkerstatic-functions

What is the difference between including a file directly and linking against it?


I found these lines in a header file (https://github.com/eyalroz/printf/blob/master/src/printf/printf.h) that is part of a printf implementation.

// If you want to include this implementation file directly rather than
// link against, this will let you control the functions' visibility,
// e.g. make them static so as not to clash with other objects also
// using them.
#ifndef PRINTF_VISIBILITY
#define PRINTF_VISIBILITY
#endif

Then it proceeds to put that label before every function declaration.

PRINTF_VISIBILITY
int  sprintf_(char* s, const char* format, ...) ATTR_PRINTF(2, 3);
PRINTF_VISIBILITY
int vsprintf_(char* s, const char* format, va_list arg) ATTR_VPRINTF(2);

I know that "link against" means doing something like

gcc -o main.o -c main.c
gcc -o printf.o -c printf.c
gcc main.o printf.o -o output

But what does the other option "include file directly" mean? What would be the gcc commands in this case?

Also, if there are other objects (which I think it means object files) using the functions, why make them static in the first place and how could they clash? How could, for example, main.c use these functions if they are static?


Solution

  • But what does the other option "include file directly" mean?

    I take that to mean source inclusion, via an #include directive.

    What would be the gcc commands in this case?

    It would normally be a matter of source code, not GCC options, but GCC does have an -include option that could be used for the purpose.

    Also, if there are other objects (which I think it means object files)

    Yes, other object files, though from a C language perspective the key concept is other translation units.

    using the functions, why make them static in the first place and how could they clash?

    If you have two different translation units contributing to the same program, and they both provide definitions of the same function, and more than one of those definitions has external linkage, then you have a collision between conflicting external function definitions. (The colliding definitions being lexically identical is irrelevant.) Declaring the functions with the static keyword gives them internal linkage instead of external. Each such definition can be referenced by other functions in the same translation unit, but not by functions from other translation units. Internal function definitions from different translation units do not clash.

    How could, for example, main.c use these functions if they are static?

    main.c having #included static definitions of these functions, any function in the translation unit can call the included functions normally. Nothing special is required, other than the inclusion of the function sources (which is a bit weird). The usual requirements for having in-scope declarations apply, of course, but typically that would be taken care of simply by performing the inclusion near the top of the source file.

    As for the PRINTF_VISIBILITY macro, the idea is that if you were using #include "printf.c", then you might want to first #define PRINTF_VISIBILITY static so that you get static function definitions. If that macro is not otherwise defined, then the file defines it to expand to nothing, so that you get external definitions.