Skip to content

Code samples: add CMakeLists.txt #249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 19, 2021
Merged

Code samples: add CMakeLists.txt #249

merged 1 commit into from
Sep 19, 2021

Conversation

kovrov
Copy link
Contributor

@kovrov kovrov commented Aug 21, 2021

Calling cmake --build . will build the sample code executables for each
chapter in it's own folders, compile corresponding shaders and copy all
required resources to appropriate sub-folders. After that any example is
ready to be run from it's build sub-folder.

CMake project requires following dependencies:

  • glfw3 dev package
  • glm dev package
  • stb_image header
  • tinyobjloader dev package
  • Vulkan sdk

@kovrov
Copy link
Contributor Author

kovrov commented Aug 22, 2021

I hadn't had a chance to test this on a windows box. Only on linux (ubuntu) and osx.

@Overv
Copy link
Owner

Overv commented Aug 22, 2021

That is quite cool, nice setup! If this is merged, it should probably also be referenced by the tutorial as a possible example of how to set up Vulkan projects. I can try to test it on Windows sometime this week.

Calling `cmake --build .` will build the sample code executables for each
chapter in it's own folders, compile corresponding shaders and copy all
required resources to appropriate sub-folders. After that any example is
ready to be run from it's build sub-folder.

CMake project requires following dependencies:
* glfw3 dev package
* glm dev package
* stb_image header
* tinyobjloader dev package
* Vulkan sdk
@kovrov
Copy link
Contributor Author

kovrov commented Aug 24, 2021

I just realized I was calling glslangvalidator with --target-env vulkan1.2. Fixed to match the value used in VkApplicationInfo::apiVersion.

@Overv
Copy link
Owner

Overv commented Aug 25, 2021

I get the following errors when trying to build on Arch Linux:

$ cmake .
CMake Error at CMakeLists.txt:46 (add_executable):
  Target "27_model_loading" links to target "glm::glm" but the target was not
  found.  Perhaps a find_package() call is missing for an IMPORTED target, or
  an ALIAS target is missing?
Call Stack (most recent call first):
  CMakeLists.txt:156 (add_chapter)
...

$ cmake --build .
[  1%] Generating 27_model_loading/shaders
[  2%] Compiling Shaders
[  2%] Built target 27_model_loading_shader
[  3%] Building CXX object CMakeFiles/27_model_loading.dir/27_model_loading.cpp.o
[  4%] Linking CXX executable 27_model_loading/27_model_loading
/usr/bin/ld: cannot find -lglm::glm
/usr/bin/ld: cannot find -ltinyobjloader::tinyobjloader
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/27_model_loading.dir/build.make:106: 27_model_loading/27_model_loading] Error 1
make[1]: *** [CMakeFiles/Makefile2:214: CMakeFiles/27_model_loading.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

When I change all glm::glm references to just glm and tinyobjloader::tinyobjloader to just tinyobjloader everything works just fine. Do you know what might be up with that? This is with cmake version 3.21.1.

@kovrov
Copy link
Contributor Author

kovrov commented Aug 25, 2021

This is interesting, looks like a "downstream" issue. Different distros may provide and maintain its own cmake configs for the dev packages.

On my ubuntu box (20.04) the glm package (0.9.9.7) is installed from ubuntu repo. The library is declared as "glm::glm" (in /usr/lib/cmake/glm/glmConfig.cmake):

add_library(glm::glm INTERFACE IMPORTED)

tinyobjloader is in similar situation - /usr/lib/x86_64-linux-gnu/cmake/tinyobjloader/tinyobjloader-targets.cmake (although libtinyobjloader-dev is not from 20.04, but rather was backported from 20.10):

add_library(tinyobjloader::tinyobjloader SHARED IMPORTED)

What's interesting is that on my macbook, the packages (installed via homebrew formulas) has the same target names. I was hoping this is universal naming convention.

Since glm is a header-only library, the only reason to "findpackage" and "link" it to the executable is to configure include paths (imported targets usually has INTERFACE_INCLUDE_DIRECTORIES property).

tinyobjloader on the other side, is an actual library we need to link against. And as far as I remember on mac, simply linking via -ltinyobjloader was failing (likely because it is not located on standard library paths).

Edit:

For what it worth, the glm manual specifies its cmake module as "glm::glm" (https://github.com/g-truc/glm/blob/master/manual.md#-15-finding-glm-with-cmake):

find_package(glm REQUIRED)
target_link_libraries(<your executable> glm::glm)

@kovrov
Copy link
Contributor Author

kovrov commented Aug 30, 2021

@Overv what are the versions of installed tinyobjloader and glm dev packages?

@Overv
Copy link
Owner

Overv commented Sep 1, 2021

The versions I have installed are:

  • glm: 0.9.9.8-1
  • tinyobjloader: The header says 1.4.0, although that release/tag doesn't seem to exist in the repo. Anyhow, the library is installed from a commit on Dec 15 2018.

I'm not sure why this is happening since I know very little about cmake myself.

The line you mention (add_library) is not in my glmConfig.cmake, but the following line is in my glmTargets.cmake:

add_library(glm INTERFACE IMPORTED)

I'm not sure why they are using a different name in the Arch Linux package.

Update: I've created a bug report to ask about this: https://bugs.archlinux.org/task/71987

@kovrov
Copy link
Contributor Author

kovrov commented Sep 1, 2021

Weird, since glm release 0.9.9.8 cmake target should be glm::glm. On the other hand your tinyobjloader library is indeed old and don't have latest cmake changes.

Anyway. This is not important. We know that correct targets are glm::glm and tinyobjloader::tinyobjloader. And this specific problem is in dev environment. Possible solutions are:

  1. Keep this change as is and rely on users to "correct" their environment if needed.

  2. Add a workaround in our cmake project, e.g:

    if (NOT TARGET tinyobjloader::tinyobjloader)
      add_library(tinyobjloader::tinyobjloader ALIAS tinyobjloader)
    endif ()
    if (NOT TARGET glm::glm)
      add_library(glm::glm ALIAS glm)
    endif ()
    

More importantly, I'd like to see if there are any issues on windows.

@Overv
Copy link
Owner

Overv commented Sep 3, 2021

I just tested it on Windows and ran into a few small issues:

  1. It couldn't find GLFW by itself:
CMake Error at CMakeLists.txt:5 (find_package):
  By not providing "Findglfw3.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "glfw3", but
  CMake did not find one.

  Could not find a package configuration file provided by "glfw3" with any of
  the following names:

    glfw3Config.cmake
    glfw3-config.cmake

  Add the installation prefix of "glfw3" to CMAKE_PREFIX_PATH or set
  "glfw3_DIR" to a directory containing one of the above files.  If "glfw3"
  provides a separate development package or SDK, be sure it has been
  installed.

It looks like it couldn't automatically find glfw3 because it installs into a directory called GLFW by default due to the project name being GLFW rather than glfw3. When I rename the install directory to glfw3 it works just fine. This is a known issue.

  1. It also couldn't find stb_image.h by itself, which makes sense.
CMake Error at CMakeLists.txt:17 (message):
  stb_image.h not found

However, it did find both glm and tinyobjloader automatically without any issues.

After generating all of the projects I could build them just fine with Visual Studio 2017. However, the executables crash because they can't find glfw3.dll. After manually copying glfw3.dll to the directory containing the executable, it starts running but crashes with a runtime exception failed to open file! because it cannot find the compiled shader shaders/vert.spv.

I fixed this by changing the "Working Directory" in the "Debugging" section of the project settings from $(ProjectDir) to $(ProjectDir)$(ProjectName). This can be fixed in CMake by adding the following line to CMakeLists.txt in add_chapter:

set_target_properties (${CHAPTER_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/${CHAPTER_NAME}")

I'm not sure what to do about the dll issue, but we should probably just recommend users to add glfw3.dll to their path.

@kovrov
Copy link
Contributor Author

kovrov commented Sep 3, 2021

Thanks!

Where is stb_image.h located on your windows box?

This statement is basically searches for stb_image.h in standard include locations (e.g. /usr/include, /usr/include/ARCH, /usr/ARCH/include, etc.) with additional subdirectory stb to check below each standard directory:

find_path (STB_INCLUDEDIR stb_image.h PATH_SUFFIXES stb)

In my case it is in /usr/include/stb/stb_image.h

Solution would be to set CMAKE_INCLUDE_PATH override in visual studio project (equivalent of -DCMAKE_INCLUDE_PATH=/path/to/stb command line argument).

@kovrov
Copy link
Contributor Author

kovrov commented Sep 3, 2021

I guess the runtime problem finding the dll is caused by changed location of the GLFW binary dir.

Try this - instead of manually renaming GLFW folder to glfw3, configure and build GLFW with CMAKE_INSTALL_PREFIX set to C:/Program Files (x86)/glfw3 and then install. E.g.:

cmake -DCMAKE_INSTALL_PREFIX="C:/Program Files (x86)/glfw3" ../glfw
cmake --build .
cmake --install .

When CMAKE_INSTALL_PREFIX not set, it going be something like c:/Program Files/${PROJECT_NAME} by default, which sounds like your case.

@Overv
Copy link
Owner

Overv commented Sep 5, 2021

Where is stb_image.h located on your windows box?

In ~/source/libs/stb-master where ~ is my Windows home directory. To my knowledge there is no standard include location in Windows so I wouldn't know where else to put it.

Try this - instead of manually renaming GLFW folder to glfw3, configure and build GLFW with CMAKE_INSTALL_PREFIX set to C:/Program Files (x86)/glfw3 and then install. E.g.:

That didn't make a difference for me. I think that it'll only find glfw3.dll automatically if it's either in the same directory as the executable or in the system path. It doesn't look like cmake is adding any directories (like C:/Program Files (x86)/glfw3) to the system path as part of the install process.

With that said, we could avoid this situation by statically linking glfw3 on Windows.

On a sidenote, the issue with the glm target being named differently in Arch will be fixed soon.

@kovrov
Copy link
Contributor Author

kovrov commented Sep 5, 2021

Configuring with -DCMAKE_INCLUDE_PATH=~/source/libs/stb-master argument (visual studio may have a gui to define cmake variables) should fix the failing check for stb_image.h.

@Overv
Copy link
Owner

Overv commented Sep 7, 2021

Configuring with -DCMAKE_INCLUDE_PATH=~/source/libs/stb-master argument (visual studio may have a gui to define cmake variables) should fix the failing check for stb_image.h.

Alright, but then you might as well configure STB_INCLUDEDIR directly.

@kovrov
Copy link
Contributor Author

kovrov commented Sep 7, 2021

Configuring with -DCMAKE_INCLUDE_PATH=~/source/libs/stb-master argument (visual studio may have a gui to define cmake variables) should fix the failing check for stb_image.h.

Alright, but then you might as well configure STB_INCLUDEDIR directly.

STB_INCLUDEDIR is meant to be set automatically on environments that either provides stb pkgconf file (e.g. ubuntu) or has the stb headers on standard locations.

Unfortunately upstream STB is not providing any config packages, because it is designed to be project-level drop-in headers.

If there is a well known windows development practice when it comes to 3rd party libraries locations, we could hard-code additional paths argument (called HINTS) to find_path invocation. Otherwise, there is nothing else I can think of but requiring user to setCMAKE_INCLUDE_PATH (which was designed exactly for this purpose).

@Overv
Copy link
Owner

Overv commented Sep 8, 2021

STB_INCLUDEDIR is meant to be set automatically on environments that either provides stb pkgconf file (e.g. ubuntu) or has the stb headers on standard locations.

Right, but I don't think it's common to have all header files together in a single directory like with /usr/include on Linux. That's why I figured that it made more sense to specify an include directory per library rather than to give CMake one global include path.

If there is a well known windows development practice when it comes to 3rd party libraries locations, we could hard-code additional paths argument (called HINTS) to find_path invocation.

I don't think there is any, unfortunately. I don't know of any myself and I couldn't find any suggestions online either.

@kovrov
Copy link
Contributor Author

kovrov commented Sep 8, 2021

I agree - having headers for all libraries in single default location is not ideal. My point is that additional include paths (plural), if required, meant to be configured by user via well known CMAKE_INCLUDE_PATH variable. STB_INCLUDEDIR is just one of internal variables.

Speaking of glfw3 runtime issue - adding glfw library location to PATH env variable is another alternative to copying the dll to each binary's folder or statically linking.

@Overv
Copy link
Owner

Overv commented Sep 19, 2021

Would you consider this ready to be merged now?

@kovrov
Copy link
Contributor Author

kovrov commented Sep 19, 2021

Would you consider this ready to be merged now?

Yes, I think it's ready.

@Overv Overv merged commit 5f0a745 into Overv:master Sep 19, 2021
@Overv
Copy link
Owner

Overv commented Sep 19, 2021

Nice, thanks again for the work in putting this together.

Overv added a commit that referenced this pull request Mar 8, 2023
Code samples: add CMakeLists.txt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants