Using #define to include a file in C++/g++ - c++

I am not trying to write:
#include MACRO(arg)
instead, I am trying to write just:
MACRO(arg)
Many people say that we cant write such macro to #include any file, but those try fails on preprocessing stage only, below one passes preprocessor but fails later, I think.
I wrote following test code tmp1.cpp (which does not compile):
#define HASH #
#define ZX(arg) HASH include <arg>
ZX(iostream)
int main()
{
}
And below is the output of some commands:
$ g++ -E tmp1.cpp
# 1 "tmp1.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "tmp1.cpp"
# include <iostream>
int main()
{
}
$ g++ -E tmp1.cpp > tmp2.cpp
$ g++ tmp2.cpp
$ ./a.out
$ g++ tmp1.cpp
tmp1.cpp:1:14: error: stray ‘#’ in program
#define HASH #
^
tmp1.cpp:2:17: note: in expansion of macro ‘HASH’
#define ZX(arg) HASH include <arg>
^
tmp1.cpp:4:1: note: in expansion of macro ‘ZX’
ZX(iostream)
^
tmp1.cpp:2:22: error: ‘include’ does not name a type
#define ZX(arg) HASH include <arg>
^
tmp1.cpp:4:1: note: in expansion of macro ‘ZX’
ZX(iostream)
^
$
I wonder why tmp2.cpp compiles and executes successfully but tmp1.cpp fails on compilation stage ? Isn't it that first the preprocessor is run then its output is fed to compiler ? tmp2.cpp is just preprocessed version of tmp1.cpp only.
[EDIT]
I had requirement of:
#ifdef SOMETHING
#define ZX(arg)
#else
#define HASH #
#define ZX(arg) HASH include <arg>
#endif

[cpp.rescan]/3 The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one...
I believe your quest is hopeless.

Related

Producing the .i source file giving error

I'm following a tutorial on how the various processes of the compiling work and in order to learn the process I'm producing the executable "by hand" by creating the .i file first. In order to do so I'm doing the command:
cpp a.cpp > a.i
a.cpp:
#include<iostream>
int main() {
return 0;
}
But an error occurs:
a.cpp:1:9: fatal error: 'iostream' file not found
#include<iostream>
^~~~~~~~~~
1 error generated.
even though the file a.i still gets created with the content:
# 1 "a.cpp"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 383 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "a.cpp" 2
int main() {
return 0;
}
Am I supposed to specify the location of iostream library in order to produce the .i file? The tutorial doesn't mention it anywhere and I wonder why is it needed at this point.
In absence of specification, cpp (the C PreProcessor) is assuming the language you're using is C.
Try passing the -x argument to tell it your language is C++.
cpp -xc++ a.cpp > a.i

List of all C or C++ header files that were used for compiling a project

I would like to know the paths of all code files that went into the compilation of a whole C/C++ project with multiple resulting binaries. I know about https://github.com/rizsotto/Bear et al which you can wrap around your "make" call and which tell you the gcc/g++ calls but they of course show me only the C/C++ files which were compiled - how can I find out which of the headers were needed for the compilation and ended up in one of the resulting binaries?
GCC has the runtime option -M. From the GCC man page:
-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.
Unless specified explicitly (with -MT or -MQ), the object file name
consists of the name of the source file with any suffix replaced
with object file suffix and with any leading directory parts
removed. If there are many included files then the rule is split
into several lines using \-newline. The rule has no commands.
This option does not suppress the preprocessor's debug output, such
as -dM. To avoid mixing such debug output with the dependency
rules you should explicitly specify the dependency output file with
-MF, or use an environment variable like DEPENDENCIES_OUTPUT.
Debug output is still sent to the regular output stream as normal.
Passing -M to the driver implies -E, and suppresses warnings with
an implicit -w.
Clang supports the very same option
GCC and Clang both support the -H option (as well as the -M option and its relatives).
-H
Print the name of each header file used, in addition to other normal activities. Each name is indented to show how deep in the ‘#include’ stack it is. Precompiled header files are also printed, even if they are found to be invalid; an invalid precompiled header file is printed with ‘...x’ and a valid one with ‘...!’ .
The -H output is reported on standard error, not standard output.
The -H option gives more and different information compared with the -M option. It reports on the nesting levels (one or more leading dots), and shows each time a header is included — even if the content is ignored because of header guard macros:
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
…content of header…
#endif /* HEADER_H_INCLUDED */
This can be useful; having the formatted make dependency lines (as generated by -M) can also be useful.
Example output (from compiling one source file from one of my programs — make generated the compiler command line, of course):
$ gcc -H -g -O3 -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -DSYSTEM=MACOS_X -DSTR_SYSTEM='"(macOS Mojave 10.14.6 - Darwin 18.7.0)"' -I/Users/jonathanleffler/inc -DDEBUG -DHASH_STATISTICS -c main.c
. make.h
.. /Users/jonathanleffler/inc/posixver.h
.. config.h
.. /usr/include/assert.h
... /usr/include/sys/cdefs.h
.... /usr/include/sys/_symbol_aliasing.h
.... /usr/include/sys/_posix_availability.h
.. /usr/include/ctype.h
... /usr/include/_ctype.h
.... /usr/include/runetype.h
..... /usr/include/_types.h
...... /usr/include/sys/_types.h
....... /usr/include/machine/_types.h
........ /usr/include/i386/_types.h
....... /usr/include/sys/_pthread/_pthread_types.h
.. /usr/include/errno.h
... /usr/include/sys/errno.h
.. /usr/include/inttypes.h
... /usr/include/Availability.h
.... /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include-fixed/AvailabilityInternal.h
... /usr/include/sys/_types/_wchar_t.h
... /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include/stdint.h
.... /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include-fixed/stdint.h
..... /usr/include/sys/_types/_int8_t.h
..... /usr/include/sys/_types/_int16_t.h
..... /usr/include/sys/_types/_int32_t.h
..... /usr/include/sys/_types/_int64_t.h
..... /usr/include/_types/_uint8_t.h
..... /usr/include/_types/_uint16_t.h
..... /usr/include/_types/_uint32_t.h
..... /usr/include/_types/_uint64_t.h
..... /usr/include/sys/_types/_intptr_t.h
...... /usr/include/machine/types.h
....... /usr/include/i386/types.h
........ /usr/include/sys/_types/_u_int8_t.h
........ /usr/include/sys/_types/_u_int16_t.h
........ /usr/include/sys/_types/_u_int32_t.h
........ /usr/include/sys/_types/_u_int64_t.h
........ /usr/include/sys/_types/_intptr_t.h
........ /usr/include/sys/_types/_uintptr_t.h
..... /usr/include/_types/_intmax_t.h
..... /usr/include/_types/_uintmax_t.h
.. /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include-fixed/limits.h
... /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include-fixed/syslimits.h
.... /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include-fixed/limits.h
..... /usr/include/limits.h
...... /usr/include/machine/limits.h
....... /usr/include/i386/limits.h
........ /usr/include/i386/_limits.h
...... /usr/include/sys/syslimits.h
.. /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include/stdbool.h
.. /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include-fixed/stdio.h
... /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include/stdarg.h
... /usr/include/_stdio.h
.... /usr/include/sys/_types/_va_list.h
.... /usr/include/sys/_types/_size_t.h
.... /usr/include/sys/_types/_null.h
.... /usr/include/sys/stdio.h
... /usr/include/sys/_types/_off_t.h
... /usr/include/sys/_types/_ssize_t.h
... /usr/include/secure/_stdio.h
.... /usr/include/secure/_common.h
.. /usr/include/stdlib.h
... /usr/include/sys/wait.h
.... /usr/include/sys/_types/_pid_t.h
.... /usr/include/sys/_types/_id_t.h
.... /usr/include/sys/signal.h
..... /usr/include/sys/appleapiopts.h
..... /usr/include/machine/signal.h
...... /usr/include/i386/signal.h
..... /usr/include/machine/_mcontext.h
...... /usr/include/i386/_mcontext.h
....... /usr/include/mach/machine/_structs.h
........ /usr/include/mach/i386/_structs.h
..... /usr/include/sys/_pthread/_pthread_attr_t.h
..... /usr/include/sys/_types/_sigaltstack.h
..... /usr/include/sys/_types/_ucontext.h
...... /usr/include/machine/_mcontext.h
..... /usr/include/sys/_types/_sigset_t.h
..... /usr/include/sys/_types/_uid_t.h
.... /usr/include/sys/resource.h
..... /usr/include/sys/_types/_timeval.h
... /usr/include/sys/_types/_wchar_t.h
... /usr/include/malloc/_malloc.h
.. /usr/include/string.h
... /usr/include/secure/_string.h
.. /usr/include/sys/stat.h
... /usr/include/sys/_types/_timespec.h
... /usr/include/sys/_types/_blkcnt_t.h
... /usr/include/sys/_types/_blksize_t.h
... /usr/include/sys/_types/_dev_t.h
... /usr/include/sys/_types/_ino_t.h
... /usr/include/sys/_types/_mode_t.h
... /usr/include/sys/_types/_nlink_t.h
... /usr/include/sys/_types/_gid_t.h
... /usr/include/sys/_types/_time_t.h
... /usr/include/sys/_types/_s_ifmt.h
.. /usr/include/unistd.h
... /usr/include/sys/unistd.h
.... /usr/include/sys/_types/_posix_vdisable.h
.... /usr/include/sys/_types/_seek_set.h
... /usr/include/sys/_types/_useconds_t.h
.. /Users/jonathanleffler/inc/debug.h
... /Users/jonathanleffler/inc/kludge.h
.. /Users/jonathanleffler/inc/emalloc.h
.. list.h
.. /Users/jonathanleffler/inc/sastrings.h
.. /Users/jonathanleffler/inc/stderr.h
... /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include/stdarg.h
. /Users/jonathanleffler/inc/getopt.h
Multiple include guards may be useful for:
/opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include-fixed/syslimits.h
/usr/include/assert.h
/usr/include/errno.h
/usr/include/machine/limits.h
/usr/include/secure/_stdio.h
/usr/include/secure/_string.h
/usr/include/sys/_posix_availability.h
/usr/include/sys/_symbol_aliasing.h
/usr/include/sys/_types/_seek_set.h
$
That lists 110 headers; there are just five that are repeated:
2 /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include-fixed/limits.h
2 /opt/gcc/v9.2.0/lib/gcc/x86_64-apple-darwin18.7.0/9.2.0/include/stdarg.h
2 /usr/include/machine/_mcontext.h
2 /usr/include/sys/_types/_intptr_t.h
2 /usr/include/sys/_types/_wchar_t.h
Other projects I work on have many more repeats. Taking one source file, more or less at random (I know it's a big file; I don't think it is the worst), there is a list of headers included 4 or more times — there are many included 2 and 3 times. The total number of header lines from -H for this file is 592. Project-specific directory and file names have been changed to protect the innocent — and the file names were massaged with realpath(2) to deal with the idiosyncratic use of ../subdir/header.h style names in the source code and in the included headers, which -H expands to names such as:
../incl/../subdir1/../subdir1/../subdir2/../subdir2/header27.h
Counts:
4 /usr/include/errno.h
4 /usr/include/time.h
4 /opt/project/incl/header1.h
4 /opt/project/incl/header2.h
4 /opt/project/subdir/header3.h
4 /opt/project/subdir/header4.h
4 /opt/project/subdir/header5.h
5 /opt/project/incl/header6.h
5 /opt/project/subdir/header7.h
6 /opt/project/subdir/header8.h
6 /opt/project/subdir/header9.h
6 /work5/gcc/v9.2.0/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include-fixed/limits.h
7 /opt/project/subdir/header10.h
14 /usr/include/bits/wordsize.h
14 /opt/project/subdir/header11.h
22 /work5/gcc/v9.2.0/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include/stddef.h

Clang: reliably detect supported C++ standard from command line or Python

In a Python script, I am trying to determine the highest C++ standard supported by the installed Clang.
One problem is that I cannot rely on the output of clang --version to always be the same - the best example is AppleClang on OSX.
Trying to compile a hello world .cpp file with test-flags like -std=c++11, -std=c++14, ... does not seem the most robust approach and would require the creation of temporary files.
Is there any command one could run to test if a certain dialect is available without actually compiling anything?
Is there any command one could run to test if a certain dialect is available without actually compiling anything?
Yes. You can ask the compiler just to preprocess an empty file. It will do that
without complaint:
$ clang++ --version
clang version 4.0.1-6 (tags/RELEASE_401/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ echo '' | clang++ -x c++ -E -
# 1 "<stdin>"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 329 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "<stdin>" 2
$ echo $?
0
You can then incidentally add a -std option. If the compiler supports it:
$ echo '' | clang++ -std=c++98 -x c++ -E -
# 1 "<stdin>"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 326 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "<stdin>" 2
$ echo $?
0
still no complaint. But if not:
$ echo '' | clang++ -std=c++17 -x c++ -E -
error: invalid value 'c++17' in '-std=c++17'
$ echo $?
1
In a python script, you can conveniently supply an empty input file in the form of an empty string to an invocation of subprocess.run that executes the compiler probing command,
and at the same time swallows the unwanted stdout. You'd iterate such
invocations over a chronologically sorted list of -std-values to find the
latest supported. It would be prudent not simply to test the return code but
also to capture the stderr and, in case of failure, parse it for the right
sort of diagnostic, in case the command has failed for some surprise reason.
Here's a shot that serves for GCC as well as clang:
$ cat std_max.py
#!/usr/bin/python3
import subprocess
standards = ['98','03','11','14','17']
gpp_barf_pattern = "error: unrecognized command line option ‘-std=c++{0}’"
clangpp_barf_pattern = "error: invalid value 'c++{0}'"
def has_standard(compiler, std_year, barf_pattern):
std_opt = '-std=c++' + std_year
try:
subprocess.run([compiler,std_opt,'-x','c++','-E','-'],\
check=True,input=b'',stdout=subprocess.PIPE,stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
barf = barf_pattern.format(std_year)
strerr = e.stderr.decode('utf8','strict')
if barf in strerr:
return False
raise
return True
def get_std_max(compiler,standards,barf_pattern):
max_std = standards[0] if len(standards) else ''
for std_year in standards:
if not has_standard(compiler,std_year,barf_pattern):
break
max_std = 'c++' + std_year
return max_std
which will tell me, correctly:
$ python3
Python 3.6.3 (default, Oct 3 2017, 21:45:48)
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from std_max import *
>>> get_std_max('clang++',standards,clangpp_barf_pattern)
'c++14'
>>> get_std_max('g++',standards,gpp_barf_pattern)
'c++17'
>>>
No C++20 yet:
>>> has_standard('g++','20',gpp_barf_pattern)
False
>>>

Sierra, cpp command throwing 'iostream' file not found

I'm following a tutorial on my macbook pro with Sierra and Xcode9.0.1
I compiled the following hello world code with g++ without problems.
#include <iostream>
main() {
using namespace std;
cout << "Hello, World!" << endl;
}
But when I execute
cpp hello.cxx | more
as required by the tutorial, I got the following error message:
hello.cpp:1:10: fatal error: 'iostream' file not found
#include <iostream>
^~~~~~~~~~
1 error generated.
# 1 "hello.cpp"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 330 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "hello.cpp" 2
Since you have a working g++ compiler, you may use the following command line for getting the preprocessed output:
g++ -E hello.cxx | more
The -E option instructs the compiler driver to execute the preprocessor and emit the preprocessed output.

DOMElement has no member named 'getFirstElementChild xercesc C++

I'm writing a xml parser file, called GetConfig.cpp.
Here is my header file of 'GetConfig.h`:
#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMDocumentType.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMImplementationLS.hpp>
#include <xercesc/dom/DOMNodeIterator.hpp>
#include <xercesc/dom/DOMText.hpp>
#include <xercesc/dom/DOMNode.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
However, When I try to compile the program, I get:
/home/pribeiro/sandbox/GetConfig.cpp:372: error: 'class xercesc_2_2::DOMElement' has no member named 'getFirstElementChild'
/home/pribeiro/sandbox/GetConfig.cpp:381: error: 'class xercesc_2_2::DOMElement' has no member named 'getFirstElementChild'
/home/pribeiro/sandbox/GetConfig.cpp:392: error: 'class xercesc_2_2::DOMElement' has no member named 'getFirstElementChild'
/home/pribeiro/sandbox/GetConfig.cpp:396: error: 'class xercesc_2_2::DOMElement' has no member named 'getNextElementSibling'
I'm not sure why I'm getting that ...
In that declaration I use:
DOMElement *volume = dynamic_cast<xercesc::DOMElement*>
(volManager);
while(volume){
// to the parsing here
volume = volume->getNextElementSibling();
}
I'm not sure ... Maybe something related to the version of xercesc? When I compiled that for xercesc 3.1 it worked fine.
Those functions were introduced in Xerces 3
You see them mentioned in the Xerces 3 API documentation:
http://xerces.apache.org/xerces-c/apiDocs-3/classDOMElement.html
but not in the Xerces 2 API documentation:
http://xerces.apache.org/xerces-c/apiDocs-2/classDOMElement.html
The string "getFirstElementChild" occurs 31 times in the Xerces 3.1.1 sources but not at all in the Xerces 2.8.0 sources:
erik#ubuntu:/tmp$ file=http://archive.apache.org/dist/xerces/c/2/sources/xerces-c-src_2_8_0.tar.gz
erik#ubuntu:/tmp$ curl -s $file | tar xfz - -O | grep getFirstElementChild | wc -l
0
erik#ubuntu:/tmp$ file=http://archive.apache.org/dist/xerces/c/3/sources/xerces-c-3.1.1.tar.gz
erik#ubuntu:/tmp$ curl -s $file | tar xfz - -O | grep getFirstElementChild | wc -l
31
erik#ubuntu:/tmp$