平台的选择

image.png

linux 上编写 GUI 程序,C 语言是比较好的选择,而且 GTK 已经移植到了 MAC 和 Windows 上

make cmake makefile

  • make工具可以看成是一个智能的批处理工具,它本身并没有编译和链接的功能,而是用类似于批处理的方式—通过调用makefile文件中用户指定的命令来进行编译和链接的。

  • make 工具就根据 makefile 中的命令进行编译和链接的。makefile命令中就包含了调用gcc(也可以是别的编译器)去编译某个源文件的命令。

  • cmake就可以更加简单的生成makefile文件给上面那个make用。当然cmake还有其他更牛X功能,就是可以跨平台生成对应平台能用的makefile,我们就不用再自己去修改了。

CMAKE

微软、Google 以及 Facebook 这三家公司都有自己的 C++ 构建系统,他们开源的项目仍支持使用 CMake 构建;并且 CMake 是除了官方构建系统之外的推荐构建系统。

CMake 是函数申明式语法,使用最为广泛的构建工具之一,几乎能成为模块描述工具了,但肯定不是最好的构建工具。

其缺点是生成了大量中间文件,语法丑陋不堪,构建效率一般;编写过程痛苦,需要查询很多文档(文档质量水平不够),如果有特殊需求会痛苦得无以复加,诸如特殊外部依赖(譬如使用某个其它位置的 boost 库)会很痛苦。

Debug

  1. message(STATUS ${PROJECT_BINARY_DIR})

打印出相关变量

Hello CMake

  1. ├── CMakeLists.txt
  2. ├── main.cpp
  • CMakeLists.txt - 包含了 CMake 命令
  • main.cpp - 源代码

CMakeLists.txt是存储所有CMake命令的文件。当cmake运行在一个文件夹中,它将寻找这个文件,如果它不存在,cmake将退出与一个错误。

cmake 版本

  1. cmake_minimum_required(VERSION 3.5)

当使用CMake创建项目时,您可以指定你的 cmake 语句所支持的CMake的最小版本。

添加执行文件

  1. add_executable(hello_cmake main.cpp)

add_executable() 函数的第一个参数是要构建的可执行文件的名称,第二个参数是要编译的源文件列表。

项目宏

  1. cmake_minimum_required(VERSION 2.6)
  2. project (hello_cmake)
  3. add_executable(${PROJECT_NAME} main.cpp)

project()函数将创建一个值为 hello_cmake 的变量 ${PROJECT_NAME}。

Variable Info
CMAKE_SOURCE_DIR The root source directory
CMAKE_CURRENT_SOURCE_DIR The current source directory if using sub-projects and directories.
PROJECT_SOURCE_DIR The source directory of the current cmake project.
CMAKE_BINARY_DIR The root binary / build directory. This is the directory where you ran the cmake command.
CMAKE_CURRENT_BINARY_DIR The build directory you are currently in.
PROJECT_BINARY_DIR The build directory for the current project.

编译含有 include 的项目

  1. ├── CMakeLists.txt
  2. ├── include
  3. └── Hello.h
  4. └── src
  5. ├── Hello.cpp
  6. └── main.cpp
  7. cmake_minimum_required(VERSION 3.5)
  8. project (hello_headers)
  9. set(SOURCES
  10. src/Hello.cpp
  11. src/main.cpp
  12. )
  13. add_executable(hello_headers ${SOURCES}) // 编译出来是一个可执行文件
  14. target_include_directories(hello_headers
  15. PRIVATE
  16. ${PROJECT_SOURCE_DIR}/include
  17. )

main 用到了 hello 中的函数,所以 main 文件中含有 hello 的头文件,只是代码分块,不代表 hello 文件是一个库。

设置源代码变量

  1. set(SOURCES
  2. src/Hello.cpp
  3. src/main.cpp
  4. )
  5. add_executable(${PROJECT_NAME} ${SOURCES})

创建源代码文件变量会让你的项目看起来更加清晰,也可以通过文件通配符来选定源文件

  1. file(GLOB SOURCES "src/*.cpp")

target_include_directories 函数

  1. target_include_directories(hello_headers
  2. PRIVATE
  3. ${PROJECT_SOURCE_DIR}/include
  4. )

编译给定目标时使用的包含目录,第一个参数是 target,必须是由 add_executable() 或 add_library() 等命令创建的,并且不能是ALIAS目标。

target_include_directories 函数的作用,是将 target 用到的 include 文件标记出来。

编译静态库

  1. ├── CMakeLists.txt
  2. ├── include
  3. └── static
  4. └── Hello.h
  5. └── src
  6. ├── Hello.cpp
  7. └── main.cpp
  8. cmake_minimum_required(VERSION 3.5)
  9. project(hello_library)
  10. ############################################################
  11. # Create a library
  12. ############################################################
  13. #Generate the static library from the library sources
  14. add_library(hello_library STATIC
  15. src/Hello.cpp
  16. )
  17. target_include_directories(hello_library
  18. PUBLIC
  19. ${PROJECT_SOURCE_DIR}/include
  20. )
  21. ############################################################
  22. # Create an executable
  23. ############################################################
  24. # Add an executable with the above sources
  25. add_executable(hello_binary
  26. src/main.cpp
  27. )
  28. # link the new hello_library target with the hello_binary target
  29. target_link_libraries(hello_binary
  30. PRIVATE
  31. hello_library
  32. )

这是一个简化的示例,显示了同一个文件夹中的库和二进制文件。

  • Add_library() 函数用于从一些源文件创建库,第一个参数是名字,第二个是源文件。

  • target_include_directories 函数的 scope 设置为了 PUBLIC ,因为这个头文件被编译在了,这个库文件,已经所有用到改库的地方。

    • PRIVATE - 只用在了 target 文件的
    • INTERFACE - 用在了任何链接该库的 target 文件中
    • PUBLIC - 两者都有
  • 传递给 target_include_directories 的目录将是包含目录树的根目录,你的 c 文件应该包含从那里到头文件的路径。#include "static/Hello.h"

  • 当创建一个将使用库的可执行文件时,必须告诉编译器有关库的信息。这可以使用 target_link_libraries() 函数来完成。

编译动态库

  1. add_library(hello_library SHARED
  2. src/Hello.cpp
  3. )

区别在于 STATIC 变成了 SHARED

  1. add_library(hello::library ALIAS hello_library)

add_library ALIAS 可以将库名变成一个别称

install

将项目生成的库文件、头文件、可执行文件或相关文件等安装到指定位置(系统目录,或发行包目录)。在cmake中,这主要是通过install方法在CMakeLists.txt中配置,make install命令安装相关文件来实现的。

基本安装路径由变量 CMAKE_INSTALL_PREFIX 控制,该变量可以通过 ccmake 设置或通过 cmake .. -DCMAKE_INSTALL_PREFIX=/install/location 命令来设置。

  1. install (TARGETS cmake_examples_inst_bin DESTINATION bin)

将 add_executable() 或 add_library() 等命令创建的目标文件安装到 ${CMAKE_INSTALL_PREFIX}/bin

  1. # Binaries
  2. install (TARGETS cmake_examples_inst_bin
  3. DESTINATION bin)
  4. # Library
  5. install (TARGETS cmake_examples_inst
  6. LIBRARY DESTINATION lib)
  7. # Header files
  8. install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
  9. DESTINATION include)
  10. # Config
  11. install (FILES cmake-examples.conf
  12. DESTINATION etc)

构建级别

CMake具有许多内置的构建配置,可用于编译工程。 这些配置指定了代码优化的级别,以及调试信息是否包含在二进制文件中。这些优化级别,主要有:

  • Release —— 不可以打断点调试,程序开发完成后发行使用的版本,占的体积小。 它对代码做了优化,因此速度会非常快, 在编译器中使用命令: -O3 -DNDEBUG 可选择此版本。、

  • Debug ——调试的版本,体积大。 在编译器中使用命令: -g 可选择此版本。

  • MinSizeRel—— 最小体积版本 在编译器中使用命令:-Os -DNDEBUG可选择此版本。

  • RelWithDebInfo—— 既优化又能调试。 在编译器中使用命令:-O2 -g -DNDEBUG可选择此版本。

第三方库

几乎所有项目都将要求包含第三方库,标头或程序。 CMake 支持使用 find_package() 函数查找这些工具的路径。 这将从 CMAKE_MODULE_PATH 中的文件夹列表中搜索格式为“ FindXXX.cmake”的 CMake 模块。 在linux上,默认搜索路径将包括/ usr / share / cmake / Modules。 在我的系统上,这包括对大约142个通用第三方库的支持。