KiCAD源码解析(2):根目录CmakeList解析

KiCAD源码解析(2):根目录CmakeList解析

Kicad根目录CmakeList解析


提示:想学习cmake的看此篇文章也用处多多


1、总体结构

代码段序号代码段简介具体介绍
1定义环境要求和编译方式
2定义所需的option
3设置一些编译的全局变量:符号隐藏、使用相对路径、c++版本
4设置调试工具
5添加需要链接的库文件目录
6设置config文件路径和默认安装路径
7生成生成系统特定的头文件(以cmake的方式生成不同头文件,而不是ifdef来生成不同的头文件)
8设置编译器警告
9配置windows下运行的变量编码方式、操作系统位数、其他依赖于arch的步骤
10提供访问CCACHE的权限
11提供访问DISTCC的权限
12通过为GCC设置标志,或将llvm视为GCC
13定义安装项的位置
14查找生成KiCad所需的库
15生成配置文件config.h
16生成Map文件
17设置卸载规则
18设置安装
19构建子目录

2、详细解析

2.1 定义环境要求和编译方式

2.1.1 所需最低cmake版本

cmake_minimum_required( VERSION 3.10 FATAL_ERROR )

2.1.2 设置编译类型

if( DEFINED CMAKE_BUILD_TYPE )
    set( CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Set to either \"Release\" or \"Debug\"" )
else()
    set( CMAKE_BUILD_TYPE Release CACHE STRING "Set to either \"Release\" or \"Debug\"" )
endif()

如果编译类型未提前设置,则默认改为Release

涉及知识点知识点介绍
CMAKE_BUILD_TYPE 作用指定单一生成器上的编译类型
CMAKE_BUILD_TYPE 可能的值Debug, Release, RelWithDebInfo, MinSizeRel
set 函数用法1. 赋值给一般变量。ex:
  set(FOO “x”)。         //FOO作用域为当前作用域。
  set(FOO “x” PARENT_SCOPE)   //FOO作用域跳上一级。
2. Set赋值给缓存变量。set(<variable> <value>… CACHE <type> <docstring> [FORCE])
  缓存变量可以理解为当第一次运行cmake时,这些变量缓存到一份文件中(即编译目录下的CMakeCache.txt)。当再次运行cmake时,这些变量会直接使用缓存值。docstring是变量的简介。ex:
  set(FOO, “x” CACHE )
  //原缓存中没有FOO则将FOO赋值为x且存入cache中。
  //原缓存中有FOO则不做任何改变,即便原cache中FOO存的不是x。
3. 设置环境变量:set(ENV{} [])。
  设置环境变量的值为<value>. 后面使用 $ENV{<variable>} 可以获取该值.

2.1.3 设置项目名称

project( kicad )

设置项目名称

涉及知识点知识点介绍
project函数用法project(<PROJECT-NAME>
  [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
  [DESCRIPTION <project-description-string>]
   [HOMEPAGE_URL <url-string>]
  [LANGUAGES <language-name>…])

  PROJECT-NAME:项目名称配置好值后,会存在CMAKE_PROJECT_NAME 变量中。
  DESCRIPTION、HOMEPAGE_URL选项暂不支持。
  VERSION:版本号,主要分为 major(主版本号)、minor(次版本号)、patch(补丁版本号)、tweak, 格式为: 10.2.1.3。设置对应的值后,会依次解析,存在各自对应的变量里面。
  LANGUAGES: 可选,如果未配置,默认使用 C 以及 CXX。
  ex:
    project(DEMO VERSION 10.2.1.3 LANGUAGES CXX C ASM )
    抽取变量:
    CMAKE_PROJECT_NAME = DEMO
    PROJECT_VERSION =10.2.1.3
    PROJECT_VERSION_MAJOR = 10
    PROJECT_VERSION_MINOR = 2
    PROJECT_VERSION_PATCH = 1
    PROJECT_VERSION_TWEAK = 3

2.1.4 设置项目名称

include( GNUInstallDirs )
include( CMakeDependentOption )
# Path to local CMake modules.
set( CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules )

添加cmake下的两个module。并设置Cmake modules的路径(即本项目所写.cmake文件位置)
设置项目名称

涉及知识点知识点介绍
include函数将本项目module下(CMAKE_MODULE_PATH定义的目录)或者cmake安装目录下的.cmake文件加载到此处。与C++中的include用法一致
GNUInstallDirs作用定义GNU标准的安装路径,提供《GNU编程标准》定义的安装路径变量:
  CMAKE_INSTALL_<dir>
  CMAKE_INSTALL_FULL_<dir>
  CMAKE_INSTALL_<dir>
  其中<dir>包括:
    BINDIR—>bin
    SBINDIR—>sbin
    INCLUDEDIR—>include等等,具体请查看Cmake\share\cmake-3.xx\Modules下相应的.cmake文件
CMakeDependentOption作用提供一个宏:提供一个option依赖于其他option。ex:
  cmake_dependent_option(USE_FOO “Use Foo” ON
              “USE_BAR;NOT USE_ZOT” OFF)
如果USE_BAR为true,USE_ZOT为false,则USE_FOO置为ON。否则为OFF

2.2 定义所需的option

option( KICAD_SCRIPTING
    "Build the Python scripting support inside KiCad binaries (default ON)."
    ON )
option( KICAD_SCRIPTING_MODULES
    "Build native portion of the pcbnew Python module: _pcbnew.{pyd,so} for OS command line use of Python."
    ON )
option( KICAD_SCRIPTING_PYTHON3
    "Build for Python 3 instead of 2 (default OFF)."
    OFF )
option( KICAD_SCRIPTING_WXPYTHON
    "Build wxPython implementation for wx interface building in Python and py.shell (default ON)."
    ON )
option( KICAD_SCRIPTING_WXPYTHON_PHOENIX
    "Use new wxPython binding (default OFF)."
    OFF )
option( KICAD_SCRIPTING_ACTION_MENU
    "Build a tools menu with registered python plugins: actions plugins (default ON)."
    ON )
option( KICAD_USE_OCE
    "Build tools and plugins related to OpenCascade Community Edition (default ON)"
    ON )
option( KICAD_USE_OCC
    "Build tools and plugins related to OpenCascade Technology (overrides KICAD_USE_OCE, default OFF)"
    OFF )
option( KICAD_INSTALL_DEMOS
    "Install KiCad demos and examples (default ON)"
    ON )
option( KICAD_BUILD_QA_TESTS
    "Build software Quality assurance unit tests (default ON)"
    ON )
option( KICAD_SPICE
    "Build KiCad with internal Spice simulator."
    ON )
option( KICAD_BUILD_I18N
    "Build the translation libraries."
    OFF )
option( KICAD_I18N_UNIX_STRICT_PATH
    "Use standard Unix locale lookup path (default OFF)."
    OFF )
# Not supported by all platforms (for instance mingw)
option( KICAD_SANITIZE_ADDRESS
    "Build KiCad with sanitizer options. WARNING: Not compatible with gold linker"
    OFF )
# Not supported by all platforms (for instance mingw)
option( KICAD_SANITIZE_THREADS
    "Build KiCad with sanitizer options. WARNING: Not compatible with gold linker"
    OFF )
option( KICAD_STDLIB_DEBUG
    "Build KiCad with libstdc++ debug flags enabled."
    OFF )
option( KICAD_STDLIB_LIGHT_DEBUG
    "Build KiCad with libstdc++ with -Wp,-D_GLIBCXX_ASSERTIONS flag enabled. Not as intrusive as KICAD_STDLIB_DEBUG"
    OFF )
cmake_dependent_option( KICAD_WIN32_BUILD_PARALLEL_CL_MP
    "Build in parallel using the /MP compiler option (default OFF for safety reasons)"
    OFF "WIN32" OFF )
option( KICAD_USE_VALGRIND
    "Build KiCad with valgrind stack tracking enabled."
    OFF )
option( KICAD_NETLIST_QA
    "Run eeschema netlist QA tests (requires Python 3)"
    OFF )
cmake_dependent_option( KICAD_WIN32_DPI_AWARE
    "Turn on DPI awareness for Windows builds only"
    OFF "WIN32" OFF )
cmake_dependent_option( KICAD_WIN32_CONTEXT_WINFIBER
    "Use win32 fibers for libcontext"
    OFF "WIN32" OFF )
option( KICAD_USE_EGL
    "Build KiCad with EGL backend support for Wayland."
    OFF )
cmake_dependent_option( KICAD_USE_BUNDLED_GLEW
    "Use the bundled version of GLEW - only available when KICAD_USE_EGL is set"
    ON "KICAD_USE_EGL"
    OFF )
option( KICAD_DRC_PROTO
    "Build the DRC prototype QA tool"
    OFF )
option( KICAD_GAL_PROFILE
    "Enable profiling info for GAL"
    OFF )
#KICAD_SCRIPTING控制着整个python脚本系统。如果它为OFF,其他有关脚本的方法都不能运行。
if ( NOT KICAD_SCRIPTING )
    message( STATUS "KICAD_SCRIPTING is OFF: Disabling all python scripting support" )
    set( KICAD_SCRIPTING_MODULES OFF )
    set( KICAD_SCRIPTING_ACTION_MENU OFF )
    set( KICAD_SCRIPTING_PYTHON3 OFF )
    set( KICAD_SCRIPTING_WXPYTHON OFF )
    set( KICAD_SCRIPTING_WXPYTHON_PHOENIX OFF)
endif()
# KICAD_SCRIPTING_WXPYTHON_PHOENIX 需要打开KICAD_SCRIPTING_WXPYTHON 使wxWidgets库版本正确
if ( KICAD_SCRIPTING AND NOT KICAD_SCRIPTING_WXPYTHON AND KICAD_SCRIPTING_WXPYTHON_PHOENIX )
    message( STATUS
        "KICAD_SCRIPTING_WXPYTHON_PHOENIX has been requested, setting KICAD_SCRIPTING_WXPYTHON to ON")
    set( KICAD_SCRIPTING_WXPYTHON ON)
endif()

2.3 设置一些编译的全局选项

2.3.1 符号隐藏

# Global setting: 符号隐藏
set( CMAKE_CXX_VISIBILITY_PRESET "hidden" )
set( CMAKE_VISIBILITY_INLINES_HIDDEN ON )

通常库不太可能是单文件组成,这些文件中有些是做接口给外部使用,有些则单纯的只是库的内部实现。对于外部使用者来说,内部实现的这些符号没有实际的作用,理论上我们完全可以像对待文件内部符号一样把它们统统隐藏掉。不同的编译器提供了不同的方式来完成这件事情。
作用如下:
1. 安全,去掉不必要的符号,可以增加逆向破解的难度。
2. 压缩空间,符号实际上是放在 dll 中的,去掉这些符号可以缩减 dll 的大小
3. 性能,符号隐藏掉意味着它不会参与到动态链接过程,编译器可以有更大的优化空间,可能会产生更好的性能。
MSVC和GCC在动态库符号的默认属性上面有较大的差别,MSVC默认所有的符号都是隐藏的,而GCC默认所有的符号都是可见的。
使用MSVC编译可以什么都不做。使用GCC编译器加上-fvisibility=hidden选项,或加上-fvisibility-inlines-hidden把内联函数隐藏掉。如果使用Autotool,设置LD_CXXFLAG来控制默认隐藏,如果使用CMake,可以通过set(CMAKE_CXX_VISIBILITY_PRESET hidden)来完成。

2.3.2 设置生成的文件为独立文件

# Global setting: 生成均使用绝对路径
set( CMAKE_POSITION_INDEPENDENT_CODE ON )

确定是否创建位置无关的可行性文件或共享库。对于SHARED和MODULE库目标,此属性默认为True,否则为False。

2.3.3 设置C++版本

# Global setting: 设置C++版本,用来配置编译器
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

编译的版本为C++ 14,它不是可选的,不且使用任何GNU或MS扩展

涉及知识点知识点介绍
CXX_STANDARD作用98, 11, 14, 17, 20, 23
CMAKE_CXX_STANDARD_REQUIRED作用如果此属性设置为“ON”,则CXX STANDARD目标属性的值将被视为一个要求。如果此属性为OFF或unset,则CXX STANDARD target属性将被视为可选属性,如果请求的属性不可用,则该属性可能会“衰减”为以前的标准。
CMAKE_CXX_EXTENSIONS 作用此属性指定是否应使用编译器特定的扩展。对于某些编译器,这会导致在编译行中添加一个标记,例如-std=gnu++11,而不是-std=c++11。

2.4 设置调试工具

# 启动内存泄漏检测工具valgrind
if( KICAD_USE_VALGRIND )
    add_definitions( -DKICAD_USE_VALGRIND )
endif()
#目前还未知GAL是用来做什么
if( KICAD_GAL_PROFILE )
    add_definitions( -DKICAD_GAL_PROFILE )
endif()
# 确保debug模式在各种编译器上都可以被定义
set_property( DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DEBUG> )
涉及知识点知识点介绍
add_definitions函数作用添加预编译宏,使用例子:
OPTION(USE_MACRO
     “Build the project using macro”
     OFF)
IF(USE_MACRO)
  add_definitions("-DUSE_MACRO")
endif(USE_MACRO)
Valgrind工具Valgrind 是个开源的工具,功能很多。
  memcheck ------> 这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。
  callgrind ------> 它主要用来检查程序中函数调用过程中出现的问题。
  cachegrind ------> 它主要用来检查程序中缓存使用出现的问题。
  helgrind ------> 它主要用来检查多线程程序中出现的竞争问题。
  massif ------> 它主要用来检查程序中堆栈使用中出现的问题。
  extension ------> 可以利用core提供的功能,自己编写特定的内存调试工具
  在这里插入图片描述
Linux程序内存空间布局在这里插入图片abc
CMake 生成器表达式$<$<CONFIG:Debug>:DEBUG> 相当于(伪代码):
if current_configuration == “Debug”
  output "Debug"
if current_configureation == “Release”
  output nothing
set_property函数set_property官方文档

2.5 添加需要链接的库文件目录

LINK_DIRECTORIES( ${LINK_DIRECTORIES_PATH} )

添加需要链接的库文件目录。它相当于g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用。

2.6 设置config文件路径和默认安装路径

set( KICAD_CONFIG_DIR "kicad" CACHE STRING "Location of user specific KiCad config files" )
mark_as_advanced( KICAD_CONFIG_DIR )
add_definitions( -DKICAD_CONFIG_DIR=${KICAD_CONFIG_DIR} )

if( NOT DEFAULT_INSTALL_PATH )
    set( DEFAULT_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}"
         CACHE
         PATH
         "Location of KiCad data files." )
endif()

设置KICAD_CONFIG_DIR(C:\Users\yin\AppData\Roaming存储用户操作等),添加预编译宏。
设置DEFAULT_INSTALL_PATH,自动生成到config.h文件中。

涉及知识点知识点介绍
mark_as_advanced函数作用mark_as_advanced([CLEAR|FORCE] VAR VAR2 VAR…)
标记已命名的缓冲变量为 advanced。
将缓存的变量标记为高级变量。其中,高级变量指的是那些在cmake GUI中,只有当”显示高级选项“被打开时才会被显示的变量。如果CLEAR是第一个选项,参数中的高级变量将变回非高级变量。如果FORCE是第一个选项,参数中的变量会被提升为高级变量。如果两者都未出现,新的变量会被标记为高级变量;如果这个变量已经是高级/非高级状态的话,它会维持原状。

2.7 生成生成系统特定的头文件

include( PerformFeatureChecks )
perform_feature_checks()

此处调用了CMakeModules下面的PerformFeatureChecks.cmake文件.
使用cmake来探查系统特定的依赖同时更新配置头文件。

2.8 设置编译器警告

include( ${CMAKE_MODULE_PATH}/Warnings.cmake )

if( KICAD_WIN32_CONTEXT_WINFIBER )
    set(LIBCONTEXT_USE_WINFIBER true)
    add_compile_definitions(LIBCONTEXT_USE_WINFIBER)
else()
    set(LIBCONTEXT_USE_WINFIBER false)
endif()

此处调用了CMakeModules下面的Warning.cmake文件.
设置是否使用winfiber(纤程)

涉及知识点知识点介绍
add_compile_definitions函数作用将预处理器定义添加到编译器命令行。

2.9 配置windows下运行的变量

2.9.1 定义编码方式

add_definitions(-DUNICODE -D_UNICODE)

KiCad使用的是unicode的编码方式。

2.9.2 定义数学常数

add_definitions( -D_USE_MATH_DEFINES )

在标准编译模式下,M_PI德国变量只有在_USE_MATH_DEFINES被设置的时候才会定义。

2.9.3 用于资源编译器和其他依赖于arch的步骤

	if( MSVC )
        #此段代码暂时用不到
    else()
        if ( NOT CMAKE_SIZEOF_VOID_P EQUAL 8 )
            set( KICAD_BUILD_ARCH "x86" )
            set( KICAD_BUILD_ARCH_X86 1 )
        elseif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
            set( KICAD_BUILD_ARCH "x64" )
            set( KICAD_BUILD_ARCH_X64 1 )
        endif()
    endif()
    add_definitions( -DKICAD_BUILD_ARCH=${KICAD_BUILD_ARCH} )
    
	if( KICAD_WIN32_DPI_AWARE )
        add_definitions( -DKICAD_WIN32_DPI_AWARE=1 )
    endif()

设置用于资源编译器和其他依赖于arch的变量和宏。MSVC编译器目前还未编译成功,所以先不关注MSVC。

涉及知识点知识点介绍
CMAKE_SIZEOF_VOID_P作用空指针的大小。32位机:4个字节;64位机:8个字节

2.9.4 设置DPI感知

add_definitions( -D_USE_MATH_DEFINES )

设置DPI感知。

涉及知识点知识点介绍
DPI感知  当应用程序具有系统DPI感知功能时,它将从主监视器获取缩放设置,无论缩放设置如何,都可以正确缩放和渲染应用程序。
  在显示器上,每英寸点数(DPI)定义构成面板的每个物理单元的像素数。 传统上,显示器每英寸输出96像素,但随着技术的发展,公司开始增加同一物理空间中的像素数,导致屏幕上的DPI达到200甚至更高。
  虽然较高的像素密度有助于确保更清晰的图像,但是需要一种显示缩放形式来正确地调整屏幕上的元素。 否则,视觉元素和文本将显得非常小,以至于难以使用。

2.10 提供访问CCACHE的权限

if (USE_CCACHE)
  find_program(CCACHE_FOUND ccache)
  if(CCACHE_FOUND)
    get_property(RULE_LAUNCH_COMPILE GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
    set(RULE_LAUNCH_COMPILE "${RULE_LAUNCH_COMPILE} ${CCACHE_FOUND}")
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${RULE_LAUNCH_COMPILE})

    get_property(RULE_LAUNCH_LINK GLOBAL PROPERTY RULE_LAUNCH_LINK)
    set(RULE_LAUNCH_LINK "${RULE_LAUNCH_LINK} ${CCACHE_FOUND}")
    set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${RULE_LAUNCH_LINK})

    message(STATUS "Used ${CCACHE_FOUND} for compilation.")
  else(CCACHE_FOUND)
    message(STATUS "CCache was requested but not found.")
  endif(CCACHE_FOUND)
endif(USE_CCACHE)
涉及知识点知识点介绍
CCACHE工具(暂时不用)  cache(“compiler cache”的缩写)工具会高速缓存编译生成的信息,并在编译的特定部分使用高速缓存的信息, 比如头文件,这样就节省了通常使用 cpp 解析这些信息所需要的时间。
  安装ccache之后,需要告诉CMake将其用作编译器的外壳。如下操作
  find_program(CCACHE_FOUND ccache)
  if(CCACHE_FOUND)
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
    set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
  endif(CCACHE_FOUND)
find_program函数find_program(<VAR> name1 [path1 path2 …])
在特定路径下查找文件

2.11 提供访问DISTCC的权限

if (USE_DISTCC)
  find_program(DISTCC_FOUND distcc)
  if(DISTCC_FOUND)
    get_property(RULE_LAUNCH_COMPILE GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
    set(RULE_LAUNCH_COMPILE "${RULE_LAUNCH_COMPILE} ${DISTCC_FOUND}")
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${RULE_LAUNCH_COMPILE})
    message(STATUS "Using ${DISTCC_FOUND} for distributed build.")
  else(DISTCC_FOUND)
    message(INFO "Distcc was requested but not found.")
  endif(DISTCC_FOUND)
endif(USE_DISTCC)
涉及知识点知识点介绍
DISTCC工具(暂时不用)  分布式编译的工具。

2.12 通过为GCC设置标志,或将llvm视为GCC

2.12.1 判断编译器类型

if( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
涉及知识点知识点介绍
CMAKE_COMPILER_IS_GNUCXX如果C++(CXX)编译器是GNU则为True
CMAKE_CXX_COMPILER_ID编译器供应商独有的短字符串。包括:
Absoft = Absoft Fortran (absoft.com)
ADSP = Analog VisualDSP++ (analog.com)
AppleClang = Apple Clang (apple.com)
ARMCC = ARM Compiler (arm.com)
ARMClang = ARM Compiler based on Clang (arm.com)
Bruce = Bruce C Compiler
CCur = Concurrent Fortran (ccur.com)
Clang = LLVM Clang (clang.llvm.org)
Cray = Cray Compiler (cray.com
Embarcadero, Borland = Embarcadero (embarcadero.com)
Flang = Flang LLVM Fortran Compiler
G95 = G95 Fortran (g95.org)
GNU = GNU Compiler Collection (gcc.gnu.org)
GHS = Green Hills Software (www.ghs.com)
HP = Hewlett-Packard Compiler (hp.com)
IAR = IAR Systems (iar.com)
Intel = Intel Compiler (intel.com)
MSVC = Microsoft Visual Studio (microsoft.com)
NVIDIA = NVIDIA CUDA Compiler (nvidia.com)
OpenWatcom = Open Watcom (openwatcom.org)
PGI = The Portland Group (pgroup.com)
PathScale = PathScale (pathscale.com)
SDCC = Small Device C Compiler (sdcc.sourceforge.net)
SunPro = Oracle Solaris Studio (oracle.com)
TI = Texas Instruments (ti.com)
TinyCC = Tiny C Compiler (tinycc.org)
XL, VisualAge, zOS = IBM XL (ibm.com)
XLClang = IBM Clang-based XL (ibm.com)

2.12.2 设置GCC优化选项

# 32位系统下为GCC设置32位标志以防止精度过高
    if( CMAKE_SIZEOF_VOID_P EQUAL 4 )
        set( CMAKE_CXX_FLAGS "-ffloat-store ${CMAKE_CXX_FLAGS}" )
    endif()
涉及知识点知识点介绍
CMAKE_COMPILER_IS_GNUCXX如果C++(CXX)编译器是GNU则为True
GCC优化选项  gcc提供了为了满足用户不同程度的的优化需要,提供了近百种优化选项,用来对{编译时间,目标文件长度,执行效率}这个三维模型进行不同的取舍和平衡。优化的方法不一而足,总体上将有以下几类:1)精简操作指令;2)尽量满足cpu的流水操作;3)通过对程序行为地猜测,重新调整代码的执行顺序;4)充分使用寄存器;5)对简单的调用进行展开等等。
  而上面代码中的**-ffloat-store**:不要在寄存器中存放浮点变量 . 这样可以防止某些机器上不希望的过高精度

2.12.3 设置debug优化选项-设置debug模式下程序大小

	if( BUILD_SMALL_DEBUG_FILES )
        set( CMAKE_C_FLAGS_DEBUG   "-g1 -ggdb1" )
        set( CMAKE_CXX_FLAGS_DEBUG "-g1 -ggdb1" )
    else()
        set( CMAKE_C_FLAGS_DEBUG   "-g3 -ggdb3" )
        set( CMAKE_CXX_FLAGS_DEBUG "-g3 -ggdb3" )
    endif()
涉及知识点知识点介绍
CMAKE_<LANG>_FLAGS_<CONFIG>对于这种语言当执行时所需的标志。
-g1 -ggdb1或者-g3 -ggdb3:
调试生成时选择Level1提供最少的信息,但是生成的文件也最小。
选择Level3提供最全的信息,但是二进制文件则大的多。

2.12.4 设置debug优化选项2-AddressSanitizer配置

   if( KICAD_SANITIZE_ADDRESS )
        add_definitions( -DKICAD_SANITIZE_ADDRESS )
        set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_SANITIZE_VECTOR -fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer" )

        # ASAN shouldn't be used with these options (https://github.com/google/sanitizers/wiki/AddressSanitizer#faq)
        set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector -U_FORTIFY_SOURCE" )
    endif()

使用AddressSanitizer选项构建KiCad。与gold linker不兼容

涉及知识点知识点介绍
AddressSanitizer该工具g++自带。它其实是一个内存错误检测工具,可以检测的问题主要有:内存泄漏、堆栈和全局内存越界访问、free后继续使用、局部内存被外层使用、初始化列表顺序错误。使用方法:
  1. 用 -fsanitize=address 选项编译和链接你的程序。
  2. 用 -fno-omit-frame-pointer 编译,以得到更容易理解stack trace。,
  3. 要获得完美的堆栈跟踪,您可能需要禁用内联(只使用-O1)和尾部调用消除(-fno-optimize-sibling-call)
  4. 检查栈对象使用超过定义范围的bug(-fsanitize-address-use-after-scope)
stack-protectorgcc提供了栈保护机制stack-protector。关于stack-protector包含三个选项,分别是stack-protector、stack-protector-all、stack-protector-strong、stack-protector-explicit四种。
  stack-protector:保护函数中通过alloca()分配缓存以及存在大于8字节的缓存。缺点是保护能力有限。
  stack-protector-all:保护所有函数的栈。缺点是增加很多额外栈空间,增加程序体积。
  stack-protector-strong:在stack-protector基础上,增加本地数组、指向本地帧栈地址空间保护。
  stack-protector-explicit:在stack-protector基础上,增加程序中显式属性"stack_protect"空间。
FORTIFY_SOURCE启用-D/U_FORTIFY_SOURCE

2.12.5 设置debug优化选项3-ThreadSanitizer配置

	if( KICAD_SANITIZE_THREADS )
        add_definitions( -DKICAD_SANITIZE_THREADS )
        set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_SANITIZE_VECTOR -fsanitize=thread -fno-optimize-sibling-calls -fno-omit-frame-pointer" )
        # Based on this warning https://github.com/JuliaLang/julia/blob/29d5158d27ddc3983ae2e373c4cd05569b9ead6c/src/julia.h#L77
        if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11 )
            message( WARNING "Clang version 11 and below may leak memory when running the thread sanitizer.\n"
                             "Be careful when using this compiler.")
        endif()
        # 复制上一节ASAN内容,因为为什么不呢
        set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector -U_FORTIFY_SOURCE" )
    endif()

使用AddressSanitizer选项构建KiCad。与gold linker不兼容

涉及知识点知识点介绍
ThreadSanitizerThreadSanitizer是一个检测数据竞争的工具。它由编译器检测模块和运行时库组成。ThreadSanitizer引入的典型减速是 5x-15x 左右。ThreadSanitizer引入的典型内存开销约为5x-10x。使用:
  1. 只需用-fsanitize=thread编译并链接程序
  2. -fno-optimize-sibling-calls作用请翻看上一节
  3. -fno-omit-frame-pointer作用请翻看上一节

2.12.6 设置debug优化选项4-开启STL检测功能

    if( KICAD_STDLIB_DEBUG )
        add_definitions( -DKICAD_STDLIB_DEBUG )
        set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG" )
    elseif( KICAD_STDLIB_LIGHT_DEBUG )
        # useless if KICAD_STDLIB_DEBUG is ON.
        # this option makes some controls to trap out of bound memory access.
        add_definitions( -DKICAD_STDLIB_LIGHT_DEBUG )
        set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wp,-D_GLIBCXX_ASSERTIONS" )
    endif()

string在GLIBCXX_DEBUG宏是否存在的情况下处理方式不同,不同的库如果没带该选项而自己的项目又定义了它,有可能造成冲突导致程序挂掉,但是又想使程序项目在STL检测的庇护下,可以修改/usr/include/c++/4.7/debug/debug.h头文件,将#ifndef _GLIBCXX_DEBUG修改为#ifndef GLIBCXX_DEBUG,然后在自己的项目中定义_GLIBCXX_DEBUG_宏,绕开冲突即可。
使用-D_GLIBCXX_DEBUG命令进行编译

2.12.7 设置mingGW选项

 	if( MINGW )
 	#给mingw_resource_compiler_INCLUDE_DIRS列表添加rc、可执行文件路径、KICAD_BUILD_ARCH值、DPI感知值。
 	#
        list(APPEND mingw_resource_compiler_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/resources/msw/ )
        # include dir to allow getting the version header
        list(APPEND mingw_resource_compiler_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/ )
        list(APPEND mingw_resource_compiler_DEFINES KICAD_BUILD_ARCH=${KICAD_BUILD_ARCH} )
        if( KICAD_WIN32_DPI_AWARE )
            list(APPEND mingw_resource_compiler_DEFINES KICAD_WIN32_DPI_AWARE=1 )
        endif()
        #
        set( CMAKE_EXE_LINKER_FLAGS_RELEASE "-s" )
		#预留一段代码:设为true则使response file 失效。
		#从版本2.8.5开始,Cmake使用一个响应文件(.jsp),来传递include paths的列表给gcc。
		#然而,在mingw32+msys模式下(mingw64不确定),至少需要gcc4.88和更新版本,这个文件不能正常展开,所以这种模式下,include paths就失效了。如果是这种情况,需要disable这个响应函数。
        if( false ) #set to true to disable the include response file
            if( WIN32 AND MSYS AND NOT CMAKE_CROSSCOMPILING )
                # fixme: it is needed only with MSYS+MINGW32? or always under MINGW
                if( ${CMAKE_SIZEOF_VOID_P} MATCHES 4 )
                	#禁掉response file
                    set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 0 )
                endif()
            endif()
        endif()
        #cmake使用响应文件存储要发给archiver的对象列表。因为这个列表太长了,有可能产生错误 ,所以强制使用响应文件存储。
        SET( CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1 )
#mingw编译器可以使用微软系统的snprintf作为标准输出,但是它和C99标准有一个坏的API,所以需要我们确保使用自己的snprintf
        # snprintf
        add_definitions(-D__USE_MINGW_ANSI_STDIO=1)

        # Allow linking for Boost for the UUID against bcrypt
        set( EXTRA_LIBS "bcrypt" )
    endif()
    #暂时不涉及苹果系统
    if( APPLE )
        set( CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -headerpad_max_install_names") # needed by fixbundle
    endif()
endif( CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
涉及知识点知识点介绍
list函数作用
其他list函数与append使用方法类似。见博客:Cmake中的list操作
snprintf函数sprintf函数、snprintf函数、asprintf函数、vsprintf
CMAKE_EXE_LINKER_FLAGS_RELEASE未搞懂什么作用,待后续更新

2.12.8 设置msvc选项

用msvc编译暂时有问题,这段代码的解析后续更新

2.13 定义安装项的位置

if( NOT APPLE )
    #所有的路径如果开头不是“/”,则都是在CMAKE_INSTALL_PREFIX路径下
    set( KICAD_BIN bin CACHE PATH "Location of KiCad binaries." )
    # Do not make these variables "PATH" b/c cmake will truncate them and we need the full path
    if( NOT IS_ABSOLUTE ${CMAKE_INSTALL_DATADIR} )
    	#设置Kicad data文件路径
        set( KICAD_DATA ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/kicad CACHE STRING "Location of KiCad data files." )
        #设置Kicad 文档文件路径
        set( KICAD_DOCS ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/doc/kicad  CACHE STRING "Location of KiCad documentation files." )
    else()
        set( KICAD_DATA ${CMAKE_INSTALL_DATADIR}/kicad CACHE STRING "Location of KiCad data files." )
        set( KICAD_DOCS ${CMAKE_INSTALL_DATADIR}/doc/kicad CACHE STRING "Location of KiCad documentation files." )
    endif()

    set( KICAD_LIBRARY_DATA ${KICAD_DATA}
        CACHE STRING "Location of KiCad stock EDA library data" )
    if( WIN32 )
        set( KICAD_PLUGINS ${KICAD_BIN}/scripting/plugins  CACHE PATH "Location of KiCad plugins." )
        set( KICAD_LIB ${KICAD_BIN}  CACHE PATH "Location of KiCad shared objects" )
        set( KICAD_USER_PLUGIN ${KICAD_BIN}/plugins CACHE PATH "Location of KiCad user-loaded plugins" )
    else()
        set( KICAD_PLUGINS ${KICAD_DATA}/plugins CACHE PATH "Location of KiCad plugins." )
        set( KICAD_LIB ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Location of KiCad shared objects" )
        set( KICAD_USER_PLUGIN ${CMAKE_INSTALL_LIBDIR}/kicad/plugins  CACHE PATH "Location of KiCad user-loaded plugins" )
    endif()

    set( KICAD_DEMOS ${KICAD_DATA}/demos
        CACHE PATH "Location of KiCad demo files." )
    set( KICAD_TEMPLATE ${KICAD_LIBRARY_DATA}/template
        CACHE PATH "Location of KiCad template files." )
else()
    #此处为APPLE配置,此时还不需解析,后续更新
endif()

mark_as_advanced( KICAD_BIN
    KICAD_PLUGINS
    KICAD_USER_PLUGIN
    KICAD_LIB
    KICAD_DATA
    KICAD_LIBRARY_DATA
    KICAD_DOCS
    KICAD_DEMOS
    KICAD_TEMPLATE )
#调用本项目中的Functions.cmake(函数生成器,是调用TokenList2DsnLexer.cmake的标准方法)
include( Functions )
include( ExternalProject )

各个安装目录输出如下图:
在这里插入图片描述

涉及知识点知识点介绍
KICAD_BINKICAD_BIN = bin:
安装时各类exe、dll等二进制可执行文件。
KICAD_PLUGINS放Kicad脚本插件的地方。默认放了一些从eeschema读取网表文件生成bom的一些脚本。
KICAD_USERS_PLUGINS放用户Kicad插件的地方:默认的只有一种:3d查看器。
KICAD_LiB放置生成的dll的地方。
KICAD_DATAKicad 所需的数据。包括3个文件夹:
demos示例工程;
resources图片icon;
template工程模板。
KICAD_LIBRARY_DATALocation of KiCad stock EDA library data。详细解释,后续更新
KICAD_DOCSLocation of KiCad documentation files.详细解释,后续更新
KICAD_DEMOS存储项目示例的路径
KICAD_TEMPLATE模板文件的路径

2.14 查找生成KiCad所需的库

  1. GettextI18N的实现,gettext是一种国际化与本地化系统,在类Unix系统中编写多语言程序时经常被使用。gettext的一个常用的实现版本为GNU gettext,1995年发布。
  2. OpenGLOpen Graphics Library,译名:开放图形库或者“开放式图形库”,是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)。这个接口由近350个不同的函数调用组成,用来绘制从简单的图形比特到复杂的三维景象。而另一种程序接口系统是仅用于Microsoft Windows上的Direct3D。OpenGL常用于CAD、虚拟现实、科学可视化程序和电子游戏开发。
  3. GLEWGLEW是一个跨平台的C++扩展库,基于OpenGL图形接口。使用OpenGL的朋友都知道,window目前只支持OpenGL1.1的涵数,但 OpenGL现在都发展到2.0以上了,要使用这些OpenGL的高级特性,就必须下载最新的扩展,另外,不同的显卡公司,也会发布一些只有自家显卡才支 持的扩展函数,你要想用这数涵数,不得不去寻找最新的glext.h,有了GLEW扩展库,你就再也不用为找不到函数的接口而烦恼,因为GLEW能自动识 别你的平台所支持的全部OpenGL高级扩展涵数。也就是说,只要包含一个glew.h头文件,你就能使用gl,glu,glext,wgl,glx的全 部函数。GLEW支持目前流行的各种操作系统(including Windows, Linux, Mac OS X, FreeBSD, Irix, and Solaris)。
  4. GLMGLM是OpenGL Mathematics的缩写,专门为OpenGL量身定做的数学库,它是一个只有头文件的库。GLM提供了与GLSL相同的命名约定和功能设计和实现的类和函数,以便了解GLSL的任何人都可以在GC++中使用GLM。
  5. zlibzlib 软件包包含 zlib 库,很多程序中的压缩或者解压缩函数都会用到这个库。zlib 适用于数据压缩的函式库,几乎适用于任何计算器硬件和操作系统。
  6. CURLCURL是一个利用URL语法在命令行下工作的文件传输工具,1997年首次发行。它支持文件上传和下载,所以是综合传输工具,但按传统,习惯称cURL为下载工具。
  7. Cairo向量图形绘图库。在资讯领域中,cairo 是一个让用于提供向量图形绘图的免费函式库,Cairo 提供在多个背景下做 2-D 的绘图,进阶的更可以使用硬件加速功能。
      虽然 Cairo 是使用C语言撰写的,但是当使用 Cairo 时,可以用许多其他种语言来使用,包括有 C++、C#、Java、Python、Perl、Ruby、Scheme、Smalltalk 以及许多种语言,Cairo 在 GPL 与 Mozilla Public License 两个认证下发行。
  8. PixmanPixman是一个用于像素处理的底层软件库,提供图像合成和梯形光栅化等功能。 pixman作为一个独立的第三方绘图库,其主要作用是根据操作模式及相应的数学算法对图形进行二次处理。常见的有Gradient(颜色渐变)、ROP(光栅操作)、矢量图操作、Alpha compositing、线性变换等。
  9. BoostBoost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称。
  10. ngspicengspice就是SPICE的改进版。
  11. OCEOCE(OpenCascade Community Edition)是一个OpenCascade三维内核的社区版本,也是三维CAD开发的一个C++库。它是由三维表面和立方体BRep建模,可视化模块,数据交换(STEP,IGES),以及快速应用程序开发的组件组成。目前版本的OCE主要是修正错误,提高代码质量和可移植性
  12. OpenCASCADEOpen CASCADE是一个功能强大的三维建模工具,提供了点、线、面、体和复杂形体的显示和交互操作,经过深度开发后可实现纹理、光照、图元填充、渲染等图形操作和放大、缩小、旋转、漫游、模拟飞行、模拟穿越等动态操作。
  13. SWIGSWIG是个帮助使用C或者C++编写的软件能与其它各种高级编程语言进行嵌入联接的开发工具。SWIG能应用于各种不同类型的语言包括常用脚本编译语言例如Perl, PHP, Python, Tcl, Ruby and PHP。
  14. PythonInterp插值工具。interpy 扩展python以支持ruby-like字符串插值 {}。快速示例:print “Hello #{your_name}”。它是经过高度优化的,并直接编译成字节码,因此 使用时将具有相同的python速度。
  15. PythonLibspython的一些依赖库
  16. wxPythonwxPython 是 Python 语言的一套优秀的 GUI 图形库,允许 Python 程序员很方便的创建完整的、功能键全的 GUI 用户界面。 wxPython 是作为优秀的跨平台 GUI 库 wxWidgets 的 Python 封装和 Python 模块的方式提供给用户的。
  17. wxWidgetswxWidgets是一个开源的跨平台的C++构架库(framework),它可以提供GUI(图形用户界面)和其它工具。目前的2.x版本支持所有版本的Windows、带GTK+或Motif的Unix和MacOS。一个支持OS/2的版本正在开发中。
  18. Doxygen:Doxygen 是一个程序的文件产生工具,可将程序中的特定注释转换成为说明文件。
全部代码太长,以GLM库为例子进行介绍。
##########################################
#查找GLM库
##########################################
find_package( GLM 0.9.8 REQUIRED )
add_definitions( -DGLM_FORCE_CTOR_INIT )
check_find_package_result( GLM_FOUND "GLM" )
include_directories( SYSTEM ${GLM_INCLUDE_DIR} )
涉及知识点知识点介绍
find_packageCMake 会到变量 CMAKE_MODULE_PATH 指示的目录中查找下查找Findxxx.cmake文件,然后在cmake安装目录下module文件夹下查找Findxxx.cmake文件。会自动给一系列变量赋值:
Once done this will define::
GLM_FOUND - system has GLM
GLM_INCLUDE_DIR - the GLM include directory
GLM_LIBRARIES - Link these to use GLM
GLM_NEED_PREFIX - this is set if the functions are prefixed with GLM
GLM_VERSION_STRING - the version of GLM found (since CMake 2.8.8)
check_find_package_resultCMAKE_MODULE_PATH(即CMakeModules目录)下CheckFindPackageResult.cmake文件
include_directoriesinclude_directories是用来提供找头文件路径的,打个比方,我现在想要#include"cv.h",但是这个cv.h的路径是/usr/local/include/opencv。include_directories(/usr/local/include)来让库文件搜索以/usr/local/include为基础,即在main函数前写上#include “opencv/cv.h"即可

2.15 生成配置文件config.h

configure_file( ${PROJECT_SOURCE_DIR}/CMakeModules/config.h.cmake
    ${CMAKE_BINARY_DIR}/config.h )
涉及知识点知识点介绍
configure_file复制一份输入文件到输出文件,替换输入文件中被@VAR@或者${VAR}引用的变量值。也就是说,让普通文件,也能使用CMake中的变量。

2.16 生成Map文件

if( KICAD_MAKE_LINK_MAPS )
    # Currently only works on linux/gcc
    if( UNIX AND NOT APPLE )
        set( MAKE_LINK_MAPS true )
    else()
        set( MAKE_LINK_MAPS false )
    endif()
endif()

目前只在linux/gcc环境下实现。

2.17 设置卸载规则

#================================================
# "make uninstall" 
#================================================
#生成卸载文件:cmake_uninstall.cmake
configure_file(
    "${CMAKE_MODULE_PATH}/cmake_uninstall.cmake.in"
    "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
    IMMEDIATE @ONLY )

add_custom_target( uninstall
    "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" )
涉及知识点知识点介绍
add_custom_target增加一个没有输出的目标,使得它总是被构建。作者也还未搞太明白(后续更新)

2.18 设置安装

#================================================
# Installation
#================================================

###
# Install scripts
###
#如果在unix系统上,设置安装
if( UNIX AND NOT APPLE )
    install( DIRECTORY scripts
        DESTINATION ${KICAD_DOCS}
        COMPONENT resources
        PATTERN "*.bat" EXCLUDE
        )
endif()

include( CTest )
enable_testing()

#如果在unix系统上,设置Cpack
if( UNIX AND NOT APPLE )
    # Create a *.deb file:
    set( CPACK_GENERATOR "DEB" )
    set( CPACK_DEBIAN_PACKAGE_MAINTAINER "http://launchpad.net/kicad" )

    set( CPACK_PACKAGE_VERSION_MAJOR 1 )
    set( CPACK_PACKAGE_VERSION_MINOR 0 )
    set( CPACK_PACKAGE_VERSION_PATCH 0 )
    #set( CPACK_PACKAGE_CONTACT Firstname Lastname <email@company.com> )
    set( CPACK_PACKAGE_DESCRIPTION_SUMMARY "KiCad built by CMake build system." )

    include( CPack )

endif()
涉及知识点知识点介绍
add_custom_target增加一个没有输出的目标,使得它总是被构建。作者也还未搞太明白(后续更新)
install函数install(TARGETS MyLib
   EXPORT MyLibTargets
   LIBRARY DESTINATION lib # 动态库安装路径
   ARCHIVE DESTINATION lib # 静态库安装路径
   RUNTIME DESTINATION bin # 可执行文件安装路径
   PUBLIC_HEADER DESTINATION include # 头文件安装路径
   )
CTestCTest是CMake集成的一个测试工具,在使用CMakeLists.txt文件编译工程的时候,CTest会自动configure、build、test和展现测试结果
CTest有两个模式:
  模式一: 使用CMake configure 和 build工程,在CMakeLists.txt文件中,使用特殊的命令取创建tests。CTest用来执行那些测试
  模式二: 使用CTest来执行一个script(这个script的语法必须和CMakeLists.txt相同),去控制整个程序的输出结果

enable_testing()执行后,才能执行add_test()函数。
add_testadd_test(NAME <name> [CONFIGURATIONS [Debug|Release|…]]
    [WORKING_DIRECTORY dir]
    COMMAND <command> [arg1 [arg2 …]])
  如果已经运行过了ENABLE_TESTING命令,这个命令将为当前路径添加一个测试目标。如果ENABLE_TESTING还没有运行过,该命令啥事都不做。测试是由测试子系统运行的,它会以指定的参数执行Exename文件。Exename或者是由该工程构建的可执行文件,也可以是系统上自带的任意可执行文件(比如tclsh)
CpackC++ 工程大部分都是用 CMake 配置编译, 而 CPack 是 CMake 内置的工具,支持打包成多种格式的安装包。因为是 CMake 的内置工具,所以使用的方式也是通过在 CMakeLists.txt 配置参数,就能达到我们的需求。使用起来很方便,容易上手。

2.19 构建子目录

#================================================
执行子目录下的CmakeList
#================================================
# Binaries ( CMake targets )
add_subdirectory( resources )
add_subdirectory( thirdparty )
add_subdirectory( bitmaps_png )
add_subdirectory( libs )
add_subdirectory( common )
add_subdirectory( 3d-viewer )
add_subdirectory( eeschema )
add_subdirectory( gerbview )
add_subdirectory( pcbnew )
add_subdirectory( pagelayout_editor )
add_subdirectory( bitmap2component )
add_subdirectory( pcb_calculator )
add_subdirectory( plugins )             # 3D plugins must be built before kicad
add_subdirectory( cvpcb )               # must be after pcbnew
add_subdirectory( kicad )               # should follow pcbnew, eeschema
add_subdirectory( tools )
add_subdirectory( utils )
add_subdirectory( qa )

# Demos
if( KICAD_INSTALL_DEMOS )
    add_subdirectory( demos )
endif ( KICAD_INSTALL_DEMOS )

# I18n Translations
if( KICAD_BUILD_I18N )
    add_subdirectory( translation )
endif()

add_subdirectory( template )
涉及知识点知识点介绍
add_subdirectory添加一个子目录并构建该子目录。

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值