How to automatically choose minimal cmake version based on used features? - cmake

For example I want to specify c++ standard in CMakeLists.txt:
set_property(TARGET tgt PROPERTY CXX_STANDARD 98)
But this is available only since cmake 3.1.3. Unfortunately I am still able to write at the first line of CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
How can I be sure that I specify correct requirements (3.1.3 instead of 2.8)?

The command cmake_minimum_required is not meant to check whether your code can be executed from the requested CMake version. The CMake policies are set depending on the requested CMake version, cf. the documentation.
As a consequence, you have to test your code with the CMake in the version given in cmake_minimum_required and hope to catch all relevant code paths.

Related

copy properties from target to target [duplicate]

I am preaty new to cmake . I was using makefiles before but due to QtCreator I am forced to use cmake. I am trying to learn glfw as well too. I have following cmake file:-
cmake_minimum_required(VERSION 3.10)
project(untitled)
find_package(glfw3 3.2 REQUIRED)
find_package(OpenGL REQUIRED)
add_executable(${PROJECT_NAME} "main.cpp")
target_include_directories(untitled ${OPENGL_INCLUDE_DIR})
target_link_libraries(untitled ${OPENGL_gl_LIBRARY})
And I get following error:-
CMakeLists.txt:8: error: target_include_directories called with invalid arguments
I have no Idea what does it mean. Please help me
If you look at the CMake documentation, you'll see that its usage differ a bit from what you wrote:
target_include_directories(<target> [SYSTEM] [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE>
[items2...] ...])
You'll notice that you miss the non optional argument <INTERFACE|PUBLIC|PRIVATE>
You must specify the visibility of the include directory:
target_include_directories(untitled PRIVATE ${OPENGL_INCLUDE_DIR})
If your executable uses OpenGL headers in a public header file, specify it as public so other targets that link to it also includes OpenGL headers.
I suggest you to get used to read the documentation, as it will be your best tool writing CMake scripts.
Even though it's optional, can also take this form for target_link_libraries, which I strongly suggest you do:
target_link_libraries(untitled PUBLIC ${OPENGL_gl_LIBRARY})

Can't seem to include Glut to my cmake project Ubuntu [duplicate]

I've been stuck for a while now and I can't figure out how to get freeglut working. I thought I knew what it was asking me to do, so I added that set(prefix_path) line but it didn't do anything. Am I supposed to write my own freeglut-config.cmake or what?
Note: I am using the freeglut for MinGW package from this website
CMake File:
cmake_minimum_required(VERSION 3.7)
project(HW1)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES Triangle.cpp)
set(CMAKE_PREFIX_PATH "C:/freeglut")
find_package(GLEW REQUIRED STATIC)
find_package(FREEGLUT REQUIRED)
find_package(OPENGL REQUIRED)
include_directories(${FREEGLUT_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIRS})
link_directories(${FREEGLUT_LIBRARY_DIRS} ${GLEW_LIBRARY_DIRS} ${OPENGL_LIBRARY_DIRS})
add_definitions(${FREEGLUT_DEFINITIONS} ${GLEW_DEFINITIONS} ${OPENGL_DEFINITIONS})
add_executable(HW1 ${SOURCE_FILES})
target_link_libraries(HW1 ${FREEGLUT_LIBRARIES} ${GLEW_LIBRARIES} ${OPENGL_LIBRARIES})
Full error:
CMake Error at CMakeLists.txt:8 (find_package):
By not providing "FindFREEGLUT.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "FREEGLUT",
but CMake did not find one.
Could not find a package configuration file provided by "FREEGLUT" with any
of the following names:
FREEGLUTConfig.cmake
freeglut-config.cmake
Add the installation prefix of "FREEGLUT" to CMAKE_PREFIX_PATH or set
"FREEGLUT_DIR" to a directory containing one of the above files. If
"FREEGLUT" provides a separate development package or SDK, be sure it has
been installed.
If your application is GLUT-compatible, that it doesn't use any extension of freeglut, then it is better to search GLUT instead of FREEGLUT:
find_package(GLUT REQUIRED)
"Find" script used by this command is already shipped into CMake distro, and it searches freeglut too.
(Note, that with that command variables for include directories and linking libraries are GLUT_INCLUDE_DIR and GLUT_LIBRARY correspondingly).
If your application requires exactly freeglut (that is, uses some of its extensions incompatible with other GLUT implementations), you need to ship your package with FindFREEGLUT.cmake script and adjust CMAKE_MODULE_PATH variable correspondingly:
# Assuming you have <source-dir>/cmake/FindFREEGLUT.cmake
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(FREEGLUT REQUIRED)
You may find existing script in the net, or write it by yourself, like here.
In any case, if you have freeglut installed into non-system location, you need to hint CMake about that. E.g., by adjusting CMAKE_PREFIX_PATH.

How to check if generator is a multi-config generator in a CMakeLists.txt

The Cmake FAQ
and
other
places
recommend to check CMAKE_CONFIGURATION_TYPES to recognize a multi-configuration generator. I have found several questions where this did not work (for example this one). The issue seems to be that the variable is not set the first time cmake is called.
I tested with the following file
cmake_minimum_required(VERSION 2.6)
if(CMAKE_CONFIGURATION_TYPES)
message("Multi-configuration generator")
else()
message("Single-configuration generator")
endif()
project(foo)
and called it like this
mkdir build
cd build
cmake -G "Visual Studio 12 2013" ..
and got Single-configuration generator.
How should I distinguish whether the current generator supports multiple configurations?
EDITED: Added information on checking and changing CMAKE_CONFIGURATION_TYPES
Check and Changing CMAKE_CONFIGURATION_TYPES
Taking the suggestions from this question you could check and change CMAKE_CONFIGURATION_TYPES, but be aware that there was a bug 0015577: The 'project' command overwrites CMAKE_CONFIGURATION_TYPES in CMake 3.2.2 that did break this behaviour for the initial VS solution generation (fixed with CMake 3.3.0):
cmake_minimum_required(VERSION 3.3)
project(foo NONE)
if(CMAKE_CONFIGURATION_TYPES)
message("Multi-configuration generator")
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "My multi config types" FORCE)
else()
message("Single-configuration generator")
endif()
enable_language(C CXX)
Preset CMAKE_CONFIGURATION_TYPES
If you just need a certain set of configurations for multi-configuration environments you can do (thanks to #Tsyvarev for the suggestion):
cmake_minimum_required(VERSION 2.8)
# NOTE: Only used in multi-configuration environments
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "My multi config types" FORCE)
project(foo)
None multi-configuration environments will just ignore it. But be aware that other CMake modules like findBoost.cmake, findCUDA.cmake may rely on CMAKE_CONFIGURATION_TYPES being empty for single-configuration environments (thanks again #Tsyvarev for the hint).
So a better solution would be adding toolchain files for all your supported generators. They are generally useful, because there you can handle all the toolchain/generator specific parts.
Here is an extract of my VSToolchain.txt:
# Reduce the config types to only Debug and Release
SET(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE)
# Standard is a console app. If you need a windows app, use WIN32 define in add_executable
set(CMAKE_WIN32_EXECUTABLE 0 CACHE INTERNAL "")
CMAKE_WIN32_EXECUTABLE is just there to show what kind of settings I have put in my Visual Studio toolchain file.
Another CMake command line solution is suggested here: How to create cmake build configuration without debug symbols and without optimizations?
Only Checking CMAKE_CONFIGURATION_TYPES
If you only want do check what CMake does set in CMAKE_CONFIGURATION_TYPES:
I just tested your above code with Visual Studio 2013 and MinGW/GCC (both with empty build directories). You just need one small change and move the check after the project() command:
project(foo)
message("CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES}")
if(CMAKE_CONFIGURATION_TYPES)
message("Multi-configuration generator")
else()
message("Single-configuration generator")
endif()
And I get for VS2013:
CMAKE_CONFIGURATION_TYPES Debug;Release;MinSizeRel;RelWithDebInfo
Multi-configuration generator
And for GCC:
CMAKE_CONFIGURATION_TYPES
Single-configuration generator
For more details about what CMake does see:
CMAKE_CONFIGURATION_TYPES set by EnableLanguage() in cmGlobalVisualStudio7Generator.cxx
CMake: In which Order are Files parsed (Cache, Toolchain, …)?
I see you are on CMake v2.6, but for anyone who is on v3.9+, v3.9 introduced the global property called GENERATOR_IS_MULTI_CONFIG:
Read-only property that is true on multi-configuration generators.
You can load the value into a CMake variable like so:
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
This very approach is recommended in "Professional CMake" by Craig Scott, along with explanations of the shortcomings of other approaches- especially those involving CMAKE_CONFIGURATION_TYPES. The book is $30 but the section I'm referring to is in the sample chapters.

Changed find_library behavior from CMake 2.8 to CMake 3.2

I have got the following problem while migrating from CMake 2.8.x to 3.2.x. Thereby, it seems that the internal behavior of find_library changed. Here is a minimal example which demonstrates my problem.
Consider that we are search for library called libopenblas.so which is located in /scratch/local_install/lib and /usr/lib/openblas-base. The LD_LIBRARY_PATH environment variable is set to /scratch/local_install/lib.
The CMakeLists.txt file is the following:
PROJECT(TEST)
cmake_minimum_required(VERSION 2.8)
SET(_libname "openblas")
SET(_libdir ENV LD_LIBRARY_PATH "/usr/lib/openblas-base")
find_library(OPENBLAS_LIBRARY
NAMES ${_libname}
HINTS ${_libdir}
PATHS ${_libdir}
)
MESSAGE("OPENBLAS: ${OPENBLAS_LIBRARY}")
If I execute this using CMake 2.8.7 or 2.8.12, I get
OPENBLAS: /scratch/koehlerm/local_install/lib/libopenblas.so
If I configure the code using CMake 3.2.1, I get
OPENBLAS: /usr/lib/openblas-base/libopenblas.so
which I only want to get if there is none libopenblas.so in the LD_LIBRARY_PATH. How can I restore the old behavior of CMake 2.8.x even if the code is configured with CMake 3.2.x?
Use NO_DEFAULT_PATH for find_library, then it will ignore the default location. See the documentation.
To get the bahvior you want, use find_library twice. First with NO_DEFAULT_PATH and after that without. If it is found the first time, the result is cached and the second call including the default path is skipped. If nothing is found first, it will be re-run and look at the default paths, too.

Using CMake with ifort compiler

I am using CMake 2.8.7 on a Linux machine with Intel 11.0 compilers. I am trying to use CMake for the first time as I would like to build this project on both Windows and Linux machines.
I though of using a simple approach first and used a standard Hello World example:
My src/HelloWorld.f90:
!Test helloworld in Fortran using Cmake
program hello
print *, "Hello World!"
end program hello
My main CMakeLists.txt:
# States that CMake required version must be greater than 2.8.7
cmake_minimum_required(VERSION 2.8.7)
enable_language (Fortran)
project(helloworld Fortran)
add_subdirectory(src)
SET_TARGET_PROPERTIES(helloworld PROPERTIES LINKER_LANGUAGE FORTRAN)
My src/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.7)
# Include the directory itself as a path to include directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# For a large number of source files you can create it in a simpler way
# using file() function:
file(GLOB helloworld_SOURCES *.f90)
I still get an error which says CMAKE_FORTRAN_LINK_EXECUTABLE variable missing. I looked at Abinader's CMake tutorial#1, but haven't had success so far.
any suggestions?? Thanks in advance !
Not a direct answer, as I've never used fortran with cmake, but I can see a few issues here.
First of all: where is your target helloworld defined? project is not a target.
Secondly: where do you use helloworld_SOURCES variable?
Try a more regular way. In your src/CMakeLists.txt add line at the end of file with:
add_executable(helloworld ${helloworld_SOURCES})
Also remove SET_TARGET_PROPERTIES(helloworld PROPERTIES LINKER_LANGUAGE FORTRAN) from main one as it should not be necessary.
Last advice: try not to use file(GLOB ). It is better to define list of all files manualy.
Probably the upper-case "FORTRAN", when setting the linker language is the problem. Try writing it as "Fortran" as in the enable_language statement. CMake derives the variables it uses from the language and this causes CMake to look for CMAKE_FORTRAN_LINK_EXECUTABLE instead of CMAKE_Fortran_LINK_EXECUTABLE.
As also mentioned by Michal, the add_executable has to be added to your CMakeLists.txt.
I tested your issue with the following CMake configurations files
main CMakeLists.txt:
# States that CMake required version must be greater than 2.8.7
cmake_minimum_required(VERSION 2.8.7)
enable_language (Fortran)
project(helloworld Fortran)
add_subdirectory(src)
src/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.7)
add_executable(helloworld HelloWorld.f90)
under Linux for following versions:
ifort (IFORT) 16.0.0.20150815
cmake version 2.8.12.2
I prefer to use cmake-gui. There you can define the ifort compiler as follows:
After definition of source code and binary folder, e.g. build, press "Configure" and select
Click "Next" and define the following compilers
Click "Finish" and "Generate".
Go to build/src folder and execute make. The helloworld executable is generated with ifort successfully and could be called here.
Hint: If ifort is already the default native compiler on your Linux computer then you don't have to specify it in cmake-gui and can go ahead with the first option "Use default native compilers".
Hope it helps.
Let's try this step-by-step:
1) Your Fortran Hello, world is OK!
src/hello.f90
!Test helloworld in Fortran using Cmake
program hello
print *, "Hello World!"
end program hello
2) Now let's write the "inner" CMakeLists.txt
src/CMakeLists.txt
add_executable(helloworld hello.f90)
set_target_properties(
helloworld
PROPERTIES
LINKER_LANGUAGE Fortran
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build)
Here we've created an executable file, which you haven't in your question. Also, we've set its linker language to Fortran (it's case-sensitive parameter!) and the output directory for the compiled file.
3) Now we'll create the "main" CMakeLists.txt
CMakeLists.txt
# States that CMake required version must be greater than 2.8.7
cmake_minimum_required(VERSION 2.8.7)
project(helloworld Fortran)
add_subdirectory(src)
Here we've specified the src subdirectory with inner CMakeLists.txt and the compiler language - it's enough to use project() function, there's not need to use it together with enable_language().
4) Finally, let's build our code in out-of-source manner and run it!
cmake -S . -B build
cmake --build build
./build/helloworld