Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get CMake project version added by add_subdirectory

Tags:

cmake

I have a CMake project that depends on Google Test library. I've added Google Test using ExternalProject_Add and add_subdirectory as described here (https://github.com/google/googletest/tree/master/googletest section Incorporating Into An Existing CMake Project).

Now, after command add_subdirectory I want to check version of included project gtest and gmock, however gtest_VERSION and gmock_VERSION variables is undefined. Is it possible to get project version added by add_subdirectory?

like image 742
Kamil Zaripov Avatar asked Mar 06 '23 13:03

Kamil Zaripov


2 Answers

Since you don't have direct access to sub-directories local variables, I wanted to add my variants of making the gtest_VERSION variable CACHED and therefore globally accessible:

  1. CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE

    A CMake language file or module to be included by the project() command. This is intended for injecting custom code into project builds without modifying their source.

    file(
        WRITE "${CMAKE_BINARY_DIR}/SetProjectVersion.cmake"
        [=[
            set(${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION}" CACHE INTERNAL "")
        ]=]
    )
    set(
        CMAKE_PROJECT_gtest_INCLUDE
        "${CMAKE_BINARY_DIR}/SetProjectVersion.cmake"
    )
    
  2. Overwrite the project() command

    cmake_policy(SET CMP0048 NEW)    
    
    macro(project)
        _project(${ARGN})
        set(${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION}" CACHE INTERNAL "")
    endmacro()
    
like image 195
Florian Avatar answered Mar 11 '23 09:03

Florian


Variable <PROJECT-NAME>_VERSION has a local scope. Thus a version variable, defined by a subproject, is not visible by a main project.

Assuming a subproject's CMakeLists.txt performs project() call like

project(<project-name> VERSION <version-string> ...)

version string can be easily extracted with regular expressions:

# subproject_version(<subproject-name> <result-variable>)
#
# Extract version of a sub-project, which was previously included with add_subdirectory().
function(subproject_version subproject_name VERSION_VAR)
    # Read CMakeLists.txt for subproject and extract project() call(s) from it.
    file(STRINGS "${${subproject_name}_SOURCE_DIR}/CMakeLists.txt" project_calls REGEX "[ \t]*project\\(")
    # For every project() call try to extract its VERSION option
    foreach(project_call ${project_calls})
        string(REGEX MATCH "VERSION[ ]+([^ )]+)" version_param "${project_call}")
        if(version_param)
            set(version_value "${CMAKE_MATCH_1}")
        endif()
    endforeach()
    if(version_value)
        set(${VERSION_VAR} "${version_value}" PARENT_SCOPE)
    else()
        message("WARNING: Cannot extract version for subproject '${subproject_name}'")
    endif()

endfunction(subproject_version)

# The function's usage:    
subproject_version(gtest gtest_version)
message("VERSION for gtest: ${gtest_version}")

Implementation above uses variable <PROJECT-NAME>_SOURCE_DIR, which contains source directory of the subproject. Unlike to <PROJECT-NAME>_VERSION variable, variable with source directory has global visibility (it is CACHED, actually), thus it can be used outside of the subproject.

like image 28
Tsyvarev Avatar answered Mar 11 '23 08:03

Tsyvarev