A codebase I work with has historically tried--purposefully--to avoid dependencies on stdio.h creeping in. It has its own print formatting and mechanisms, and those are what's supposed to be used instead of printf etc.
But someone adds a dependency every so often that has to get noticed and taken out. So I tried to make an alarm for the easiest of cases:
#if !defined(NDEBUG)
void printf(float dont_link_with_stdio_h);
#endif
The gcc people seem to have been thinking along the lines of stopping easy errors too, because there's a helpful message if you do this...whether you've included <stdio.h> or not.
conflicting types for built-in function 'printf'
There's a way to turn this warning off (-fno-builtin). And there are all kinds of approaches that would do things like filter the symbol dump for things you don't want to be there...
But is there a trivially easy non-warning-causing (if you didn't include stdio.h) way to alert someone that they've introduced an unwanted printf usage?
You can redefine printf to be some nasty value that will cause a compilation or linking error. For example:
#define printf do_not_include_stdio_h
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0;
}
produces the output:
undefined reference to `do_not_include_stdio_h'
You can munge the macro if you want it to be an even more obscure name or include invalid symbols if you're worried that some poor soul will have defined do_not_include_stdio_h.
You can set the macro definition in the compiler flags so you don't have to manually edit the file(s). For example:
gcc -Dprintf=do_not_include_stdio_h my_file.c
I wouldn't touch the source files at all. I'd modify the build script. Much easier to maintain, and much easier to prevent people from circumventing the restriction (e.g. by changing the code which causes compilation to fail).
For example, in a makefile, assuming you have an all target that build everything
all:
grep stdio *.h *.c
if ["$?" -eq 0 ]; then
echo "Do not use stdio. Contact Joe for info"; exit 2;
fi
<other stuff to do the build here>
You can also do it on particular targets. For example, if you have a target that compiles a .c file to produce a .o file, just check the .c file before compiling it.
%.o : %.c
grep stdio $<
if ["$?" -eq 0 ]; then
echo "Do not use stdio. Contact Joe for info"; exit 2;
fi
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $#
Your only problem now is what to do if you have someone who is determined to bypass your restriction (e.g. by #include "bypass.joe" where bypass.joe has an #include <stdio.h>). For that, look up tools to generate dependencies (e.g. gcc -MM, makedepend, etc) and use that to set up a way to search all of the files your source files depend on. If someone is that determined, also set protections on your makefiles so only you can edit them.
EDIT: If you have a tool set up to generate a dependency file, simply search that file for stdio. If any compilation unit, directly or indirectly, includes stdio.h , then it will be listed in the dependency file.
To prevent inclusion of <stdio.h>, I would go with
#if !defined(NDEBUG)
#if defined(EOF)
#error Do not include stdio.h, contact Joe for more information
#endif
#endif
Related
I'm writing a program using libraries foo1.a and foo2.a.
Inside foo2.a, it uses foo3.a, which implements a function funcfoo. But foo1.a contains the same function that implements its own funcfoo. My main program wants to use funcfoo from foo1.a, and some other functions from foo2.a, while also makes sure that foo2.a only uses funcfoo from foo3.a.
Is there anyway I can enforce this to happen?
Short answer : you can't
Long answer : you still can't because name (like function name as well as global variable or enum name ... any name) have to be unique across your binary[1]
but
there is maybe action you can do.
If you own the source code of any library involved in this mess, make a complete new library with the same stuff but renamed.
Basically, i say "make a new major version of you library, since you will change the function name present in the library, thus breaking the retro-compatibility".
If you library is "foo1.a" containing the function "min", then make a "foo2.a" with "foo2_min" function.
It's usually a good pratice to prefix/suffix your internal function (be it in a library or directly in your binary) with something. Like if your company name is "My Little Pony", "MLP_" sound a good prefix (do a google search, just in case).
That's what user694733 said in the comment.
If you're using an IDE, then it should be easy and quick to do so with the "rename refactoring" feature.
I advise to do the most renaming possible in order to avoid further scenario like the one your stuck with now.
You don't have the source code, but the library licence allow you to modify it.
If it's format is open (like a good old so), you can use objcopy.
I read it can do that, but I never do it myself so .... good luck
If it's a close format, either you have the documentation about it and you have to do a lot of work, or you're completly stuck.
A third party own the code source, and/or the library licence don't allow you to modify it
If it's a third party library, maybe your company has subscribed to his support, so you better contact them directly.
.
As far as I know, there is no possibility to "encapsulate" a library into a "spacename" nativly in C.
I hope this answer an help, and I hope it's accurate and complete.
[1] Well, this is not completly rigth as you can create a local variable with a global variable's name, and this will compile and run. In the local context, it's the local variable that will be used. gcc can warn about this kind of scenario with -Wshadow option.
But unless you're doing some shady hack, this situation is usually something that you want to avoid.
Most linkers obey the order of the libraries as you provide them on the command line. If you link your program first with "foo1.a", it will resolve the references of funcfoo in your program with the implemention of "foo1.a". Place "foo2.a" second, which will leave an open reference to funcfoo. With "foo3.a" placed third, this will be resolved with the second implementation.
EDIT 1:
I'm afraid that I was wrong. A quick check (just before going to sleep) revealed that when "foo2.a" is linked, the reference to funcfoo is resolved with the implementation of the already loaded "foo1.a". :-(
I will do some more research, but please don't hold your breath.
EDIT 2:
OK, it took some time, but with the help of "objcopy" is works as proposed. You can use its option --redefine-sym old=new to "rename" symbols even in a library.
I have prepared a small example to follow the steps as a prove of concept. In the real project, the libraries are already built, so just the last commands of the shown list are needed.
Let's start with the main source:
#include "foo1.h"
#include "foo2.h"
int main(void) {
funcfoo();
funcbar();
return 0;
}
It includes the following header files, first "foo1.h" and second "foo2.h":
#ifndef FOO1_H
#define FOO1_H
void funcfoo(void);
#endif
#ifndef FOO2_H
#define FOO2_H
void funcbar(void);
#endif
Of course there are implementations of both, again first "foo1.c" and second "foo2.c":
#include <stdio.h>
#include "foo1.h"
void funcfoo(void) {
puts("funcfoo() in foo1");
}
#include "foo2.h"
#include "foo3.h"
void funcbar(void) {
funcfoo();
}
The third library "foo3" implements the same function as "foo1", first the header file and then the implementation file:
#ifndef FOO3_H
#define FOO3_H
void funcfoo(void);
#endif
#include <stdio.h>
#include "foo3.h"
void funcfoo(void) {
puts("funcfoo() in foo3");
}
These are the commands to build the application:
gcc -c -Wall -Wextra foo1.c -o foo1.o
ar cr libfoo1.a foo1.o
gcc -c -Wall -Wextra foo2.c -o foo2.o
ar cr libfoo2.a foo2.o
gcc -c -Wall -Wextra foo3.c -o foo3.o
ar cr libfoo3.a foo3.o
# In the real prject, only the following steps are needed:
gcc -c -Wall -Wextra main.c -o main.o
objcopy --redefine-sym funcfoo=funcfoo2 libfoo2.a libfoo2n.a
objcopy --redefine-sym funcfoo=funcfoo2 libfoo3.a libfoo3n.a
gcc main.o -L. -lfoo1 -lfoo2n -lfoo3n -o app
As you can see, the tool "objcopy" of the common "binutils" is used to redefine the name of the conflicting function from funcfoo to funcfoo2. I also let it create a new output library to save the original.
And when run, the application prints:
funcfoo() in foo1
funcfoo() in foo3
In order to improve the aesthetics of some code, I would like to have a .h file contain some code that sets a #define based on which file the .h file is included from. For example
#if (__file__ == "main.c")
#define MOUDLE MODULE_MAIN
#elif (__file__ == "foo.c")
#define MODULE MODULE_FOO
#endif
Is there any way to accomplish something like this? The main motivation is to avoid putting a #define MODULE at the top of every file and instead have one location where the mapping is defined and to just include the same .h file.
No, you can't do this. #if can only do integer expressions. It knows nothing about strings or how to compare them.
What you want is not possible with the standard C preprocessor. Check by reading the C standard, eg n1570, or some C reference, or the wikipage on the C preprocessor, or the GNU cpp manual.
But consider another way to achieve the same: configure appropriately your build automation.
For example, if you use make, then edit your Makefile appropriately. How to do that is a very different question.
You could have a rule for make which passes a specific -DMODULE=name to gcc
For example in my bismon (on github) the Makefile has near line 141 something similar to
modules/modbm_%.so: modules/modbm_%.c bismon.h $(GENERATED_HEADERS) $(BM_HEADERS)
$(CCACHE) $(LINK.c) -fPIC \
-DBISMON_MODID=$(patsubst modules/modbm_%.c,_%,$<) -shared $< -o $#
Be creative. The build machinery is part of your source code. Adapt it to do what you want. Don't expect the standard preprocessor to cover all your needs. Learn how to invoke GCC (or your favorite compiler) on the command line. In some cases, it is even worthwhile to generate some C file (perhaps some header file), and you might use another preprocessor (like GPP or m4) for that purpose.
Remember that the compiler (notably GCC and Clang) is a command line program, that you should drive from something else (like make, ninja or many other build automation tools).
(even on microsoft systems the compiler is still a command line thing, but that fact is often ignored)
BTW, I dislike many IDEs because they are hiding the build process, and you need to master it. So you need to configure it (e.g. by writing your Makefile or something else) and to understand and tailor it.
The main motivation is to avoid putting a #define MODULE at the top of every file and instead have one location where the mapping is defined
That single location defining such a mapping should probably be your build infrastructure (e.g. your Makefile if using make); you'll adapt it to invoke gcc or clang (or most other C compilers) with an appropriate -DMODULE=name flag. (BTW, you also want the convention that your base name of sources files are C identifiers, so you won't have any a-1.c file -since a-1 is not an identifier-, but a bcde.c one).
If using GNU make, read its documentation, then run make -p to understand the rules (both builtin, and custom) relevant to your case. Then consider perhaps a rule similar to:
%.o: %.c $(YOURHEADERS)
$(COMPILE.c) -DMODULE=$(patsubst %.c,MODULE_%,$^) -c $< -o $#
but adapt that rule to your needs. (you could need some $(shell ... ) inside it if your file names are lower cases, and you want upper case MODULE).
BTW, you could also generate parts of your Makefile (or have some generated C files, which you would #include appropriately).
How can I tell where g++ was able to find an include file? Basically if I
#include <foo.h>
g++ will scan the search path, using any include options to add or alter the path. But, at the end of days, is there a way I can tell the absolute path of foo.h that g++ chose to compile? Especially relevant if there is more than one foo.h in the myriad of search paths.
Short of a way of accomplishing that... is there a way to get g++ to tell me what its final search path is after including defaults and all include options?
g++ -H ...
will also print the full path of include files in a format which shows which header includes which
This will give make dependencies which list absolute paths of include files:
gcc -M showtime.c
If you don't want the system includes (i.e. #include <something.h>) then use:
gcc -MM showtime.c
Sure use
g++ -E -dI ... (whatever the original command arguments were)
If your build process is very complicated...
constexpr static auto iWillBreak =
#include "where/the/heck/is/this/file.h"
This will (almost certainly) cause a compilation error near the top of the file in question. That should show you a compiler error with the path the compiler sees.
Obviously this is worse than the other answers, but sometimes this kind of hack is useful.
If you use -MM or one of the related options (-M, etc), you get just the list of headers that are included without having all the other preprocessor output (which you seem to get with the suggested g++ -E -dI solution).
For MSVC you can use the /showInclude option, which will display the files that are included.
(This was stated in a comment of Michael Burr on this answer but I wanted to make it more visible and therefore added it as a separate answer.)
Usability note: The compiler will emit this information to the standard error output which seems to be suppressed by default when using the windows command prompt. Use 2>&1 to redirect stderr to stdout to see it nonetheless.
I am trying to add warning as error flag in my makefiles. But I am getting the following problem.
When I am compiling without adding the flag it is successful. But when I am adding Werror flag in some ".mk" files, compilation is failing with some error. But in the successful build log warning was not there for that source file(".c") which is throwing error now(Werror).
I am adding he following flags.
UN_CDEFS := -Wno-error=%
CDEFS := -Wall -Werror -Wextra
SUB_CDEFS := -Wall -Werror -Wextra
So please suggest what might be the problem.
Caveat: This isn't a complete answer because we need more information, but it would become [too] lengthy for more top comments like the ones I've already posted.
As you refine the problem and/or post more data, I can edit this answer accordingly. At a minimum, posting your actual makefiles might help, as well as, the actual final cc commands and the compiler warning/error output for the failing .c file [There may be multiple ones, but the single/first one should be sufficient].
Below are some detailed instructions on how to debug this, based on my own experience with such issues.
But, before I get to that, I'll hazard a guess. I notice that you're doing:
CDEFS := -Wall -Werror
[leaving off the -Wextra as you mentioned in a comment].
If this is done as [nearly] the first thing in the makefile, it's fine. However, if it occurs in the middle, you are replacing CDEFS with your own value. If a prior line in the makefile did (e.g.):
CDEFS = -Dwont_build_cleanly_without_this_option
then, when you add your line, that could be the issue, because this gets [effectively] removed. You might try this instead:
CDEFS += -Wall -Werror
This just appends to the existing symbol, so any prior value will be retained.
Also, the base makefile might have something like:
ifndef CDEFS
CDEFS := -Dwont_build_cleanly_without_this_option
endif
Normally, make will output the full text of commands it executes to create targets. For compilation, this is (e.g.) cc -c foo.c.
Some fancier builds wrap the command in (e.g.) #doit cc -c foo.c where doit prints a message like compiling foo.c ... and only outputs the full command if there is an error. (e.g. the linux kernel build does this, IIRC). I'm assuming you don't have this, but if you do, there is usually a command line override such as make VERBOSE=1
So, there is some .c file somewhere that builds cleanly with the normal options but generates an error when extra compile options are added. Let's call this file badnews.c
What we want to see is the compilation command that make printed for badnews.c and the warning/error output for two cases:
without the extra options
with the extra options in various combinations
In particular, examining the case (1) command against the case (2) commands might show that options other than the -W are different. This indicates a makefile issue, similar to my "guess" above. You've said that [your equivalent of] case (1) is clean with no warnings, but, given the trouble you're having, it wouldn't hurt to double check.
You can cut and paste the case (1) cc command into a shell script and manually add the -W options. Watch out for things with spaces, such as -DSTRING="foo bar" in the makefile that may need extra quotes in a shell script.
To alleviate conflicts similar to yours, in my own makefiles I separate the symbols.
DFLAGS for all -DFOO=1
COPTS for -g, -O2, -Wall, -fno-inline-functions, etc.
Then, I either do:
CFLAGS := $(COPTS) $(DFLAGS)
Or:
%.o: %.c:
cc -c $(COPTS) $(DFLAGS) $<
There are other ways to do this as well.
UPDATE:
I am using following command to build: emq PRODUCT=ASG >build_log_0508.log
I'm unfamiliar with emq. I can't find a reference to it, except as "enterprise mail queue for JIRA", which [AFAICT] may be part of cPanel?
Getting the following error on compilation: prod/libs/app/app.c:720:5: error: incompatible implicit declaration of built-in function 'free' [-Werror] free(tmp_dn);
This is the smoking gun ...
I don't know what compiler you're using, or what OS/environment, but it appears to not flag this as a warning/error by default.
However, it is a bug in the source app.c that needs to be fixed. It was correctly flagged as a warning/error by the addition of -Wall and -Werror
Note: As I mentioned in my original answer, it would be helpful to have the final cc command line that produced this error [as well as the cc command when this file is not flagged].
I created a simple test case:
void
myfree(void *ptr)
{
free(ptr);
}
Here, under gcc, I did gcc -c test.c and I get:
test.c: In function 'myfree':
test.c:5:2: warning: implicit declaration of function 'free' [-Wimplicit-function-declaration]
free(ptr);
^
test.c:5:2: warning: incompatible implicit declaration of built-in function 'free'
test.c:5:2: note: include '<stdlib.h>' or provide a declaration of 'free'
So, gcc flags this by default [even without -Wall or -Werror]. But, your compiler does not unless it is given -Wall. This could occur if your compiler were clang and you also specified -std=c89
As I implied earlier, if you just specify -Wall but not -Werror, you should get the same warnings but they just won't stop the build. In a large build, they can be easily overlooked in the log [by a human (e.g.) me :-)].
Referring to the suggestions in my original answer, assuming that the cc commands between case (1) ["good"] and case (2) ["bad"] only differed by the addition of -Wall, the correct way to fix this is to edit app.c and add #include <stdlib.h> as part of the includes.
Is there any problem with "SUB_CDEFS := -Wall -Werror"?
It will have similar problems/benefits as with CDEFS.
I am adding at the end of the makefiles
This is all the more reason to use += instead of :=. You might be "killing off" the -std=c89 if that were specified somewhere.
UPDATE #2:
It worked after doing += instead of :=.
As I mentioned, using := removed some critical compile options, that were specified elsewhere in the makefile(s).
But, once again, the source code has a bug and is broken. It was broken before you ever touched it. By adding -Wall -Werror using :=, you uncovered this bug, that previously was masked incorrectly. This is a good thing.
Using += just sweeps the bug under the rug [again], by restoring some build options that were lost with :=. But, these "lost" build options were wrong. They allowed a genuine flaw in the C code to escape detection.
This is not about getting the build to work [with a workaround], but to fix the root cause of the build problems, which is to modify the C source code. There are probably other such C source code bugs and some may be more severe.
With the workaround to "fix" the build, you've now got a piece of built software that can not be trusted to run correctly. It could fail in intermittent ways on your system(s). Or, produce incorrect results. Or, allow your system to be hacked [and potentially expose you to legal liability] if you're putting this on a publicly facing site.
If you're not comfortable doing the source modification yourself, file a bug report with the original author of the software. The source code should have a README file, or BUGS file, or whatever that should outline a procedure for doing so.
Just need one more clarification for what is the difference between SUB_CDEFS, UN_CDEFS, and CDEFS
It's completely arbitrary.
Software projects built with make, can often build multiple programs or libraries. These often are placed in subdirectories. Each such subdirectory often has its own Makefile.
To avoid needless duplication [and potential error], the parts that would be common to these makefiles are placed in a single makefile, often called a rules file [but it's just a makefile]. The individual makefiles then have a line like: include ../common/rules.mk
The rules file expects that certain symbols are defined that help guide it to build the targets for the given subdirectory.
CDEFS et. al. are an example of such symbols. Names that are descriptive of function are [should be] chosen. That is, CDEFS [probably] means "C definitions". The actual symbol names and their function depends upon the rules file. We could use the symbol SHRONK instead of CDEFS. That doesn't help much with understanding things, but if all makefiles were edited to change CDEFS to SHRONK, it would work.
For example, in other software, instead of CDEFS, a similar symbol might be named CFLAGS or COPTS. This is fairly common.
Side note: It's a bit moot at this point, but things would have gone much more smoothly and quickly if you had edited your question and posted the output cc commands and [some of] your makefiles as I had requested. You would have gotten specific answers in a matter of hours instead of general guidelines [that took several days].
So, without the rules file, it's not possible to tell. Only make a guess, based upon the names:
CDEFS -- global cc options for a subdirectories
SUB_CDEF -- cc options for this particular subdirectory
UN_CDEFS -- specify -Ufoo options
The particular software you are building may have documentation for this in a documentation file or in comments in one or more of the makefiles.
To understand this generally, there are many online guides to make. Under Linux, there are "info" files. So, try info make. Other systems have detailed manpages, so do man make
I have a main file like so:
main_a.c:
#define MAIN_A
#include <stdio.h>
#include "shared.h"
extern int i;
int main() {
printf("i is: %d\n", i);
return 0;
}
I want to use the define in shared.h like this:
shared.h
#if defined(MAIN_A)
# define A
#endif
So I can declare a variable according to whether the main file is present or not, like this:
shared.c
#include "shared.h"
#if defined(A)
int i = 1;
#else
int i = 0;
#endif
I build it using a makefile which looks like this:
Makefile:
all : a
./a
a : main_a.o shared.o
gcc -o $# $^
%.o : %.c
gcc -c $<
However this prints
i is: 0
Now my question is: Why is it that the define seems to be lost when I compile the shared module? I know the main module is compiled first, so the define should have been resolved by the time shared.c is compiled.
One suspicion I have is that the preprocessor might get run at the start of each module build and not just at the start of the project. If this is correct is there a way of compiling more than a single module at a time to use the preprocessor as I attempt above?
Preprocessor is run for each file before it is compiled, i.e. once for main_a.c and then again independently for shared.c. When shared.c is compiled MAIN_A is undefined.
Preprocessor can't be used the way you're attempting, i.e. remembering state across compilation units.
What you can do is define a name (for example MAIN_A) using the -Dcompiler option in your Makefile and test this name using preprocessor the same way you're doing it now. This way the definition takes place on the project level (in the Makefile) rather than on a compilation unit level (in a .c file).
Let me do the preprocessor's work here and expand all your macros. In main.c, MAIN_A is defined, so A is defined. Nothing depends on A in main.c, and i is extern.
In shared.c, MAIN_A and thereby A are undefined, and i is 0.
In short, the preprocessor cannot transport information between compilation units. That's good practice, because otherwise programs would quickly become unreadable and you would have to recompile all compilation units when one unit changes (because symbols might have changed). Resolve the issue by setting i explicitly in main:
int main() {
i = 1;
}
It is more verbose, but is also much clearer to the reader. If you want to encapsulate, define a function InitializeShared. If you truly want to compile some code as a single compilation unit, make one of the files a header file and #include it into the other.
Yes you are right, they are completely separate compilation units.
MAIN_A is only defined in main_a.c
One thought that comes to mind is to cat the files together to make one compilation unit?
Global define A
gcc main_a.c shared.c -DA
Defines almost work the same as any variable. If you want to share a variable across modules, you put it in a header. Same goes for #defines.
However, it is strange to use the #ifdef as you are always going to have main.c. You don't want to change the code each time you compile. Instead, use the method described by Adam Zalcman