cmake(14):利用set_property命令设置全局属性

本文介绍了如何在CMake中利用set_property()和get_property()命令,根据不同操作系统动态选择子目录并附加源文件到编译列表,实现源代码的有条件编译。示例详细展示了如何在Linux和Windows下分别处理property.c文件,并通过CMakeLists.txt进行管理。

目录

说明

简单示例

main.c 

property.c 

根目录下的 CMakeLists.txt

子目录下的 CMakeLists.txt 

set_property() 命令

get_property() 命令

参考资料


说明

在开发过程碰到需要在上级目录中构建,而源代码又分别写在下级目录的情况,同时又要根据不同的情况选择性地添加不同的源代码进行编译,所以考虑将需要编译的源代码放到一个 cmake 列表中。但是 set() 对应生成的变量都是局部变量(即不同的目录下不共用),于是使用 set_property() 命令。

简单示例

为了简化,我这里假设在 main() 函数下调用一个 show_system() 函数用于显示当前系统的名称。程序整体结构如下:

$ tree
├── CMakeLists.txt              
├── linux
│   ├── CMakeLists.txt
│   ├── property.c
│   └── property.h
├── main.c
└── win
    ├── CMakeLists.txt
    ├── property.c
    └── property.h

main.c 

程序很简单,就调用子目录下定义的函数。

#include <stdio.h>

#include <property.h>

int main()
{
    show_system();

    return 0;
}

property.c 

在 linux 和 win 的实现都一样。

#include <stdio.h>

#include "property.h"

void show_system()
{
    printf("This is linux\n");    // in linux
    printf("This is windows\n");  // in win
}

 

根目录下的 CMakeLists.txt

cmake_minimum_required (VERSION 3.13.0)

project (property_test VERSION 0.0.4)

# 设置全局属性 SOURCE_LIST
set_property( GLOBAL APPEND PROPERTY SOURCE_LIST)

# 如果是 Linux 系统,选择编译 linux 目录
IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
    include_directories (linux)
    add_subdirectory (linux)

# Window 系统下选择编译 win 目录
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Windows")
    include_directories (win)
    add_subdirectory (win)
ENDIF (CMAKE
<think> 我们正在解决三个CMake错误: 1. find_package for module Qt6 called with REQUIRED, but CMAKE_DISABLE_FIND_PACKAGE_Qt6 is enabled 2. get_target_property() called with non-existent target "Qt6::qmake" 3. get_filename_component called with incorrect number of arguments 根据引用[1]和[2]提供的线索以及用户的问题描述,我们逐步分析。 错误1:当调用`find_package(Qt6 REQUIRED ...)`时,如果设置了`CMAKE_DISABLE_FIND_PACKAGE_Qt6`为启用状态,则会导致此错误。因为`CMAKE_DISABLE_FIND_PACKAGE_<PackageName>`是一个变量,用于禁用对特定包的查找。 错误2:尝试获取一个名为`Qt6::qmake`的目标属性,但该目标不存在。通常,`Qt6::qmake`目标是由Qt6的CMake包提供的,但在某些情况下可能没有正确导入。 错误3:`get_filename_component`函数被调用时参数数量不正确。这个函数通常需要3个或4个参数(具体取决于使用方式),可能是在调用时传递的参数数量不对。 解决方案: 对于错误1: - 检查CMake中是否设置了`CMAKE_DISABLE_FIND_PACKAGE_Qt6`变量。如果设置了,需要将其设置为OFF或者未设置。可以在CMakeLists.txt中添加: ```cmake set(CMAKE_DISABLE_FIND_PACKAGE_Qt6 OFF) ``` 或者确保没有地方将其设置为ON。 对于错误2: - 目标`Qt6::qmake`不存在,可能是因为没有正确找到Qt6安装。确保已经通过`find_package`成功找到Qt6。另外,在Qt6中,通常不需要直接使用`Qt6::qmake`目标,因为qmake是用于构建Qt本身的工具,在应用程序中通常使用`Qt6::Core`等组件。因此,检查代码中是否有不必要的对`Qt6::qmake`的引用,如果有,将其移除。 对于错误3: - 检查调用`get_filename_component`的语句。该函数的常用形式有两种: ```cmake get_filename_component(<var> <filename> <comp> [CACHE]) ``` 和 ```cmake get_filename_component(<var> <filename> <comp> [BASE_DIR <dir>] [CACHE]) ``` 确保传递了正确的参数数量(至少3个,最多5个)。通常,我们使用三个参数:变量名、文件名、要获取的组件类型(如ABSOLUTE、DIRECTORY、NAME等)。例如: ```cmake get_filename_component(my_var ${some_file} ABSOLUTE) ``` 另外,根据引用[1]中的内容,使用Qt6的DataVisualization模块需要: ```cmake find_package(Qt6 REQUIRED COMPONENTS DataVisualization) target_link_libraries(appdicpAUV PRIVATE Qt6::DataVisualization) ``` 但是,在查找Qt6之前,需要确保没有禁用该包,并且Qt6的安装正确。 综合以上,我们可以采取以下步骤: 步骤1:确保没有禁用Qt6的查找 在调用`find_package`之前,确保`CMAKE_DISABLE_FIND_PACKAGE_Qt6`没有被设置为ON。可以在CMakeLists.txt的开头添加: ```cmake if (DEFINED CMAKE_DISABLE_FIND_PACKAGE_Qt6) unset(CMAKE_DISABLE_FIND_PACKAGE_Qt6) endif() ``` 步骤2:正确查找Qt6 按照引用[1]的方式调用`find_package`,并指定所需的组件(如DataVisualization)。注意,如果项目需要其他组件,也要一并列出。 步骤3:移除对不存在的目标`Qt6::qmake`的引用 在CMakeLists.txt中搜索`Qt6::qmake`,如果找到了,考虑删除或替换为正确的目标。在Qt6中,通常使用`Qt6::moc`、`Qt6::rcc`等目标,但很少直接使用`Qt6::qmake`。如果确实需要获取qmake的路径,可以使用`Qt6_QMAKE_EXECUTABLE`变量(在找到Qt6包后设置)。 步骤4:修正`get_filename_component`的调用 找到调用该函数的地方,检查参数数量。通常,我们只需要三个参数:变量名、文件名、组件类型。例如,将错误的调用: ```cmake get_filename_component(my_var some_file) ``` 改为: ```cmake get_filename_component(my_var some_file ABSOLUTE) ``` 步骤5:设置编译器选项(如果需要) 根据引用[2],如果使用MSVC编译器,可能需要设置编码和C++标准,例如: ```cmake if (MSVC) add_compile_options(/std:c++17 /utf-8) add_compile_definitions(_HAS_STD_BYTE=0) endif() ``` 下面是一个修改后的CMakeLists.txt的示例片段: ```cmake cmake_minimum_required(VERSION 3.10) project(MyProject) # 步骤1:确保没有禁用Qt6的查找 if (DEFINED CMAKE_DISABLE_FIND_PACKAGE_Qt6) unset(CMAKE_DISABLE_FIND_PACKAGE_Qt6) endif() # 步骤2:查找Qt6 find_package(Qt6 REQUIRED COMPONENTS Core DataVisualization) # 这里以Core和DataVisualization为例,根据实际需要添加组件 # 步骤5:设置编译器选项(如果需要) if (MSVC) add_compile_options(/std:c++17 /utf-8) add_compile_definitions(_HAS_STD_BYTE=0) endif() # 步骤3:避免使用Qt6::qmake,如果确实需要qmake可执行文件,可以使用Qt6_QMAKE_EXECUTABLE # 例如:message(STATUS "Qmake path: ${Qt6_QMAKE_EXECUTABLE}") # 但通常不需要在目标中链接它。 add_executable(appdicpAUV main.cpp) # 链接目标库 target_link_libraries(appdicpAUV PRIVATE Qt6::Core Qt6::DataVisualization) # 步骤4:确保在调用get_filename_component时参数正确 # 假设在某个地方需要获取当前目录的绝对路径 get_filename_component(PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR} ABSOLUTE) ``` 注意:以上代码需要根据实际项目调整。 如果问题仍然存在,请检查Qt6的安装路径是否正确,并确保CMake能够找到它。可以通过设置`Qt6_DIR`变量来指定Qt6安装目录下的`lib/cmake/Qt6`路径。 例如,在配置CMake时使用: ``` cmake -DQt6_DIR=/path/to/Qt/6.0.0/gcc_64/lib/cmake/Qt6 .. ``` 希望这些步骤能解决你的问题。 §§相关问题§§ 1. 如何在CMake中正确设置Qt6的路径? 2. CMake中`find_package`的工作原理是什么? 3. 如何解决CMake中目标不存在的问题? 4. 在CMake中如何正确使用`get_filename_component`函数? 5. 如何为MSVC编译器设置C++标准? </think> 针对您遇到的CMake错误,以下是分步解决方案: ### 错误1:`find_package for module Qt6 called with REQUIRED, but CMAKE_DISABLE_FIND_PACKAGE_Qt6 is enabled` **原因**:CMake设置了`CMAKE_DISABLE_FIND_PACKAGE_Qt6=ON`,这会显式禁用Qt6包的查找[^1]。 **解决方法**: ```cmake # 在find_package前添加(推荐全局取消禁用) set(CMAKE_DISABLE_FIND_PACKAGE_Qt6 OFF) # 显式关闭禁用标志 # 或检查并覆盖可能存在的缓存变量 if(DEFINED CMAKE_DISABLE_FIND_PACKAGE_Qt6) set(CMAKE_DISABLE_FIND_PACKAGE_Qt6 OFF CACHE BOOL "Override" FORCE) endif() ``` ### 错误2:`get_target_property() called with non-existent target "Qt6::qmake"` **原因**:`Qt6::qmake`不是有效目标,Qt6中qmake被封装为工具链的一部分,应通过变量访问[^2]。 **解决方法**: ```cmake # 替换错误的目标引用 # get_target_property(QMAKE_EXE Qt6::qmake IMPORTED_LOCATION) ❌ # 正确方式:使用Qt6提供的变量 find_package(Qt6 REQUIRED COMPONENTS Core) # 确保先找到Qt6 set(QMAKE_EXE ${Qt6_QMAKE_EXECUTABLE}) # 直接使用预定义变量 ✅ ``` ### 错误3:`get_filename_component called with incorrect number of arguments` **原因**:函数参数数量错误,该函数需3个基本参数(变量名、路径、类型)[^2]。 **正确用法**: ```cmake # 错误示例:缺少类型参数 # get_filename_component(OUT_VAR "some/path") ❌ # 正确示例(获取绝对路径): get_filename_component(ABS_PATH "some/path" ABSOLUTE) ✅ # 其他常用类型: # DIRECTORY = 提取目录部分 # NAME = 提取文件名部分 ``` ### 完整修正示例 ```cmake cmake_minimum_required(VERSION 3.10) project(YourProject) # 关键修复1: 显式启用Qt6查找 set(CMAKE_DISABLE_FIND_PACKAGE_Qt6 OFF) # 关键修复2: 正确查找Qt6组件 find_package(Qt6 REQUIRED COMPONENTS Core DataVisualization # 根据引用[1]添加 ) # 关键修复3: 使用变量替代错误目标 message(STATUS "Qmake路径: ${Qt6_QMAKE_EXECUTABLE}") # 关键修复4: 修正路径获取函数 get_filename_component(PROJECT_DIR ${CMAKE_SOURCE_DIR} ABSOLUTE) # 链接库(引用[1]) add_executable(appdicpAUV main.cpp) target_link_libraries(appdicpAUV PRIVATE Qt6::Core Qt6::DataVisualization ) ``` ### 补充建议 1. **Qt安装验证**: 运行`qt-cmake --find-package -DNAME=Qt6`检查Qt6安装路径是否被正确识别。 2. **路径分隔符问题**: 在Windows上使用`/`代替`\`避免转义问题: ```cmake set(CMAKE_PREFIX_PATH "C:/Qt/6.5.0/msvc2019_64/lib/cmake") ``` 3. **工具链重置**: 删除`CMakeCache.txt`和`CMakeFiles`目录后重新生成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翔底

您的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值