C++ conditional link with preprocessor - c++

I have a MSVC C++ project, I am conditionally compiling parts of the source code by passing specifing Preprocessor Defintions in the C++/Preprocessor section of the Project Properties.
What I would also like to do is conditionally link with libraries based on the preprocessor definitions, how do I achieve this?
For example in my project if CLSOPENLDV is defined I want to exclude:
nodetalk32_vcpp.obj
and include:
ldv32.lib
And when it isn't defined I want to do the opposite.

You probably need this:
#ifdef SOME_MACRO
#pragma comment( lib, "ldv32" )
#endif
This is Microsoft specific, it probably won't work with gcc, clang or other compilers.
For excluding nodetalk32_vcpp.obj the only thing you can do that comes into my mind is:
#ifndef SOME_MACRO
// content of nodetalk32_vcpp.cpp
#endif

Related

How to avoid apply compilation flag for third party header

We want to add -Werror=conversion to our code base, but the header of the Eigen library will trigger a lot of these error. I am wondering what is the best approach here so that the compilation flag only applies to our code but not for third party header.
One solution we are thinking is to create a wrapper library for Eigen that only contains stuff we need. We will compile the wrapper without the flag. But this is a somewhat big undertaking. I am wondering if there are other solutions.
With gcc you can include Eigen headers via -isystem. They will be treated like system headers and no warnings will be reported. This silences all warnings, though with well tested 3rd party libraries this is usually ok.
You can create a header Eigen.h with this:
#pragma once
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#endif
#include <Eigen/Core>
// ...
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

What does compile with -DPSAPI_VERSION=1 mean?

In the link below the C++ code's comments it says;
// and compile with -DPSAPI_VERSION=1
https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules
How do we compile with -DPSAPI_VERSION=1 ?
Two possibilities
just before the include of windows.h add
#define PSAPI_VERSION=1
or in the project properties there is a place to define macros, add PSAPI_VERSION=1 there
Macros are defined in the program. I usually define a macro in the cmake file as a switch. Then in the program, if the macro is found to be defined, the algorithm library call is executed, because my algorithm library is sometimes not configured properly.
CMakeLists.txt
add_definitions(-DRecognitionLIB")
in cpp file
#ifdef RecognitionLib
#include <GBProcess.h>
#include <AIScrapperVision.h>
#endif
function aaa()
{
#ifdef RecognitionLib
some code
#endif
}

C++ preprocessor executing both #ifdef and #ifndef

So I'm currently working on something that uses OpenCL. The OpenCL spec provides the users with a directive which must be included before the inclusion of the header (cl.h)
#define CL_TARGET_OPENCL_VERSION 110
Which basically defines the version they want to use. Suppose I'm making a library and I want my users to define this instead of me defining this inside my files. What I did was.
-----main.cpp---
#define CL_TARGET_OPENCL_VERSION 110
#include "library.h"
-------x---------
----library.h-----
#ifdef CL_TARGET_OPENCL_VERSION
#pragma message("def")
#endif
#ifndef CL_TARGET_OPENCL_VERSION
#pragma message("ndef")
#endif
.... include other headers.
--------x---------
And the compiler prints both def and ndef messages. And the OpenCL library also throws a warning that it's undefined. I thought that the library header would get substituted into main and it'd only print the def message. Is there anything I understood wrong?
I'm particularly confused as to where does the preprocessor start? If it starts from main.cpp and goes from top to down, then it surely has defined the macro. After that it sees the library inclusion, then it should only print the def message but it prints both.
This leds me to believe the preprocessor does scan the header file before including it in main? Dunno the reason why. Also I have assured that the library header isn't included elsewhere.
One interesting thing I noticed was, if i did this
-----helper.h---
#define CL_TARGET_OPENCL_VERSION 110
-------x---------
----library.h-----
#include helper.h
#ifdef CL_TARGET_OPENCL_VERSION
#pragma message("def")
#endif
#ifndef CL_TARGET_OPENCL_VERSION
#pragma message("ndef")
#endif
.... include other headers.
--------x---------
It prints the def message "twice". If anybody can explain all this I'd be grateful.
EDIT:- The files I'm compiling are main.cpp library.h and library.cpp
Library.cpp includes library.h from the start as usual. Maybe this other cpp is causing the problem?
In C/C++ programs, the compiler handles each .c and .cpp file separately.
The compilers build each source file (NOT the header files, only .c and .cpp files) independently from each other (this source files are called compilation unit).
Thus, when your main.cpp is built, the compiler finds the #define CL_TARGET_OPENCL_VERSION 110 you have added on top of the main.cpp file, emiting the defmessage.
But when the compiler builds the library.cpp file, it does not find the version define, so it emits the ndef message.
So, following this explanation, it is completely normal that in your last case, when you add the define to the .h file, the compiler emits the def message twice, once for the main.cpp file and once for the library.cpp file.
Now, the problem is where should you add the define, in order to have the program built consistently, with the same version for all the .cpp files.
Usually, all the IDEs have some configuration page where you can add global defines, for all the project, which are "inserted" into all the compilation units before everything else. So when the IDE calls the compiler, it passes the same defines to all the compilation units. You should add this kind of defines in this page.
In your IDE (I am using Code::Blocks, v 17.12), you can find this page in the menu: Project / Build Options
For each type (Debug or Release), you have to go to the tab Compiler Settings, and there to the sub tab #defines. There you can add global defines, which can be different if you are building in Debug or in Release mode (of course, if you set the same in both modes, they would be the same).
Once you have added your define here, please, remove it from the main.cpp, library.h and any other place where you may have added it, in order to avoid duplicities.
From the comments about portability:
You have several options:
Always use Code::Blocks: this would be the easiest way, since you can pass the Code::Blocks project along with the source files, and everything would be already setup.
Use cmake, which is a script build system, where you can set defines and so in the same way as using an IDE. cmake is much widely used than Code::Blocks, so maybe it is a better option.
Add a new options.h header file, where you set all the defines, and include it to all your .c/.cpp. This setup has the additional benefit that for different systems, changing only the options.h file the build can be completely different. This is a manually setup of what the IDE is doing. It has the advantage that does not rely on external tools, but the disadvantage that you have to remember to add it in all the new .cpp files added to the project.
My recommendation is go with cmake, just as the others have said.
Prefer using #ifndef XXXX_h #define XXXX_h #endif over #pragma once
If your #include search path is sufficiently complicated, the compiler may be unable to tell the difference between two headers with the same basename (e.g. a/foo.h and b/foo.h), so a #pragma once in one of them will suppress both. It may also be unable to tell that two different relative includes (e.g. #include "foo.h" and #include "../a/foo.h" refer to the same file, so #pragma once will fail to suppress a redundant include when it should have.
This also affects the compiler's ability to avoid rereading files with #ifndef guards, but that is just an optimization. With #ifndef guards, the compiler can safely read any file it isn't sure it has seen already; if it's wrong, it just has to do some extra work. As long as no two headers define the same guard macro, the code will compile as expected. And if two headers do define the same guard macro, the programmer can go in and change one of them.
#pragma once has no such safety net -- if the compiler is wrong about the identity of a header file, either way, the program will fail to compile. If you hit this bug, your only options are to stop using #pragma once, or to rename one of the headers. The names of headers are part of your API contract, so renaming is probably not an option.
(The short version of why this is problematic to use #pragma is that neither the Unix nor the Windows filesystem API offer any mechanism that guarantees to tell you whether two absolute pathnames refer to the same file.)

Scope of a C++ symbol

AFAIK, symbols are useful to prevent multiple parsing. If both a.h and b.h include c.h, a
#ifndef C_H
#define C_H
...
// c.h definition would go here
...
#endif
will prevent c.h from being "parsed" (I believe it's not the right word) more than once.
However, I have seen something like
#ifdef WIN32
...
in other people's code. That symbol must have been defined somewhere else because a search for
#define WIN32
in the whole project returns empty. My question is: where are these symbols actually defined? Does the OS keep something similar to a pool of symbols that different programs can use to query for OS or other processes properties?
There are two options where those which are not in the code itself can originate from:
The compiler suite itself sets it as a default when you start compiling your code.
You give the compiler (or preprocessor, to be exact) a list of those definitions when you compile the code (or your IDE project preferences do, when you are using an IDE. For example, in Visual Studio 2013 you will find those when you open Project > Properties > Configuration Properties > C/C++ > Preprocessor > Preprocessor Definitions).
In general, those definitions are not only used for the reason you describe (as include guards), but also to enable or disable code based on the platform you develop for - for example, you can have code branches only compiled for windows, or only if you are using a 64 bit compiler.
You might want to take a look at some predefined compiler macros
Microsoft
AFAIK this is part of the compiler you use.
The Microsoft C++ compiler internally defines some macros such as WIN32, that's why it's not defined in any particular header. So when you build a source file with VC++ the stuff in inside #ifdef WIN32 gets compiled, but not on say Linux gcc.
Also your nomenclature is a bit off -- these are called preprocessor macros, not symbols. The names of the variables, functions, etc in your code are symbols.
Each compiler has a list of defined macros. MSVC defines WIN32 when compilation target is 32-bit Windows.

Where is WIN32 defined, and how can I include this definition in my project?

I am including a third party header and source file into my project.
At the top of the header there is this:
#if defined(WIN32) || defined(WIN16)
#ifndef MSDOS
#define MSDOS
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#ifndef MSDOS
#include <unistd.h>
#endif
#include "des.h"
The problem is that #if defined(WIN32) fails and the compilation fails when trying to #include unistd.h which I don't want to do.
I have third party project that works with this header file i.e. WIN32 is defined and it doesn't try to include In Visual Studio I did "Go To Definition" on "WIN32" and was taken to the following definition in WinDefs.h.
#define WIN32
I'm not sure this is where its getting WIN32 definition from, as the third party project does not appear to include "WinDefs.h".
So my problem is, how can I get WIN32 to be defined in my current new project?
Depends on your project setup. WIN32 is defined inside the windows header files, but you can pass it to the compiler as well ("-DWIN32" for gcc for example). Try it and see whether it compiles.
Visual Studio has the built-in define _WIN32. mingw-gcc has WIN32 and _WIN32 built-in so the project was likely tested using gcc. You might add
#if defined(_WIN32) && !defined(WIN32)
#define WIN32
#endif
or just add a -DWIN32 to the CFLAGS.
Check your includes. I am guessing that the third party header is included prior to the windows.h. So, in your main.cpp or equal it should be
#include <windows.h> // this will also include windefs.h
#include <thirdParty.h>
and not the other way around.
Hope that helps.
You can simply include the windows header files (windows.h) before including the third party header - as you already found out WIN32 is defined there but technicaly it could be defined anywhere (so if the third party project is not including the windows headers check if it's being defined in the compiler project settins directly).
BTW there is also a _WIN32 define that is set by the compiler, it's possibly a better idea to look for this define if checking if the code is being compiled under windows;
For those seeking answers to the
where is WIN32 defined
part of the questions, I've found it defined in:
minwindef.h
ole2.h
Note, I have no confidence that these are the only places it's defined. I expect there are probably other files where it's defined. Nevertheless, I thought this might help some people.
Some WIN32 defined in the compiler . Just like this,If you use the gcc for windows , WIN32 is defined . If you use the gcc for linux , WIN32 is not defined :)
So , the macros is a switch. You can define it to use somethine , and not define it to unuse something.