【问题标题】:How to set "global" cmake variables from within a cmake function如何从 cmake 函数中设置“全局”cmake 变量
【发布时间】:2018-04-24 17:53:07
【问题描述】:

我编写了一个我喜欢下载和构建外部资源的函数。但是,实际上,我遇到了 cmake 函数的范围问题,我想在函数之外公开变量。我已经尝试过 GLOBAL PROPERTY、PARENT_SCOPE、CACHE STRING 和 CACHE INTERNAL,但都没有成功。如何更新以下函数中的“全局”变量?

function(DownloadExternal name source options lib_path)
    string(TOUPPER "${parent}" PARENT)
    MESSAGE(STATUS "${name}")
    MESSAGE(STATUS "     source: ${source}")
    MESSAGE(STATUS "     options: ${options}")
    MESSAGE(STATUS "     lib_path: ${lib_path}")

    set(${name}_prefix      ${EXTERNAL_FOLDER}/${name})
    set(${name}_install_dir ${${name}_prefix})
    list(APPEND ${name}_cmake_args
            ${DEFAULT_CMAKE_FLAGS}
            -DCMAKE_INSTALL_PREFIX=${${name}_prefix}
            -DBUILD_SHARED_LIBS=OFF
            -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}
            -DBUILD_SHARED_LIBS=FALSE
            ${options}
            )

    # GLOBAL Variable here is only updated locally
    #  Attempted GLOBAL PROPERTY, CACHE INTERNAL/STRING, PARENT_SCOPE
    list(APPEND EXTRA_LIBS ${${name}_install_dir}/lib/${lib_path})
    externalproject_add(${name}
            PREFIX             ${${name}_prefix}
            GIT_REPOSITORY     ${source}
            GIT_SHALLOW        1
            DOWNLOAD_DIR       ${${name}_prefix}
            UPDATE_COMMAND     git pull
            INSTALL_DIR        ${${name}_install_dir}
            CMAKE_ARGS         ${${name}_cmake_args}
            )
    include_directories(${${name}_prefix}/include)
    link_directories(${${name}_prefix}/lib)
    MESSAGE(STATUS "     prefix: ${${name}_prefix}")
    MESSAGE(STATUS "     cmake: ${${name}_cmake_args}")
    MESSAGE(STATUS "     install: ${${name}_install_dir}")
    MESSAGE(STATUS "     libs: ${EXTRA_LIBS}")
endfunction(DownloadExternal)

用法(这两行太长了。我想在函数内添加依赖):

# ----------------------------------------------------------------------------------------------------------------------
#  harfbuzz - A Freetype dependency
# ----------------------------------------------------------------------------------------------------------------------
DownloadExternal(harfbuzz https://github.com/harfbuzz/harfbuzz "-DHB_HAVE_FREETYPE=ON")
ExternalProject_Get_Property(harfbuzz install_dir)
set(harfbuzz_install_dir ${install_dir})

以后的使用:

add_executable(${CMAKE_PROJECT_NAME} ${${PROJECT_NAME}_SOURCE_FILES})

# TODO: Find a way to make this a list
add_dependencies(freetype harfbuzz)
add_dependencies(${CMAKE_PROJECT_NAME} freetype)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

#  TODO: Find a way to add these in the function
target_link_libraries(${CMAKE_PROJECT_NAME}
        ${harfbuzz_install_dir}/lib/libharfbuzz.a
        )

我想要做的或多或少是这样的:

# ----------------------------------------------------------------------------------------------------------------------
#  harfbuzz - A Freetype dependency
# ----------------------------------------------------------------------------------------------------------------------
DownloadExternal(harfbuzz https://github.com/harfbuzz/harfbuzz "-DHB_HAVE_FREETYPE=ON" libharfbuzz.a)

...snip...

target_link_libraries(${CMAKE_PROJECT_NAME}
        ${EXTRA_LIBS}
        )

【问题讨论】:

标签: function variables scope cmake


【解决方案1】:

我相信这行得通。

必须在 cmake 顶部附近定义全局属性...

DEFINE_PROPERTY(GLOBAL PROPERTY EXTRA_LIBS
        BRIEF_DOCS "Contains linkable libraries"
        FULL_DOCS "Contains paths to libraries for linking")

然后在函数内部,我们必须将一个局部变量设置为全局属性的内容。此外,更新局部变量,然后将其重新添加到全局属性中。

function(DownloadExternal name source options lib_path)
    string(TOUPPER "${parent}" PARENT)
    MESSAGE(STATUS "---------------------------------------------------------------------------")
    MESSAGE(STATUS "${name}")
    MESSAGE(STATUS "     source: ${source}")
    MESSAGE(STATUS "     options: ${options}")
    MESSAGE(STATUS "     lib_path: ${lib_path}")
    GET_PROPERTY(extra_libs GLOBAL PROPERTY EXTRA_LIBS)
    set(${name}_prefix      ${EXTERNAL_FOLDER}/${name})
    set(${name}_install_dir ${${name}_prefix})
    list(APPEND ${name}_cmake_args
            ${DEFAULT_CMAKE_FLAGS}
            -DCMAKE_INSTALL_PREFIX=${${name}_prefix}
            -DBUILD_SHARED_LIBS=OFF
            -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}
            -DBUILD_SHARED_LIBS=FALSE
            ${options}
            )
    list(APPEND extra_libs ${${name}_install_dir}/lib/${lib_path})
    SET_PROPERTY(GLOBAL PROPERTY EXTRA_LIBS ${extra_libs})
    externalproject_add(${name}
            PREFIX             ${${name}_prefix}
            GIT_REPOSITORY     ${source}
            GIT_SHALLOW        1
            DOWNLOAD_DIR       ${${name}_prefix}
            UPDATE_COMMAND     git pull
            INSTALL_DIR        ${${name}_install_dir}
            CMAKE_ARGS         ${${name}_cmake_args}
            )
    include_directories(${${name}_prefix}/include)
    link_directories(${${name}_prefix}/lib)
    MESSAGE(STATUS "     prefix: ${${name}_prefix}")
    MESSAGE(STATUS "     cmake: ${${name}_cmake_args}")
    MESSAGE(STATUS "     install: ${${name}_install_dir}")
    MESSAGE(STATUS "     libs: ${extra_libs}")
endfunction(DownloadExternal)

最后,为了以后使用该属性,我们还必须再次获取它。

GET_PROPERTY(extra_libs GLOBAL PROPERTY EXTRA_LIBS)
target_link_libraries(${CMAKE_PROJECT_NAME}
        ${BZIP2_LIBRARIES}
        ${OPENGL_LIBRARIES}
        ${extra_libs}
        )

【讨论】:

    【解决方案2】:

    您可以使用extra_libs 的输入/输出参数DownloadExternal

    function(DownloadExternal name source options lib_path extra_list)
            ...
            set(tmpExtra_list ${extra_list} NEW_STUFF_TO_ADD)
            set(${extra_list} ${tmpExtra_list} PARENT_SCOPE) # return value
    endfunction()
    

    优点:

    • 许多编程语言中的已知概念
    • 变量的来源并不神奇
    • 您的函数的用户可以为变量定义一个名称

    对比:

    • 必须修改函数的签名

    【讨论】:

      猜你喜欢
      • 2012-04-19
      • 2017-03-09
      • 1970-01-01
      • 2018-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多