使用带有 check_c_source_runs() 或 try_run() 的接口库
Using an interface library with check_c_source_runs() or try_run()
用例:我正在尝试编译一个测试程序,该程序使用 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)
Link 库很复杂,因为在 SDL2_ttf::SDL2_ttf
中引用了接口库,例如FreeType::FreeType
.
建议?
函数 try_compile
和 try_run
以及基于它们的所有内容(例如 check_c_source_runs
)实际上是 构建其他一些 CMake 项目。因为不能给CMake工程传targets,所以有两种方式:
将所有需要的目标属性提取到变量中,并将它们传递给新生成的项目。正如你已经做的那样。
手动为其他项目编写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()
棘手?是的。但这就是 CMake 的工作方式...
用例:我正在尝试编译一个测试程序,该程序使用 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)
Link 库很复杂,因为在 SDL2_ttf::SDL2_ttf
中引用了接口库,例如FreeType::FreeType
.
建议?
函数 try_compile
和 try_run
以及基于它们的所有内容(例如 check_c_source_runs
)实际上是 构建其他一些 CMake 项目。因为不能给CMake工程传targets,所以有两种方式:
将所有需要的目标属性提取到变量中,并将它们传递给新生成的项目。正如你已经做的那样。
手动为其他项目编写
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()
棘手?是的。但这就是 CMake 的工作方式...