Can I set a compile time flag to include a header? - c++

I have a configuration class that I would like to use for a variety of builds. The class itself changes between builds, but the class name remains the same, as does the header file name.
The separate versions of this class are held in separate subfolders.
ex.
main/config.h
main/config.cpp
secondary/config.h
secondary/config.cpp
Is there a good way to, through a compile-time flag or command line option, have the build determine which header/cpp to use? I have quite a few configurations already, and expect to have many more in the future. I would like to avoid a long list of #ifdef/#elif/#elif/etc..
edit: I would like to avoid having separate builds, and would like to avoid using #defines throughout the code. I'm sorry if I didn't make that clear before! >_<

Depending on what build system you are using you would create a variable that points to the main or secondary path. This variable is then used to append to the INCLUDE path so all of your sources can just #include "config.h" when they need access to config. In your Makefile (or equivalent) you will need to add the $CONFIGPATH/config.cpp to your sources to build.
MSBuild
Update source file paths:
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="$(ConfigToUse)/config.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(ConfigToUse)/config.h" />
</ItemGroup>
And the include path:
<PropertyGroup>
<ConfigurationType>Application</ConfigurationType>
<ShowAllFiles>false</ShowAllFiles>
<IncludePath>...;$(ConfigToUse);</IncludePath>
</PropertyGroup>
Then call msbuild build.xml /p:ConfigToUse=PathToConfig

The #include directive doesn't really care about content.
You can just as easily have a stub class that you use in your project:
stub.cpp
#ifdef BUILD1
#include "main/realimpl1.cpp"
#else
#include "secondary/realimpl2.cpp"
#endif
And, of course, you can do the same thing with headers if necessary.

You can put into your header/cpp guards like this:
#ifdef OPTION_A
...
#endif

You can use compile-time #define such as
#define USE_BUILD_X 1
//#define USE_BUILD_Y 1
...
...
#ifdef (USE_BUILD_X)
#include "mainheader.h"
#elif (USE_BUILD_Y)
#include "secondheader.h"
#endif

I suppose the good choise is to use several makefiles or whatever you use. One for each configuration. Do not make your source files unreadable.
You can place common files in the Common directory, and other files in separate directories - one directory for each configuration.

In Visual Studio (if that's your IDE) you can have multiple "configurations" (by default Debug and Release), and it's possible to have certain files not included in each build. You could make configuration "Debug main" which excludes secondary/config.cpp, and configuration "Debug second" which excludes main/config.cpp.
If you're using not using Visual Studio, I believe there's a way to do something similar with make files.

You can just add the relevant directory to the front of the compiler's include path.
You can change the compiler's include path via some compiler option (it depends on the compiler).
For the .cpp file it's the same. Just have a .cpp file in your ordinary source tree, that includes that .cpp file via a #include directive.
Cheers & hth.,

Related

How to deal with changing folder names when your header guards and #includes use exact paths?

I am coding in C++ using the Visual Studio 2019 IDE.
I have followed the convention that every file #includes project files using the exact path. For example:
#include "ProjectName/FolderName2/HeaderName2.h"
#include "ProjectName/FolderName/src/HeaderName1.h"
I have also followed the convention of including the path in my #ifndef header guards:
#ifndef PROJECTNAME_FOLDERNAME_FILENAME_H
#define PROJECTNAME_FOLDERNAME_FILENAME_H
//...
#endif
This is the style suggest by the Google Style Guide.
However, as I am coding, I may want to change folder names. For example, I may decide that ProjectName is not a correct description of the contents of the folder and that I should change the name to ProjectName2. This change, however, requires correcting header guards and each #include that uses ProjectName in the path description. This problem becomes significantly worse if I totally reorganize my code.
Are there (automatic) tools to make this easier? Is #includeing the exact path (from the solution folder) the way to go?

Eclipse C exclude header file in build configuration

In Eclipse, using CDT.
Is there a quick way to have two identical build configurations, but in one configuration to use only src/foo.h and in the other only src/bar/foo.h ?
The src/ dir has lots of other header files, and I am optimistically hoping to not have to add them all one by one when only one file is actually different.
I also don't really want to move either of the files or modify them, since they are not libraries or directory structures that I have written myself.
(If i really have to, then I guess I have to sort it out)
I suppose some sort of "exclude" list would be ideal. Does that exist?
Define a macro which tells you which build configuration your are building for and then use that to decide which file to include.
Right-click on your project, choose Properties. Then in the dialog which pops up choose C/C++ Build, then Settings. You should end up in a view which let's you define preprocessor definitions (macros).
Then in your header file either do the following:
#ifndef MY_MACRO
// contents of header file only available when MY_MACRO is NOT defined
#endif
Or you can (and should probably) do at the point of inclusion instead, so for this is a source file:
#ifdef MY_MACRO
# include "bar.h"
#else
# include "foo/bar.h"
#endif
If you include the header file from several source files and do not want to copy the above-mentioned lines you can add another header which does the inclusion for you by just copy-pasting the lines above and then including that header everywhere.

including .h file from a different application/directory

I have some .h files as follows (on Linux)
Source/Server/connect.h
Source/Server/message.h
...
I am developing another application that needs the two .h files but is in a different directory
Source/App2/..
How can I include the connect.h file in the App2 application, considering that I use perforce and everyone else working on the application would have their own copy so adding an absolute path to the include library might not be a good idea but im not sure.
EDIT:
I use a proprietary build mechanism for building the code so will not be able to specify gcc options directly.
You can #include a relative path to the files:
#include "../Server/connect.h"
or you can add a flag to tell the compiler to look in the other directory. For gcc you can use -I../Server; for Visual C++ you can use /I"../Server"; other compilers, I'm sure, have their own flags for this purpose.
I think the second is better in most cases, since it allows you to move your projects around while only requiring you to modify the include path in one place (the makefiles or property sheets).
What about adding include search path to he compiler, for gcc it's -I switch.
I suggest removing paths from the #include statements. As others have stated, put the paths into the parameters to the compiler. Resolve the path differences in the makefile or use environment variables (may need to do both).
My experience is that files will move. Anything that doesn't use relative paths will break the build (which is very bad).
in addition static relative paths, you can also play with preprocessor chicanery. One technique I saw used at Adobe for cross-platform code, was to do something like this:
/* globalplatform.h */
#ifdef MAC
#define PLATFORM "../Platform/Mac/MacPlatform.h"
/* custom standard IO etc */
#define STDIO "../Platform/Mac/io/stdio.h"
#define CTYPE "../Platform/Mac/io/ctype.h"
#endif
#ifdef WIN32
#define PLATFORM "../Platform/Win/WinPlatform.h"
#define STDIO <stdio.h>
#define CTYPE <ctype.h>
#endif
/* etc */
#ifndef PLATFORM
#error undefined PLATFORM
#endif
/* some C file */
#include "globalplatform.h"
#include PLATFORM
#include STDIO
/* don't need CTYPE, no penalty */
While the platform problem isn't your problem, you can define the relative paths based on build configuration if you want to and the config changes happen in one place instead of many and client files only pull in what they need. The down side is that any tools you use for browsing header files (right-click and so on) are hosed.
You can change the compiler directives as above, or modify the path within your code (either relative or absolute).
I would suggest that you consider the best locations for headers and object files (and libraries) for all your projects and set that up.
If you have standard include and lib locations you'll simplify the development down the road

Stripping Down VS 2008 Win32 DLL to one file

I have a VS generated C++ Win32 DLL project. It has the following files:
stdafx.h
targetver.h
myProject.h
dllmain.cpp
myProject.cpp
stdafx.cpp
I can remove targetver.h, and merge dllmain.cpp into myProject.cpp. What more can I do to get the simplest file structure, preferably one file. I need to dynamically emit this code file and build it into a Win32 DLL.
If you want a minimalistic file structure, you could just create the files yourself. Start an empty project, or delete all the files. Heck, just make a folder, write main.cpp, and compile it from the command line with cl.
Few IDEs really try to minimize files like you're trying to -- but when you create the project, you can cut back a little: stdafx.[h, cpp] are for precompiled headers, which you could disable when creating the project.
That said, I don't really see the value in minimizing the amount of source code in a compiled language project -- it's not going to have a meaningful impact on the number of output files/dlls and, properly used, using more files only helps your code's clarity.
In addition to what Andy said, you can merge the myProject header and implementation files as well with dllmain.cpp. But why not just keep these files and create the vsproj file at runtime?
Or you could just create an empty project.
IIRC, myProject.h and myProject.cpp both contain an example of an exported class. You can easily delete those.
stdafx.cpp and stdafx.h are used for the standard precompiled header file. If you turn off the setting that requires a precompiled header, then those files won't be necessary, either.
You could #include your generated file into a existing multi-file project. That way you can have a shell of a complicated project and only emit something smaller, like a simple function.
For example:
#include <system_stuff>
void main()
{
Go();
}
#include "generated_file_that_has_method_go.cpp"
void other_code()
{
}

Can the C preprocessor be used to tell if a file exists?

I have a very large codebase (read: thousands of modules) that has code shared across numerous projects that all run on different operating systems with different C++ compilers. Needless to say, maintaining the build process can be quite a chore.
There are several places in the codebase where it would clean up the code substantially if only there were a way to make the pre-processor ignore certain #includes if the file didn't exist in the current folder. Does anyone know a way to achieve that?
Presently, we use an #ifdef around the #include in the shared file, with a second project-specific file that #defines whether or not the #include exists in the project. This works, but it's ugly. People often forget to properly update the definitions when they add or remove files from the project. I've contemplated writing a pre-build tool to keep this file up to date, but if there's a platform-independent way to do this with the preprocessor I'd much rather do it that way instead. Any ideas?
Little Update
Some compilers might support __has_include ( header-name ).
The extension was added to the C++17 standard (P0061R1).
Compiler Support
Clang
GCC from 5.X
Visual Studio from VS2015 Update 2 (?)
Example (from clang website):
// Note the two possible file name string formats.
#if __has_include("myinclude.h") && __has_include(<stdint.h>)
# include "myinclude.h"
#endif
Sources
SD-6: SG10 Feature Test Recommendations
Clang Language Extensions
Create a special folder for missing headers, and make that folder to be searched last
(that is compliler specific - last item in "INCLUDES" environment variable, something like that)
Then if some header1.h can be missing, create in that folder a stub
header1.h:
#define header1_is_missing
Now you can always write
#include <header1.h>
#ifdef header1_is_missing
// there is no header1.h
#endif
Generally this is done by using a script that tries running the preprocessor on an attempt at including the file. Depending on if the preprocessor returns an error, the script updates a generated .h file with an appropriate #define (or #undef). In bash, the script might look vaguely like this:
cat > .test.h <<'EOM'
#include <asdf.h>
EOM
if gcc -E .test.h
then
echo '#define HAVE_ASDF_H 1' >> config.h
else
echo '#ifdef HAVE_ASDF_H' >> config.h
echo '# undef HAVE_ASDF_H' >> config.h
echo '#endif' >> config.h
fi
A pretty thorough framework for portably working with portability checks like this (as well as thousands others) is autoconf.
The preprocessor itself cannot identify the existence of files but you certainly can use the build environment to do so. I'm mostly familiar with make, which would allow you to do something like this in your makefile:
ifdef $(test -f filename && echo "present")
DEFINE=-DFILENAME_PRESENT
endif
Of course, you'd have to find an analog to this in other build environments like VisualStudio, but I'm sure they exist.
Another possibility: populate a directory somewhere with zero-length versions of all of the headers you wish to optionally include. Pass a -I argument to this directory as the last such option.
The GCC cpp searches its include directories in order, if it finds a header file in an earlier directory it will use it. Otherwise, it will eventually find the zero-length file, and be happy.
I presume that other cpp implementations also search their include directories in the order specified.
You could have a pre-build step run that generates an include file that contains a list of #defines that represent the names of the files existing in the current directory:
#define EXISTS_FILE1_C
#define EXISTS_FILE1_H
#define EXISTS_FILE2_C
Then, include that file from within your source code, and then your source can test the EXISTS_* defines to see whether a file exists or not.
So far as I know cpp does not have a directive regarding the existence of a file.
You might be able to accomplish this with a bit of help from the Makefile, if you're using the same make across platforms. You can detect the presence of a file in the Makefile:
foo.o: foo.c
if [ -f header1.h ]; then CFLAGS+=-DHEADER1_INC
As #Greg Hewgill mentions, you can then make your #includes be conditional:
#ifdef HEADER1_INC
#include <header1.h>
#endif
Contrary to some claims here and on the internet, Visual Studio 2015 does NOT support the __has_include feature - at least according to my experience. Tested with Update 3.
The rumors may have arisen from the fact that VS 2017 is also referred to as "Version 15"; VS 2015 is instead referred to as "Version 14". Support for the feature seems to have been officially introduced with "Visual Studio 2017 Version 15.3".
I had to do something similar for the Symbian OS. This is how i did it:
lets say you want to check if the file "file_strange.h" exists and you want to include some headers or link to some libraries depending on the existance of that file.
first creat a small batch file for checking the existence of that file.
autoconf is good but an over kill for many small projects.
----------check.bat
#echo off
IF EXIST [\epoc32\include\domain\middleware\file_strange] GOTO NEW_API
GOTO OLD_API
GOTO :EOF
:NEW_API
echo.#define NEW_API_SUPPORTED>../inc/file_strange_supported.h
GOTO :EOF
:OLD_API
echo.#define OLD_API_SUPPORTED>../inc/file_strange_supported.h
GOTO :EOF
----------check.bat ends
then i created a gnumake file
----------checkmedialist.mk
do_nothing :
#rem do_nothing
MAKMAKE :
check.bat
BLD : do_nothing
CLEAN : do_nothing
LIB : do_nothing
CLEANLIB : do_nothing
RESOURCE : do_nothing
FREEZE : do_nothing
SAVESPACE : do_nothing
RELEASABLES : do_nothing
FINAL : do_nothing
----------check.mk ends
include the check.mk file in your bld.inf file, it MUST be before your MMP files
PRJ_MMPFILES
gnumakefile checkmedialist.mk
now at compile time the file file_strange_supported.h will have an appropriate flag set.
you can use this flag in your cpp files or even in the mmp file
for example in mmp
#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
LIBRARY newapi.lib
#else
LIBRARY oldapi.lib
#endif
and in .cpp
#include "../inc/file_strange_supported.h"
#ifdef NEW_API_SUPPORTED
CStrangeApi* api = Api::NewLC();
#else
// ..
#endif