I'm working on a project in C which extends an existing library (via standard includes). As the library develops a number of functions become deprecated. However this is shown only in the documentation; the code does not mark this status in any way.
I'd like to have my project warn me whenever I attempt to use one of these deprecated functions, especially since the library is under active development so I might have used something before deprecation and not noticed when its status changed. Is there any way I can do this under gcc, short of modifying the library code itself? (For one thing, it changes often enough that keeping a local version with gcc attributes is impractical.)
Is this possible? It seems like Visual Studio could do this with its
#pragma deprecated(X,Y,...)
syntax, but I don't think gcc supports this, just
__attribute__ ((deprecated))
on a function declaration itself.
Pulled from a working project
#ifdef __GNUC__
#define DEPRECATED(X) X __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED(X) __declspec(deprecated) X
#else
#define DEPRECATED(X) X
#endif
See http://msdn.microsoft.com/en-us/library/dabb5z75.aspx and http://msdn.microsoft.com/en-us/library/044swk7y.aspx
Then
DEPRECATED(void foo(int a, int b, int c));
Related
Original Question
What I'd like is not a standard C pre-processor, but a variation on it which would accept from somewhere - probably the command line via -DNAME1 and -UNAME2 options - a specification of which macros are defined, and would then eliminate dead code.
It may be easier to understand what I'm after with some examples:
#ifdef NAME1
#define ALBUQUERQUE "ambidextrous"
#else
#define PHANTASMAGORIA "ghostly"
#endif
If the command were run with '-DNAME1', the output would be:
#define ALBUQUERQUE "ambidextrous"
If the command were run with '-UNAME1', the output would be:
#define PHANTASMAGORIA "ghostly"
If the command were run with neither option, the output would be the same as the input.
This is a simple case - I'd be hoping that the code could handle more complex cases too.
To illustrate with a real-world but still simple example:
#ifdef USE_VOID
#ifdef PLATFORM1
#define VOID void
#else
#undef VOID
typedef void VOID;
#endif /* PLATFORM1 */
typedef void * VOIDPTR;
#else
typedef mint VOID;
typedef char * VOIDPTR;
#endif /* USE_VOID */
I'd like to run the command with -DUSE_VOID -UPLATFORM1 and get the output:
#undef VOID
typedef void VOID;
typedef void * VOIDPTR;
Another example:
#ifndef DOUBLEPAD
#if (defined NT) || (defined OLDUNIX)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
Ideally, I'd like to run with -UOLDUNIX and get the output:
#ifndef DOUBLEPAD
#if (defined NT)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */
This may be pushing my luck!
Motivation: large, ancient code base with lots of conditional code. Many of the conditions no longer apply - the OLDUNIX platform, for example, is no longer made and no longer supported, so there is no need to have references to it in the code. Other conditions are always true. For example, features are added with conditional compilation so that a single version of the code can be used for both older versions of the software where the feature is not available and newer versions where it is available (more or less). Eventually, the old versions without the feature are no longer supported - everything uses the feature - so the condition on whether the feature is present or not should be removed, and the 'when feature is absent' code should be removed too. I'd like to have a tool to do the job automatically because it will be faster and more reliable than doing it manually (which is rather critical when the code base includes 21,500 source files).
(A really clever version of the tool might read #include'd files to determine whether the control macros - those specified by -D or -U on the command line - are defined in those files. I'm not sure whether that's truly helpful except as a backup diagnostic. Whatever else it does, though, the pseudo-pre-processor must not expand macros or include files verbatim. The output must be source similar to, but usually simpler than, the input code.)
Status Report (one year later)
After a year of use, I am very happy with 'sunifdef' recommended by the selected answer. It hasn't made a mistake yet, and I don't expect it to. The only quibble I have with it is stylistic. Given an input such as:
#if (defined(A) && defined(B)) || defined(C) || (defined(D) && defined(E))
and run with '-UC' (C is never defined), the output is:
#if defined(A) && defined(B) || defined(D) && defined(E)
This is technically correct because '&&' binds tighter than '||', but it is an open invitation to confusion. I would much prefer it to include parentheses around the sets of '&&' conditions, as in the original:
#if (defined(A) && defined(B)) || (defined(D) && defined(E))
However, given the obscurity of some of the code I have to work with, for that to be the biggest nit-pick is a strong compliment; it is valuable tool to me.
The New Kid on the Block
Having checked the URL for inclusion in the information above, I see that (as predicted) there is an new program called Coan that is the successor to 'sunifdef'. It is available on SourceForge and has been since January 2010. I'll be checking it out...further reports later this year, or maybe next year, or sometime, or never.
I know absolutely nothing about C, but it sounds like you are looking for something like unifdef. Note that it hasn't been updated since 2000, but there is a successor called "Son of unifdef" (sunifdef).
Also you can try this tool http://coan2.sourceforge.net/
something like this will remove ifdef blocks:
coan source -UYOUR_FLAG --filter c,h --recurse YourSourceTree
I used unifdef years ago for just the sort of problem you describe, and it worked fine. Even if it hasn't been updated since 2000, the syntax of preprocessor ifdefs hasn't changed materially since then, so I expect it will still do what you want. I suppose there might be some compile problems, although the packages appear recent.
I've never used sunifdef, so I can't comment on it directly.
Around 2004 I wrote a tool that did exactly what you are looking for. I never got around to distributing the tool, but the code can be found here:
http://casey.dnsalias.org/exifdef-0.2.zip (that's a dsl link)
It's about 1.7k lines and implements enough of the C grammar to parse preprocessor statements, comments, and strings using bison and flex.
If you need something similar to a preprocessor, the flexible solution is Wave (from boost). It's a library designed to build C-preprocessor-like tools (including such things as C++03 and C++0x preprocessors). As it's a library, you can hook into its input and output code.
I don't have much experience with C and am now working on a HPC project which very often uses __attribute__ ((always_inline)) void foo() function definitions.
I see the point of doing it for performance runs, but for debugging, testing, and developing, the compilation time is way to long. Just earlier I wanted to add a simple printf in a function to see when the function is called, and had to wait 5min for it to compile.
Is there a possibility to pass gcc a flag to ignore the attribute requests? I already am compiling with the lowest level of optimization.
A hackish way of disabling the attribute might be to define it away in the preprocessor:
#define always_inline noinline
A better approach, however, would be to apply those attributes in a macro so that they can be configured globally, e.g.
#ifndef DEBUG
# define HOT_FUNCTION __attribute__ ((always_inline))
#else
# define HOT_FUNCTION /* nothing */
#endif
…
HOT_FUNCTION void foo() { … }
I'd like to generate a compiler warning for a specific situation. I'm building a sort of universal code that will be built based on several pre-compiler definitions. For instance I might have something like the following.
sdcard.h
#ifdef PART_BOARD1
#include "port/board1.h"
#elif PART_BOARD2
#include "port/board2.h"
#endif
extern void sdcardConfigure(void);
sdcard.c
#ifndef FLAG_SDCARD
#warning "No SD Card available for this board, or this board has not been defined"
#define sdcardConfigure(...) void(0)
#endif
port/board1.h (similar for port/board2)
#define FLAG_SDCARD
void sdcardConfigure(void);
port/board1.c
void sdcardConfigure(void) {
// sd card is configured here
}
Essentially what I'd like to do is modify the #define sdcardConfigure(...) statement in sdcard.c so that I'm only seeing the warning message if sdcardConfigure() is actually called. Making it act like:
void sdcardConfigure(void) {
#warning "sdcardConfigure() not available on this board"
}
The idea being that this gives me the flexibility to create a universal (I know many fear universal) program that adapts to the parts that it's using. I.E. if there is an SD Card use it, otherwise generate a warning saying "you're calling a function that doesn't exist for this part" and let the developer decide if the function is needed.
The answer to this will most-likely be compiler-dependent.
For gcc et al you can use __attribute__ ((deprecated)) (see gcc manual).
For Visual Studio you can use __declspec(deprecated).
This question is intentionally very generic and I'm not much of a C programmer although I dabble here and there. The following code is intentionally vague and probably won't compile, but I hope you get the point...
Handling platform specifics seems dynamically in a compiled language like C seems unnecessary and even scary:
int main(int argc, char *argv[]) {
if (windows)
dowindowsroutine();
else
dounixroutine();
return 0;
}
However, handling platform specifics through really very basic macros seems gross too as the function gets chopped up into small pieces which may not compile properly (read answer to C #define macro for debug printing for a similar problem).
int main(int argc, char *argv[]) {
#ifdef windows
dowindowsroutine();
#else
dounixroutine();
#endif
return 0;
}
So what's the "right" way to do this? Is it a case-by-case basis? Is there a good way to keep these gross macros out of functions entirely? I remember reading somewhere (probably in the kernel docs or something related) that macros (more importantly, complex macro logic) is meant for header files, not .c files. How do you handle this kind of stuff?
I'm sick of "spaghetti code" with ifdef's inside of functions... I spose there are some cases where it may be OK, but the majority of code I see abuse it.
Note: I've seen some perl XS code look like it wraps function prototypes to and things, but is that the only way? Isn't that somewhat gross in the community? Or is that OK? Coming from a mostly "scripted" background of perl, python, shell,... It's hard for me to tell.
Update: Let me be more clear, the problem I'm trying to avoid is that I don't want choppy code. I want to be able to ensure that if my code breaks at compile time in linux, it also breaks at compile time in windows. With the choppy code, its possible to break windows from compiling, but not linux and vice versa. Is this kind of thing possible? The closest thing to this so far is ifdef'ing the entire function, but the function names are the same, is there a better solution where there is one interface, but the OS specific parts have their OS name embedded into the name?
I think the right way to handle this is to split your code base into platform specific modules and have them assembled at build time (this of course requires some sort of platform abstraction layer.) That way your Unix code is not littered with Windows calls, and vise versa. Effectively you move your ifdef headache to the makefiles.
I've spent the better part of my career having to support multiple platforms concurrently. This is generally how I've approached the problem in the past: abstract out the platform-dependent bits and hide them behind a portable interface, create separate implementations of that interface for each platform you need to support, and use appropriate makefile magic to build what you need.
Example:
/**
* MyGenericModule.h
*/
typedef myAbstractType ...;
void genericFunction(MyAbstractType param);
...
This interface provides platform-neutral types and prototypes that the application code will reference.
/**
* Windows implementation
*/
#include "MyGenericModule.h"
#include "WindowsSpecificHeader.h"
...
void genericFunction(MyAbstractType param)
{
WindowsSpecificType lparam = convertToWindows(param);
/**
* Implement Windows-specific logic here
*/
}
This is the Windows version (WindowsModule.c).
/**
* Unix implementation
*/
#include "MyGenericModule.h"
#include "UnixSpecificHeader.h"
...
void genericFunction(MyAbstractType param)
{
UnixSpecificType lparam = convertToUnix(param);
/**
* Implement Unix-specific logic here
*/
}
And this is the Unix-specific version.
Now it's just a matter of setting up the right rules in your makefiles. Whether you build everything statically or build the platform-specific code into .dlls is driven less by portability and more by what makes sense for the application in question. Most of what I've done was linked statically.
Yes, it's a pain in the ass, but it scales much better than using the preprocessor. I've worked on "portable" code that was a nigh-unreadable rat's nest of #ifdefs . Never again.
The trick is getting the abstract types right, so that they contain everything the underlying implementation needs without overly burdening the programmer with implementation details. Yes, it's hard to do well, and I don't have any good "cookbook" examples to demonstrate.
In C++ or some other object-oriented language you could abstract the platform away and use a factory (etc) to instantiate the right kind of platform-specific implementation.
That said, if you need/want to #ifdef as outlined above I'd suggest something more like:
#if WINDOWS
void routine()
{
/* windows implementation here */
}
#else
void routine()
{
/* non-windows implementation here */
}
#endif
int main(int argc, char *argv[]) {
routine();
return 0;
}
Quite often the code fragments become large enough that it looks like this:
#if WINDOWS
void dowindowsroutine()
{
}
#else
void dounixroutine()
{
}
#endif
int main(int argc, char *argv[]) {
#if WINDOWS
dowindowsroutine();
#else
dounixroutine();
#endif
return 0;
}
Yes, here's an example of where you would indent preprocessor macros.
Sometimes it becomes large enough that we do it in the linker (linking against impwindows.o or impunix.o depending on makefile switch).
If you don't like ifdefs inside of functions... just write your code in such a way that the parts you would ifdef out, are taken into it's own function. And ifdef those functions. But just write your program naturally, don't re-write the entire program twice, one for windows and one for linux ;)
There is no absolute truth.
The way I would do it. I would abstract the routine away, and only call a single function that would check what platform you're using. I've included that as well because I like it so there.
#define PLATFORM_WINDOWS 0
#define PLATFORM_LINUX 1
#define PLATFORM_MACINTOSH 2
#define PLATFORM_WM6 3
#define PLATFORM_ANDROID 4
#define PLATFORM_SOMETHINGELSE 1000
#define COMPILER_VS6 1200
#define COMPILER_VSDOTNET 1300
#define COMPILER_VS2005 1400
#define COMPILER_VS2008 1500
#define COMPILER_GPP 100
#ifndef PLATFORM
/*
Detect which platform this is being run on.
Thanks go to Pixel Toaster for most of the flags.
*/
#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
#define PLATFORM PLATFORM_WINDOWS
#define PLATFORM_NAME "Windows"
#elif defined(__APPLE__) || defined(__MACH__)
#define PLATFORM PLATFORM_MACINTOSH
#define PLATFORM_NAME "Macintosh"
#elif defined(linux) || defined(__linux) || defined(__linux__) || defined(__CYGWIN__)
#define PLATFORM PLATFORM_LINUX
#define PLATFORM_NAME "Linux"
#else
#define PLATFORM PLATFORM_SOMETHINGELSE
#define PLATFORM_NAME "Something Else"
#endif
/*
How many bits is this system?
*/
// Windows
#if (defined(_WIN64) || defined(WIN64))
#define PLATFORM_BITS 64
// Macintosh
#elif (defined(__LP64__) || defined(_LP64) || defined(__ppc64__))
#define PLATFORM_BITS 64
// Linux
#elif (defined(__x86_64__) || defined(__64BIT__) || (__WORDSIZE == 64))
#define PLATFORM_BITS 64
#else
#define PLATFORM_BITS 32
#endif
/*
Determine which compiler was used to compile this program.
*/
#ifdef _MSC_VER
#define COMPILER_VERSION _MSC_VER
#if (COMPILER_VERSION >= 1500)
#define COMPILER COMPILER_VS2008
#define COMPILER_NAME "Visual Studio 2008"
#elif (COMPILER_VERSION >= 1400)
#define COMPILER COMPILER_VS2005
#define COMPILER_NAME "Visual Studio 2005"
#elif (COMPILER_VERSION >= 1300)
#define COMPILER COMPILER_VSDOTNET
#define COMPILER_NAME "Visual Studio .NET"
#elif (COMPILER_VERSION >= 1200)
#define COMPILER COMPILER_VS6
#define COMPILER_NAME "Visual Studio 6"
#else
#error This version of Visual Studio is not supported.
#endif
#elif defined(__GNUC__)
// TODO: get actual compiler information for G++
#define COMPILER_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#define COMPILER_NAME "G++"
#define PLATFORM PLATFORM_LINUX
#endif
/*
Compiler specific options
*/
#if PLATFORM == PLATFORM_WINDOWS
// Support for Windows 98
#if COMPILER_VERSION >= COMPILER_VS6 && COMPILER_VERSION < COMPILER_VSDOTNET
#pragma comment(linker, "/OPT:NOWIN98")
#endif
#if COMPILER_VERSION >= COMPILER_VSDOTNET
#define FAST_CALL __declspec(noinline) __fastcall
#else
#define FAST_CALL __fastcall
#endif
#endif
#endif
#define MAIN int main(int argc, char *argv[])
void DoRoutine()
{
#if PLATFORM == PLATFORM_WINDOWS
// do stuff
#elif PLATFORM == PLATFORM_LINUX
// do other stuff
#endif
}
MAIN
{
DoRoutine();
}
You could create separate shared libraries for each platform (.so or .dll), then dynamically load the appropriate library at runtime. Each library would contain the platform-specific code. You would need a wrapper for the OS-specific load library calls, but that would probably be your only #ifdef'd function.
If you are really serious about handling platform dependent code (Everyone else, shield your eyes now!), you should look into imake or autoconf/automake, especially the latter.
Imake, originally used by the X window system, works something like knight666's answer; it uses a bunch of system-dependent configuration files to determine what exactly your system is and to allow you to handle the differences between systems. As far as I know, it never saw much actual usage, and judging by the Wikipedia page, even the X window system does not use it any more. Imake is a bit of a crawling horror.
Autoconf/automake (and libtool) are a bundle of shell scripts, Makefile templates, and m4 macros which generate the "configure" script known and loved by everyone who has built software on anything vaguely Unixish. The configure script runs a bunch of tests and then defines preprocessor macros and writes a Makefile, both of which allow your code to handle the system dependencies. If you are interested, a fairly decent book, GNU Autoconf, Automake, and Libtool, is available, although it looks to be hideously out of date. Autoconf and automake are a bit of a crawling horror.
Ideally, you would create a "platform abstraction layer" that hides the system-specific calls without duplicating any of your application logic. Typically, you will end up with #ifdef's or a code build system that only compiles the parts of the platform abstraction layer that match your specific platform.
Doing dynamic things like "if (windows) { doWindowsRoutine(); }" typically will not work, because doWindowsRoutine will not compile on a non-Windows machine.
In all, the whole area is more than a bit of a crawling horror.
Say I have this small function in a source file
static void foo() {}
and I build an optimized version of my binary yet I don't want this function inlined (for optimization purposes). is there a macro I can add in a source code to prevent the inlining?
You want the gcc-specific noinline attribute.
This function attribute prevents a
function from being considered for
inlining. If the function does not
have side-effects, there are
optimizations other than inlining that
causes function calls to be optimized
away, although the function call is
live. To keep such calls from being
optimized away, put
asm ("");
Use it like this:
void __attribute__ ((noinline)) foo()
{
...
}
GCC has a switch called
-fno-inline-small-functions
So use that when invoking gcc. But the side effect is that all other small functions are also non-inlined.
I know the question is about GCC, but I thought it might be useful to
have some information about compilers other compilers as well.
GCC's
noinline
function attribute is pretty popular with other compilers as well. It
is supported by at least:
Clang (check with __has_attribute(noinline))
Intel C/C++ Compiler (their documentation is terrible, but I'm
certain it works on 16.0+)
Oracle Solaris Studio back to at least 12.2
ARM C/C++ Compiler back to at least 4.1
IBM XL C/C++ back to at least 10.1
TI 8.0+ (or 7.3+ with --gcc, which will define __TI_GNU_ATTRIBUTE_SUPPORT__)
Additionally, MSVC supports
__declspec(noinline)
back to Visual Studio 7.1. Intel probably supports it too (they try to
be compatible with both GCC and MSVC), but I haven't bothered to
verify that. The syntax is basically the same:
__declspec(noinline)
static void foo(void) { }
PGI 10.2+ (and probably older) supports a noinline pragma which
applies to the next function:
#pragma noinline
static void foo(void) { }
TI 6.0+ supports a
FUNC_CANNOT_INLINE
pragma which (annoyingly) works differently in C and C++. In C++, it's similar to PGI's:
#pragma FUNC_CANNOT_INLINE;
static void foo(void) { }
In C, however, the function name is required:
#pragma FUNC_CANNOT_INLINE(foo);
static void foo(void) { }
Cray 6.4+ (and possibly earlier) takes a similar approach, requiring
the function name:
#pragma _CRI inline_never foo
static void foo(void) { }
Oracle Developer Studio also supports a pragma which takes the
function name, going back to at least Forte Developer
6,
but note that it needs to come after the declaration, even in recent
versions:
static void foo(void);
#pragma no_inline(foo)
Depending on how dedicated you are, you could create a macro that
would work everywhere, but you would need to have the function name as
well as the declaration as arguments.
If, OTOH, you're okay with something that just works for most people,
you can get away with something which is a little more aesthetically
pleasing and doesn't require repeating yourself. That's the approach
I've taken for Hedley, where the
current version of
HEDLEY_NEVER_INLINE
looks like:
#if \
HEDLEY_GNUC_HAS_ATTRIBUTE(noinline,4,0,0) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
HEDLEY_TI_VERSION_CHECK(8,0,0) || \
(HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
# define HEDLEY_NEVER_INLINE __attribute__((__noinline__))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
# define HEDLEY_NEVER_INLINE __declspec(noinline)
#elif HEDLEY_PGI_VERSION_CHECK(10,2,0)
# define HEDLEY_NEVER_INLINE _Pragma("noinline")
#elif HEDLEY_TI_VERSION_CHECK(6,0,0)
# define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
#else
# define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif
If you don't want to use Hedley (it's a single public domain / CC0
header) you can convert the version checking macros without too much
effort, but more than I'm willing to put in ☺.
A portable way to do this is to call the function through a pointer:
void (*foo_ptr)() = foo;
foo_ptr();
Though this produces different instructions to branch, which may not be your goal. Which brings up a good point: what is your goal here?
In case you get a compiler error for __attribute__((noinline)), you can just try:
noinline int func(int arg)
{
....
}
static __attribute__ ((noinline)) void foo()
{
}
This is what worked for me.
Use the noinline attribute:
int func(int arg) __attribute__((noinline))
{
}
You should probably use it both when you declare the function for external use and when you write the function.
I work with gcc 7.2. I specifically needed a function to be non-inlined, because it had to be instantiated in a library. I tried the __attribute__((noinline)) answer, as well as the asm("") answer. Neither one solved the problem.
Finally, I figured that defining a static variable inside the function will force the compiler to allocate space for it in the static variable block, and to issue an initialization for it when the function is first called.
This is sort of a dirty trick, but it works.
I couldn't get __attribute__((noinline)) to work, but this works on clang and GCC.
The Linux kernel defines noinline.
include/linux/compiler_attributes.h:#define noinline __attribute__((__noinline__))
#include <linux/kernel.h>
static noinline void foo(void);