Search code examples
c++includegame-engineglfwglew

c++ Library with nested includes


So I'm trying to create my own library in C++ and use it in another project. So far it works with example code, but I have to include other libraries in my own library. So the problem is, that when I include the header files off my library, the include paths in the header files are messed up. A simple solution would be to add the search directories, but I don't think, thats how its supposed to be resolved.

Sample Code - Library header file:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
int test();

The source file:

#include "sample.h"
int test() { return 20; }

Now the project in which I want to include the sample

#include <sample.h>
int main() { int a = test(); }

The problem is, that the include copies the code from sample.h directly into the main.cpp and the search directories for the other includes from sample.h are no longer defined


Solution

  • A simple solution would be to add the search directories, but I don't think, thats how its supposed to be resolved.

    This is certainly the easiest solution since it requires no modifications to the code, and is usually an acceptable thing to do - however obviously it means the project can call the functions from glew.h and glfw3.h


    The only alternative is to ensure the headers are not included by the library header, but instead by the source.

    IE:

    Library Header:

    int test();
    

    Library Source:

    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    #include "sample.h"
    int test() { return 20; }
    

    And the project's source file left unchanged.

    This requires that the types defined in glew.h and glfw3.h are not part of the public interface exposed by your library.

    Eg, if your library had a function like:

    GLFWwindow* window = openWindow(...);
    

    You would need to change it to:

    Library header:

    struct WindowHandle;
    WindowHandle* openWindow(...);
    

    Library source:

    struct WindowHandle{
        GLFWwindow* window;
    };
    
    WindowHandle* openWindow(...){
        WindowHandle* result;
        //... do stuff...
        result->window = //whatever;
        return result;
    }
    

    This approach requires changing the library code, but has the advantage that the users of the library can't directly call the things the library depends on (glew and glfw in this case). This is particularly beneficial if you want to support multiple platforms, you could have a source file for opening windows via glfw, and another using direct x. The library's public interface would not need to be changed to support both backends.

    If you want to know more about this approach try searching for "Opaque data types"