I'm creating a game using opengl, glfw and glm. Now I have two projects, the engine (named Cheetah) and the game. The engine is a dll library and the game implements that library. Both the engine and the game projects contain a CMakeLists.txt, and there is one top level CMakeLists.txt that builds both.
The folder structure is as below:
The issue
I'm trying to add glm to the library, but now I'm running in to the issue that I can build my library but I'm unable to build the game project that implements the library, throwing the compile error:
Error C1083 Cannot open include file: 'glm/common.hpp': No such file
or
directory C:\Projects\Game\out\build\x64-Debug\Game C:\Projects\Game\Cheetah\src\Engine\Renderer\OrthoGraphicCamera.h
Here are the CMake files per project:
Cheetah(Engine project)
# CMakeList.txt : CMake project for Cheetah, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.8)
project ("Cheetah")
# Platform defines
IF (WIN32)
add_compile_definitions(CH_PLATFORM_WINDOWS)
ELSE()
# set stuff for other systems
ENDIF()
#----------------------------------------------
# ADD CHEETAH LIBRARY
#----------------------------------------------
message(${PROJECT_SOURCE_DIR})
# Define Cheetah variables
set(LIB_DIR "${PROJECT_SOURCE_DIR}/dependencies")
set(INCLUDES_DIR_PUBLIC "${PROJECT_SOURCE_DIR}/includes")
set(INCLUDES_DIR_PRIVATE "${PROJECT_SOURCE_DIR}/src")
set(ENGINE_DIR "${PROJECT_SOURCE_DIR}/src/Engine")
set(ENGINE_CORE_DIR "${ENGINE_DIR}/Core")
set(ENGINE_INPUT_DIR "${ENGINE_DIR}/Input")
set(ENGINE_EVENTS_DIR "${ENGINE_DIR}/Events")
set(ENGINE_RENDERER_DIR "${ENGINE_DIR}/Renderer")
set(ENGINE_DEBUG_DIR "${ENGINE_DIR}/Debug")
set(ENGINE_MATH_DIR "${ENGINE_DIR}/Math")
set(ENGINE_RESOURCES_DIR "${ENGINE_DIR}/Resources")
set(PLATFORM_DIR "${PROJECT_SOURCE_DIR}/src/Platform")
set(PLATFORM_WINDOWS_DIR "${PLATFORM_DIR}/Windows")
set(PLATFORM_OPENGL_DIR "${PLATFORM_DIR}/OpenGL")
# Set default files
list(APPEND SOURCE_FILES
"${ENGINE_DIR}/Engine.h"
"${ENGINE_CORE_DIR}/Application.h"
"${ENGINE_CORE_DIR}/Application.cpp"
"${ENGINE_CORE_DIR}/Core.h"
"${ENGINE_CORE_DIR}/EntryPoint.h"
"${ENGINE_CORE_DIR}/Window.h"
"${ENGINE_CORE_DIR}/UpdateLayer.h"
"${ENGINE_CORE_DIR}/UpdateLayer.cpp"
"${ENGINE_CORE_DIR}/UpdateLayerQueue.h"
"${ENGINE_CORE_DIR}/UpdateLayerQueue.cpp"
"${ENGINE_CORE_DIR}/Time.h"
"${ENGINE_CORE_DIR}/Time.cpp"
"${ENGINE_RENDERER_DIR}/RenderAction.h"
"${ENGINE_RENDERER_DIR}/RenderAction.cpp"
"${ENGINE_RENDERER_DIR}/GraphicsContext.h"
"${ENGINE_RENDERER_DIR}/GraphicsContext.cpp"
"${ENGINE_RENDERER_DIR}/RenderAPI.h"
"${ENGINE_RENDERER_DIR}/RenderAPI.cpp"
"${ENGINE_RENDERER_DIR}/Renderer.h"
"${ENGINE_RENDERER_DIR}/Renderer.cpp"
"${ENGINE_RENDERER_DIR}/Renderer2D.h"
"${ENGINE_RENDERER_DIR}/Renderer2D.cpp"
"${ENGINE_RENDERER_DIR}/IndexBuffer.h"
"${ENGINE_RENDERER_DIR}/IndexBuffer.cpp"
"${ENGINE_RENDERER_DIR}/VertexBuffer.h"
"${ENGINE_RENDERER_DIR}/VertexBuffer.cpp"
"${ENGINE_RENDERER_DIR}/VertexArray.h"
"${ENGINE_RENDERER_DIR}/VertexArray.cpp"
"${ENGINE_RENDERER_DIR}/Shader.h"
"${ENGINE_RENDERER_DIR}/Shader.cpp"
"${ENGINE_RENDERER_DIR}/VertexBufferLayout.h"
"${ENGINE_RENDERER_DIR}/VertexBufferLayout.cpp"
"${ENGINE_RENDERER_DIR}/Texture.h"
"${ENGINE_RENDERER_DIR}/Texture.cpp"
"${ENGINE_RENDERER_DIR}/OrthoGraphicCamera.h"
"${ENGINE_RENDERER_DIR}/OrthoGraphicCamera.cpp"
"${ENGINE_RENDERER_DIR}/Renderer2DQueue.h"
"${ENGINE_RENDERER_DIR}/Renderer2DQueue.cpp"
"${ENGINE_INPUT_DIR}/Input.h"
"${ENGINE_INPUT_DIR}/Input.cpp"
"${ENGINE_EVENTS_DIR}/ApplicationEvents.h"
"${ENGINE_EVENTS_DIR}/ApplicationEvents.cpp"
"${ENGINE_EVENTS_DIR}/Event.h"
"${ENGINE_EVENTS_DIR}/Event.cpp"
"${ENGINE_EVENTS_DIR}/EventDispatcher.h"
"${ENGINE_EVENTS_DIR}/EventDispatcher.cpp"
"${ENGINE_EVENTS_DIR}/EventTypes.h"
"${ENGINE_EVENTS_DIR}/InputEvents.h"
"${ENGINE_EVENTS_DIR}/InputEvents.cpp"
"${ENGINE_RESOURCES_DIR}/ResourceCache.h"
"${ENGINE_RESOURCES_DIR}/ResourceCache.inl"
"${ENGINE_RESOURCES_DIR}/ResourceLoader.h"
"${ENGINE_RESOURCES_DIR}/ResourceLoader.cpp"
)
# Set platform specific files
# Windows
list(APPEND SOURCE_FILES_WINDOWS
"${PLATFORM_WINDOWS_DIR}/WindowsWindow.h"
"${PLATFORM_WINDOWS_DIR}/WindowsWindow.cpp"
"${PLATFORM_WINDOWS_DIR}/WindowsTime.h"
"${PLATFORM_WINDOWS_DIR}/WindowsTime.cpp"
"${PLATFORM_WINDOWS_DIR}/WindowsInput.h"
"${PLATFORM_WINDOWS_DIR}/WindowsInput.cpp"
)
# OpenGL
list(APPEND SOURCE_FILES_OPENGL
"${PLATFORM_OPENGL_DIR}/OpenGLRenderAPI.h"
"${PLATFORM_OPENGL_DIR}/OpenGLRenderAPI.cpp"
"${PLATFORM_OPENGL_DIR}/OpenGLGraphicsContext.h"
"${PLATFORM_OPENGL_DIR}/OpenGLGraphicsContext.cpp"
"${PLATFORM_OPENGL_DIR}/OpenGLVertexBuffer.h"
"${PLATFORM_OPENGL_DIR}/OpenGLVertexBuffer.cpp"
"${PLATFORM_OPENGL_DIR}/OpenGLIndexBuffer.h"
"${PLATFORM_OPENGL_DIR}/OpenGLIndexBuffer.cpp"
"${PLATFORM_OPENGL_DIR}/OpenGLShader.h"
"${PLATFORM_OPENGL_DIR}/OpenGLShader.cpp"
"${PLATFORM_OPENGL_DIR}/OpenGLVertexArray.h"
"${PLATFORM_OPENGL_DIR}/OpenGLVertexArray.cpp"
"${PLATFORM_OPENGL_DIR}/OpenGLTexture.h"
"${PLATFORM_OPENGL_DIR}/OpenGLTexture.cpp"
)
list(APPEND SOURCE_FILES ${SOURCE_FILES_OPENGL})
# Append Platform specific files
# Operating platform
IF (WIN32)
list(APPEND SOURCE_FILES ${SOURCE_FILES_WINDOWS})
# TODO: Linux
# TODO: MacOS
# TODO: Android
# TODO: IOS
ENDIF()
# Add source to this project's executable.
add_library(Cheetah SHARED ${SOURCE_FILES})
target_include_directories (Cheetah INTERFACE ${INCLUDES_DIR_PUBLIC})
target_include_directories (Cheetah PRIVATE ${ENGINE_DIR})
target_include_directories (Cheetah PRIVATE ${INCLUDES_DIR_PRIVATE})
# Add compile definitions
list(APPEND CHEETAH_COMP_DEFS
"CH_BUILD_DLL"
${RENDER_API}
)
target_compile_definitions(Cheetah PRIVATE ${CHEETAH_COMP_DEFS})
target_compile_definitions(Cheetah PUBLIC "$<$<CONFIG:DEBUG>:DEBUG>")
target_compile_definitions(Cheetah PUBLIC "$<$<CONFIG:DEBUG>:CH_ASSERT_ENABLED>")
set_target_properties(Cheetah PROPERTIES LINKER_LANGUAGE CXX)
# Copy dll to game project build folder
IF(${APPLICATION_NAME})
message("---------------------------------------------------------------------")
add_custom_command(
TARGET Cheetah
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${PROJECT_BINARY_DIR}/Cheetah.dll"
"${PROJECT_BINARY_DIR}/${APPLICATION_NAME}"
)
ENDIF()
#----------------------------------------------
# ADD OPENGL LIBRARY DEPENDENCY
#----------------------------------------------
find_package(OpenGL REQUIRED)
target_link_libraries(Cheetah ${OpenGL})
#----------------------------------------------
# ADD GLFW LIBRARY DEPENDENCY
#----------------------------------------------
set(GLFW_DIR "${LIB_DIR}/glfw")
set(GLFW_BUILD_EXAMPLES OFF CACHE INTERNAL "Build the GLFW example programs")
set(GLFW_BUILD_TESTS OFF CACHE INTERNAL "Build the GLFW test programs")
set(GLFW_BUILD_DOCS OFF CACHE INTERNAL "Build the GLFW documentation")
set(GLFW_INSTALL OFF CACHE INTERNAL "Generate installation target")
add_subdirectory("${GLFW_DIR}")
target_include_directories(Cheetah PRIVATE "${GLFW_DIR}/include")
target_link_libraries(Cheetah "glfw" "${GLFW_LIBRARIES}")
target_compile_definitions(Cheetah PRIVATE "GLFW_INCLUDE_NONE")
#----------------------------------------------
# ADD GLAD LIBRARY DEPENDENCY
#----------------------------------------------
set(GLAD_DIR "${LIB_DIR}/glad")
add_library("glad" "${GLAD_DIR}/src/glad.c")
target_include_directories("glad" PRIVATE "${GLAD_DIR}/include")
target_include_directories(Cheetah PUBLIC "${GLAD_DIR}/include")
target_link_libraries(Cheetah "glad" "${CMAKE_DL_LIBS}")
#----------------------------------------------
# ADD STB_IMAGE LIBRARY DEPENDENCY
#----------------------------------------------
set(STB_IMAGE_DIR "${LIB_DIR}/stb_image")
add_library("stb_image" "${STB_IMAGE_DIR}/stb_image.cpp")
target_include_directories("stb_image" PRIVATE "${STB_IMAGE_DIR}/include")
target_include_directories(Cheetah PUBLIC "${STB_IMAGE_DIR}/include")
target_link_libraries(Cheetah "stb_image" "${CMAKE_DL_LIBS}")
#---------------------------------------------
# ADD GLM LIBRARY DEPENDENCY
# --------------------------------------------
set(GLM_DIR "${LIB_DIR}/glm")
add_subdirectory("${LIB_DIR}/glm")
target_include_directories(Cheetah PRIVATE "${GLM_DIR}/glm")
target_link_libraries(Cheetah glm)
Game
# CMakeList.txt : CMake project for Cheetah, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.13)
set(SOURCE_DIR "${PROJECT_SOURCE_DIR}/Game/src")
list(APPEND SOURCE_FILES
"${SOURCE_DIR}/Main.cpp"
"${SOURCE_DIR}/GameLayer.cpp"
"${SOURCE_DIR}/GameLayer.h"
"${SOURCE_DIR}/GameObject.h"
"${SOURCE_DIR}/GameObject.cpp"
"${SOURCE_DIR}/Scene.h"
"${SOURCE_DIR}/Scene.cpp"
"${SOURCE_DIR}/GameScene.h"
"${SOURCE_DIR}/GameScene.cpp"
)
# Platform defines
IF (WIN32)
add_compile_definitions(CH_PLATFORM_WINDOWS)
ELSE()
# set stuff for other systems
ENDIF()
find_library( CHEETAH_LIB
NAMES Cheetah
HINTS "${CMAKE_BINARY_DIR}/Cheetah")
# Add source to this project's executable.
add_executable (Game ${SOURCE_FILES})
target_include_directories(Game PUBLIC "${PROJECT_SOURCE_DIR}/Cheetah/includes")
# TODO: Add tests and install targets if needed.
target_link_libraries(Game ${CHEETAH_LIB})
Top level CMakeList
# CMakeList.txt : Top-level CMake project file, do global configuration
# and include sub-projects here.
#
cmake_minimum_required (VERSION 3.8)
project ("Game")
set(APPLICATION_NAME "Game")
set(RENDER_API "OPENGL")
# Include sub-projects.
add_subdirectory("Cheetah")
add_subdirectory ("Game")
Anything that could point me in the right direction is much appreciated!
The include directories you specify for the Game target is a pretty short list, compared to what you specify for Cheetah:
target_include_directories(Game PUBLIC "${PROJECT_SOURCE_DIR}/Cheetah/includes")
It seems like you may need some of these Cheetah include directories for Game as well.
Note: If you are willing to re-organize the design of these two projects to always use the top-level CMake file, there is no need to use find_library() to find the Cheetah library. CMake already knows about the Cheetah target, as it was just created! The Game CMakeLists.txt file could look like this:
# CMakeList.txt : CMake project for Game, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.13)
set(SOURCE_DIR "${PROJECT_SOURCE_DIR}/Game/src")
list(APPEND SOURCE_FILES
"${SOURCE_DIR}/Main.cpp"
"${SOURCE_DIR}/GameLayer.cpp"
"${SOURCE_DIR}/GameLayer.h"
"${SOURCE_DIR}/GameObject.h"
"${SOURCE_DIR}/GameObject.cpp"
"${SOURCE_DIR}/Scene.h"
"${SOURCE_DIR}/Scene.cpp"
"${SOURCE_DIR}/GameScene.h"
"${SOURCE_DIR}/GameScene.cpp"
)
# Platform defines
# Note, this block can also be removed if target_compile_definitions
# is used for Cheetah instead.
IF (WIN32)
add_compile_definitions(CH_PLATFORM_WINDOWS)
ELSE()
# set stuff for other systems
ENDIF()
# Add source to this project's executable.
add_executable (Game ${SOURCE_FILES})
# TODO: Add tests and install targets if needed.
target_link_libraries(Game PUBLIC Cheetah)
The Cheetah target will carry all of the include directories along with it, so there is no need to list them all separately again. It can propagate the compile definitions as well, just use target_compile_definitions() when defining them for the Cheetah target.
Related
I was trying to make a cross platform imgui project in visual studio 2022, starting with android. In the beginning, I was not able to include some android libraries properly, so after following several tutorials, I ended up with this CMakeLists.txt:
# CMakeList.txt : CMake project for CMakeProject3 (imgui Cross-platform), include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.8)
project ("CMakeProject3 (imgui Cross-platform)")
list(APPEND CMAKE_PREFIX_PATH "C:/Users/HP/source/repos/CMakeProject3 (imgui Cross-platform)/build/vcpkg_installed/x64-windows/share/")
find_package(imgui REQUIRED)
# Add source to this project's executable.
add_executable (CMakeTarget "CMakeProject3 (imgui Cross-platform).cpp" "CMakeProject3 (imgui Cross-platform).h" "imgui_android.cpp" "imgui_impl_android.cpp" "imgui_impl_android.h")
target_include_directories(CMakeTarget PRIVATE "C:/Microsoft/AndroidNDK/android-ndk-r23c/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/android/"
"C:/Microsoft/AndroidNDK/android-ndk-r23c/sources/android/native_app_glue/")
target_link_libraries(CMakeTarget
PRIVATE
imgui::imgui
)
if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET CMakeTarget PROPERTY CXX_STANDARD 20)
endif()
# TODO: Add tests and install targets if needed.
It works partially but according to example of android imgui example, it needs
#include <android/log.h>
#include <android_native_app_glue.h>
#include <android/asset_manager.h>
I changed to:
#include "log.h"
#include "android_native_app_glue.h"
#include "asset_manager.h"
It started to give several errors for cannot open source file. The errors were for poll.h, pthread.h, sched.h, android/configuration.h, etc. It seems to me that I need to inlcude android ndk completely but
include(AndroidNdkGdb)
include(AndroidNdkModules)
gives error in cmake even when I installed android ndk and sdk.
I want to be able to use android libraries in my cross-platform project in visual studio 2022.
I fixed the error by updating CMakeLists.txt to:
# CMakeList.txt : CMake project for CMakeProject3 (imgui Cross-platform), include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.8)
project ("CMakeProject3 (imgui Cross-platform)")
list(APPEND CMAKE_PREFIX_PATH "C:/Users/HP/source/repos/CMakeProject3 (imgui Cross-platform)/build/vcpkg_installed/x64-windows/share/")
find_package(imgui REQUIRED)
set(CMAKE_SYSROOT C:/Microsoft/AndroidNDK/android-ndk-r23c/toolchains/llvm/prebuilt/windows-x86_64/sysroot)
# Add source to this project's executable.
add_executable (CMakeTarget "CMakeProject3 (imgui Cross-platform).cpp" "CMakeProject3 (imgui Cross-platform).h" "imgui_android.cpp" "imgui_impl_android.cpp" "imgui_impl_android.h")
target_include_directories(CMakeTarget PRIVATE "C:/Microsoft/AndroidNDK/android-ndk-r23c/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/"
"C:/Microsoft/AndroidNDK/android-ndk-r23c/sources/android/native_app_glue/"
"C:/Microsoft/AndroidNDK/android-ndk-r23c/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/asm/")
target_link_libraries(CMakeTarget
PRIVATE
imgui::imgui
)
if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET CMakeTarget PROPERTY CXX_STANDARD 20)
endif()
# TODO: Add tests and install targets if needed.
Either this is really easy and I'm just not able to find the correct way to do it, or I've wildly misunderstood something. I'm attempting to add a conditional to a CMakeLists.txt file to include the proper .lib file depending on which build configuration type is being used (within visual studio at the moment). So for example, if configuration in visual studio is set to Debug then use file zlibstaticd.lib vs zlibstatic.lib. Below is what I have that's not working:
add_library(ZLIB_LIBRARY OBJECT IMPORTED)
# zlib added via assimp, and I can't get CMAKE_DEBUG_POSTFIX value to overwrite (because it's set within zlibs cmake file when using MSVC)
# so we have to do this check
if($<CONFIG:Debug>)
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstaticd.lib)
else()
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstatic.lib)
endif()
I've also tried CMAKE_BUILD_TYPE but it's always an empty string. Below is my entire CMakeLists.txt file so you can see what it is I'm doing (building a singular static library which contains many other static libraries):
cmake_minimum_required(VERSION 3.20.0)
# Define our project name
set(PROJECT_NAME myProjectName)
project(${PROJECT_NAME})
# Make sure binary directory is not the same as source directory
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(
FATAL_ERROR
"In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there."
)
endif()
# This Project Depends on External Project(s)
include(ExternalProject)
set(libGLFW glfw)
ExternalProject_Add(${libGLFW}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}
GIT_REPOSITORY https://github.com/glfw/glfw.git
GIT_TAG 3.3.4
GIT_SHALLOW ON
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}/install
-DGLFW_BUILD_DOCS:BOOL=OFF
-DGLFW_BUILD_EXAMPLES:BOOL=OFF
-DGLFW_BUILD_TESTS:BOOL=OFF
)
set(libGLAD glad)
ExternalProject_Add(${libGLAD}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}
GIT_REPOSITORY https://github.com/Dav1dde/glad.git
GIT_TAG origin/master
GIT_SHALLOW ON
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}/install
-DGLAD_INSTALL:BOOL=ON
-DGLAD_PROFILE:STRING="core"
-DGLAD_ALL_EXTENSIONS:BOOL=ON
-DUSE_MSVC_RUNTIME_LIBRARY_DLL:BOOL=OFF
)
set(libGLM glm)
ExternalProject_Add(${libGLM}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLM}
GIT_REPOSITORY https://github.com/g-truc/glm.git
GIT_TAG origin/master
GIT_SHALLOW ON
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLM}/install
-DBUILD_SHARED_LIBS:BOOL=OFF
-DBUILD_STATIC_LIBS:BOOL=OFF
-DGLM_TEST_ENABLE:BOOL=OFF
)
set(libAssimp assimp)
ExternalProject_Add(${libAssimp}
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libAssimp}
GIT_REPOSITORY https://github.com/assimp/assimp.git
GIT_TAG v5.0.1
GIT_SHALLOW ON
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libAssimp}/install
-DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT:BOOL=OFF
-DASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT:BOOL=OFF
-DBUILD_SHARED_LIBS:BOOL=OFF
-DASSIMP_BUILD_ASSIMP_TOOLS:BOOL=OFF
-DASSIMP_BUILD_TESTS:BOOL=OFF
-DASSIMP_BUILD_FBX_IMPORTER:BOOL=ON
-DASSIMP_BUILD_OBJ_IMPORTER:BOOL=ON
-DASSIMP_BUILD_OBJ_EXPORTER:BOOL=ON
-DASSIMP_LIBRARY_SUFFIX:STRING=
-DLIBRARY_SUFFIX:STRING=
-DCMAKE_DEBUG_POSTFIX:STRING=
-DASSIMP_INJECT_DEBUG_POSTFIX:BOOL=OFF
)
# Note set_target_properties will need conditionals for windows/linux since extensions differ
# Create the oject files we will join together to create our singular static library, using the projects
# that were previously added above via ExternalProject_Add
# INSTALL_DIR not being set to value of CMAKE_INSTALL_PREFIX, so manuallysetting
#ExternalProject_Get_Property(${libGLFW} INSTALL_DIR)
# SETUP GLFW
set(GLFW_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}/install)
add_library(GLFW_LIBRARY OBJECT IMPORTED)
set_target_properties(GLFW_LIBRARY PROPERTIES IMPORTED_OBJECTS ${GLFW_INSTALL_DIR}/lib/glfw3.lib)
# SETUP GLAD
set(GLAD_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}/install)
add_library(GLAD_LIBRARY OBJECT IMPORTED)
set_target_properties(GLAD_LIBRARY PROPERTIES IMPORTED_OBJECTS ${GLAD_INSTALL_DIR}/lib/glad.lib)
# SETUP GLM
# GLM is header only library, so we simply include it's include directory in target_include_directories below
set(GLM_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLM}/install)
# SETUP ASSIMP and it's dependencies
set(ASSIMP_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libAssimp}/install)
add_library(ASSIMP_LIBRARY OBJECT IMPORTED)
set_target_properties(ASSIMP_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/assimp.lib)
add_library(IRRXML_LIBRARY OBJECT IMPORTED)
set_target_properties(IRRXML_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/IrrXML.lib)
add_library(ZLIB_LIBRARY OBJECT IMPORTED)
# zlib added via assimp, and I can't get CMAKE_DEBUG_POSTFIX value to overwrite (because it's set within zlibs cmake file when using MSVC)
# so we have to do this check
if($<CONFIG:Debug>)
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstaticd.lib)
else()
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstatic.lib)
endif()
# Documentation states not to do this, but do it anyway for the time being since it prevents us from having
# to manually list all project files
file(GLOB_RECURSE headers CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/inc/*.h")
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# Create a single .lib file containing our compiled objects, and the compiled objects of all other dependencies
add_library(${PROJECT_NAME} STATIC ${headers} ${sources}
$<TARGET_OBJECTS:GLFW_LIBRARY>
$<TARGET_OBJECTS:GLAD_LIBRARY>
$<TARGET_OBJECTS:ASSIMP_LIBRARY>
$<TARGET_OBJECTS:IRRXML_LIBRARY>
$<TARGET_OBJECTS:ZLIB_LIBRARY>
)
# Add all include file paths
target_include_directories(${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inc
PUBLIC ${GLFW_INSTALL_DIR}/include
PUBLIC ${GLAD_INSTALL_DIR}/include
PUBLIC ${GLM_INSTALL_DIR}/include
PUBLIC ${ASSIMP_INSTALL_DIR}/include
)
# Specify the order in which libs depend on each other, use the name of the ExternalProject, not the name of the
# library object you create and use with add_library
add_dependencies(${PROJECT_NAME} ${libGLFW} ${libGLAD} ${libGLM} ${libAssimp})
add_library(ZLIB_LIBRARY OBJECT IMPORTED)
# zlib added via assimp, and I can't get CMAKE_DEBUG_POSTFIX value to overwrite (because it's set within zlibs cmake file when using MSVC)
# so we have to do this check
if($<CONFIG:Debug>)
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstaticd.lib)
else()
set_target_properties(ZLIB_LIBRARY PROPERTIES IMPORTED_OBJECTS ${ASSIMP_INSTALL_DIR}/lib/zlibstatic.lib)
endif()
Generator expressions are evaluated after the configuration step has run, so they're just literal strings when the if() statement sees them. Basically, the CMake configure step is meta-programming a declarative language of targets and generator expressions that gets compiled into Ninja build files (or whatever) by the generator.
You can set the library up as follows:
add_library(zlib OBJECT IMPORTED)
set_target_properties(
zlib
PROPERTIES
IMPORTED_OBJECTS_RELEASE "${ASSIMP_INSTALL_DIR}/lib/zlibstatic.lib"
IMPORTED_OBJECTS_DEBUG "${ASSIMP_INSTALL_DIR}/lib/zlibstaticd.lib"
)
CMake first tries IMPORTED_OBJECTS_$<CONFIG> before trying IMPORTED_OBJECTS when resolving a library path.
All that said, I have to wonder why you don't just use find_package, vcpkg, Conan, or maybe add_subdirectory / FetchContent to manage your dependencies. This seems like a lot of pain given that all of those libraries (I think) either provide their own find_package config packages or CMake provides a find module for them.
I've learned that I need to compile my main project as a library, so my unit tests can link to them. This works on Linux, but on Windows, via Visual Studio, it provides unresolved externals.
Here's the parent project CMakeLists:
cmake_minimum_required(VERSION 3.9.1)
set(CMAKE_LEGACY_CYGWIN_WIN32 1)
set (CMAKE_CXX_STANDARD 11) # Set C++11
project(CHIP8)
# To maintain a clean tree, set some useful variables so we're not building everything in root.
# set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # static library
# set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # dynamic library
# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # executables
# set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/modules" ${CMAKE_MODULE_PATH})
# Include SFML
add_subdirectory(${CMAKE_SOURCE_DIR}/dep/SFML)
include_directories(${CMAKE_SOURCE_DIR}/dep/SFML/include)
# Add our test directory
add_subdirectory (test)
#Include where to find headers
include_directories(./src)
include_directories(./src/headers)
set(EXECUTABLE_NAME "CHIP8")
add_library (ch8lib ${CMAKE_SOURCE_DIR}/src/chipeight.cpp ${CMAKE_SOURCE_DIR}/src/headers/chipeight.h)
# Here we will include all our source files to be built to the executable (include all so they show in IDE).
add_executable(${EXECUTABLE_NAME}
${CMAKE_SOURCE_DIR}/src/main.cpp
${CMAKE_SOURCE_DIR}/src/chipeight.cpp
${CMAKE_SOURCE_DIR}/src/headers/chipeight.h
)
target_link_libraries(ch8lib sfml-graphics sfml-window sfml-audio)
target_link_libraries(${EXECUTABLE_NAME} ch8lib)
The important part is here:
add_library (ch8lib ${CMAKE_SOURCE_DIR}/src/chipeight.cpp ${CMAKE_SOURCE_DIR}/src/headers/chipeight.h)
And the unit test CMakeLists:
cmake_minimum_required(VERSION 3.9.1)
set (CMAKE_CXX_STANDARD 11) # Set C++11
set(CMAKE_LEGACY_CYGWIN_WIN32 1)
PROJECT(CHIP8TESTS)
# Prepare "Catch" library for other executables
set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_library(Catch INTERFACE)
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
#Include where to find headers
include_directories(../src)
include_directories(../src/headers)
set(TEST_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/tests.cpp
)
add_executable(tests ${TEST_SOURCES})
target_link_libraries(tests Catch ch8lib sfml-graphics sfml-window sfml-audio)
# enable_testing()
# add_test(NAME RunTests COMMAND tests)
I'm making sure to link SFML because it seems the errors originate from there: https://i.imgur.com/FV18cqC.png
Does anyone know a solution to this problem of unresolved externals?
What I want to do is this:
1) Compile my main project
2) Compile my test project
3) Run my test project
Thanks.
I have cli wrapper function which i am trying to configure in cmake. After i generate the project with cmake the generated .proj file does not have the property of clr support is set to no common languaage runtime support. below is my cmake file
# This is the root ITK CMakeLists file.
cmake_minimum_required(VERSION 2.8.9)
if(COMMAND CMAKE_POLICY)
cmake_policy(SET CMP0003 NEW)
endif()
set_target_properties(${TargetName} PROPERTIES COMPILE_FLAGS "/clr")
SET(LINK_LIBRARIES
D:\\2016\\RandomSlicing\\Processing\\lib\\obliquePlane.lib
)
# The header files
SET(HEADERS
ObliquePlaneWrapper.h
obliquePlane.h
)
# The implementation files
SET(SOURCES
ObliquePlaneWrapper.cpp
)
# Find ITK.
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
# Add this as include directory
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}
${SOURCE_PATH}
${VXL_INCLUDE_DIRS}
)
# Main library
#ADD_EXECUTABLE(obliquePlane ${HEADERS} ${SOURCES})
ADD_LIBRARY(ObliquePlaneWrapper SHARED ${HEADERS} ${SOURCES})
TARGET_LINK_LIBRARIES(ObliquePlaneWrapper ${LINK_LIBRARIES} ${ITK_LIBRARIES})
I manually set this property in the All_build project and the corresponding .proj file. When i build the project it is searching for the ObliquePlaneWrapper.dll which it should be generating. Is this a problem because of some flag not set for common language runtime support
You can manually supply Compile Flags to specific sources to be compiled with specific flags. This includes \CLR for Visual C++. See example here.
https://cmake.org/pipermail/cmake/2011-April/043773.html
I've wrote a C++ library MyLib and I'd like to integrate it with another project ExternPro. So in ExternPro I wrote CMakeLists.txt like this:
add_subdirectory(MyLib)
ADD_EXECUTABLE(test test.cpp)
include_directories(${MyLib_INCLUDE_DIRS})
target_link_libraries(test ${MyLib_LIBRARIES})
To set variables MyLib_LIBRARIES and MyLib_INCLUDE_DIRS I wrote:
set(MyLib_LIBRARIES ${PROJECT_SOURCE_DIR}/src/MyLib.a CACHE INTERNAL "")
set(MyLib_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/include CACHE INTERNAL "")
But something wrong "No rule to make target MyLib/src/MyLib.a, needed by test. Stop."
So my question is, how should I wrote CMakeLists.txt correctly so cmake could help me build MyLib first and then take care of dependencies of ExternPro?
If those are two separate projects, I normally use "CMake find scripts" to reference one library from the other: http://www.vtk.org/Wiki/CMake:How_To_Find_Libraries#Writing_find_modules
But I normally use slightly different find script than described there (FindMyLibrary.cmake):
# Find MyLibrary installation
#
# This module needs following variables specified (e.g. through cmake -Dvar=)
# MyLibrary_ROOT_DIR - root directory of the library installation
#
# This module defines the following variables:
# MyLibrary_INCLUDE_DIRS - Where to find the public headers
# MyLibrary_LIBRARIES - List of mandatory and optional libraries
# MyLibrary_FOUND - True if an installation was found
#
# Configuration variables for tis module:
# MyLibrary_USE_STATIC_LIBS - Set to ON to force the use of the static
# libraries. Default is OFF.
# If MyLibrary_ROOT_DIR was defined in the environment, use it.
if(NOT MyLibrary_ROOT_DIR AND NOT $ENV{MyLibrary_ROOT_DIR} STREQUAL "")
set(MyLibrary_ROOT_DIR $ENV{MyLibrary_ROOT_DIR})
endif()
if(NOT MyLibrary_ROOT_DIR)
set(MyLibrary_ROOT_DIR /usr)
endif()
message(STATUS "Using MyLibrary_ROOT_DIR: ${MyLibrary_ROOT_DIR}")
find_path(MyLibrary_INCLUDE_DIRS
NAMES mylib/mylib.hpp
PATHS ${MyLibrary_ROOT_DIR}
PATH_SUFFIXES include)
# Here we set the default components
if(NOT MyLibrary_FIND_COMPONENTS)
set(MyLibrary_FIND_COMPONENTS mylibrary)
endif()
# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
if(MyLibrary_USE_STATIC_LIBS)
set(_mylib_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
if(WIN32)
set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
else()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
endif()
endif()
foreach(COMPONENT ${MyLibrary_FIND_COMPONENTS})
find_library(MyLibrary_${COMPONENT}_LIBRARY
NAMES ${COMPONENT}
HINTS ${MyLibrary_ROOT_DIR}
PATH_SUFFIXES lib64 lib
NO_DEFAULT_PATH)
set(MyLibrary_LIBRARIES ${MyLibrary_LIBRARIES} ${MyLibrary_${COMPONENT}_LIBRARY})
endforeach()
# Restore the original find library ordering
if(MyLibrary_USE_STATIC_LIBS)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_mylib_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
endif()
# handle the QUIETLY and REQUIRED arguments and set MyLibrary_FOUND to
# TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
MyLibrary "Could NOT find MyLibrary: set MyLibrary_ROOT_DIR to a proper location"
MyLibrary_LIBRARIES
MyLibrary_INCLUDE_DIRS)
mark_as_advanced(MyLibrary_INCLUDE_DIRS MyLibrary_LIBRARIES)
Then used like this:
find_package(MyLibrary REQUIRED)
include_directories(SYSTEM ${MyLibrary_INCLUDE_DIRS})
target_link_libraries(${TARGET}
${MyLibrary_LIBRARIES}
)
Basically, it goes like this:
The library is built and installed (make install) to either the default location (e.g. /usr), or some other location (usual in development).
The FindMyLibrary.cmake is part of the library installation (for RPM the library devel package) and installs as well (into ${instdir}/share/cmake/Modules, for example).
The dependent project then adds the path to the CMAKE_MODULE_PATH and uses the find script to find the public headers and libraries as installed.
The advantage is that this way you can either use it during the development (when you have the library sources and build the library), or without the library sources as well (with just the library and headers - the devel package - installed in the system).
Similar technique is normally used by Boost etc. (the find scripts provided already by the CMake).
Instead of path to the library, use library target for target_link_libraries.
Assuming your library project contains
add_library(MyLib ...)
Linking of executable in main project should be performed with
target_link_libraries(test MyLib)
First of all this doesn't work because variables set in a subdirectory are not set for the parent directory.
So to solve this properly you should define MyLib like:
add_library(MyLib ...)
target_include_directories(MyLib INTERFACE ${PROJECT_SOURCE_DIR}/include)
And for the ExternPro you just need to link to MyLib:
target_link_libraries(test MyLib)
This will automatically add the include directory to test and link MyLib properly.