Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why create an include/ directory in C and C++ projects?

Tags:

c++

c

include

People also ask

What is the include directory for?

The include directories are added to the INCLUDE_DIRECTORIES directory property for the current CMakeLists file. They are also added to the INCLUDE_DIRECTORIES target property for each target in the current CMakeLists file. The target property values are the ones used by the generators.

What is include path in C?

For include files that are specified as #include "path-spec" , directory search begins in the directory of the parent file and then proceeds through the directories of any grandparent files. That is, the search begins relative to the directory that contains the source file that's being processed.

How do you add your project directory to your compiler include path?

Open the project's Property Pages dialog box. For details, see Set C++ compiler and build properties in Visual Studio. Select the Configuration Properties > C/C++ > General property page. Modify the Additional Include Directories property.

Where does include look for files?

If you declare #include "" , the compiler first searches in current directory of source file and if not found, continues to search in the above retrieved directories. If you declare #include <> , the compiler searches directly in those directories obtained from the above command.


The main reason to do this is that compiled libraries need headers in order to be consumed by the eventual user. By convention, the contents of the include directory are the headers exposed for public consumption. The source directory may have headers for internal use, but those are not meant to be distributed with the compiled library.

So when using the library, you link to the binary and add the library's include directory to your build system's header paths. Similarly, if you install your compiled library to a centralized location, you can tell which files need to be copied to the central location (the compiled binaries and the include directory) and which files don't (the source directory and so forth).


It used to be that <header> style includes were of the implicit path type, that is, to be found on the includes environment variable path or a build macro, and the "header" style includes were of the explicit form, as-in, exactly relative to where-ever the source file is that included it. While some build tool chains still allow for this distinction, they often default to a configuration that effectively nullifies it.

Your question is interesting because it brings up the question of which really is better, implicit or explicit? The implicit form is certainly easier because:

  1. Convenient groupings of related headers in hierarchies of directories.
  2. You only need include a few directories in the includes path and need not be aware of every detail with regard to exact locations of files. You can change versions of libraries and their related headers without changing code.
  3. DRY.
  4. Flexible! Your build environment doesn't have to match mine, but we can often get nearly exact same results.

Explicit on the other hand has:

  1. Repeatable builds. A reordering of paths in an includes macro/environment variable, doesn't change resulting header files found during the build.
  2. Portable builds. Just package everything from the root of the build and ship it off to another dev.
  3. Proximity of information. You know exactly where the header is with #include "\X\Y\Z". In the implicit form, you may have to go searching along multiple paths and might even find multiple versions of the same file, how do you know which one is used in the build?

Builders have been arguing over these two approaches for many decades, but a hybrid form of the two, mostly wins out because of the effort required to maintain builds based purely of the explicit form, and the obvious difficulty one might have familiarizing one's self with code of a purely implicit nature. We all generally understand that our various tool chains put certain common libraries and headers in particular locations, such that they can be shared across users and projects, so we expect to find standard C/C++ headers in one place, but we don't initially know anything about the specific structure of any arbitrary project, lacking a locally well documented convention, so we expect the code in those projects to be explicit with regard to the non-standard bits that are unique to them and implicit regarding the standard bits.

It is a good practice to always use the <header> form of include for all the standard headers and other libraries that are not project specific and to use the "header" form for everything else. Should you have an include directory in your project for your local includes? That depends to some extent on whether those headers will be shipped as interfaces to your libraries or merely consumed by your code, and also on your preferences. How large and complex is your project? If you have a mix of internal and external interfaces or lots of different components, you might want to group things into separate directories.

Keep in mind that the directory structure your finished product unpacks to, need not look anything like the directory structure under which you develop and build that product in. If you have only a few .c/.cpp files and headers, it's ok to put them all in one directory, but eventually, you're going to work on something non-trivial and will have to think through the consequences of your build environment choices, and hopefully document it for others to understand it.


1 . .hpp and .cpp doesn't necessary have 1 to 1 relationship, there may have multiple .cpp using same .hpp according to different conditions (eg:different environments), for example: a multi-platform library, imagine there is a class to get the version of the app, and the header is like that:

Utilities.h

#include <string.h>
class Utilities{
    static std::string getAppVersion();
}

main.cpp

#include Utilities.h
int main(){
    std::cout << Utilities::getAppVersion() << std::ends;
    return 0;
}

there may have one .cpp for each platform, and the .cpp may be placed at different locations so that they are easily be selected by the corresponding platform, eg:

.cpp for iOS (path:DemoProject/ios/Utilities.cpp):

#include "Utilities.h"
std::string Utilities::getAppVersion(){
    //some objective C code
}

.cpp for Android (path:DemoProject/android/Utilities.cpp):

#include "Utilities.h"
std::string Utilities::getAppVersion(){
    //some jni code
}

and of course 2 .cpp would not be used at the same time normally.


2.

#include "file.h" 

instead of

#include "include/file.h" 

allows you to keep the source code unchanged when your headers are not placed in the "include" folder anymore.