C++ precompiler conditionally include code - preprocessor

I have a few projects that share a lot of common code, but sometimes I need to not include certain parts of the common code depending on the project.
I've tried creating a separate file called project_names.hh, containing this:
// list of project names
#define FIRSTPROJECT 0
#define SECONDPROJECT 1
// PROJECT_NAME must be set to one of the above names in the project's main.cc file
#define PROJECT_NAME
Then in one of the projects' main files I do this:
#define PROJECT_NAME FIRSTPROJECT
The problem is that even though I include project_names.hh in another file, I can't seem to get this statement to compile:
#if PROJECT_NAME == FIRSTPROJECT
I get this error:
error: operator '==' has no left operand
Does anyone have a good way to do this?
Thanks!
Marlon

That's because you've defined PROJECT_NAME to be the empty string with your line
#define PROJECT_NAME
you want to change it to
#define PROJECT_NAME FIRSTPROJECT
This needs to be in a header file that all the files of that project #include.
Alternatively, you could get rid of the #define PROJECT_NAME and instead use
-DPROJECT_NAME=FIRSTPROJECT on the compiler command line for all the files in that project. Note that if the same file is used in multiple projects, you'll need to compile it mulitple times with different options, and have it put the output in different places...

If I were in your situation I would simply define either FIRSTPROJECT or SECONDPROJECT instead of setting PROJECT_NAME to either of those values. I would then use #ifdef to check whether that value is set.

rather than #define PROJECT_NAME FIRSTPROJECT,
use #define FIRSTPROJECT,
then check its existence with #ifdef FIRSTPROJECT

You should include project_names.hh in the file in which you're running the #if PROJECT_NAME == FIRSTPROJECT. The preprocessor might not have loaded and executed the statements setting PROJCET_NAME in the first place.

This is most probably because the PROJECT_NAME isn't set. You should check, which file is being compiled and check if the #define is set there.
It might help to set the define as a compiler option for the whole building process. For most compilers that I know (gcc, MSVC, clang, xlC), the compiler option would be
-DPROJECT_NAME=FIRSTPROJECT

Related

How to check whether system has some header file using bazel build?

What I want to find is the existence of some platform specific header file.
For example, in source code there will be some #ifdef section like this.
#ifdef HAVE_XXX_H
//...do something
#else
//...do other thing
#endif
In Autoconf or Cmake, there exists dedicated macro or command for detecting platform specific header file or definition. So, I can easily set 'HAVE_XXX_H' as 1 or 0 according to the result of that macro.
Using bazel, how can I achieve this kind of thing?
Thanks.
If you are sure that the header is always present on a particular platform, use select() as elaborated by László.
If you actually need to detect the header at the build time, you will have to implement a custom repository_rule that will query the system and will generate a workspace with a header defining the macro.
You can use select().
Example: select() in cc_library.srcs. You can do the same in cc_library.hdrs.

How to global import my own DLog macros without use pch file

I wrote my own macros to output detail message in development environment
#ifdef DEBUG
#define GCLog(fmt, ...) NSLog((fmt), ##__VA_ARGS__);
#else
#define GCLog(...);
I don't want to import this in every file, and I know the shortcoming of PCH file.
So what can I do with this?
You've got four options:
Import some file containing that macro in every file you want to use
it in
Put it in the PCH which is automatically imported for you
Put it in a file and import that file in the PCH
Include that macro in every file you want to use it (generally a bad plan)
Personally when I was writing Objective-C, I would go with option 2 when I wanted something available in every file.

How to get string value from a specific plists in a multiple targets app?

In my app there are five targets. Every target has its own plist.
I want to get 2 urls in AppDelegate when I build a target. Those 2 urls are different for each target. There are 5 plists (MyApp1-Info.plist, MyApp2-Info.plist, MyApp3-Info.plist, MyApp4-Info.plist, MyApp5-Info.plist). Each attached with only 1 target.
I have put those urls in plists. If I build MyApp2 then I should get urls from MyApp2-Info.plist. How can I do that? Or is there any better way to do that?
Thanks in advance.
The better method of using a common source file within multiple targets is to use preprocessor macro that is different for each target. This directs the source file to perform different actions, or use different values, depending on which target is being compiled.
For example assume you set the prepropressor macro TARGET to 1, 2, etc. (or something more meaningful to your project), by setting the flag -DTARGET=1, -DTARGET=2, etc in the Xcode build settings, then the source file can use different URLs as simply as:
#if TARGET == 1
#define URL "http://one.com"
#elif TARGET == 2
#define URL "http://two.com"
#else
#error Invalid TARGET value
#endif
and away you go.
You can obviously also provide any amount of conditional-compilation using this method, for example:
#if TARGET == 1
doSomethingDrastic();
#endif
This is a much simpler, and a much more traditional, approach to defining per-target behaviour than embedding stuff within a .plist file.

iOS App Contains Developer Path Information

Inspecting an archived app, I can see the full path listed for a few source code files in the app binary. Not all source code files are listed.
strings - the_binary_app | grep "\.m"
reveals
/Users/bbarnhart/myPath/myPath/App/path/path/SourceCodeFile.m
as well as a few others. I can not determine how the full paths for a few source code files are embedded in the app binary. I would like to remove them. Any ideas? Is this a build setting or is the project file slightly corrupted?
Some belong to a lib and others are files that belong to the project.
The __FILE__ macro expands to full path to the current file. This is one likely way you might be getting the paths into your executable. For example, the expansion of the assert macro includes the __FILE__ macro.
Look at the output of your strings | grep pipeline. For each of those files, go into your project in Xcode and open that file. Then go to the Related Files doodad and choose “Preprocess”:
Then search through the preprocessor output for the file's path. You will find lots of false positives, because there will be lots of # line number/path directives. You can ignore these, because they only produce debug output, which is not included in your executable file (unless you've done something weird with your build settings). You might find it faster to save the preprocessor output to a file, then open that file and pipe it through grep or use a regexp search/replace to delete all lines starting with #.
Find the other instances where your path appears as a string constant. For example, if you used the assert macro, you will find something like this:
(__builtin_expect(!(argc > 0), 0) ? __assert_rtn(__func__, "/Volumes/b/Users/mayoff/TestProjects/textViewChanged/textViewChanged/main.m", 16, "argc > 0") : (void)0);
That's a case where the path will end up embedded in your executable.
If that doesn't find all the places where you're embedding your path, try selecting “Assembly” from the Related Files doodad. The assembly will be full of comments containing your path; everything after # is a comment in the assembly output, so ignore those.
You will also see your paths in .file directives. I believe these only produce debug symbol output, which doesn't go into your executable, so you can ignore those too.
You will also see your paths in .asciz directives shortly after .section DWARF,... directives. This is more debug symbol stuff that you can ignore.
Look for the remaining cases where your path appears in the assembly output. You need to figure out how to eliminate these cases. How you do that will depend on the context in which the paths appear, so if you need more help, update your question with what you find.
Sounds like your code contains the __FILE__ macro somewhere.

how do I add preprocessor #define in devenv command line?

Is there a way to add extra preprocessor #define in devenv command line?
I am not entirely sure what you mean by vcbuild command line but if you mean the Visual C++ command line compiler then you can add defines by add /Dxxxx, e.g.
cl.exe /DSHAREWARE ....
Additional answer based on comments:
You should be able to set the CL environment variable with the extra preprocessor define:
SET CL=/DSHAREWARE
devenv ....
Mere information can be found at MSDN
in your project settings, add the following preprocessor definition:
$(MyPreprocessorDefinitions);
then in your *.bat file, use
REM #define MY_DEF
set MyPreprocessorDefinitions=MY_DEF
devenv.exe ...
REM #undefine MY_DEF
set MyPreprocessorDefinitions=
The #defines are defined in your Visual Studio project file (.dsp or .vcproj file). This is a simple text file. So you could edit the project file from a script, then call devenv.exe.
In my case, I needed to use devenv for other reasons, (and was running in cygwin, so i had sed).
I set a Compilation symbol in the project's properties SED_REPLACE_THIS
and then used sed to set it to something meaningful (ie: DONT_CRASH_AS_MUCH)
sed -i 's/SED_REPLACE_THIS/DONT_CRASH_AS_MUCH/g' project.csproj
I couldn't find a way without modifying solution or project files so I came up with the following:
Create empty file as part of build e.g. feature_flag.h
Replace #if FEATURE_FLAG with #if !__has_include("feature_flag.h")
Remove feature_flag.h at the end of the build
It's not using #define but it does use the preprocessor which was what I needed.

Resources