Использование интерфейсной библиотеки с check_c_source_runs () или try_run () - PullRequest
1 голос
/ 21 января 2020

Вариант использования: я пытаюсь скомпилировать тестовую программу, которая проверяет список шрифтов TrueType (tm), используя SDL2_ttf (с SDL2, Freetype, PNG и Zlib). Интерфейсная библиотека 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 .

Предложения?

1 Ответ

1 голос
/ 22 января 2020

Функции try_compile и try_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})

Основная задача - передать столько переменных в другой проект, сколько необходимо для его встраивания в один и тот же проект. "environment" как основной проект.

Пример ниже обрабатывает только переменные, которые могут повлиять на 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()

Tricky? Да. Но так работает CMake ...

...