Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Handle Resources in a C++ library

I'm building a very light-weight library/wrapper for OpenGL and I've run into a little problem. Let's say I have a directory structure that looks sort of like this:

GraphicsProject
|GraphicsApp
||main.cpp
|GraphicsLib
||include
|||fileA.h
|||fileB.h
||library
|||fileA.cpp
|||fileB.cpp
||shaders
|||shader1.txt
|||shader2.txt
|| build
||| bunch of build stuff

What is the best way to get the path to shader1.txt at runtime? Or else, make it such that the path will not change no matter who is using this project or where it is located on a user's machine?

Some options I've considered: 1) Get the current working directory and use that path to work my way up to where I need to be. My main concern with this solution is that I'm not sure how much the current directory will change based on how the user builds the project or other factors out of my control. It also doesn't feel very elegant. 2) Store the source code for the shaders as char arrays/strings in a .h file that is in the include directory. This seems like a better solution, except that it would make writing the shaders slightly more cumbersome.

Is there a standard way of doing this? I'm using CMake to build the project, if that changes anything.

like image 913
williamg Avatar asked Aug 03 '13 22:08

williamg


1 Answers

I'm assuming you're talking about making the "shaders" folder available to other devs who are building your project, since if you meant end-users (which would involve installing the components) you wouldn't be talking about build folders.

I think the simplest way to provide a fixed location to the shaders folder at runtime is to copy it from your source tree to your build tree. In this way, other devs can place their root build folder anywhere outside your project (or even inside if they want) and the app will still have a single fixed relative path to deal with when accessing the copied shaders folder.

There are other options in case you don't want to copy (e.g. you could have CMake write a config file to the build tree; the config file could specify the path to the shaders folder) but I think they're more complex and probably more fragile. Regardless, I think the crux is to copy info from the source tree to the build tree at configure-time (when CMake executes), so that the runtime code doesn't involve a difficult search for the potentially very distant source tree.

An example root CMakeLists.txt would be:

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(example)

add_executable(GraphicsApp GraphicsApp/main.cpp)
add_library(GraphicsLib
    GraphicsLib/library/fileA.cpp
    GraphicsLib/library/fileB.cpp
    GraphicsLib/include/fileA.h
    GraphicsLib/include/fileB.h
    GraphicsLib/shaders/shader1.txt
    GraphicsLib/shaders/shader2.txt
    )
include_directories(GraphicsLib/include)
target_link_libraries(GraphicsApp GraphicsLib)

add_custom_command(TARGET GraphicsApp POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${CMAKE_SOURCE_DIR}/GraphicsLib/shaders
        $<TARGET_FILE_DIR:GraphicsApp>/shaders)

To expand a little on the add_custom_command call, this basically causes the "shaders" subdirectory to be copied to the folder where GraphicsApp will be built to. The command executes any time GraphicsApp is built. If GraphicsApp is built and up to date and you try and rebuild it, the custom command won't execute.

The custom command actually executes

cmake -E copy_directory <path to shaders source> <path to shaders copy>

making use of CMake's -E cross-platform command mode.

The "destination" part of the command (the "copy to" location) uses a generator expression to deduce the location where GraphicsApp will be built to: $<TARGET_FILE_DIR:GraphicsApp>. This is probably the most robust way of achieving that aim; it will be correct regardless of config type (where e.g. MSVC inserts a "Debug/" or "Release/" folder to the build path).

So this hopefully gets you most of the way to your aim. I imagine you still have to get the full path to the running exe to then deduce the full path to the copied shaders folder. However, this should be much more simple and robust than searching from the current working directory. Even calculating the current working dir is non-trivial.

like image 163
Fraser Avatar answered Oct 18 '22 22:10

Fraser