8

I would like to target a specific version of CMake that is older than the version I am using myself (related to this question, i.e. correctly using cmake_minimum_required()), and it would be nice to be able to determine which features to stay away from, for instance.

Is it possible to find the first version that a certain feature (variable, function, property, ...) was introduced in CMake?

As far as I can tell, the CMake documentation does not directly include this information (except for indirectly via the release notes). A great example of how this could work is the Qt API documentation (e.g. see the documentation for QCryptographicHash).

EDIT: I created a git repo with a modified version of the solution provided by Florian: https://github.com/mbitsnbites/cmake-minver

Community
  • 1
  • 1
m-bitsnbites
  • 994
  • 7
  • 19
  • 1
    It would be nice if this would be part of the documentation. So far I think there is only something like [CMake Version Compatibility Matrix](https://cmake.org/Wiki/CMake_Version_Compatibility_Matrix) (which is not updated anymore). See also [here](https://cmake.org/pipermail/cmake/2015-October/061747.html). I'm often just check for certain commands/policy/etc. availability with e.g. `if (COMMAND ...)`. Some projects just deliver their own/required CMake version with it. – Florian Nov 28 '16 at 12:53
  • 1
    That's a big miss in CMake's documentation. You can find that "manually" when reading a page: version number is part of the url, so you can test the same url with earlier version numbers until the page becomes unavailable. That's tough, but AFAIK there is no other (up to date) way – rocambille Nov 28 '16 at 13:11
  • The approach described by Daniele Domenichelli is certainly interesting, though I was hoping for a more "official" solution. Maybe the best solution is to just install the target version of CMake and build my project using it most of the times? – m-bitsnbites Nov 28 '16 at 13:25
  • @wasthishelpful, that sounds like something that could be made into a meta service (perhaps possible to implement as a Firefox plugin). – m-bitsnbites Nov 28 '16 at 13:39
  • @m-bitsnbites maybe... I will think about it. Let me know if you implement it before I do ;) – rocambille Nov 28 '16 at 13:42

3 Answers3

5

After reading the comments here is my CMake version of a command/property/etc. checker:

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.5)

function(version_required_by)
    set(_keywords ${ARGN})
    set(_temp_file "${CMAKE_CURRENT_BINARY_DIR}/download.txt")
    foreach(_ver IN ITEMS 2.6 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.8.10 2.8.11 2.8.12 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7)
        message(STATUS "Check version required: ${_ver}")
        if (_ver VERSION_LESS 2.8)
            set(_url "https://cmake.org/cmake/help/cmake${_ver}docs.html")                
        elseif (_ver VERSION_LESS 3.0)
            set(_url "https://cmake.org/cmake/help/v${_ver}/cmake.html")
        else()                
            set(_url "https://cmake.org/cmake/help/latest/release/${_ver}.html")
        endif()
        file(DOWNLOAD "${_url}" "${_temp_file}")                
        file(READ "${_temp_file}" _help_text)
        foreach(_keyword IN LISTS _keywords)
            string(FIND "${_help_text}" "${_keyword}" _found)
            if (NOT _found EQUAL -1)  
                message(STATUS "${_keyword} -> v${_ver}")
                list(REMOVE_ITEM _keywords "${_keyword}")
            endif()
        endforeach()
        if (NOT _keywords)
            message("cmake_minimum_required(VERSION ${_ver} FATAL_ERROR)") 
            if (NOT CMAKE_MINIMUM_REQUIRED_VERSION)
                cmake_minimum_required(VERSION ${_ver} FATAL_ERROR)
            endif()
            break()
        endif()
    endforeach()
    if (_keywords)
        message(FATAL_ERROR "Check version required error: Not found ${_keywords}") 
    endif()
endfunction()

if (CMAKE_SCRIPT_MODE_FILE)
    foreach(_i RANGE 3 ${CMAKE_ARGC})
        list(APPEND _args "${CMAKE_ARGV${_i}}")
    endforeach()
else()
    list(
        APPEND _args
        "string(FIND" 
        "target_include_directories" 
        "BUILDSYSTEM_TARGETS"
    )
endif()
version_required_by(${_args})

Would give for those examples I used for testing it:

-- Check version required: 2.6
...
-- Check version required: 2.8.5
-- string(FIND -> v2.8.5
...
-- Check version required: 2.8.11
-- target_include_directories -> v2.8.11
...
-- Check version required: 3.7
-- BUILDSYSTEM_TARGETS -> v3.7
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)

Edit: Or if you e.g. run the above in script mode:

> cmake -P CMakeLists.txt target_include_directories
-- Check version required: 2.6
...
-- Check version required: 2.8.11
-- target_include_directories -> v2.8.11
cmake_minimum_required(VERSION 2.8.11 FATAL_ERROR)

Reference

Florian
  • 39,996
  • 9
  • 133
  • 149
  • That's a sweet (meta) solution! I will try it out. In this form (a local tool) I think I would turn it into a shell command so that you can easily do something like `cmake-minver target_include_directories` and get a result on stdout. – m-bitsnbites Nov 30 '16 at 13:09
  • @m-bitsnbites You can always run the above in script mode with `cmake -P` and checking for additional arguments with [`CMAKE_ARGV0 ...`](https://cmake.org/cmake/help/latest/variable/CMAKE_ARGV0.html). I'll update my answer later today accordingly. – Florian Nov 30 '16 at 13:15
  • @m-bitsnbites Ok. Modified the script a little so it can be also run in CMake's script mode. – Florian Nov 30 '16 at 20:48
  • 1
    It works nicely! I created a github repo with a slightly more scriptified version: [github.com/mbitsnbites/cmake-minver](https://github.com/mbitsnbites/cmake-minver). Feel free to do pull requests ;-) – m-bitsnbites Dec 01 '16 at 08:50
  • @m-bitsnbites You're welcome. And bringing it to GitHub was a good idea. So the script may develop further over time. Couldn't resist and already added a pull request :-) – Florian Dec 01 '16 at 21:00
  • Thanks! I'm sym-linking cmake-minver (in my PATH) to a clone of the GitHub repo. Convenient! – m-bitsnbites Dec 01 '16 at 21:46
1

I made a firefox plugin, named CSince, available in https://addons.mozilla.org/firefox/addon/csince/.

When viewing a page of CMake documentation, it checks since which version the corresponding feature exists, and adds the information to the html contents.

A first checking is performed for versions starting with v3.0: the url pattern is checked for prior versions until a 404 error is returned by the server. For example, considering url for property BINARY_DIR:

https://cmake.org/cmake/help/latest/prop_dir/BINARY_DIR.html

Here urls are tested replacing latest with a version string:

https://cmake.org/cmake/help/v3.0/prop_dir/BINARY_DIR.html
https://cmake.org/cmake/help/v3.1/prop_dir/BINARY_DIR.html
https://cmake.org/cmake/help/v3.2/prop_dir/BINARY_DIR.html
...

Versions are tested using a dichotomic approach, to limit requests.

If the first checking process returns v3.0, a second pass is performed for older versions using a less reliable test: the single-page documentation is requested, and the feature string is searched in the text.

This two-passes system allows for example to find the right version for the property BINARY_DIR: the string BINARY_DIR obviously exists in CMake documentation v2.6, while it exists as a property only since CMake v3.7.

Any bug report or improvement request are welcome. Code source is available on GitHub under license MIT/X11: https://github.com/wasthishelpful/csince.

rocambille
  • 15,398
  • 12
  • 50
  • 68
  • That's very high level, you only get newly introduced commands. Often you need to know when a new key word or behavior was added to an existing command. Fortunately, CMake will provide this information more often with the upcoming version 3.20. – usr1234567 Jan 13 '21 at 08:37
1

The issue is a known problem, and there are brave souls that are trying to get the situation improved. CMake 3.19.0, 3.19.1, and the upcoming 3.20.0 got added the CMake version when a feature was introduced. This happened to hundreds of places in the CMake documentation. See one of the commits from Nikita Nemkin, more are linked in the issue above.

In the CMake documentation it looks like the screenshot. Mind the New in version 3.xx and that the screenshot is the currently documentation generated from Git master. enter image description here

Technically, the version is annotated in the documentation with the Sphinx' builtin command versionadded.
CMake provides a script, to generate the version added information, in Utilities/Sphinx/stamp_version.py.

usr1234567
  • 21,601
  • 16
  • 108
  • 128