windows--cmake与c++的使用教程(11)

1 概述

本节目标:设置项目包含头文件路径, 关键语法target_include_directories

2 目标

  • main.cc 与 Typedef.h不在同一个目录下, Typedef.h 位于include目录下,main.cc位于src目录下
  • main.cc 使用TypeDef.h中定义的类型和函数

2.1 目录结构

  • 目录结构
.
│  CMakeLists.txt
│  
├─Common
│      CommonOutput.cmake
│      
├─include
│      Typedef.h
│      
└─src
        main.cc

2.2 main.cc代码

  • 使用头文件 Typedef.h 中的函数 engine_count 和 结构体stAir
#include <iostream>
#include <Typedef.h>

/// 调用飞机属性
void call_air_demo()
{
	// 结构体使用范例
	cmake_demo::stAir aircraft(5678, std::string("B-0001"));

	// 输出
	std::cout << "\nid=" << aircraft.id_ << ", name=" << aircraft.name_.c_str() << "\n";

	// 函数使用范例
	std::cout << "engine_count=" << cmake_demo::air_engine_count() << "\n";
}

/// 程序入口
int main(int argc, char* argv[], char* env[])
{
	call_air_demo();
	
	return 0;
}

2.3 Typedef.h代码

  • 定义函数engine_count 和 结构体 stAir
  • 上码:
#ifndef TYPE_DEF_H_
#define TYPE_DEF_H_
#include <string>

namespace cmake_demo
{
    //----------------------------------------------------------------
    // 飞机引擎数量
    //----------------------------------------------------------------
    int air_engine_count()
    {
        return 4;
    }

    ///----------------------------------------------------------------
    /// 定义飞机属性
    ///----------------------------------------------------------------
    struct stAir_
    {
    public:
        stAir_(const int & id, const std::string& newName)
        {
            id_ = id;
            name_ = newName;
        }

    public:
        /// 飞机ID
        int     id_;
        /// 唯一飞机机号
        std::string name_;
    };

    using stAir = stAir_;

} // namespace 

#endif /// ! TYPE_DEF_H_

3 编写CMake脚本

3.1 头文件加入项目

  • 项目因为使用到了 typedef.h 文件, 所以, 也需要将其纳入项目中

3.2 指定项目搜索头文件路径 target_include_directories

  • 主角: target_include_directories
  • 具体用法可参考官方文档。 这里仅仅演示自己够用的语法
  • target_include_directories使用时,需要指定 目标路径 以及 属性传递(这里,不展开,以后专门出一随笔说明) (属性传递有3个: PRIVATE, PUBLIC 和 INTERFACE)
  • target_include_directories 使用时, 一次调用,可以指定多个路径, 比如
target_include_directories( ${PROJECT_NAME}        
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include     # 路径1
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src    		# 路径2
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}     		# 路径3
)
  • 上面的代码也可以写成:
target_include_directories( ${PROJECT_NAME}        
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include     # 路径1
    ${CMAKE_CURRENT_SOURCE_DIR}/src    				# 路径2, 少了关键字 PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}     				# 路径3, 少了关键字 PRIVATE
)
  • target_include_directories本文演示中的例子
# 指定 ${PROJECT_NAME}, 也就是 HelloCMake 的头文件搜索路径
target_include_directories( ${PROJECT_NAME}         # 参数1 项目名称
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include     # 参数2, 指定哪个搜索头文件路径, 这里的PRIVATE是cmake内置系统关键字,这里不展开,后面专门出一期随笔说清楚
)

target_include_directories 作用

target_include_directories 作用

target_include_directories 作用

  • target_include_directories 用于解决代码中使用 #include<头文件> ,编译器无法找到头文件的问题。它的作用就是告诉编译器,应该去哪个目录下搜索头文件
  • 本文范例中的例子,告诉编译器, 编译HelloCmake时, 应该去${CMAKE_CURRENT_SOURCE_DIR}/include目录下找 头文件Typedef.h

target_include_directories 使用顺序

  • 使用 target_include_directories 需要创建项目后再使用,也就是位于 add_libraryadd_executable之后使用,否则不会生效。 因为target_include_directories的第一个参数需要指定目标。
...
add_library( 项目A ...) # add_executable(...)
...
target_include_directories( 项目A ...)

3.3 CMakeLists.txt完整脚本

# 指定CMake脚本解析的最低版本,
cmake_minimum_required(VERSION 3.18)

# 指定项目
project(HelloCMake)

# 引入脚本:参数为脚本文件的全路径
include(${CMAKE_CURRENT_SOURCE_DIR}/Common/CommonOutput.cmake)

# 用于可执行程序
add_executable(${PROJECT_NAME}    				# 参数1: 要生成的项目名称,这里对应的是HelloCMake, 而HelloCMake就是projec中的参数
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cc    		# 参数2 : 项目所需的文件
${CMAKE_CURRENT_SOURCE_DIR}/include/typedef.h   # 参数3: 项目所需的文件

 )

# 指定 ${PROJECT_NAME}, 也就是 HelloCMake 的头文件搜索路径
target_include_directories( ${PROJECT_NAME}         # 参数1 项目名称
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include     # 参数2, 指定哪个搜索头文件路径, 这里的PRIVATE是cmake内置系统关键字,这里不展开,后面专门出一期文章说清楚
)

5. 结果

  • CMake Tools 编译, 使用VSCode命令面板 (ctrl+shift+p):
>cmake:Build
  • 项目编译结果:
[proc] Executing command: C:\major\development\tools\cmake_64\bin\cmake.exe --build c:/A/build --config Debug --target HelloCMake -j 14 --
[build] 用于 .NET Framework 的 Microsoft (R) 生成引擎版本 16.11.2+f32259642
[build] 版权所有(C) Microsoft Corporation。保留所有权利。
[build] 
[build]   main.cc
[build] C:\A\src\main.cc(1,1): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 [C:\A\build\HelloCMake.vcxproj]
[build] C:\A\include\Typedef.h(1,1): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 [C:\A\build\HelloCMake.vcxproj]
[build]   HelloCMake.vcxproj -> C:\A\publish\x64\bin\debug64\HelloCMake.exe
[build] Build finished with exit code 0

可见项目已经编译成功

6 去掉 target_include_directories 调用

6.1 CMakeLists.txt脚本修改

  • 简单修改CMakeLists.txt中的脚本,注释 target_include_directories的调用
# 指定CMake脚本解析的最低版本,
cmake_minimum_required(VERSION 3.18)

# 指定项目
project(HelloCMake)

# 引入脚本:参数为脚本文件的全路径
include(${CMAKE_CURRENT_SOURCE_DIR}/Common/CommonOutput.cmake)

# 用于可执行程序
add_executable(${PROJECT_NAME}    # 参数1: 要生成的项目名称,这里对应的是HelloCMake, 而HelloCMake就是projec中的参数
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cc     # 参数2 : 项目所需的文件
${CMAKE_CURRENT_SOURCE_DIR}/include/typedef.h   # 参数3: 项目所需的文件

 )

# # 指定 ${PROJECT_NAME}, 也就是 HelloCMake 的头文件搜索路径
# target_include_directories( ${PROJECT_NAME}         # 参数1 项目名称
#     PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include     # 参数2, 指定哪个搜索头文件路径, 这里的PRIVATE是cmake内置系统关键字,这里不展开,后面专门出一期文章说清楚
# )

VSCode编写CMake脚本中, 多行注释 与取消注释 快捷键: ctrl + /

6.2 项目编译结果

  • 你瞧, 编译器报错提示,说找不到头文件
[build] C:\A\src\main.cc(2,10): fatal error C1083: 无法打开包括文件: “Typedef.h”: No such file or directory [C:\A\build\HelloCMake.vcxproj]
  • 看图嘛, 一图胜千言。

7 总结

  • 这下,可以将头文件和源文件分类存放,使得代码文件结构有序。解决之前需要将所有文件放在一个目录下的问题了。

posted @ 2022-11-20 11:42  mohist  阅读(343)  评论(0编辑  收藏  举报