C/C++ file before preprocessing - c-preprocessor

Is it possible to look at a c/c++ file before preprocessing? Or rather after just a half-hearted pre-processing? Basically there is a
#define <commonly_used_word> 0
in a third party library header and I want to figure out where it is. So basically, I just want the compiler to include all the headers but not the the preprocessor as such.

Your original source file is file before preprocessing.
It sounds like you want your #include directives processed, yet you want to keep macros non-substituted. Both actions are carried out by the preprocessor.
In general case it is impossible, since in C and C++ it is legal to use macros as include file names, as in
#define INCLUDE_FILE "stdio.h"
#include INCLUDE_FILE
Achieving what you want would require a preprocessor specifically designed to satisfy your request. I, for one, don't know of any such preprocessor implementation.
If you want to find where a specific macro is defined, you might try the following trick: define your own macro with the same name before including any headers, and start compilation. The compiler (the preprocessor) should complain about macro redefinition when it encounters the library definition of the same macro and point out its location to you.

There are GCC-specific -M and -MM options:
To list absolute paths of include files, use -M
Instead of outputting the result of preprocessing, output a rule
suitable for make describing the dependencies of the main source file.
The preprocessor outputs one make rule containing the object file name
for that source file, a colon, and the names of all the included
files, including those coming from -include or -imacros command line
options. gcc -M test.c
If you dont want the system includes like
#include <stdio.h>,
then use -MM Like -M but do not mention header files that are found in
system header directories, nor header files that are included,
directly or indirectly, from such a header. gcc -MM test.c
That could significantly narrow down the search area.
http://www.math-linux.com/spip.php?article263

You can tell cpp to generate the list of included files using -M option:
$ cpp -M a.c
a.o: a.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.1/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.1/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
It gives you a Makefile rule format but you could ignore that and use with any other command.
For example, you can grep for the symbol (here I'm ignoring stderr because of \ and a.o: not being a real file names -- laziness):
$ grep '#\s*define\s*BUFSIZ' $(cpp -M a.c) 2>/dev/null
/usr/include/stdio.h:# define BUFSIZ _IO_BUFSIZ
You can also use a program like ctags to find the symbol for you:
$ ctags $(cpp -M a.c)
...
$ grep BUFSIZ tags
BUFSIZ /usr/include/stdio.h 128;" d

If you know which header files contain the definition you're looking for, e.g by using find and grep as suggested, you may be able to pinpoint which one is affecting the current source file by getting gcc to print the header inclusion tree. As described in gcc's documentation, you can achieve this by using the -H option, possibly combined with -MG to eliminate normal processing.

Related

C Project - How to manage a feature list?

I have multiple features that can be enabled or disabled at the build time in a project.
The current implementation uses declarations such as #define FEATURE_FOO. Whenever I need to do something related to a particular feature, I use a pre-processor directive such as #ifdef.
The features definitions are stored inside a global header file.
This approach have two drawbacks:
It requires to #include this global header in every file, before any other header.
I cannot easily disable a C file:
This is not very good:
// file: foo.c
#include <stdio.h>
#include "main_header.h"
#ifdef FEATURE_FOO
...
#endif
Because I prefer this:
// file: foo.c
#ifdef FEATURE_FOO
#include <stdio.h>
...
#endif
So, another approach to this problem is to declare all my features at the build time:
gcc -DFEATURE_FOO -c %< -o %#
What I don't like here is that I manually need to pass each feature to my compiler.
An acceptable workaround would be to read a features.list file that contains all the features. In my Makefile I will have:
DEFINES=$(shell perl -ne 'print "-DFEATURE_$1 " if /(\w+)/' features.list)
%o: %c
gcc $(DEFINES) -c %< -o $#
What better alternative can I find?
You can use gcc's option -include myheader.h.
It adds the content of myheader.h to the very beginning of the current translation unit's source.
I am using a GNU make based build process for most of my projects and although it wasn't about features so far, I used techniques that could help you here, too.
First, the idea to have a configuration file is very good, but why not just have it in make syntax and include it?
I use something like this
# default configuration
CC := gcc
DEBUG := 0
GCC32 := 0
USELTO := 1
# read local configuration
-include defaults.mk
You could use this for having a list of features, e.g. in your defaults.mk
FEATURES := foo bar baz
and then do something like
FEATUREDEFINES := $(addprefix -DFEATURE_, $(FEATURES))
There's a lot more black magic possible with GNU make when you use the $(eval ...) function -- this might be a good alternative for completely excluding a source file from compilation depending on your settings. I use this for platform-specific implementations. For example I have this included Makefile for building a binary:
P:= src
T:= csnake
csnake_SOURCES:= csnake.c utils.c game.c board.c snake.c food.c screen.c
csnake_PLATFORMSOURCES:= ticker.c
csnake_LDFLAGS:= -lm
csnake_posix_LDFLAGS:= -lcurses
csnake_dos_LDFLAGS:= -Wl,-Bstatic -lpdcurses
csnake_win32_LDFLAGS:= -static-libgcc -Wl,-Bstatic -lpdcurses \
-Wl,-Bdynamic -lwinmm
csnake_win32_RES:= res$(PSEP)csnake.rc
$(eval $(BINRULES))
My P is the current relative path in the source tree, T is the target to build and PSEP is just a helper variable containing / or \ in order to be compatible with windows. The rest should be quite self-explanatory -- for $(T)_PLATFORMSOURCES, $(BINRULES) looks in the relative path platform/$(PLATFORM)/. It works like this:
define BINRULES
BINARIES += $$(BINDIR)$$(PSEP)$(T)$$(EXE)
$(T)_SOURCES_FULL := $$(addprefix $(P)$$(PSEP),$$($(T)_SOURCES))
ifneq ($$(strip $$($(T)_PLATFORMSOURCES)),)
$(T)_SOURCES_FULL += $$(addprefix \
$(P)$$(PSEP)platform$$(PSEP)$$(PLATFORM)$$(PSEP), \
$$($(T)_PLATFORMSOURCES))
endif
[...] (... further rules ... )
endef
All these double dollars are there because $(eval ...) will expand variables -- that's desired for $(T) and $(P) but not for all the other ones, so they are protected with an extra dollar. I'm just quoting the part doing the magic for deciding which files to compile here. If you consider doing something like this, see the full example

How do I display pre-processed macro (just user defined) using gcc?

I know "gcc -E main.c" option gives all the values pre-processed output. Is there a way to just expand the user defined macros?
For example
#define MACRO(z) z+z
c = a + (MACRO(z))
When I use this hypothetical gcc option, I should see:
c = a + (z+z)
I do not want any other system-defined MACRO's to be expanded. Is there an option in GCC?
Effectively what you want to do is to have the preprocessor ignore errors opening include files. I think there is a compiler with such a feature, but GCC isn't it. (Or maybe I'm confusing it with the GCC feature to ignore missing include files when generating dependency files.)
However what you can do instead is to create a shadow directory of empty files matching all the names and sub-directories for the system headers. You can then use the -nostdinc (to ignore the system include directories) and -I option (to point at your new shadow directory).
The shadow directory can be created with something like:
mkdir $HOME/tmp/emptystdinc
cd $HOME/tmp/emptystdinc
find /usr/include -type d -print | sed 's|/usr/include|.|' | xargs mkdir -p
find /usr/include -type f -print | sed 's|/usr/include|.|' | xargs touch
Now see what your post-processed code looks like:
cc -E -nostdinc -I$HOME/tmp/emptystdinc test.c
Good luck! This works fine for me!
Quoting from cpp man page:
-undef
Do not predefine any system-specific or GCC-specific macros. The standard predefined macros remain defined.
This means that macros such as __FILE__ or __LINE__ will be expanded, but this may be sufficient for your needs. You can also undefine these standard predefined macros using -U. The full list can be found here.

Can I use Preprocessor Directives in .ld file

Can I use Preprocessor Directives in .ld file?
I need to to use one of two sets of .ld file and wants to let Build engine deside that using macro, Can I do that?
Yes, you can. You need to run preprocessor manually for your linker script, like this:
in="your_linker_script.ld"
out="generated_script.ld"
cflags=-Iinclude/
gcc -E -P -x c $cflags $in >$out
Flags:
-E specifies GCC to only run preprocessor
-P prevents preprocessor from generating linemarkers (#line directives)
-x c tells GCC to treat your linker script as C source file (it's needed to run GCC with your LD script)
Or you can simply use cpp tool, which is actually C preprocessor.
After this you will be able to use generated linker script to build your program (e.g. in Makefile).
Example
Here is how I solved this problem in my project:
Here is my linker script uses preprocessor (#include directive and CONFIG_TEXT_BASE constant). Excerpt:
#include <config.h>
. = CONFIG_TEXT_BASE;
Here is script to generate preprocessed linker script. Excerpt:
gcc -E -P -x c -Iinclude $cflags $in >>$out
Here is my Makefile, it's generating preprocessed linker script at $(LDS_GEN) target (line 53) and the this generated script is being used to build result binary (line 42). Excerpt:
$(LDS_GEN): $(LDS)
build/gen-lds.sh $(LDS) $(LDS_GEN) $(CFLAGS)
$(APP).bin: $(OBJS) $(LDS_GEN)
$(LD) $(OBJS) -T $(LDS_GEN) -o $(APP).elf
Small update after long time. This way of pre-processing works until the memory file does not contain lines that are fooling the pre-processor. E.g.:
"KEEP(*path/*.o(.rodata .rodata*))"
The "/*" after path is considered comment start (the line contains what is considered a C multi-line comment start and not a match pattern).
This line is valid for the linker but it is considered comment and the output from C pre-processor will remove everything till a supposed closing comment is found:
"KEEP(*path"
The resulting file is clearly invalid for the linker. I have no solution at the moment.
As a simplification of Sam's answer, I added the below to my makefile and away we go :)
PRE_LD_FILE = $(PROG_NAME).ld
LD_FILE = $(PROG_NAME)_generated.ld
$(LD_FILE) : $(PRE_LD_FILE)
cpp $(PRE_LD_FILE) | grep -v '^#' >>$(LD_FILE)

Check what files is 'make' including

I'm compiling a kernel module and I'm including <asm/unistd.h>, but I'm not sure if the compiler is using the unistd.h from /usr/includes/ (wrong) or the one from /usr/src/kernel-3.x.x/arch/x86/includes/ (right).
My question is: How can I check which one of those two is the compiler using?
And also, is there a way to force the file from the kernel headers instead of the one from /usr/include?
cpp code.c | grep unistd.h
or
gcc -E code.c | grep unistd.h
To answer the second part of your question:
And also, is there a way to force the file from the kernel headers instead of the one from /usr/include?
You can pass the -nostdinc option to gcc:
"Do not search the standard system directories for header files. Only the directories you have specified with -I options (and the directory of the current file, if appropriate) are searched."
GCC: Options Controlling the Preprocessor

how #Include works when I compile a linux kernel

I need to compile a 2.6.28 linux kernel with arm-linux-gcc as an embeded system.I'm running Ubuntu 12.10 x86.
I viewed the 2.6 kernel source code and found this:
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <asm/io.h>
#include <asm/irq.h>
...
Will gcc compiler include these files from /usr/include /usr/local/include or from Linux_2.6.28 source folder?
The Kernel is self-contained. This means that it is not allowed to have any external dependency. In other words, your Kernel source tree contains all the material needed to build your Kernel. There is no point to look for code anywhere else.
As I suggested in my comments, just take a glance at the main Makefile. You'll find it under the root of your source tree. A little ctrl+f with "include" and here's interesting quotes I can feed back to you :
# Look for make include files relative to root of kernel src
MAKEFLAGS += --include-dir=$(srctree)
# .... Other stuff
# Use USERINCLUDE when you must reference the UAPI directories only.
USERINCLUDE := \
-I$(srctree)/arch/$(hdr-arch)/include/uapi \
-Iarch/$(hdr-arch)/include/generated/uapi \
-I$(srctree)/include/uapi \
-Iinclude/generated/uapi \
-include $(srctree)/include/linux/kconfig.h
# Use LINUXINCLUDE when you must reference the include/ directory.
# Needed to be compatible with the O= option
LINUXINCLUDE := \
-I$(srctree)/arch/$(hdr-arch)/include \
-Iarch/$(hdr-arch)/include/generated \
$(if $(KBUILD_SRC), -I$(srctree)/include) \
-Iinclude \
$(USERINCLUDE)
These files should not be directly accessible in the /usr/local etc. If they are, it's a problem, because your kernel will not build correctly unless it uses the ones that belong to that kernel. Some of these files change on a regular basis, as the kernel is being updated and improved.
The files used by the kernel are found in the linux/include/... directory. The compiler options use -nostdinc to avoid the standard include locations from being searched, and then add the appropriate locations from within the kernel source directory.
To find out what files are included for some given compilation, pass -H to gcc.
To add a directory for searching included files, pass -I somedir to gcc, e.g. -I /usr/local/include/; there are preprocessor options to remove directories or to clear the include path.

Resources