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.
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 install
ing 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With