I work on a C++ program which I develop on my personal Ubuntu 15.04 machine which eventually has to run on openSUSE 13.1 at work. To make it work on both systems I carefully chose the libraries and the versions to use.
Now I have a problem with the includes. I want to use Qwt 6, which is available on both distributions. The location of the header files differs, though. On Debian they are at /usr/include/qwt/qwt_*.h but on openSUSE they are at /usr/include/qwt6/qwt_*.h. My code currently has #include <qwt/qwt_plot.h>. This does not work on openSUSE since I would have to insert that 6 there.
The easiest solution that I currently see is just including either directory using CMake and then just writing #include <qwt_plot.h> in the source code. However, I think that this is not a really nice solution since those subdirectoryies of /usr/include are there to provide namespaces. Just adding all directories to the include path will mangle those together and might even lead to conflicts.
Is there a nice way to solve this?
In fairness: This is for a project I am paid to work on.
In CMake you can configure platform checks like you could for autoconf. The idea is that you include a config.h file that always exists but use tools to generate that file in each platform. You can check how here but as a summary you can have a config.h.in file with the checks you want to make and use in your headers.
#cmakedefine HAVE_QWT_H
#cmakedefine HAVE_QWT6_H
You then have CMake check if the headers are present and process that file into a final config.h file. In the CMakeLists.txt file you could have the following.
INCLUDE (CheckIncludeFiles)
CHECK_INCLUDE_FILES (qwt/qwt_plot.h HAVE_QWT_H)
CHECK_INCLUDE_FILES (qwt6/qwt_plot.h HAVE_QWT6_H)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
Finally, in your headers, you include the config.h and use the macros to conditionally include one header or another.
// always included
#include "config.h"
// conditionally include headers based one macros from config.h
#ifdef HAVE_QWT_H
#include <qwt/qwt_plot.h>
#elseif HAVA_QWT6_H
#include <qwt6/qwt_plot.h>
#else
#error QWT headers required and not present in supported locations
#endif
Related
I'm (cross-)compiling a shared C library with support for many different platforms which is handled by an hierarchy of CMakeLists files. In those files, several platform specific compiler flags are conditionally produced (with add_definitions()). I can successfully compile and link the source code leading to an appropriate .so file.
But to use the library in any project, I need to provide the right header files, too. The following install command of CMake selects the right header files to copy but does not apply the replacement of preprocessor defines/includes:
install(FILES ${headers} DESTINATION include/mylibrary)
So how can I generate/install the "post-compiled" header files?
What I thought of so far:
As add_definitions() should stack my -D's in the COMPILE_DEFINITIONS variable, maybe running a foreach loop on the copied raw headers and replace the define/include placeholders?
Using add_custom_command() to apply some logic before copying?
Edit: As pointed out by Tsyvarev, there is an answer quite near to my needs here, but unfortunately not quite it. In summary, the answer gives 2 options:
Include a special 'config' header in all of the library's headers and leverage the cmakedefine command to call configure_file() on this header. I can't use this approach because I don't want to alter the library headers.
Create a target-specific .cmake file which helps external projects in including the right headers together with all necessary -D defines. I can't use this approach either, because my external projects do not use cmake for building. Plus, I wish to create a library that is as easy to include as possible.
Any other thoughts?
Edit 2: I may have to elaborate on my statement, that the install command of CMake is not replacing defines. Take the following example:
//sampleheader.hpp
#ifndef SAMPLEHEADER_HPP_
#define SAMPLEHEADER_HPP_
#include OS_SPECIFIC_HEADER
//...
Now I have a CMakeLists.txt file that does something like this:
# ...
if (${OS} MATCHES "arm-emblinux")
add_definitions(-DOS_SPECIFIC_HEADER="emblinuxHeader.hpp")
elseif (${OS} MATCHES "linux")
add_definitions(-DOS_SPECIFIC_HEADER="linuxHeader.hpp")
endif()
# ...
Everything compiles fine, but when the install command above gets called, I have a header file in my ../include/ directory still with OS_SPECIFIC_HEADER placeholder in it. And of course, this cannot be properly included in any development project.
I'm trying to manually add freetype 2.9.0 as a framework build target to my toy project in Xcode. Freetype uses preprocessor macros to include its headers with angled brackets (<freetype/config/xx.h>) which is confusing the Xcode build system and I get the error expected "FILENAME" or <FILENAME>, indicating that it can't find my system level includes. Instead of hardcoding the subfolder headers, how would I configure the Xcode build system to find these config files?
I tried this in another file
#define SOME_CONFIG <glfw/glfw3.h> /*this header is included as a system header in a subfolder <project/glfw/... , and works fine*/
#ifdef SOME_CONFIG
#include SOME_CONFIG
#endif
And it works perfectly. But when I try this with freetype it cannot find the expanded in the macros.
The freetype include structure looks like this:
include/ftbuild.h -- points to include/freetype/config/ftheader.h
include/config/ftheader.h -- has all the #define macros to ->
include/config/... -- a bunch of headers with options which Xcode refuse to see
Apparently it was actually working all along I just forgot to add the environment variable FT2_BUILD_LIBRARY to both debug and release build, and I had it set to debug, so the internal header macros was not being precompiled, and therefore not found. Works perfectly fine to do what I am trying to do in Xcode 9.
I have a solution which contains several projects. My projects (but not all of them) use precompiled headers. I decided to use protobuf and I've met a problem. After generetaing *.pb.h from *.proto by protoc.exe I'm trying to include the header and get the error - precompiled header wasn't included into *.pb.h.
How I can solve this problem? I have an idea (but I don't like it at all) - after protoc generates *.pb.h I can run some script, which'll include my precompiled header into the *.pb.h. But I don't like it because some projects may not use PCH, and PCH file name can be different.
I understand that I can just remove PCH from my projects, but I don't like that idea too.
Dont add the generated myproto.pb.cc to your project. Instead, create a myproto.cpp with
#include "pch.h"
#include "myproto.pb.cc"
I resolved my problem by creating a static library called proto-objects (without PCH) and including all my *pb.h(cpp) files there. After it I link that library to every project where I need my protobuf objects. Profit!
You can disable the pre-compiled header option on a file-by-file basis.
Given that the pch option is intended to speed up compilation, you can turn it off for the whole project, and no further changes should be necessary.
The choice of name of the header file, and the pch file are also selectable per file in the project
Update
The idea behind Microsoft's Pre-compilation PCH system is to
Speed up compilation
Make it easy to use
The header file system in C/C++ is problematic, as it is really a textual replacement.
That means that
#include "localdefs.h"
#include <windows.h>
#include "project.h"
#include "support.h"
Is in no way similar to
#include <windows.h>
#include "project.h"
#include "support.h"
That is because localdefs.h can redefine the behavior of all of the other includes.
Further to this the costs of walking through the complexities of the windows.h header files, is time consuming.
The PCH system tries to solve this by the observation that most projects have a fixed set of include files which are included by most/all of the CPP files.
Defining this set in stdafx.h allows the textual result of that parsing to be pasted in the cpp file and save a lot of work.
If most of the includes in the project are different, then there is no need to use it.
So if you are including the same qt header files in lots of places - add them to a pre-compiled header file. The more of the common includes added to this file, the better the compile speed improvements will be.
Any non-standard cpp file can be excluded by being specifically disabled - examples are "generated files". Where the template generator does not understand the MSVC system.
If all the files are different, then only limited performance benefit will be gained - as each compile would probably also include a pch recompile.
I'm working on a project that system headers can appear in "" and also in <>
for example: "io.h" and <io.h>
I need to determine if the included header is a customer one or not.
someone knows if there is a way to do it?
Aside from "asking the compiler", there is no trivial way to determine if "io.h" or <io.h> is taken from a local directory or somewhere in the standard headers. For example, a program will compile perfectly happily with #include "iostream".
The main difference is that the compiler will look FIRST in the local directory for the file "io.h" when using "io.h", where if you use <io.h> it will look in the include directories specified as "system include directories". However, there is nothing saying that system include directories does not include "current directory" in one way or another.
You can use g++ -M myfile.cpp to list what include files are used in the file "myfile.cpp". Unfortunately, as far as I can tell, there is no such option for Visual Studio.
Edit: The MS compiler does indeed support a similar feature using the /showinclude option.
Take a look to the documentation of your compiler, for example the MS C++ compiler will check system includes after local with quotes (so #include "io.h" will get the system include if there are no io.h local header files), but it won't look locally for angled brackets:
http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx
I guess that you will have to manually check for project files if there are names collisions for include files.
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