基本概念(3)——cmake、qmake
cmake
cmake
是自动生成makefile
的工具,编写txt文件,CMakeLists.txt
,调用cmake
编译CMakeLists.txt
来生成
- make可以识别的Makefile
- ninja可以识别的build.ninja
- visual studio工程
- 等等其他各种工程
调用cmake -h
能看到cmake支持的生成的工程模板
例子
cmake_minimum_required(VERSION 3.14)
project(main LANGUAGES C)
##########################
#add include path
##########################
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(${CMAKE_SOURCE_DIR}/inc)
##########################
#set c11 -std=c11
##########################
set(C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
##########################
#set c++11 -std=c++11
##########################
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 打开详细输出,也可以在make的时候使用 make VERBOSE=1
set(CMAKE_VERBOSE_MAKEFILE ON)
##########################
#set b.c to lib
##########################
set(LIB_B
SHARED
lib/b.c
)
add_library(lib_b ${LIB_B})
message("lib_b is ${LIB_B}")
##########################
#add source files
##########################
set(PROJECT_SOURCES
src/main.c
)
add_executable(main ${PROJECT_SOURCES})
##########################
#link lib_b
##########################
target_link_libraries(main lib_b)
基本使用
桌面新建工程文件夹test,然后填充文件:
各文件内容如下:
然后创建build目录,把cmake生成的文件放到这里
引入头文件
上一小节已经实现了,头文件在header目录中,如果直接使用gcc编译是无法通过的,需要g++ -I
指定目录
cmake文件中使用了INCLUDE_DIRECTORIES(./header)
来引入头文件
但是,在实际使用的过程中直接在代码中指定头文件会更好,如下图
google 的c++代码规范中也是推荐这样做。这样就不用再cmake中指定头文件的目录了
扯远了。。。
第三方库
cmake使用find_package()
添加第三方库,例如qt中
需要为find_package()
提供搜索目录,他才会去找到
工程文件组织
例子 cmake qt项目
qtcreator创建一个cmake类型的项目,得到的cmakelists如下
cmake_minimum_required(VERSION 3.14) //指定cmake需求的最低cmake版本
project(helloCmake LANGUAGES CXX) //创建项目
set(CMAKE_INCLUDE_CURRENT_DIR ON) //set语句,定义变量,为变量赋值,CMAKE_INCLUDE_CURRENT_DIR是cmake自带的变量,设置为ON则自动将当前源和构建目录添加到包含路径。默认是OFF
// https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html 这里可以查看所有的cmake自带变量
set(CMAKE_AUTOUIC ON) //qt相关 调用uic.exe把.ui文件编译成标准c++文件
set(CMAKE_AUTOMOC ON) //qt相关 调用moc.exe把qt的扩展语法(Q_OBJECT)编译成标准c++语法
set(CMAKE_AUTORCC ON) //qt相关 调用rcc.exe把资源文件.qrc编译成标准c++文件
set(CMAKE_CXX_STANDARD 11) //设置c++语言标准
set(CMAKE_CXX_STANDARD_REQUIRED ON) //设置需求最低c++标准
# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check https://doc.qt.io/qt/deployment-android.html for more information.
# They need to be set before the find_package(...) calls below.
#if(ANDROID)
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
# if (ANDROID_ABI STREQUAL "armeabi-v7a")
# set(ANDROID_EXTRA_LIBS
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
# endif()
#endif()
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick LinguistTools REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick LinguistTools REQUIRED)
set(TS_FILES helloCmake_zh_CN.ts)
set(PROJECT_SOURCES
main.cpp
qml.qrc
${TS_FILES}
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(helloCmake
${PROJECT_SOURCES}
)
qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
else()
if(ANDROID)
add_library(helloCmake SHARED
${PROJECT_SOURCES}
)
else()
add_executable(helloCmake
${PROJECT_SOURCES}
)
endif()
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif()
target_compile_definitions(helloCmake
PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_link_libraries(helloCmake
PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Quick)
在qt creator中可以看到编译过程
qtcreator的编译不是直接调用cmake而是为cmake添加了很多参数,而且这些参数都是以变量的形式存在的 比如 %{Qt:qmakeExecutable}
-GNinja #使用ninja(替代make)
-DCMAKE_BUILD_TYPE:String=Debug
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
在qt的配置页面是可以看到这些变量值的。
修改下qtcreator中的参数,用真实值代替qtcreator的变量,下面是用mingw32编译器的配置,注意最后四条要对应:c编译器、c++编译器、qmake、搜索路径
上面命令我另外添加了-Bbuild
是为了指定生成目录,要在项目目录下先创建一个build文件夹
-GNinja N要大写
-Bbuild
-DCMAKE_BUILD_TYPE:String=Debug
-DQT_QMAKE_EXECUTABLE:STRING=C:/Qt/5.15.2/mingw81_32/bin/qmake.exe
-DCMAKE_PREFIX_PATH:STRING=C:/Qt/5.15.2/mingw81_32
-DCMAKE_C_COMPILER:STRING=C:/Qt/Tools/mingw810_32/bin/gcc.exe
-DCMAKE_CXX_COMPILER:STRING=C:/Qt/Tools/mingw810_32/bin/g++.exe
注意不要有换行符,上面是为了看起来方便,实际命令如下:
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE:String=Debug -DQT_QMAKE_EXECUTABLE:STRING=C:/Qt/5.15.2/mingw81_32/bin/qmake.exe -DCMAKE_PREFIX_PATH:STRING=C:/Qt/5.15.2/mingw81_32 -DCMAKE_C_COMPILER:STRING=C:/Qt/Tools/mingw810_32/bin/gcc.exe -DCMAKE_CXX_COMPILER:STRING=C:/Qt/Tools/mingw810_32/bin/g++.exe
然后cd到build目录执行 ninja(需要先配置ninja的环境变量)
指定编译器
如果系统中安装了多个编译器(比如gcc,clang),可以通过cmake指定用哪个
指定安装目录
常见的开源代码会给出make install
的选项,可以通过CMAKE_INSTALL_PREFIX
选项指定安装目录
比如我编译flatbuffers的时候:
cmake -Bbuild -DCMAKE_INSTALL_PREFIX=/home/kun/usr
cd build
make
make install
安装之后的文件:
# kun @ ubuntu in ~/usr [21:29:06]
$ tree
.
├── bin
│ └── flatc
├── include
│ └── flatbuffers
│ ├── allocator.h
│ ├── array.h
│ ├── base.h
│ ├── buffer.h
│ ├── buffer_ref.h
│ ├── code_generator.h
│ ├── code_generators.h
│ ├── default_allocator.h
│ ├── detached_buffer.h
│ ├── file_manager.h
│ ├── flatbuffer_builder.h
│ ├── flatbuffers.h
│ ├── flatc.h
│ ├── flexbuffers.h
│ ├── flex_flat_util.h
│ ├── grpc.h
│ ├── hash.h
│ ├── idl.h
│ ├── minireflect.h
│ ├── pch
│ │ ├── flatc_pch.h
│ │ └── pch.h
│ ├── reflection_generated.h
│ ├── reflection.h
│ ├── registry.h
│ ├── stl_emulation.h
│ ├── string.h
│ ├── struct.h
│ ├── table.h
│ ├── util.h
│ ├── vector_downward.h
│ ├── vector.h
│ └── verifier.h
└── lib
├── cmake
│ └── flatbuffers
│ ├── BuildFlatBuffers.cmake
│ ├── flatbuffers-config.cmake
│ ├── flatbuffers-config-version.cmake
│ ├── FlatBuffersTargets.cmake
│ ├── FlatBuffersTargets-noconfig.cmake
│ ├── FlatcTargets.cmake
│ └── FlatcTargets-noconfig.cmake
├── libflatbuffers.a
└── pkgconfig
└── flatbuffers.pc
qmake
环境变量
编译器、build工具(make ninja等)、调试器
三类工具,安装完之后需要配置一下环境变量,来让命令行找到这些工具,并且让编译器找到一些dll文件