1

用例:我正在尝试编译一个测试程序,该程序使用 SDL2_ttf(使用 SDL2、Freetype、PNG 和 Zlib)探测 TrueType(tm) 字体列表。接口库存在SDL2_ttf::SDL2_ttf并与目标可执行文件成功链接。我的问题是如何获取check_c_source_runs()定义,包括目录和库。我宁愿不必手动从属性中提取所有内容,如以下代码片段所示:

include(CheckCSourceRuns)

get_property(defs TARGET SDL2_ttf::SDL2_ttf PROPERTY INTERFACE_COMPILE_DEFINITIONS)
get_property(incs TARGET SDL2_ttf::SDL2_ttf PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
get_property(libs TARGET SDL2_ttf::SDL2_ttf PROPERTY INTERFACE_LINK_LIBRARIES)

## Transform the definitions with "-D"
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.12")
    list(TRANSFORM defs PREPEND "-D")
    list(TRANSFORM incs PREPEND "-I")
else ()
    ## Code that does what list(TRANSFORM...) does in less capable CMake
    ## versions.
endif ()

set(CMAKE_REQUIRED_DEFINITIONS ${defs})
set(CMAKE_REQUIRED_INCLUDES    ${incs})
set(CMAKE_REQUIRED_LIBRARIES   ${libs})
check_c_source_runs("
#include <stdint.h>
#include <SDL.h>
#include <SDL_ttf.h>
int main(int argc, char *argv[])
{
    const char *fonts[] = {\"DejaVuSans.ttf\", \"LucidaSansRegular.ttf\", \"FreeSans.ttf\", \"AppleGothic.ttf\", \"tahoma.ttf\"};
    size_t i, cnt = 0;
    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();
    for (i = 0; i < sizeof(fonts)/sizeof(fonts[0]); ++i) {
        TTF_Font *ttf = TTF_OpenFont(fonts[i], 10);
        if (ttf != NULL) {
            fputs(fonts[i], stderr);
            if (cnt++ > 0) {
                fputc(';', stderr);
            }
            TTF_CloseFont(ttf);
        }
    }
    TTF_Quit();
    SDL_Quit();
    return 0;
}" ttfprobe_run)

链接库很麻烦,因为有从内部引用的接口库SDL2_ttf::SDL2_ttf,例如FreeType::FreeType.

建议?

4

1 回答 1

1

函数try_compiletry_run基于它们的所有东西(例如check_c_source_runs)实际上是在构建其他一些 CMake 项目。因为不能将目标传递给 CMake 项目,所以有两种方法:

  1. 将所有需要的目标属性提取到变量中,并将它们传递给新生成的项目。正如你已经做的那样。

  2. 手动为其他项目编写CMakeLists.txt,并在其中使用调用find_package和其他包发现功能。

例如,你可以CMakeLists.txt为其他项目写这样的:

# Source file is in SOURCE_FILE parameter,
# resulted executable is copied into the file pointed by EXE_FILE parameter.
cmake_minimum_required(...)
project(test_project)

# This will create 'SDL2_ttf::SDL2_ttf' target
find_package(SDL2_ttf REQUIRED)

add_executable(test_exe ${SOURCE_FILE})
target_link_libraries(test_exe SDL2_ttf::SDL2_ttf)

add_custom_command(OUTPUT ${EXE_FILE}
    COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:test_exe> ${EXE_FILE}
    DEPENDS $<TARGET_FILE:test_exe>
)

add_custom_target(copy_exe ALL DEPENDS ${EXE_FILE})

主要挑战是将尽可能多的变量传递给另一个项目,以便将其构建在与主项目相同的“环境”中。

下面的示例仅处理可能影响find_package(SDL2_ttf)通话的变量:

# Main project
# Somewhere you have this call too.
find_package(SDL2_ttf REQUIRED)

# List of arguments for the subproject
set(SUBPROJECT_ARGS
    # This affects on searching for possible `FindSDL2_ttf.cmake` script
    -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}
    # This affects on searching for `find_*` calls in find script.
    -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
)

if (SDL2_ttf_DIR)
    # This is a directory with `SDL2_ttfConfig.cmake` script
    list(APPEND SUBPROJECT_ARGS -DSDL2_ttf_DIR=${SDL2_ttf_DIR})
endif()

# build subproject
try_compile(TTF_TEST_RESULT # Variable which will contain result of building the subproject
 ${CMAKE_CURRENT_BINARY_DIR}/ttf_test # Build directory for the subproject
 <src-dir> # Source directory for the subproject, where its `CMakeLists.txt` resides.
 test_project # Project name of the subproject
 CMAKE_FLAGS
 -DSOURCE_FILE=<src-file> # Source file 
 -DEXE_FILE=<exe-file> # Path to the resulted executable file
 ${SUBPROJECT_ARGS} # The rest of arguments for subproject
 OUTPUT_VAR TTF_TEST_OUTPUT # Variable which will contain output of the build process
)

if (TTF_TEST_RESULT)
  # Subproject has been built successfully, now we can try to execute resulted file
  ...
endif()

棘手?是的。但这就是 CMake 的工作方式......

于 2020-01-21T22:25:09.040 回答