C throw compiler warning (clang) if transitively included function is used - c

I have three classes and corresponding header files, user.c, foo.c, and util.c. util.c contains functions that foo.c depends on, but I would prefer that user.c not call. Ideally, user.c would only be calling functions in foo.c. Right now, user.h/.c includes foo.h/.c, which includes util.h/.c, so all of the util functions are included transitively in user.c.
I don't need to keep the util.c contents hidden from the user, but I was wondering if there was a way to throw a compiler error/warning (or something like that) with clang if user.c ever calls something from util.c. Is this possible?
I've seen some things about PIMPL to hide private headers, but would rather not handle the additional memory and other tradeoffs of that.
I have the following includes:
user.c
#include user.h
foofunction(); //can call both of these just fine
utilfunction(); //would like to have a compiler warning if this is called
user.h
#include foo.h
foo.c
#include foo.h
void foofunction(){utilfunction();};
foo.h
#include util.h
void foofunction();
util.h
#include util.c
void utilfunction();
util.c
//no includes, just some functions
void utilfunction(){};

For C, there isn't any protection to any API/variables as long as it is global. In order to not expose API in other files you should:
Should not include private file in .h. All includes are perform in .c file
In case don't want user include private .h file, it is possible that you created a #define and check for the existence in private .h file and throw #error if not existence.

Related

Include C file which is located in the same folder as the main c file

I have a folder which contains 3 files:
main.c
file1.c
file2.c
The idea is to compile only one file basing on a symbol if it's defined or not.
in main.c, I added the following lines:
#ifdef MY_SYMBOL
#include "file1.c"
#else
#include "file2.c"
#endif
The problem that I found is that when MY_SYMBOL is defined, file1.c is compiled twice because in the makefile it's mentionned to compile all source files inside each folder.
The limitation is that I shouldn't modify the makefile! So, to avoid that I modified the extension of file1.c and file2.c to file1.h and file2.h respectively, by keeping their content (definition of all private functions), and I updated the content of main.c as following:
#ifdef MY_SYMBOL
#include "file1.h"
#else
#include "file2.h"
#endif
Taking into account the above limitation, is the last proposal the best way ?
Note that file1.c and file2.c contain the same functions but with different implementation.
Among others, C programers usually do not expect one of the following:
.h-files that contain function implementations or variable definitions
.c-files that get included.
So I'd say with both ways you will somehow "surprise" others.
If you must not alter the makefile (BTW: why?), you could encapsulate the implementation variants in your .c-files within preprocessor-directives:
// file1.c (OR: file_mysym_implementation.c):
#ifdef MY_SYMBOL
// code goes here
#endif
// file2.c (OR: file_non_mysym_implementation.c):
#ifndef MY_SYMBOL
// code goes here
#endif
Additionally, you will need one header file which declares all the functions exposed by the respective implementation.

C How to manage #include relationship among multiple source files and create correct makefile

I again re-edited my question and this time it is final.
note: the program is working (thanks for all the help). But I still have some confusion about how the dependency/linkage actually works. Specifically I would like to be walked through the process that the makefile compiles and runs. (example, the compiler first looks at main.c, starting from line 1, which is main.h, goes into main.h, starting from line 1, which points to function1.h, and so on.)
My main question here is though: is it true that compiler/makefile operates in a backwards way, that is once the compiler reaches the last stop (no more link), it started to gather the content recursively and put it in the object file. And what happens if we have multiple object file and the connect is cross-linked? Should each object file be independent from each other?
Below is my final result.
I know it is a lot of parts, but I have tried my best to put them in a organized way and added description.
FINALE MAKEFILE / DEPENDENCY
File layout
primary module: main.c
supplementary modules: builder1.c, builder2.c builder1_function.c builder2_function.c
header files: main.h control.h builder1.h builder2.h builder1_function.h builder2_function.h builder1_shared.h builder2_shared.h
1) main.c uses calls one primary function from each of builder1.c and builder2.c
2) builder1_function, builder2_function store child functions used by the primary function in builder1.c and builder2.c
3) builder1 has a set of new structures just used by it, builder2 has another set of new structures just used by it. These structures are declared in builder1_shared.h and builder2_shared.h.
4) function prototypes are declared in builder1.h builder2.h main.h
5) main.c, builder1.c, builder2.c share some constants and all uses standard libraries. These constants are declared in control.h
6) control.h: declare system-wide constants
HEADER DEPENDENCY
main.c: *include* main.h and *define* system-wide constants (declared in control.h)
main.h: *include* all std libs, *include* control.h, *include* builder1.h, *include* builder2.h
builder1.c: *include* builder1.h, uses system-wide constants, child functions of builder1, and new structures of builder1, stdlib
build1.h: *include* builder1_funcion.h *include* builder1_share.h *include* primary function prototype
builder1_function.c: *include* builder1_function.h
builder1_function.h: *include* builder1_shared.h *include* child function prototype
builder_shared.h: *include* main.h, declare new structure for buidler1
builder2.c: *include* builder2.h, uses system-wide constants, child functions of builder2, and new structures of builder2, stdlib
build2.h: *include* builder2_funcion.h *include* builder2_share.h *include* primary function prototype
builder2_function.c: *include* builder2_function.h
builder2_function.h: *include* builder2_shared.h *include* child function prototype
builder_shared.h: *include* main.h, declare new structure for buidler2
MAKEFILE
main: main.o builder1.o builder1_function.o builder2.o builder2_function.o
gcc -o main main.c builder1.c builder1_function.c builder2.c builder2_function.c -g
builder1.o: builder1.c
gcc -c builder1.c
builder1_function.o: builder1_function.c
gcc -c builder1_function.c
builder2.o: builder2.c
gcc -c builder2.c
builder2_function.o: builder2_function.c
gcc -c builder2_function.c
Headers provide information to multiple source files. If a source file doesn't provide any services to other files, it doesn't need any header. That means main.h might not be needed, but functions.h is needed. A header should contain the minimum necessary code to allow consumers to use the functions (and variables) defined in the source code. Any other headers should be included directly in the source code (so the headers should be small, and self-contained, and idempotent).
Note that the main source file corresponding to a header (main.c for main.h, or functions.h for functions.c) should include the header as the first included file. This ensures that the header is self-contained; it won't compile if it is not. Each consumer of services from another source file should include the corresponding header. Each non-static function (and global variable if you have any) should be declared in precisely one header; that header should be used wherever the function (or global variable) is needed.
Given your problem, it appears that functions.c should include main.h (and main.h is therefore needed).
In your makefile, you should probably use:
OBJECTS = main.o functions.o
all: main
main: ${OBJECTS}
${CC} -o $# ${OBJECTS} ${CFLAGS} ${LDFLAGS} ${LDLIBS}
main.o: main.h functions.h
functions.o: functions.h main.h
See also:
What are extern variables in C?
Should I use #include in headers?
#include is a pre-processing command that just does text inclusion - nothing more complex or magic than that.
So:
if a .c file has code that uses a structure, then it needs to include the header file that defines that structure.
if a .c file implements or calls a function, then it needs to include the header file that decares that function's prototype (this is usually the header file that matches the .c file that implements the function).
if a .c file uses certain system calls or types, then it needs to include the relevant system header file
Once you've got used to the concept of #include, you'll be able to work out how to structure your modules and header files efficiently and elegantly, for easy reading and maintenance.

How to remap a c header file

I am troubling myself with the following.
I have a file foo.c
that includes foo.h and does some stuff.
The tricky thing is this one. I would like to remap foo.h to my_foo.h. So when the compiler sees foo.h it should go to my_foo.h.
One thing that could work is to include my_foo.h to foo.h. Any other suggestions?
No I cannot include in foo.c my_foo.h
Thank you all in advance
Alter the include path to use a directory controlled by you before it uses the directory holding "foo.h"
In the directory controlled by you make a symlink called "foo.h" which points to "my_foo.h" as the target
Depending on which system you work, you might have no symlinks.
But maybe you can create a foo.h with the following content:
#include "my_foo.h"
What an interesting issue. I'd love to know what you're doing with it.
So if you have control over foo.h, here's a variation on a trick that is used when sharing header files between kernel code and user code in the Linux kernel.
/* File: foo.h */
#ifdef USE_MY_FOO_H
#include <my_foo.h>
#else
#define OVERRIDABLE_FOO_MACRO do { stuff() } while(0)
int overridable_foo_func();
#endif
int not_overridable_foo_func();
Then in your Makefile
/* File: Makefile */
default: foo.c foo.h
$(CC) foo.c -o foo
use_my_foo_h: foo.c foo.h my_foo.h
$(CC) -DUSE_MY_FOO_H foo.c -o foo
BTW, this is not really a great way to form your Makefile, it just demonstrates the compiler commands you can use to switch between the two foo.h files.

Which way should I compile my C code?

I have three files, test.c, foo.c, foo.h.
In foo.c i
#include "foo.h"
In test.c i
#include "foo.c."
Then when I compile my code, I use gcc -o test test.c, and it compiles.
However, my professor told me, I should use
#include "foo.h"
inside my test.c rather than #include foo.c, and I should compile it this way
gcc -o test test.c foo.c
Is the second way more preferred? If it is, why? What's the difference between these two compilation?
In most cases you should never include source files (apart from cases where you would probably want to include a piece of code generated dynamically by a separate script). Source files are to be passed directly to the compiler. Only header files should be included.
Although the way that your professor suggests is correct, the following way has more educational value in this case:
gcc -c test.c
gcc -c foo.c
gcc -o test foo.o test.o
The first two lines compile each source file to an object file, and the third line doesn't really compile but only invokes the linker to produce an executable out of the 2 object files. The idea is to make a distinction between compiling and linking, which would be performed transparently in the way your professor suggests.
The major reasons not to #include .c files in other .c files are:
Avoid duplicate definition errors: suppose foo.c defines the function foo(). You have two other files that use foo(), so you #include "foo.c" in both of them. When you try to build your project, the compiler will translate foo.c multiple times, meaning it will see multiple attempts to define the foo function, which will cause it to issue a diagnostic and halt.
Minimize build times: even if you don't introduce duplicate definition errors, you wind up recompiling the same code needlessly. Suppose you #include "foo.c" in bar.c, and you discover you need to make a one-line change in bar.c. When you rebuild, you wind up re-translating the contents of foo.c unnecessarily.
C allows you to compile your source files separately of each other, and then link the resulting object files together to build your applications or libraries. Ideally, header files should only contain non-defining object declarations, function prototype declarations, type definitions, and macro definitions.
It is common practice to #include header files instead of source files, and compile source files individually. Separation of concerns makes it easier to work with in large projects. In your example, it may be trivial, but could be confusing when you have hundreds of files to work with.
Doing it the way your professor suggests means you can compile each source separately. So, if you had a large project where the sources were thousands of lines of code, and you changed something in test.c, you can just recompile test.c instead of having to recompile foo.c along with it.
Hope this makes some sense :)
If you want to compile several files in gcc, use:
gcc f1.c f2.c ... fn.c -o output_file
Short answer:
YES the second way is more preferred.
Long answer:
In this specific case you will get the same result.
To have a dipper understanding you need first to know that "#include" statement basically copy the file it's include and put its value instead of the "#include" statement.
Therefore "h" files are used for forward declaration which you have no problem several different file will include.
while "c" files have the implementations, in that case if both files will implement the same function you will have error in linking them.
Lets say you would have "test2.c" and you will also include foo.c and try to link it with the test.c you will have two implementations of foo.c. But if you only include foo.h in all 3 files (foo.c, test.c and test2.c) you can still link them cause foo.h shouldn't have any implementations.
It is not good practice to include .c files.
In your case
Include foo.h in both test.c and foo.c , but add this inside your header file
#ifndef foo.h
#define foo.h
..your header code here
#endif
Writing the header the above way , ensures that you can include it multiple times , just to be on the safe side.
Coming to how you must put your code in files>
In foo.h
You place all your global structures ,and variables along with function prototypes , that you will use.
In foo.c
Here you define your modular functions
In test.c
Here you generally have your main() , and you will call and test the functions defined in foo.c
You Generally put all the files in the same folder , and the compiler will find them and compile them individually , they will be connected later by the linker.
gcc f1.c f2.c ... fn.c -o output_file

How are you intended to include files in a C project?

I have three files.
trees.h
// a bunch of typedefs and function prototypes
#include <trees.c>
trees.c
// a bunch of function bodies
main.c
#include <trees.h>
This isn't right, because every function in trees.c is giving me "undefined type" errors about the type defined in trees.h. I've tried every configuration I can think of - include trees.c from main and include trees.h from trees.c, include trees.c at the end of trees.h, include it at the beginning of trees.h... Every combination of includes I could think of, and each one gives a different set of errors. Sometimes it's multiple defines, sometimes it's undefined functions...
So how exactly does this work? What do I put in which files, and which files do I include and where?
Like this:
trees.h
// a bunch of typedefs and function declarations (prototypes)
trees.c
#include <trees.h>
// a bunch of function definitions (bodies)
main.c
#include <trees.h>
Explanation:
#include is basically the same as copying the entire included file to this file (where you put the #include).
So including trees.h in main.c allows that file to know about functions in trees.c.
Including trees.h in trees.c allows functions lower down in trees.c to be usable and this is also where defines, etc. used in trees.c is specified.
You also may not know about creating multiple objects and linking them, refer to Joachim Pileborg's answer.
The (very ugly) alternative is:
trees.h
// a bunch of typedefs and function declarations (prototypes)
trees.c
#include <trees.h>
// a bunch of function definitions (bodies)
main.c
#include <trees.c>
Then you just need to compile main. But for any project of a few .c files, this becomes impractical.
You compile each source file into object files, then link these object files together to form the final executable. If you use e.g. GCC and compile on the command line you can put both source files in the command line and GCC will handle it for you:
$ gcc main.c tree.c -o tree
The above command tells gcc to compile and link the files main.c and tree.c, and name the output executable tree. You can also compile the source file separately into object files, and then manually link them together:
$ gcc -c main.c -o main.o
$ gcc -c tree.c -o tree.o
$ gcc main.o tree.o -o tree
In the above commands, the -c option tells gcc to create an object file, and the -o option tells gcc what to name that object file. The last command takes these object files and create the final executable and names it (with the -o option) tree.
In the source files, you include the header(s) needed, not the other way around.
The reason it's not working is because you have to use 'extern' to define a variable or function that is declared in a different include file to the standard ones. You should also save all header files as *.h. So, assuming you had defined the struct 'tree' in tree.h:
#include <tree.h>
int main() {
extern tree; /* Get variable 'tree' declared in tree.h */
extern make_tree(void); /* Get function make_tree() declared in tree.h */
make_tree(); /* Call function */
return (0); /* End */
}
Begin with not including implementation (.c) files. Only include header (.h) files. Include them whenever you need the types or functions declared in them. To avoid multiple declarations, use include guards (whatever they are - just google it).
The way to go is including your header file trees.h in trees.c and then including trees.c within main.c
Have a look at this thread here

Resources