So I've been trying to learn CMake and use it with C++. I'd like to have a go at creating a portable game engine which uses Direct3D 12 on Windows.
Currently, I have the following CMakeLists.txt for my project:
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(PsychoEngineCore)
set(SRCS_CXX ${CMAKE_CURRENT_LIST_DIR})
include(${CMAKE_CURRENT_SOURCE_DIR}/src/dir_src.cmake)
set(LIB_TYPE "STATIC" CACHE STRING "Static or Dynamic Linking")
if(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU OR
${CMAKE_CXX_COMPILER_ID} STREQUAL Clang)
set(warnings "-Wall -Wextra -Werror")
elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
set(warnings "/W4 /WX /EHsc")
endif()
if(NOT CONFIGURED_ONCE)
set(CMAKE_CXX_FLAGS "${warnings}"
CACHE STRING "Flags used by the compiler during all build types." FORCE)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
# Do we want static libraries?
# When STATIC_LINKING is TRUE, then cmake looks for binaries ending in ".a".
# THIS IS FOR LINUX ONLY!
if(LIB_TYPE EQUAL STATIC)
if (UNIX AND NOT APPLE)
set(CMAKE_FIND_LIBRARY_SUFFIXES(".a"))
endif(UNIX AND NOT APPLE)
set(CMAKE_EXE_LINKER_FLAGS "-static")
set_target_properties(surface PROPERTIES LINK_SEARCH_END_STATIC 1)
endif(LIB_TYPE EQUAL STATIC)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
include(GenerateExportHeader)
add_library(${PROJECT_NAME} ${LIB_TYPE} ${SRCS_CXX})
GENERATE_EXPORT_HEADER(
${PROJECT_NAME}
EXPORT_MACRO_NAME PE_API
EXPORT_FILE_NAME ${CMAKE_CURRENT_SOURCE_DIR}/include/Engine/API/${PROJECT_NAME}Export.hpp
DEPRECATED_MACRO_NAME PE_API_DEP
STATIC_DEFINE PE_STATIC
)
Currently I have my d3d12.lib file in the following location:
C:\Program Files (x86)\Windows Kits\10\Libs\10.0.16299.0\um\x64
Is there a way to keep the path dynamic and preferably "update" if a newer version is available on said system?
Thanks!
Turning my comment into an answer
Generally speaking, just add a
target_link_libraries((${PROJECT_NAME} d3d12.lib)
The Windows SDK (where the Direct3D SDK is now part of) is in the standard search paths e.g. of the linker for libraries. So it's found automatically by the MSVC compiler and linker.
And I don't think that upgrading to a newer (yet unknown) API version automatically is a good idea. You're writing your program for a specific API version.
Working Example
Here is a minimal working example (Tested VS2017 15.5.5, CMake 3.9.0):
cmake_minimum_required(VERSION 3.0)
project(Direct3DExample)
find_package(Git REQUIRED)
set(_path "${CMAKE_BINARY_DIR}/DirectX-Graphics-Samples/Samples/Desktop/D3D12HelloWorld/src/HelloTriangle")
if (NOT EXISTS "${_path}")
execute_process(
COMMAND "${GIT_EXECUTABLE}" clone https://github.com/Microsoft/DirectX-Graphics-Samples.git
)
endif()
file(GLOB _files "${_path}/*")
list(APPEND _shader ${_files})
list(FILTER _files EXCLUDE REGEX "\\.vcxproj|\\.hlsl")
list(FILTER _shader INCLUDE REGEX "\\.hlsl")
get_filename_component(_name "${_path}" NAME)
add_executable(${_name} WIN32 ${_files})
target_compile_definitions(${_name} PRIVATE "UNICODE" "_UNICODE")
target_link_libraries(${_name} PRIVATE "d3d12.lib" "dxgi.lib" "d3dcompiler.lib")
add_custom_command(
TARGET ${_name}
POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy ${_shader} $<TARGET_FILE_DIR:${_name}>
)
If you need more (compilers/linkers that are not finding the Windows SDK automatically), you may want to look the following find_package() config code:
https://github.com/Microsoft/DirectXShaderCompiler/blob/master/cmake/modules/FindD3D12.cmake
Related
Thrust allows for one to specify different backends at cmake configure time via the THRUST_DEVICE_SYSTEM flag. My problem is that I have a bunch of .cu files that I want to be compiled as regular c++ files when a user runs cmake with -DTHRUST_DEVICE_SYSTEM=OMP (for example). If I change the extension of the .cu files to .cpp they compile fine (indicating that I just need tell cmake to use the c++ compiler on the .cu files). But if I add .cu to CMAKE_CXX_SOURCE_FILE_EXTENSIONS then I get a CMake Error: Cannot determine link language for target "cuda_kernels". Here's a minimal cmake example:
cmake_minimum_required(VERSION 3.19)
project(kernels LANGUAGES C CXX Fortran)
set(KERNELS_USE_OMP OFF)
if ("${THRUST_DEVICE_SYSTEM}" STREQUAL "OMP")
set(KERNELS_USE_OMP ON)
endif()
# verify CUDA support
include(CheckLanguage)
check_language(CUDA)
if (CMAKE_CUDA_COMPILER AND NOT KERNELS_USE_OMP)
enable_language(CUDA)
else()
list(PREPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS "cu;CU")
endif()
message(STATUS "${CMAKE_CXX_SOURCE_FILE_EXTENSIONS}")
find_package(Thrust REQUIRED CONFIG)
thrust_create_target(Thrust FROM_OPTIONS)
add_library(cuda_kernels my_kernels.cu)
target_link_libraries(cuda_kernels Thrust)
The output of the message command on my system is: -- cu;CU;C;M;c++;cc;cpp;cxx;mm;mpp;CPP;ixx;cppm
Why is cmake not respecting my CMAKE_CXX_SOURCE_FILE_EXTENSIONS changes?
Why is cmake not respecting my CMAKE_CXX_SOURCE_FILE_EXTENSIONS changes?
The extension-to-language for <LANG> is set as soon as <LANG> is enabled by inspecting the value of the CMAKE_<LANG>_SOURCE_FILE_EXTENSIONS variable when the language detection module exits.
Unfortunately, there is no blessed way to override this list for CXX as it is hard-coded in Modules/CMakeCXXCompiler.cmake.in.
Perhaps the best way of working around the actual error would be to use the LANGUAGE source file property to tell CMake how to compile the individual CUDA files, like so:
cmake_minimum_required(VERSION 3.19)
project(kernels LANGUAGES CXX)
find_package(Thrust REQUIRED)
thrust_create_target(Thrust FROM_OPTIONS)
thrust_is_cuda_system_found(USE_CUDA)
if (USE_CUDA)
enable_language(CUDA)
endif()
set(cuda_kernel_sources my_kernels.cu)
add_library(cuda_kernels ${cuda_kernel_sources})
target_link_libraries(cuda_kernels PRIVATE Thrust)
if (NOT USE_CUDA)
set_source_files_properties(
${cuda_kernel_sources}
PROPERTIES
LANGUAGE CXX
)
endif ()
This will certainly be friendlier to other projects that might try to add_subdirectory yours.
However, if we want to be very naughty, we can do this:
cmake_minimum_required(VERSION 3.19)
project(kernels LANGUAGES NONE)
###
# Hacky language extension override
function(add_cuda_extensions variable access value current_list_file stack)
if (NOT cu IN_LIST value)
list(PREPEND "${variable}" "cu" "CU")
set("${variable}" "${${variable}}" PARENT_SCOPE)
endif ()
endfunction()
# verify CUDA support
include(CheckLanguage)
check_language(CUDA)
if (CMAKE_CUDA_COMPILER AND NOT THRUST_DEVICE_SYSTEM STREQUAL "OMP")
enable_language(CUDA)
enable_language(CXX)
else()
variable_watch(CMAKE_CXX_SOURCE_FILE_EXTENSIONS add_cuda_extensions)
enable_language(CXX)
endif()
###
# Normal project code starts here
message(STATUS "${CMAKE_CXX_SOURCE_FILE_EXTENSIONS}")
find_package(Thrust REQUIRED)
thrust_create_target(Thrust FROM_OPTIONS)
add_library(cuda_kernels my_kernels.cu)
target_link_libraries(cuda_kernels PRIVATE Thrust)
This waits for the platform module to try to write CMAKE_CXX_SOURCE_FILE_EXTENSIONS and then any time it's accessed, quickly inserts the cu and CU extensions to the list.
I'm operating under a new learning curve here with c++ and using CMake in Visual Studio. Here is the partial code up until the point where I receive the error:
project(libfranka
VERSION 0.8.0
LANGUAGES CXX
)
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(MSVC)
add_compile_options(/W0)
else()
add_compile_options(-Wall -Wextra)
endif()
set(THIRDPARTY_SOURCES_DIR "${CMAKE_SOURCE_DIR}/3rdparty" CACHE PATH
"Directory for third-party sources")
## Dependencies
find_package(Poco REQUIRED COMPONENTS Net Foundation)
find_package(Eigen3 REQUIRED)
Once it hits the first find_package is where I encounter the error:
Here is the code within FindPoco.cmake.
find_package(Poco COMPONENTS ${Poco_FIND_COMPONENTS} CONFIG QUIET)
if(Poco_FOUND)
return()
endif()
find_path(Poco_INCLUDE_DIR Poco/Poco.h)
mark_as_advanced(FORCE Poco_INCLUDE_DIR)
foreach(component ${Poco_FIND_COMPONENTS})
set(component_var "Poco_${component}_LIBRARY")
find_library(${component_var} Poco${component})
mark_as_advanced(FORCE ${component_var})
if(${component_var})
set(Poco_${component}_FOUND TRUE)
list(APPEND Poco_LIBRARIES ${component})
if(NOT TARGET Poco::${component})
add_library(Poco::${component} SHARED IMPORTED)
set_target_properties(Poco::${component} PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${Poco_INCLUDE_DIR}
IMPORTED_LOCATION ${${component_var}}
)
endif()
endif()
endforeach()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Poco
FOUND_VAR Poco_FOUND
REQUIRED_VARS Poco_INCLUDE_DIR Poco_LIBRARIES
VERSION_VAR Poco_VERSION
HANDLE_COMPONENTS
)
I installed poco using vcpkg in a directory titled vcpkg. Within the vcpkg directory is the libfranka directory, which houses the CMakeLists.txt file that I compile in Visual Studio. Here is an image of that directory:
Finally, here is the tutorial that I am using: https://frankaemika.github.io/docs/installation_windows.html#building-from-source
EDIT:
Per the link I followed the instructions for solving the build dependencies and here is an image of that:
Then I ran the CMakeLists.txt again and in the CMake Settings this is what I see:
Note also that I ran through the install of poco again and I noticed this and am unsure if it could be the source of the problem or if it means nothing (again, this was the out put after running vcpkg install poco):
After this I still receive the same error.
Does anyone see what it is that I am doing incorrectly?
Thank you!
I'm trying to specify to the compiler to ignore all messages + warnings originating from the libs folder, where I keep my external libraries used in my project.
The LLVM library is the main cause of the problem, since the warnings produced fill up the entire screen making it very difficult for me to efficiently identify compile-time errors, etc.
I'm using CMake and have my LLVM 9.0.0 library under the libs folder. I would like to instruct the compiler (using CMake) to ignore all warnings and messages originating from the libs folder.
This is my CMakeLists.txt file:
# General project settings.
cmake_minimum_required(VERSION 3.12.4)
project(ionir)
# Setup compiler flags.
set(CMAKE_CXX_STANDARD 17)
# General project information.
set(PROJECT_URL "https://github.com/ionlang/ir-c")
# Setup source and build directories.
set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
option(USE_MD "Use MD instead of MTd" OFF)
if (USE_MD)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MD")
#set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
endif(USE_MD)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
# Setup versioning.
set(VERSION_MAJOR "1")
set(VERSION_MINOR "0")
set(VERSION_PATCH "0")
set(VERSION "$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)")
# Configure and use LLVM. Also ensures LLVM 9.0.0 is installed.
find_package(LLVM 9.0.0 EXACT REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
# Include LLVM source directories (for syntax support, etc.). The SYSTEM symbol supposedly marks the directory to supress warnings.
include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) #---> COMMENTED TO SOLVE CIRCULAR DEPS. PROBLEM.
add_definitions(${LLVM_DEFINITIONS})
# Disable warnings from includes.
#add_library(llvm INTERFACE)
#target_sources(llvm INTERFACE)
#target_include_directories(llvm PRIVATE include/ SYSTEM INTERFACE include/)
# Set source file(s).
file(GLOB_RECURSE SOURCES
"src/*.h"
"src/*.cpp"
)
# Specify that this project is a library.
add_library(${PROJECT_NAME} ${SOURCES})
# Provide include directories to be used in the build command. Position in file matters.
#target_include_directories(${PROJECT_NAME} PRIVATE "src")
include_directories("src")
# Find the libraries that correspond to the LLVM components
# that we wish to use
# llvm_map_components_to_libnames(llvm_libs support core irreader)
# Link against LLVM libraries.
target_link_libraries(${PROJECT_NAME} ${llvm_libs})
# Setup unit testing using Google Test (GTest) if applicable. This binds the CMakeLists.txt on the test project.
option(BUILD_TESTS "Build tests" ON)
if (BUILD_TESTS)
add_subdirectory(libs/googletest)
add_subdirectory(test)
endif()
And below is some of the warnings/messages I'm receiving that are filling up the console.
How can I accomplish this?
I had a https://github.com/simongog/sdsl-lite library installed on a remote Linux server. What I did was to create lib, include directories inside my home directory and then run the script as ./install.sh /my/home/dir, as indeed explained on the above page. I was able to do it once and successfully linked it to my other programs by using a CMakeLists.txt file as the one similar to the following:
cmake_minimum_required(VERSION 2.8)
set (CMAKE_CXX_STANDARD 14)
macro(use_cxx14)
if (CMAKE_VERSION VERSION_LESS "3.1")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O2 -mcmodel=large")
endif ()
else ()
set (CMAKE_CXX_STANDARD 14)
endif ()
endmacro(use_cxx14)
use_cxx14()
# Locate GTest
link_directories(/my/home/dir/)
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /my/home/dir/)
list(APPEND CMAKE_PREFIX_PATH "/my/home/dir/")
list(APPEND CMAKE_LIBRARY_PATH /my/home/dir/lib/)
INCLUDE_DIRECTORIES(/my/home/dir/include)
LINK_DIRECTORIES(/my/home/dir/lib)
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
# Link runTests with what we want to test and the GTest and pthread library
add_executable(runTests rs_bitvector_test.cpp)
# SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
# SET(BUILD_SHARED_LIBRARIES OFF)
# SET(CMAKE_EXE_LINKER_FLAGS "-static")
target_link_libraries(runTests sdsl ${GTEST_LIBRARIES} pthread)
(the server was missing C++14 but the name remains, although really I use the C++11 option)
Now I've changed a source file inside the previously downloaded location of the library and recompiled it. And now linking stopped working. What could be the reason? During re-compilation, the remote server kept telling me about some "modification time in the future" and "build may be incomplete". Is that the reason? What can be done?
EDIT: based off the suggestions in the comments, I removed the build directory (analog of make clean) and replaced it with that from the directory of the original bundle. Now, the timstamps issue is gone, but the linking still fails.
Funnily, after noticing that sdsl detected g++ 7.3 during installation while cmake was compiling using 4.8, I used https://cmake.org/Wiki/CMake_FAQ#How_do_I_use_a_different_compiler.3F to set the compiler to g++ 7.3 (using Method 3 in the above link), and it finally worked (still some issues with GTest, but it is OK).
I already read and searched a lot (e.g. 1 2 3, several docs for CMake, similar projects, etc. to find a solution but I have not been able to solve my problem. I am relatively new to Cmake and Linux (Ubuntu 14.04).
I want to use libsbp (https://github.com/swift-nav/libsbp) to write a program in C++ to communicate with a GPS module. I cloned the repository and installed the C-Library. So now in /usr/local/lib there are two files: libsbp.so and libsbp-static.a and the headers are in /usr/local/include/libsbp
In my own project I include the headers with #include "libsbp/sbp.h" which also works.
Now the Problem: if I want to use a method from libsbp e.g. sbp_state_init(&s); I get undefined reference to "sbp_state_init(sbp_state_t*)"
The relevant part of my Cmake for my own project:
link_directories(/usr/local/lib)
add_executable(main ${QT_SOURCES} ${QT_HEADER_HPP})
target_link_libraries(main ${QT_LIBRARIES} ${catkin_LIBRARIES} sbp)
As I said before, I tried some things:
find_library(SBP_LIB sbp /usr/local/lib) -> same error
same goes for using libsbp in target_link_libraries or searching for it
link_directory(/usr/local/lib)
trying different paths, even moveing libsbp.so into the project directory and "finding" it with ${CMAKE_CURRENT_SOURCE_DIR}
Maybe you can help me!
edit:
this is the CMakeList.txt from the libsbp/c/src directory
if (NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON)
endif (NOT DEFINED BUILD_SHARED_LIBS)
file(GLOB libsbp_HEADERS "${PROJECT_SOURCE_DIR}/include/libsbp/*.h")
include_directories("${PROJECT_SOURCE_DIR}/CBLAS/include")
include_directories("${PROJECT_SOURCE_DIR}/clapack-3.2.1-CMAKE/INCLUDE")
include_directories("${PROJECT_SOURCE_DIR}/lapacke/include")
include_directories("${PROJECT_SOURCE_DIR}/include/libsbp")
set(libsbp_SRCS
edc.c
sbp.c
)
add_library(sbp-static STATIC ${libsbp_SRCS})
install(TARGETS sbp-static DESTINATION lib${LIB_SUFFIX})
if(BUILD_SHARED_LIBS)
add_library(sbp SHARED ${libsbp_SRCS})
install(TARGETS sbp DESTINATION lib${LIB_SUFFIX})
else(BUILD_SHARED_LIBS)
message(STATUS "Not building shared libraries")
endif(BUILD_SHARED_LIBS)
install(FILES ${libsbp_HEADERS} DESTINATION include/libsbp)
this is the CMakeList.txt from /libsbp/c/
cmake_minimum_required(VERSION 2.8.9)
project(libsbp)
# Setup flags for Code Coverage build mode
set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG} --coverage" CACHE STRING
"Flags used by the C++ compiler for building with code coverage."
FORCE )
set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_DEBUG} --coverage" CACHE STRING
"Flags used by the C compiler for building with code coverage."
FORCE )
SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE
"${CMAKE_EXE_LINKER_FLAGS_DEBUG} --coverage" CACHE STRING
"Flags used for linking binaries with code coverage."
FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} --coverage" CACHE STRING
"Flags used by the shared libraries linker during builds with code coverage."
FORCE )
mark_as_advanced(
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
# Update the documentation string of CMAKE_BUILD_TYPE for GUIs
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage."
FORCE )
# Set project version using Git tag and hash.
execute_process(
COMMAND git describe --dirty --tags --always
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE GIT_VERSION_FOUND
ERROR_QUIET
OUTPUT_VARIABLE GIT_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (GIT_VERSION_FOUND)
set(VERSION "unknown")
else (GIT_VERSION_FOUND)
set(VERSION ${GIT_VERSION})
endif (GIT_VERSION_FOUND)
# Set project version explicitly for release tarballs.
#set(VERSION foo)
message(STATUS "libsbp version: ${VERSION}")
cmake_minimum_required(VERSION 2.8)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# Some compiler options used globally
set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-strict-prototypes -Wno-unknown-warning-option -Werror -std=gnu99 ${CMAKE_C_FLAGS}")
add_subdirectory(src)
add_subdirectory(docs)
add_subdirectory(test)
It seems that your program uses C++ and the library is written in C.
Symbols in C and C++ are encoded differently (mangled). When including C headers from C++ you need to tell the compiler. This can be done by declaring the symbols extern "C".
extern "C" {
#include <libsbp/sbp.h>
}
Some libraries already include this in their headers, but not sbp.
You have (at least) two possibilities:
Installing the library (this is what you did)
Integrating the library in your CMake project
When installing the library, the target_link_libraries command needs to be modified slightly:
find_library(SBP_LIB sbp /usr/local/lib)
target_link_libraries(main ${QT_LIBRARIES} ${catkin_LIBRARIES} ${SBP_LIB})
When you integrate the library in your CMake project, you can directly use the following command without using find_library. This works, because the library is known to CMake since it is built within the current project.
target_link_libraries(main ${QT_LIBRARIES} ${catkin_LIBRARIES} sbp)