Francis Cugler
Francis Cugler

Reputation: 7925

How to properly navigate directory paths in C++

I'm working on a solution within Visual Studio. It currently has two projects.

I will represent Directories or folders with capitals letters, and filenames will be all lower case. My solution structure is as follows:

Within ProjectLib I have a function to open and read my Shader files. Here is what my function looks like:

std::vector<char> VRXShader::readFile(std::string_view shadername) {
    std::string filename = std::string("Shaders/");
    filename.append(shadername);

    std::ifstream file(filename.data(), std::ios::ate | std::ios::binary);

    if (!file.is_open()) {
        throw std::runtime_error("failed to open file!");
    }

    size_t fileSize = static_cast<size_t>(file.tellg());
    std::vector<char> buffer(fileSize);

    file.seekg(0);
    file.read(buffer.data(), fileSize);
    
    file.close();

    return buffer;       
}

This function is being called within my VRXDevices::createPipeline function and here is the relevant code:

void VRXDevices::createPipeline(
    VkDevice device, VkExtent2D swapChainExtent, VkRenderPass renderPass, 
    const std::vector<std::string_view>& shaderNames, 
    VkPipelineLayout& pipelineLayout, VkPipeline& pipeline
) {
    std::vector<std::vector<char>> shaderCodes;
    shaderCodes.resize(shaderNames.size());

    for (auto& name : shaderNames) {
        auto shaderCode = VRXShader::readFile(name.data());
    }

    // .... more code
}

The names are being created and passed to this function from my VRXEngine::initVulkan function which can be seen here:

void VRXEngine::initVulkan(
    std::string_view app_name, std::string_view engine_name, 
    glm::ivec3 app_version, glm::ivec3 engine_version
) {
    //... code

    std::vector<std::string_view> shaderFilenames{ "vert.spv", "frag.spv" };
    VRXDevices::createPipeline(device_, swapChainExtent_, renderPass_, shaderFilenames, pipelineLayout_, graphicsPipeline_);
    
}

I'm using just the name of the shader files such as vert.spv, frag.spv, geom.spv etc. I'm not including the paths here because these will be used as the key to a std::map<string_view, object>. So I'm passing a vector of these names from my ::initVulkan function into ::createPipeline().

Within ::createPipeline() is where ::readFile() is being called passing in the string_view.

Now as for my question... within ::readFile() I'm creating a local string and trying to initialize it with the appropriate path... then append to it the string_view for the shader's filename as can be seen from these two lines...

std::string filename = std::string("Shaders/");
filename.append(shadername);

I'm trying to figure out the appropriate string to initialize filename with... Shaders/ will be a part of the name, but it's not finding the file and I'm not sure what the appropriate prefix should be...

My working directories within both projects are as follows:

So I need to go back 2 directories then into VRX Engine/Shader...

What is the correct string value for navigating back directories?

Would I initialize filename with "../../VRX Engine/Shaders/" or is it "././" also, should I have quotes around VRX Engine since there is a space in the folder name? What do I need to initialize filename with before I append the shader name to it?

Upvotes: 1

Views: 3177

Answers (2)

How to properly navigate directory paths in C++

It depends on which C++ standard your implementation claims to be compliant with.

Or else which additional libraries can you use.

C++ is useful on computers without directories (e.g. inside some operating system kernel coded in C++ and compiled with GCC, see OSDEV for examples).

Look on en.cppreference.com for details.

Licensing constraints could matter when using extra open source libraries.

If your implementation is C++17 compliant (in a "hosted" not "freestanding" way), use the std::filesystem part of the standard library.

If your operating system supports the Qt or POCO frameworks and you are allowed to use them (e.g. on C++11), you could use appropriate APIs. So QDir and related classes with Qt, Poco::Path and related classes with POCO.

Perhaps you want to code just for the WinAPI. Then read its documentation (I never coded on Windows myself, just on POSIX or Unix -e.g. Linux- and MSDOS....).

Upvotes: 1

Francis Cugler
Francis Cugler

Reputation: 7925

I was originally initializing my local temp string properly with "../../VRX Engine/Shaders/" before appending the string_view to it to be able to open the file. This was actually correct, but because it didn't initially work, I was assuming that it was wrong.

The correct string value for going back one directory should be "../" at least on Windows, I'm not sure about Linux, Mac, Android, etc...

My problem wasn't with the string at all, it pertained to settings within my projects. Within my project that builds into an executable, I had its working directory set to $(SolutionDir)x64/Debug and $(SolutionDir)x64/Release respectively which is correct for my solutions structure.

The issue was within my Engine project that is being built as a static library. Within its settings for its working directory, I had forgotten to modify both of the Debug and Release build options... These were still set to the default values of Visual Studio which I believe is (ProjectDir). Once I changed these to $(SolutionDir)x64/Debug and $(SolutionDir)x64/Release to match that of my ApplicationProject, I was able to open and read the contents of the files.

Upvotes: 0

Related Questions