Configure $(CC) to warn when inclusion is safe to be removed [closed] - c

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
Read this source code doc:
// foo.c
#include<stdint.h>
main(){}
I can do this:
$ gcc -Wno-implicit-int foo.c
$ ./a.out
$ gcc -dumpversion
6.3.0
GCC compiles without warnings.
Let's modify the source:
// foo.c
main(){}
But the same happens:
$ gcc -Wno-implicit-int foo.c
$ ./a.out
$ gcc -dumpversion
6.3.0
The output is the same. I want to believe that this means the inclusion can be removed safely.
Can I configure GCC in order to warn such inclusion can be safely removed?
What about the same for LLVM?
Is it costly for the compiler to figure out?
Would you ever consider activating the feature?

Expanding on Peter's comment, I'm going address the third question, regarding the cost of this. TL;DR: this is not functionality that would be trivial to add to a compiler.
Currently, the compiler simply processes the source, line by line, respecting #includes as a means to go and fetch a different source, and insert it at the appropriate place in the input stream. This is all handled by the preprocessor.
It goes as far as to add some special directives (typically #line), so that error messages match up with where they actually happen, but that's about it.
What would be needed to do what the OP is asking for is for every single declaration to have meta data added to it specifying which file it was found in. Then as the source is being processed, it would be necessary to mark every declaration that gets used. Then finally at the end of compilation, the compiler would be have to run over the entire symbol table, to see if any file has the condition that none of the symbols in it were ever used.
That's not a "five line of code" fix, it's going to be a fair sized investment.
And what I've just outlined doesn't begin to deal with nested #includes. Suppose outer.c includes middle.h. Now middle.h doesn't have any symbols in it that are used in outer.c but it does include inner.h that is used. So without saving the "route" to each variable, you risk throwing away middle.h and thus losing inner.h.

Related

Compile old C code (on Linux) that throws errors (Multiply defined) with modern gcc? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Why would I want this?
I'd like to use a C package that was initially built in 2007 and last updated in 2016 according to the Changelog. I gather that it would have compiled cleanly back than.
Sadly, this is no longer the case.
The error
Running ./configure and make, I get a Multiply defined error:
gcc -g -O2 -o laplaafit laplaafit.o multimin.o common.o lib/libgnu.a -lgsl -lgslcblas -lm
/usr/bin/ld: common.o:/home/<user>/build/subbotools/subbotools-1.3.0/common.c:27: multiple definition of `Size'; laplaafit.o:/home/<user>/build/subbotools/subbotools-1.3.0/laplaafit.c:38: first defined here
/usr/bin/ld: common.o:/home/<user>/build/subbotools/subbotools-1.3.0/common.c:26: multiple definition of `Data'; laplaafit.o:/home/<user>/build/subbotools/subbotools-1.3.0/laplaafit.c:37: first defined here
Specifically, both files (laplaafit.c and common.c) have the declaration
double *Data; /*the array of data*/
unsigned Size;/*the number of data*/
with a definition of both variables following further down in the code in both files (I believe with load(&Data,&Size,infile); which calls function int load() in common.c which reads the array *Data from a file and determines its length Size).
This is what causes the error. The variables are important in both files (removal in either leads to '(variable)' undeclared errors). Moving to a header files would not change anything if the header (say common.h) is included in both .c files.
Edit: Since it was raised in the comments that load(&Data,&Size,infile); is "far from being a definition" I figure I should be a bit more detailed.
load(&Data,&Size,infile);
calls the int load(...) function from common.c
int load(double **data,unsigned *size,FILE *input)
Here, *Data is the array starting in address Data. &Data is the pointer to the pointer (double pointer?) to the start of the array. **data is a double pointer to a local array in load(). If the function obtains &Data for this, data actually refers to the original global array and the program gan write into it by accessing it via pointer *data.
And *size (for which the function obtains &Size) is the value in address &Size so the other global variable.
The function then writes into *data and *size multiple times, e.g., in the very end:
*size=i;
*data = (double *) my_realloc((void *) *data,(*size)*sizeof(double));
If I am not mistaken, this may count as the global variables *Data and Size being defined.
Furthermore, the comment says that I do not actually know enough C to diagnose the program and that I should therefore rather hire someone who does. This would raise the bar for being allowed to post in Stackoverflow to a very high level; a level that is not always attained in the questions that are commonly posted and seen as perfectly acceptable. It may actually be a reasonable suggestion, but it would leave no place for me to ask questions I might have about C or any other language. If the author of the comment is serious about this, it may be worth posting in Meta and suggesting splitting Stackoverflow in two, one for experts, one for everyone else.
How to solve the problem (making the code compile)
As I see it, there are two ways to approach this:
Rewrite the software package avoid multiple definitions. I would ideally like to avoid this.
Find a way to compile as it would have been compiled between 2007 and 2016. I assume it would have compiled cleanly back then. There are multiple potential problems with this: Would the old compiler still work with my 2021 system? Would that work with the libraries in a modern system? Even if I succeed, will the resulting executable behave as it would have been intended by the authors? Still, this seems the preferable option.
It is also still possible that I misinterpret the error or misunderstand something.
It is also possible that even between 2007 and 2016 this would not have compiled cleanly with my compiler (gcc) and that the authors used a different compiler that accepts multiple definitions.
Solution by compiling with old compiler behavior
Include the -fcommon option as discussed in kaylum's answer below.
Attempt to solve by changing the code
The intended behavior is obviously for the two variables Data and Size in the two files to refer to the same variable (the same point in memory). Therefore, declaring the variable as extern in laplaafit.c should recover the same behavior. Specifically, exchanging
double *Data; /*the array of data*/
unsigned Size;/*the number of data*/
for
extern double *Data; /*the array of data*/
extern unsigned Size;/*the number of data*/
The code compiles cleanly then again. I am not sure how certain I am that the bahavior is actually the same as intended by the authors (and achieved with old gcc versions and recent gcc with -fcommon) though.
Why I think this question is of general interest for programming (and this belongs on Stackoverflow)
I am guessing, however, that the question is more general. There are many old software packages around. Given enough time, most of them will break eventually.
Software
My system is Arch Linux kernel 5.11.2; C compiler: gcc 10.2.0; GNU Make 4.3.
Multiple definitions of global variables of the same type with the same name are permitted in gcc if the source is built with -fcommon. From the gcc manual:
The -fcommon places uninitialized global variables in a common block. This allows the linker to resolve all tentative definitions of the same variable in different compilation units to the same object, or to a non-tentative definition. This behavior is inconsistent with C++, and on many targets implies a speed and code size penalty on global variable references. It is mainly useful to enable legacy code to link without errors.
The default of pre-10 gcc used to be -fcommon but that has been changed to -fno-common in gcc 10. From the gcc 10 release notes:
GCC now defaults to -fno-common. As a result, global variable accesses are more efficient on various targets. In C, global variables with multiple tentative definitions now result in linker errors. With -fcommon such definitions are silently merged during linking.
This explains why the build fails in your environment using gcc 10 but was able to build with older gcc versions. Your options are to either add -fcommon into the build or use a gcc version prior to 10.
Or as pointed out by #JohnBollinger another option is to fix the code to remove those multiple definitions and make the code conform strictly to the C standard.

Making `too many arguments in call to function` an error in Clang [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I am trying to make the compiler warning warning: too many arguments in call to 'IF' an error (where IF is a function).
I am having trouble configuring clang, as I cannot figure out the actual name of the warning.
I tried the following:
clang -Werror=too-many-arguments main.c
warning: unknown warning option '-Werror=too-many-arguments'; did you mean '-Werror=unknown-argument'?
[-Wunknown-warning-option]
But that just produces the warning above.
With
clang -Werror main.c
The warning does become an error, but I am trying to make only this specific warning an error.
How do I find the name of this compiler warning so I can promote it to a compiler error?
Thanks.
I checked the current sources in Subversion and found this: test/Misc/warning-flags.c in the Clang sources list warn_call_wrong_number_of_arguments (the internal code for this warning), which means that that it is expected that this warning has no separate -W flag. I'm sure the Clang developers would accept a patch which introduces an explicit name for this option.
But until that, -Werror is your only option.
-Werror is turning all warnings into errors. You could turn off all warnings except for that particular one you are interested in, but that is wrong on so many levels, I mention it only for academic reasons.
You might also consider getting a good lint, such as Gimpel's FlexeLint product. This is a lint with completely configurable warnings, errors and informational messages.
This does not directly answer your question, but I believe I can provide a better solution than what you're looking for.
This:
void test () {
printf("test\n");
}
is an old-style non-prototype function definition. As a definition, it specifies that the function has no parameters, but as a declaration, it does not specify the number and types of any expected arguments. Given this definition, a call that incorrectly passes an argument, like test("test") or test(42), is not a constraint violation and does not require a diagnostic, even though such a call has undefined behavior if it's evaluated.
clang is going above and beyond the language requirements to warn you about the incorrect call. (I'm mildly surprised it does so. gcc, for example, does not.)
This kind of thing is exactly why prototypes were added to the language back in 1989. As you mention in the question, you can define the function like this:
void test(void) {
printf("test\n");
}
Given that this definition is visible, a conforming compiler must diagnose any attempt to call this function incorrectly with one or more arguments.
The solution to your problem is not to coax the compiler into diagnosing a problem that the language doesn't require it to diagnose. It's to fix the code. There is very rarely a good reason not to use prototypes for all function declarations and definitions.
Old-style declarations and definitions are obsolescent, but they're still legal even in the 2011 version of ISO C. (I personally consider this unfortunate.)
(You say you don't want to specify void as a parameter, but you haven't explained why.)

How do you add/specify predefined macros for GCC? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
important thing: -D does not apply here.
Is it possible to declare macros that appear in every compilation (much like predefined macros) in some dynamic manner (meaning I'm lazy to recompile gcc)? or do I have to recompile my gcc? Should I have to recompile, how do I specify my predefined macros?
You might consider providing some (or improving yours) spec file.
You could patch the gcc/c-family/c-cppbuiltin.c file of the source code of GCC.
You could code then use a GCC plugin defining additional predefined macros.
But I am sure it is a very bad idea; I recommend instead passing explicitly some -D flag to your compiler; your question smells badly as some XY problem. You need to motivate your question.
You could instead organize your PATH variable and add appropriately some gcc shell script adding that -DMACRO option and explicitly invoking e.g. /usr/bin/gcc with it.
On Linux you can
use an alias:
alias gcc="gcc -DMACRO1 -DMACRO2"
Copy old /usr/bin/gcc to /usr/bin/gcc.original. Make your own shell script and name it /usr/bin/gcc, inside which you have
exec /usr/bin/gcc.original -DMACRO1 -DMACRO2 "$#"

What is the purpose of a makefile? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
What does it do? Do you just run make on the command line? Is the makefile just like a list of commands to execute and at the end of the make command you have a bunch of executable files?
The answer above is pretty correct, but misses an important point: makefiles are intelligent, they are meant to run only the needed commands, not all. This is done with the concept of dependencies between items, like:
to generate A from B, it is necessary to run (for example) "cc -o A B".
These rules/dependencies can be cascaded (to have A you must use B; to have B, you must use C+D+E, to have D you must do ...)
If your project is structured in many files, a makefile will (normally) recreate the objects whose dependencies are changed, not all the objects.
Think of a C project split in 10 files. You modify one, say "main.c" and then want to test the project. With Makefile, only "main.c" gets recompiled and then the final executable gets linked. Without a Makefile, perhaps all the 10 files would get recompiled.
Yes it is essentially just a list of instructions. The purpose of a makefile is to be easily build an executable that might take many commands to create (which would be a pain to compile over and over again manually).

Multi-pass C preprocessor [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Is it remotely sane to apply the C preprocessor to the same codebase multiple times (specifically, twice in sequence?)
For instance, having declarations such as the following:
##define DECLARE(FILE) # define DECLARATIONS \
# include FILE \
# undef DECLARATIONS
Have you ever seen such an idiom before? If so, what codebase? Can you link it? What sort of patterns would be followed to compile a project doing something like this? Can the CPP as it stands be made to do this, or do I need to write a meta-preprocessor to “hide” the single-hash declarations while processing the double-hash declarations, and so on?
I think when you need multiple CPP passes, you might want to consider m4 or some other sophisticated macro system/code generator. I think it will be hard to do what you want, and since you are going to be changing your build process for this anyway, look at other templating or macro systems.
Oh wow, why would you want to do this? I am sure GCC could be coerced into doing something like this with some clever make tricks (use the -E flag for GCC) but I can't imagine anyone being able to maintain it later.
Google threw this up, so here's a four-years-late use case for multiple (pre)compilation passes.
The largest benefit to multiple-pass compilation that I can see comes from optionally preprocessing the file. Specifically, when one would like to see the preprocessed source without including the very large standard headers at the top. E.g.,
#ifdef PRECOMPILATION
#ifdef TMPINCLUDE
#error "This stunt assumes TMPINCLUDE isn't already defined"
#endif
#define TMPINCLUDE #include <stdlib.h>
TMPINCLUDE
#undef TMPINCLUDE
#else
#include <stdlib.h>
#endif
This will compile as normal in the absence of PRECOMPILATION, but if compiled as gcc -E -P -DPRECOMPILATION or similar, will translate into a source file containing all your code, post expansion, and the #include statement at the top. So it's still valid code and can also be compiled from the already-preprocessed file.
Macros are unpopular in the C and C++ world. I would like to release a plausibly useful library to the wider world, but it's very heavily based on macros to reduce code duplication. Using an either-one-or-two pass compilation model means I can use the library directly, macros and all, in my own work, but can also release a sanitised version which only uses the preprocessor to include standard libraries.
Whether that is remotely sane or not is rather subjective.

Resources