include processed prepocessor directives into `g++ -E' output - g++

I'm having some preprocessing mishap while compiling a 3rd party library with g++.
I can see in -E output that a certain header wrapped with #ifndef SYMBOL is being bypassed. Apparently, that symbol has been defined somewhere else.
But I cannot see where because processed directives are not present in the -E output.
Is there a way to include them (as comments, probably)?

No, there is no standard way to get preprocessed directives as comments.
However, you could use g++ -C -E and the line numbers (output in lines starting with #) and the comments (which are then copied to the preprocessed form).
And you might also use the -H option (to get the included files)

The closest thing I found is the -d<chars> family of options:
-dM dumps all the macros that are defined
-dD shows where they are defined (dumps #define directives)
-dU shows where they are used (in place of #if(n)def, it outputs #define or #undef depending on whether the macro was defined)
Adding I to any of these also dumps #include directives.
The downside is only one of the three can be used at a time and they suppress normal output.
Another, less understandable downside is -dD and -dU do not include predefined macros.

Related

can gcc make test if a defined symbol exists in a source file

Is it possible for gcc make to test if a define exists in one of the source files ie.
ifeq (DEFINED_BLAH_BLAH,3)
#echo is equal to 3
else
#echo is not equal to 3
endif
I've looked at this and to expend on the suggestion from the comment, you could do the following. Not elegant, probably not the best available solution, but it works:
echo -ne "#if 1==MYVAL\n0\n#else\n1\n#endif\n" | cpp -P -imacros test.h
Or to call it through gcc or g++:
echo -ne "#if 1==MYVAL\n0\n#else\n1\n#endif\n" | \
gcc -Xpreprocessor -P -E -imacros test.h -
These would return shell style 0 (true for MYVAL defined in test.h and being 1) or 1 on stdout which you could test for in make / shell.
You may also want to strip all blank lines appending | grep -v '^$'.
To elaborate a bit more on the above. I create (echo) as simple file that I run through the preprocessor which check for equality on given macro and results in 0 or 1 being in the output. -P for cpp, because it's not really a C file and we do not need any of the extra bits in the output. -imacros means retain the macros defined in that file, but discard any output generated by processing it.
It should also be noted, if you'd have any conditional definitions needed to consider any defines passed to the compiler, you would need to pass them to this cpp run as well.
Also note whether you test.h being your header file you know should include the macro defintion. Or main.c being a source file including that (and other) headers doesn't really matter / yields the same result (whatver the value was when cpp was done with the file read and (pre)processed for -imacros.

Recursive rsync over ssh, include only one file extension

I'm trying to rsync files over ssh from a server to my machine. Files are in various subdirectories, but I only want to keep the ones that match a certain pattern (IE blah.txt). I have done extensive googling and searching on stackoverflow, and I've tried just about every permutation of --include and --excludes that have been suggested. No matter what I try, rsync grabs all files.
Just as an example of one of my attempts, I have used:
rsync -avze 'ssh' --include='*blah*.txt' --exclude='*' myusername#myserver.com:/path/top/files/directory /path/to/local/directory
To troubleshoot, I tried this command:
rsync -avze 'ssh' --exclude='*' myusername#myserver.com:/path/top/files/directory /path/to/local/directory
expecting it to not copy anything, but it still grabbed all of the files.
I am using rsync version 2.6.9 on OSX.
Is there something obvious I'm missing? I've been struggling with this for quite a while.
I was able to find a solution, with a caveat. Here is the working command:
rsync -vre 'ssh' --prune-empty-dirs --include='*/' --include='*blah*.txt' --exclude='*' user#server.com:/path/to/server/files /path/to/local/files
However! If I type this into my command line directly, it works. If I save it to a file, myfile.txt, and I try `cat myfile.txt` it no longer works! This makes no sense to me.
OSX follows BSD style rsync
https://www.freebsd.org/cgi/man.cgi?query=rsync&apropos=0&sektion=0&manpath=FreeBSD+8.0-RELEASE+and+Ports&format=html
-C, --cvs-exclude
This is a useful shorthand for excluding a broad range of files
that you often don't want to transfer between systems. It uses a
similar algorithm to CVS to determine if a file should be
ignored.
The exclude list is initialized to exclude the following items
(these initial items are marked as perishable -- see the FILTER
RULES section):
RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS
.make.state .nse_depinfo *~ #* .#* ,* _$* *$ *.old *.bak
*.BAK *.orig *.rej .del-* *.a *.olb *.o *.obj *.so *.exe
*.Z *.elc *.ln core .svn/ .git/ .bzr/
then, files listed in a $HOME/.cvsignore are added to the list
and any files listed in the CVSIGNORE environment variable (all
cvsignore names are delimited by whitespace).
Finally, any file is ignored if it is in the same directory as a
.cvsignore file and matches one of the patterns listed therein.
Unlike rsync's filter/exclude files, these patterns are split on
whitespace. See the cvs(1) manual for more information.
If you're combining -C with your own --filter rules, you should
note that these CVS excludes are appended at the end of your own
rules, regardless of where the -C was placed on the command-
line. This makes them a lower priority than any rules you spec-
ified explicitly. If you want to control where these CVS
excludes get inserted into your filter rules, you should omit
the -C as a command-line option and use a combination of --fil-
ter=:C and --filter=-C (either on your command-line or by
putting the ":C" and "-C" rules into a filter file with your
other rules). The first option turns on the per-directory scan-
ning for the .cvsignore file. The second option does a one-time
import of the CVS excludes mentioned above.
-f, --filter=RULE
This option allows you to add rules to selectively exclude cer-
tain files from the list of files to be transferred. This is
most useful in combination with a recursive transfer.
You may use as many --filter options on the command line as you
like to build up the list of files to exclude. If the filter
contains whitespace, be sure to quote it so that the shell gives
the rule to rsync as a single argument. The text below also
mentions that you can use an underscore to replace the space
that separates a rule from its arg.
See the FILTER RULES section for detailed information on this
option.

make targets depend on variables

I want (GNU) make to rebuild when variables change. How can I achieve this?
For example,
$ make project
[...]
$ make project
make: `project' is up to date.
...like it should, but then I'd prefer
$ make project IMPORTANTVARIABLE=foobar
make: `project' is up to date.
to rebuild some or all of project.
Make wasn't designed to refer to variable content but Reinier's approach shows us the workaround. Unfortunately, using variable value as a file name is both insecure and error-prone. Hopefully, Unix tools can help us to properly encode the value. So
IMPORTANTVARIABLE = a trouble
# GUARD is a function which calculates md5 sum for its
# argument variable name. Note, that both cut and md5sum are
# members of coreutils package so they should be available on
# nearly all systems.
GUARD = $(1)_GUARD_$(shell echo $($(1)) | md5sum | cut -d ' ' -f 1)
foo: bar $(call GUARD,IMPORTANTVARIABLE)
#echo "Rebuilding foo with $(IMPORTANTVARIABLE)"
#touch $#
$(call GUARD,IMPORTANTVARIABLE):
rm -rf IMPORTANTVARIABLE*
touch $#
Here you virtually depend your target on a special file named $(NAME)_GUARD_$(VALUEMD5) which is safe to refer to and has (almost) 1-to-1 correspondence with variable's value. Note that call and shell are GNU Make extensions.
You could use empty files to record the last value of your variable by using something like this:
someTarget: IMPORTANTVARIABLE.$(IMPORTANTVARIABLE)
#echo Remaking $# because IMPORTANTVARIABLE has changed
touch $#
IMPORTANTVARIABLE.$(IMPORTANTVARIABLE):
#rm -f IMPORTANTVARIABLE.*
touch $#
After your make run, there will be an empty file in your directory whose name starts with IMPORTANTVARIABLE. and has the value of your variable appended. This basically contains the information about what the last value of the variable IMPORTANTVARIABLE was.
You can add more variables with this approach and make it more sophisticated using pattern rules -- but this example gives you the gist of it.
You probably want to use ifdef or ifeq depending on what the final goal is. See the manual here for examples.
I might be late with an answer, but here is another way of doing such a dependency with Make conditional syntax (works on GNU Make 4.1, GNU bash, Bash on Ubuntu on Windows version 4.3.48(1)-release (x86_64-pc-linux-gnu)):
1 ifneq ($(shell cat config.sig 2>/dev/null),prefix $(CONFIG))
2 .PHONY: config.sig
3 config.sig:
4 #(echo 'prefix $(CONFIG)' >config.sig &)
5 endif
In the above sample we track the $(CONFIG) variable, writing it's value down to a signature file, by means of the self-titled target which is generated under condition when the signature file's record value is different with that of $(CONFIG) variable. Please, note the prefix on lines 1 and 4: it is needed to distinct the case, when signature file doesn't exist yet.
Of course, consumer targets specify config.sig as a prerequisite.

How to create a C #define for a certain target using CMake?

I feel a little stupid right now. After recently converting a few smaller projects to use CMake, I decided to also get rid of a few "Platform_Config.h" files. These files contain a few preprocessing directives like #define USE_NEW_CACHE and control compilation.
How would I 'convert' these defines to be controlled with CMake? Ideally by using these "cache" variables the user can easily edit.
There are two options. You can use the add_definitions method to pass defines as compiler flags: E.g. somewhere in your projects cmakelists.txt:
add_definitions( -DUSE_NEW_CACHE )
CMake will make sure the -D prefix is converted to the right flag for your compiler (/D for msvc and -D for gcc).
Alternatively, check out configure_file. It is more complex, but may be better suited to your original approach with a Platform_Config file.
You can create an input-file, similar to your original Platform_Config.h and add "#cmakedefine" lines to it.
Let's call in Platform_Config.h.in:
// In Platform_Config.h.in
#cmakedefine USE_NEW_CACHE
// end of Platform_Config.h.in
When then running
configure_file( ${CMAKE_SOURCE_DIR}/Platform_Config.h.in ${CMAKE_BINARY_DIR}/common/Platform_Config.h )
it will generate a new Platform_Config file in your build-dir. Those variables in cmake which are also a cmakedefine will be present in the generated file, the other ones will be commented out or undefed.
Of course, you should make sure the actual, generated file is then correctly found when including it in your source files.
option command might provide what you are looking for.
use it with the COMPILE DEFINITIONS property on the target and i think you are done.
To set the property on the target, use the command set target properties
option(DEBUGPRINTS "Prints a lot of debug prints")
target(myProgram ...)
if(DEBUGPRINTS)
set_target_properties(myProgram PROPERTIES COMPILE_DEFINITIONS "DEBUGPRINTS=1")
endif()
edit:
The option i wrote in the example shows up as a checkbox in the CMake GUI.
In case you want to set defines per target: Since 2.8.11 you can use target_compile_definitions.
In earlier versions you probably don't want to use set_target_properties as is, since it overwrites any defines you set previously. Call get_target_property first instead, then merge with previous values. See add_target_definitions here.
Use target_compile_options. Do not quote your define or it not be detected as a define. CMake parses off the /define and adds the actual define to the DefineConstants section of the csproj, if there are quotes it will put the entire quoted string in the AdditionalOptions section of the csproj.
An example from one of my projects that uses generator expressions:
target_compile_options( ${LIBRARY_NAME} PRIVATE
$<${IS_ART_ITERATION_BUILD}:/define:ART_ITERATION_BUILD>
)
An example without generator expressions:
target_compile_options( ${LIBRARY_NAME} PRIVATE
/define:GRAPHICS_VULKAN
)

Generating a VERSION_STRING from major/minor/patch/build defines for use in a plist

I have a plist that is processed with a precompiled header file and in it there is the "variable" VERSION_STRING used a few times in such fields as CFBundleGetInfoString, ie the value for the key CFBundleGetInfoString is: MyProduct VERSION_STRING Copyright © 2009 MyCorp
In MyHeader.h (which is the set as the Info.plist prefix header I would like to be able to build VERSION_STRING into the form MAJOR.MINOR.PATCH.BUILD where I have
#define MAJOR 1
#define MINOR 0
#define PATCH 0
#define BUILD 23
For some reason I seem to be incapable of doing this. I might just be having one of those moments
Turns out there is actually an Apple Tech Note on this and a solution to the very problem I was having. So, for anyone that may come across this and is having the same problems I was check out Technical Note TN2175: Preprocessing Info.plist files in Xcode Using the C Preprocessor
Take your plist file and rename it with an extra extension (perhaps a P?). Add #include "MyHeader.h" to the beginning of the file, and preprocess it in your build with the C preprocessor (usually cpp). You may need to filter out extra # lines, but I don't see why it wouldn't work.
By default, cpp should output to stdout, so adding a command like this might work fine:
cpp myplist.plist.P | grep -v '^#' > myplist.plist