Tabla de contenido
- Reimpresión
- ColorMarkDown
- 1.Chacer descripción general
- 2. Uso de CMake
- 3. Macros predefinidas
Reimpresión
Autor: Su Bingqu
Enlace: https://subingwen.cn/cmake/CMake-advanced/
Fuente: DaBing de iProgramming. Los derechos de autor pertenecen al autor. Para reimpresiones comerciales, comuníquese con el autor para obtener autorización. Para reimpresiones no comerciales, indique la fuente.
ColorMarkDown
Gitee: Tutorial de nivel de niñera de CMake: Big C que ama la programación
1.Chacer descripción general
CMake es una herramienta de creación de proyectos y es multiplataforma. En cuanto a la construcción de proyectos, también estamos familiarizados con Makefile (construcción de proyectos mediante el comando make), la mayoría del software IDE integra make, como: nmake de VS, make de GNU en Linux, qmake de Qt, etc. Descubra que el archivo MAKE generalmente depende de la plataforma de compilación actual, la carga de trabajo de escribir el archivo MAKE es relativamente grande y es fácil cometer errores al resolver dependencias.
CMake puede resolver exactamente los problemas anteriores. Permite a los desarrolladores especificar el proceso de compilación de todo el proyecto. Según la plataforma de compilación, el 自动生成本地化的Makefile和工程文件
usuario final solo necesita make
compilar. Por lo tanto, CMake puede considerarse como una herramienta que genera automáticamente Makefiles. El proceso de compilación es el siguiente en la imagen:
makefile
La línea discontinua azul representa el proceso de construcción de un proyecto utilizando- La línea roja continua representa
cmake
el proceso de construcción de un proyecto utilizando
Después de presentar las funciones de CMake, resumamos sus ventajas:
-
Multiplataforma
-
Capacidad para gestionar grandes proyectos.
-
Simplifique el proceso de compilación y el proceso de compilación.
-
Extensible: puede escribir módulos de funciones específicas para cmake para expandir las funciones de cmake
2. Uso de CMake
CMake
Admite comandos en mayúsculas, minúsculas y mayúsculas y minúsculas. Si CMakeLists.txt
la herramienta que utiliza al escribir un archivo tiene un símbolo del sistema correspondiente, déjela como está y no le preste demasiada atención.
2.1 Notas
2.1.1 Líneas de comentarios
CMake
Uso , #
que 行注释
se puede colocar en cualquier lugar.
# 这是一个 CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.0.0)
2.1.2 Bloque de comentarios
CMake
Utilice #[[ ]]
el formulario 块注释
.
#[[ 这是一个 CMakeLists.txt 文件。
这是一个 CMakeLists.txt 文件
这是一个 CMakeLists.txt 文件]]
cmake_minimum_required(VERSION 3.0.0)
2.1 Sólo archivos fuente
2.1.1 Vivir en la misma habitación
-
Trabajo de preparación, para facilitar las pruebas, he preparado varios archivos de prueba en mi computadora local.
-
agregar.c
#include <stdio.h> #include "head.h" int add(int a, int b) { return a+b; }
-
sub.c
#include <stdio.h> #include "head.h" // 你好 int subtract(int a, int b) { return a-b; }
-
mucho c
#include <stdio.h> #include "head.h" int multiply(int a, int b) { return a*b; }
-
div.c
#include <stdio.h> #include "head.h" double divide(int a, int b) { return (double)a/b; }
-
cabeza.h
#ifndef _HEAD_H #define _HEAD_H // 加法 int add(int a, int b); // 减法 int subtract(int a, int b); // 乘法 int multiply(int a, int b); // 除法 double divide(int a, int b); #endif
-
C Principal
#include <stdio.h> #include "head.h" int main() { int a = 20; int b = 12; printf("a = %d, b = %d\n", a, b); printf("a + b = %d\n", add(a, b)); printf("a - b = %d\n", subtract(a, b)); printf("a * b = %d\n", multiply(a, b)); printf("a / b = %f\n", divide(a, b)); return 0; }
-
-
La estructura de directorios de los archivos anteriores es la siguiente:
$ tree . ├── add.c ├── div.c ├── head.h ├── main.c ├── mult.c └── sub.c
-
agregar
CMakeLists.txt
archivoAgregue un nuevo archivo CMakeLists.txt en el directorio donde se encuentra el archivo fuente anterior. El contenido del archivo es el siguiente:
cmake_minimum_required(VERSION 3.0) project(CALC) add_executable(app add.c div.c main.c mult.c sub.c)
A continuación, presentaremos sucesivamente los tres comandos agregados en el archivo CMakeLists.txt:
-
cmake_minimum_required
:Especifique la versión mínima de cmake utilizada- Opcional, no obligatorio, puede haber una advertencia si no se agrega
-
project
: Defina el nombre del proyecto y especifique la versión del proyecto, la descripción del proyecto, la dirección de la página de inicio web y los idiomas admitidos (todos los idiomas son compatibles de forma predeterminada). Si no los necesita, puede ignorarlos. Solo necesita para especificar el nombre del proyecto.# PROJECT 指令的语法是: project(<PROJECT-NAME> [<language-name>...]) project(<PROJECT-NAME> [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]] [DESCRIPTION <project-description-string>] [HOMEPAGE_URL <url-string>] [LANGUAGES <language-name>...])
-
add_executable
: La definición del proyecto generará un programa ejecutable.add_executable(可执行程序名 源文件名称)
-
El nombre del programa ejecutable aquí no tiene
project
nada que ver con el nombre del proyecto en -
El nombre del archivo fuente puede ser uno o varios, si hay varios espacios o
;
intervalos disponibles.# 样式1 add_executable(app add.c div.c main.c mult.c sub.c) # 样式2 add_executable(app add.c;div.c;main.c;mult.c;sub.c)
-
-
-
ejecutar
CMake
comandoTodo está listo. Después de editar el archivo CMakeLists.txt, puede ejecutar
cmake
el comando.# cmake 命令原型 $ cmake CMakeLists.txt文件所在路径
$ tree . ├── add.c ├── CMakeLists.txt ├── div.c ├── head.h ├── main.c ├── mult.c └── sub.c 0 directories, 7 files robin@OS:~/Linux/3Day/calc$ cmake .
Después de ejecutar el comando
cmake
, se ejecutarán los comandos en CMakeLists.txt, así que tenga cuidadocmake
de no cometer errores al especificar la ruta del comando.Después de ejecutar el comando, verifique si hay más archivos en el directorio donde se encuentra el archivo fuente:
$ tree -L 1 . ├── add.c ├── CMakeCache.txt # new add file ├── CMakeFiles # new add dir ├── cmake_install.cmake # new add file ├── CMakeLists.txt ├── div.c ├── head.h ├── main.c ├── Makefile # new add file ├── mult.c └── sub.c
Podemos ver que se genera un archivo en el directorio correspondiente
makefile
, si ejecutamosmake
el comando en este momento podemos construir el proyecto y obtener el programa ejecutable requerido.$ make Scanning dependencies of target app [ 16%] Building C object CMakeFiles/app.dir/add.c.o [ 33%] Building C object CMakeFiles/app.dir/div.c.o [ 50%] Building C object CMakeFiles/app.dir/main.c.o [ 66%] Building C object CMakeFiles/app.dir/mult.c.o [ 83%] Building C object CMakeFiles/app.dir/sub.c.o [100%] Linking C executable app [100%] Built target app # 查看可执行程序是否已经生成 $ tree -L 1 . ├── add.c ├── app # 生成的可执行程序 ├── CMakeCache.txt ├── CMakeFiles ├── cmake_install.cmake ├── CMakeLists.txt ├── div.c ├── head.h ├── main.c ├── Makefile ├── mult.c └── sub.c
app
Finalmente, se compila el programa ejecutable (el nombre seCMakeLists.txt
especifica en).
2.1.2 Sala privada VIP
Como se puede ver en el ejemplo anterior, si CMakeLists.txt
ejecuta cmake
el comando en el directorio donde se encuentra el archivo, se generarán algunos directorios y archivos ( 包括 makefile 文件
), si makefile文件
ejecuta make
el comando nuevamente, el programa también generará algunos archivos intermedios y un archivo ejecutable durante el proceso de compilación. Esto hará que todo el directorio del proyecto parezca confuso y difícil de administrar y mantener. En este momento, podemos colocar los archivos generados que no tienen nada que ver con el código fuente del proyecto en el directorio correspondiente. Por ejemplo, nombre este directorio build
:
$ mkdir build
$ cd build
$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/robin/Linux/build
Ahora cmake
el comando se build
ejecuta en el directorio, pero CMakeLists.txt
el archivo está build
en el directorio un nivel por encima del directorio, por lo que cmake
la ruta especificada después del comando ..
es el directorio un nivel por encima del directorio actual.
Cuando se ejecuta el comando, build
se generará un makefile
archivo en el directorio
$ tree build -L 1
build
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
└── Makefile
1 directory, 3 files
De esta manera, puede build
ejecutar make
comandos en el directorio para compilar el proyecto y los archivos relacionados generados naturalmente se almacenarán en build
el directorio. De esta manera, todos los archivos pasados cmake
y make
generados quedan completamente aislados de los archivos fuente del proyecto y todos regresan a sus hogares para encontrar a su propia madre.
2.2 Orden privada
2.2.1 Definir variables
En el ejemplo anterior, se proporcionan un total de 5 archivos fuente. Suponiendo que estos cinco archivos fuente deben usarse repetidamente, es realmente problemático escribir sus nombres directamente cada vez. En este momento, debemos definir una variable para Consulte el archivo. La cadena correspondiente al nombre se almacena y debe usarse para definir variables en cmake set
.
# SET 指令的语法是:
# [] 中的参数为可选项, 如不需要可以不写
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
VAR
:nombre de la variableVALUE
:variable
# 方式1: 各个源文件之间使用空格间隔
# set(SRC_LIST add.c div.c main.c mult.c sub.c)
# 方式2: 各个源文件之间使用分号 ; 间隔
set(SRC_LIST add.c;div.c;main.c;mult.c;sub.c)
add_executable(app ${SRC_LIST})
2.2.2 Especificar el estándar C++ utilizado
Al escribir un programa C++, puede usar nuevas funciones como C++11, C++14, C++17, C++20, etc. Luego, debe determinar cuál usar en el comando de compilación al compilar. .estándar:
$ g++ *.cpp -std=c++11 -o app
En el ejemplo anterior, los parámetros -std=c++11
se usan para especificar que el programa debe compilarse usando el estándar C++ 11, y el estándar C++ corresponde a una macro llamada DCMAKE_CXX_STANDARD
. Hay dos formas de especificar el estándar C++ en CMake:
-
Especificado por el comando set en CMakeLists.txt
#增加-std=c++11 set(CMAKE_CXX_STANDARD 11) #增加-std=c++14 set(CMAKE_CXX_STANDARD 14) #增加-std=c++17 set(CMAKE_CXX_STANDARD 17)
-
Especifique el valor de esta macro al ejecutar el comando cmake
#增加-std=c++11 cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=11 #增加-std=c++14 cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=14 #增加-std=c++17 cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=17
En el ejemplo anterior, la ruta después de CMake debe modificarse según corresponda de acuerdo con la situación real.
2.2.3 Especificar la ruta de salida
Especifique la ruta de salida del programa ejecutable en CMake, que también corresponde a una macro llamada EXECUTABLE_OUTPUT_PATH
, y su valor aún lo set
establece el comando:
set(HOME /home/robin/Linux/Sort)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)
- Línea 1: Defina una variable para almacenar una ruta absoluta
- La segunda línea: establezca el valor de la ruta empalmada en
EXECUTABLE_OUTPUT_PATH
la macro- Si el subdirectorio en esta ruta no existe, se generará automáticamente, no es necesario crearlo manualmente
Dado que el programa ejecutable se obtiene en función del archivo MAKE generado por el comando cmake y luego ejecutado por el comando make, si se usa la ruta relativa ./xxx/xxx al especificar aquí la ruta de generación del programa ejecutable, entonces ./ en esta ruta Correspondiente al directorio donde se encuentra el archivo makefile.
2.3 Buscar archivos
Si hay muchos archivos fuente en un proyecto, CMakeLists.txt
es imposible enumerar cada archivo en el directorio del proyecto uno por uno al escribir el archivo, lo que es demasiado problemático y poco realista. Por lo tanto, CMake nos proporciona un comando para buscar archivos, puedes usar aux_source_directory
el comando o file
comando.
2.3.1 Método 1
Utilice el comando en CMake aux_source_directory
para buscar en una ruta determinada 所有源文件
. El formato del comando es:
aux_source_directory(< dir > < variable >)
dir
: Directorio para buscarvariable
:dir
almacena la lista de archivos fuente buscados en el directorio en esta variable
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
# 搜索 src 目录下的源文件
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
add_executable(app ${SRC_LIST})
2.3.2 Método 2
Si hay muchos archivos fuente en un proyecto, CMakeLists.txt
es imposible enumerar cada archivo en el directorio del proyecto uno por uno al escribir el archivo, lo que es demasiado problemático. Por lo tanto, CMake nos proporciona un comando para buscar archivos, y es file(当然,除了搜索以外通过 file 还可以做其他事情)
.
file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
GLOB
: Genera una lista de todos los nombres de archivos que cumplen con las condiciones buscadas en el directorio especificado y la almacena en una variable.GLOB_RECURSE
: busque recursivamente el directorio especificado, genere una lista de los nombres de archivos buscados que cumplan las condiciones y guárdela en una variable.
Busque todos los archivos fuente en el directorio src del directorio actual y guárdelos en variables
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
-
La macro CMAKE_CURRENT_SOURCE_DIR indica la ruta donde se encuentra el archivo CMakeLists.txt al que se accede actualmente.
-
Puede agregar comillas dobles o no para la ruta del archivo y el tipo que se buscará:
file(GLOB MAIN_HEAD "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h")
2.4 Incluir archivos de encabezado
Al compilar archivos fuente del proyecto, a menudo es necesario especificar la ruta del archivo de encabezado correspondiente al archivo fuente, para garantizar que el compilador pueda encontrar estos archivos de encabezado durante el proceso de compilación y pasar la compilación con éxito. Configurar el directorio que se incluirá en CMake también es muy simple. Se puede hacer con un comando, que es include_directories
:
include_directories(headpath)
Por ejemplo, hay varios archivos fuente y su estructura de directorios es la siguiente:
$ tree
.
├── build
├── CMakeLists.txt
├── include
│ └── head.h
└── src
├── add.cpp
├── div.cpp
├── main.cpp
├── mult.cpp
└── sub.cpp
3 directories, 7 files
CMakeLists.txt
El contenido del archivo es el siguiente:
cmake_minimum_required(VERSION 3.0)
project(CALC)
set(CMAKE_CXX_STANDARD 11)
set(HOME /home/robin/Linux/calc)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin/)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_executable(app ${SRC_LIST})
Entre ellos, la sexta línea especifica la ruta al archivo de encabezado, y PROJECT_SOURCE_DIR
el valor correspondiente a la macro es el directorio que sigue cuando usamos el comando cmake, que generalmente es el directorio raíz del proyecto.
2.5 Crear biblioteca dinámica o biblioteca estática
A veces, el código fuente que escribimos no necesita ser compilado en programas ejecutables, pero algunas bibliotecas estáticas o dinámicas se generan para que las utilicen terceros. A continuación se explica cómo generar estos dos tipos de archivos de biblioteca en cmake.
2.5.1 Crear una biblioteca estática
- ESTÁTICO
En cmake, si desea crear una biblioteca estática, los comandos que debe utilizar son los siguientes:
add_library(库名称 STATIC 源文件1 [源文件2] ...)
En Linux, el nombre de la biblioteca estática se divide en tres partes: lib
+ 库名字
+ .a
. Aquí solo necesita especificar el nombre de la biblioteca. Las otras dos partes se completarán automáticamente cuando se genere el archivo.
Aunque el nombre de la biblioteca en Windows es diferente del formato de Linux, solo necesita especificar el nombre.
src
Hay un directorio a continuación. Los archivos fuente en el directorio deben compilarse en una biblioteca estática y luego usarse:
$ tree
.
├── build
├── CMakeLists.txt
├── include # 头文件目录
│ └── head.h
├── main.cpp # 用于测试的源文件
└── src # 源文件目录
├── add.cpp
├── div.cpp
├── mult.cpp
└── sub.cpp
Según la estructura de directorios anterior, CMakeLists.txt
el archivo se puede escribir así:
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc STATIC ${SRC_LIST})
Esto eventualmente generará el archivo de biblioteca estática correspondiente libcalc.a
.
2.5.2 Crear bibliotecas dinámicas
- COMPARTIDO
En cmake, si desea crear una biblioteca dinámica, los comandos que debe utilizar son los siguientes:
add_library(库名称 SHARED 源文件1 [源文件2] ...)
En Linux, el nombre de la biblioteca dinámica se divide en tres partes: lib
+ 库名字
+ .so
. Aquí solo necesita especificar el nombre de la biblioteca. Las otras dos partes se completarán automáticamente cuando se genere el archivo.
Aunque el nombre de la biblioteca en Windows es diferente del formato de Linux, solo necesita especificar el nombre.
Según la estructura de directorios anterior, CMakeLists.txt
el archivo se puede escribir así:
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc SHARED ${SRC_LIST})
Esto eventualmente generará el archivo de biblioteca dinámica correspondiente libcalc.so
.
2.5.3 Especificar la ruta de salida
Forma 1: para bibliotecas dinámicas
Para los archivos de biblioteca generados, la ruta de salida se puede especificar de la misma manera que para los programas ejecutables. 由于在Linux下生成的动态库默认是有执行权限的
, por lo que puedes especificar el directorio que genera de la misma manera que genera un programa ejecutable:
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库生成路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library(calc SHARED ${SRC_LIST})
Para este método, en realidad establece una ruta set
para la macro mediante un comando , y esta ruta es la ruta donde se genera el archivo ejecutable.EXECUTABLE_OUTPUT_PATH
Método 2: se aplica a ambos
Dado que las bibliotecas estáticas generadas en Linux no tienen permisos ejecutables de forma predeterminada, no se pueden usar EXECUTABLE_OUTPUT_PATH
macros al especificar la ruta para generar bibliotecas estáticas, sino que se deben LIBRARY_OUTPUT_PATH
usar.Esta macro es aplicable tanto a archivos de biblioteca estática como a archivos de biblioteca dinámica.
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库/静态库生成路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 生成动态库
#add_library(calc SHARED ${SRC_LIST})
# 生成静态库
add_library(calc STATIC ${SRC_LIST})
2.6 Incluir archivos de biblioteca
En el proceso de escribir un programa, puede utilizar algunas bibliotecas dinámicas proporcionadas por el sistema o bibliotecas dinámicas o archivos de biblioteca estática producidos por usted mismo. cmake también nos proporciona comandos relevantes para cargar bibliotecas dinámicas.
2.6.1 Vincular biblioteca estática
src
├── add.cpp
├── div.cpp
├── main.cpp
├── mult.cpp
└── sub.cpp
Ahora compilamos los archivos src
en el directorio anterior add.cpp、div.cpp、mult.cpp、sub.cpp
en un archivo de biblioteca estática libcalc.a
.
Crear y utilizar bibliotecas de enlaces estáticos mediante comandos
La estructura del directorio de prueba es la siguiente:
$ tree
.
├── build
├── CMakeLists.txt
├── include
│ └── head.h
├── lib
│ └── libcalc.a # 制作出的静态库的名字
└── src
└── main.cpp
4 directories, 4 files
En cmake, el comando para vincular la biblioteca estática es el siguiente:
link_libraries(<static lib> [<static lib>...])
- Parámetro 1 : especifique el nombre de la biblioteca estática que se vinculará
- Puede ser nombre completo
libxxx.a
- También puede ser el nombre después de pellizcar la cabeza (
lib
) y quitarle la cola ( ).a
xxx
- Puede ser nombre completo
- Parámetro 2-N : el nombre de la otra biblioteca estática que se vinculará
Si el sistema no proporciona la biblioteca estática (hágalo usted mismo o utilice una biblioteca estática proporcionada por un tercero), es posible que no se encuentre la biblioteca estática. En este caso, también puede especificar la ruta de la biblioteca estática:
link_directories(<lib path>)
De esta forma, el CMakeLists.txt
contenido del archivo modificado es el siguiente:
cmake_minimum_required(VERSION 3.0)
project(CALC)
# 搜索指定目录下源文件
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 包含头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 包含静态库路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 链接静态库
link_libraries(calc)
add_executable(app ${SRC_LIST})
Después de agregar el código en la línea 8 , puede encontrar esta biblioteca estática de acuerdo con la ruta especificada por el parámetro.
2.6.2 Vincular bibliotecas dinámicas
En el proceso de programación, además de introducir bibliotecas estáticas en el proyecto, muchas veces también se utilizan algunas bibliotecas estándar o dinámicas proporcionadas por terceros. En cuanto a la producción y uso de bibliotecas dinámicas y cómo cargarlas en la memoria, las bibliotecas estáticas son todos diferentes, no entraré en detalles aquí. Si tiene alguna duda, consulte la biblioteca estática y la biblioteca dinámica de Linux.
cmake
El comando para vincular la biblioteca dinámica es el siguiente :
target_link_libraries(
<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
-
objetivo : especifique el nombre del archivo para cargar la biblioteca dinámica
- El archivo puede ser un archivo fuente.
- Este archivo puede ser un archivo de biblioteca dinámica.
- El archivo puede ser un archivo ejecutable.
-
PRIVADO|PÚBLICO|INTERFACE : Permisos de acceso para bibliotecas dinámicas, el valor predeterminado es
PUBLIC
-
Si no hay dependencias entre las distintas bibliotecas dinámicas, no es necesario realizar ninguna configuración. No hay diferencia entre las tres. Generalmente no es necesario especificar, solo use el PÚBLICO predeterminado.
-
动态库的链接具有传递性
, si la biblioteca dinámica A se vincula a las bibliotecas dinámicas B y C, y la biblioteca dinámica D se vincula a la biblioteca dinámica A, entonces la biblioteca dinámica D es equivalente a vincularse también a las bibliotecas dinámicas B y C, y puede usar los métodos definidos en las bibliotecas dinámicas B y C. .target_link_libraries(A B C) target_link_libraries(D A)
-
PUBLIC
: La biblioteca detrás de pública se vinculará al objetivo anterior y los símbolos internos también se exportarán y proporcionarán a terceros. -
PRIVATE
: La biblioteca detrás de privada solo se vincula al objetivo anterior y se finaliza. El tercero no puede detectar qué biblioteca ha ajustado. -
INTERFACE
: La biblioteca importada después de la interfaz no se vinculará al destino anterior y solo se exportarán los símbolos.
-
-
Biblioteca dinámica del sistema de enlace
La vinculación de bibliotecas dinámicas es completamente diferente a la de bibliotecas estáticas:
- La biblioteca estática se empaquetará en el programa ejecutable durante la fase de vinculación de generación del programa ejecutable, de modo que cuando se inicie el programa ejecutable, la biblioteca estática se cargará en la memoria.
- La biblioteca dinámica no se empaquetará en el programa ejecutable durante la fase de vinculación de generación del programa ejecutable. La biblioteca dinámica solo se cargará en la memoria cuando se inicie el programa ejecutable y se llamen las funciones de la biblioteca dinámica.
Por lo tanto, cmake
al especificar la biblioteca dinámica a vincular,应该将命令写到生成了可执行文件之后:
cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 添加并指定最终生成的可执行程序名
add_executable(app ${SRC_LIST})
# 指定可执行程序要链接的动态库名字
target_link_libraries(app pthread)
en target_link_libraries(app pthread)
:
-
app:
Correspondiente al nombre del programa ejecutable final generado -
pthread
: Esta es la biblioteca dinámica que cargará el programa ejecutable. Esta biblioteca es la biblioteca de subprocesos proporcionada por el sistema. Su nombre completo es. Cuando selibpthread.so
especifica, la cabeza (lib) y la cola (.so) generalmente están pellizcadas.
Vincular bibliotecas dinámicas de terceros
Ahora, yo mismo he generado una biblioteca dinámica y la estructura de directorio correspondiente es la siguiente:
$ tree
.
├── build
├── CMakeLists.txt
├── include
│ └── head.h # 动态库对应的头文件
├── lib
│ └── libcalc.so # 自己制作的动态库文件
└── main.cpp # 测试用的源文件
3 directories, 4 files
Supongamos que en el archivo de prueba se utilizan main.cpp
la biblioteca dinámica producida por usted y la biblioteca de subprocesos proporcionada por el sistema. En este momento, el archivo se puede escribir así:libcalc.so
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_executable(app ${SRC_LIST})
target_link_libraries(app pthread calc)
En la sexta línea , hay nombres de bibliotecas dinámicas que pthread、calc
el programa ejecutable app
vinculará . Cuando app
se genera el programa ejecutable y se ejecuta el archivo, aparecerá el siguiente mensaje de error:
$ ./app
./app: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory
Esto se debe a que después de iniciar el programa ejecutable, calc
se carga la biblioteca dinámica, pero no se conoce la ubicación de la biblioteca dinámica para resolver el problema de que la biblioteca dinámica no se puede cargar , por lo que la carga falla. En CMake, puede cargar el biblioteca dinámica antes de generar el programa ejecutable. , use el comando para especificar la ubicación de la biblioteca dinámica que se vinculará. Este comando también se usa para especificar la ubicación de la biblioteca estática:
link_directories(path)
Entonces el CMakeLists.txt
archivo modificado debería verse así:
cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 指定源文件或者动态库对应的头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 指定要链接的动态库的路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 添加并生成一个可执行程序
add_executable(app ${SRC_LIST})
# 指定要链接的动态库
target_link_libraries(app pthread calc)
Después de link_directories
especificar la ruta de la biblioteca dinámica, no habrá ningún problema de que no se pueda encontrar la biblioteca dinámica al ejecutar el programa ejecutable generado.
Recordatorio: utilice el comando target_link_libraries para vincular bibliotecas dinámicas o archivos de biblioteca estática.
2.7 registro
En CMake, puede utilizar el usuario para mostrar un mensaje. El nombre del comando es message
:
message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
(无)
: noticias importantesSTATUS
: mensaje no importanteWARNING
: Advertencia de CMake, continuará ejecutándoseAUTHOR_WARNING
: Advertencia de CMake (dev), continuará ejecutándoseSEND_ERROR
: Error de CMake, continúa la ejecución, pero omite el paso de generaciónFATAL_ERROR
: Error de CMake, finalizando todo el procesamiento
La herramienta de línea de comandos de CMake muestra mensajes en stdout STATUS
y todos los demás mensajes en stderr. La GUI de CMake muestra todos los mensajes en su área de registro.
El texto de los mensajes de advertencia y error de CMake se muestra utilizando un lenguaje de marcado simple. El texto no tiene sangría, las líneas que exceden la longitud se ajustan y las líneas nuevas se utilizan como separadores entre párrafos.
# 输出一般日志信息
message(STATUS "source path: ${PROJECT_SOURCE_DIR}")
# 输出警告信息
message(WARNING "source path: ${PROJECT_SOURCE_DIR}")
# 输出错误信息
message(FATAL_ERROR "source path: ${PROJECT_SOURCE_DIR}")
2.8 Operaciones variables
2.8.1 Adición
A veces, los archivos fuente del proyecto no están necesariamente en el mismo directorio, pero estos archivos fuente eventualmente deben compilarse juntos para generar el archivo ejecutable o el archivo de biblioteca final. Si file
buscamos los archivos fuente en cada directorio a través de comandos, al final debemos realizar una operación de empalme de cadenas, puede usar set
comandos o comandos para empalmar cadenas list
.
Usar empalme conjunto
Si usa set para empalmar cadenas, el formato de comando correspondiente es el siguiente:
set(变量名1 ${变量名1} ${变量名2} ...)
El comando anterior en realidad concatena todas las cadenas a partir del segundo parámetro y finalmente almacena el resultado en el primer parámetro. Si hay datos originales en el primer parámetro, los datos originales se sobrescribirán.
cmake_minimum_required(VERSION 3.0)
project(TEST)
set(TEMP "hello,world")
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/src1/*.cpp)
file(GLOB SRC_2 ${PROJECT_SOURCE_DIR}/src2/*.cpp)
# 追加(拼接)
set(SRC_1 ${SRC_1} ${SRC_2} ${TEMP})
message(STATUS "message: ${SRC_1}")
Usar empalme de listas
Si usa la lista para empalmar cadenas, el formato de comando correspondiente es el siguiente:
list(APPEND <list> [<element> ...])
list
La función del comando es set
relativamente poderosa. El empalme de cadenas es solo una de sus funciones, por lo que debemos especificar la operación que queremos realizar en la posición de su primer parámetro, lo que significa APPEND
agregar datos. Los parámetros posteriores set
son los mismos.
cmake_minimum_required(VERSION 3.0)
project(TEST)
set(TEMP "hello,world")
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/src1/*.cpp)
file(GLOB SRC_2 ${PROJECT_SOURCE_DIR}/src2/*.cpp)
# 追加(拼接)
list(APPEND SRC_1 ${SRC_1} ${SRC_2} ${TEMP})
message(STATUS "message: ${SRC_1}")
En CMake, set
puedes crear uno usando el comando list
. A list
es internamente un 分号;
conjunto de cadenas divididas por . Por ejemplo, set(var a b c d e)
el comando creará un list:a;b;c;d;e
, pero lo que obtendrá cuando finalmente imprima el valor de la variable es abcde
.
set(tmp1 a;b;c;d;e)
set(tmp2 a b c d e)
message(${tmp1})
message(${tmp2})
Resultado de salida:
abcde
abcde
2.8.2 Eliminación de cuerdas
file
Obtenemos todos los archivos fuente en un directorio buscando en un directorio, pero algunos de los archivos fuente no son los que necesitamos, como por ejemplo:
$ tree
.
├── add.cpp
├── div.cpp
├── main.cpp
├── mult.cpp
└── sub.cpp
0 directories, 5 files
Hay cinco archivos fuente en el directorio actual, uno de los cuales main.cpp
es un archivo de prueba. Si queremos generar una biblioteca dinámica a partir de archivos fuente relacionados con la calculadora para que otros la usen, entonces solo necesitamos add.cpp、div.cp、mult.cpp、sub.cpp
estos cuatro archivos fuente. En este momento, main.cpp
debe excluir los datos buscados. Para lograr esta función, también puede utilizarlist
list(REMOVE_ITEM <list> <value> [<value> ...])
A través del prototipo de comando anterior, puede ver que eliminar y agregar datos son similares, excepto que el primer parámetro ha cambiado REMOVE_ITEM
.
cmake_minimum_required(VERSION 3.0)
project(TEST)
set(TEMP "hello,world")
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/*.cpp)
# 移除前日志
message(STATUS "message: ${SRC_1}")
# 移除 main.cpp
list(REMOVE_ITEM SRC_1 ${PROJECT_SOURCE_DIR}/main.cpp)
# 移除后日志
message(STATUS "message: ${SRC_1}")
Como puede ver, 第8行
simplemente especifique el nombre del archivo que desea eliminar list
. Pero asegúrese de tener en cuenta que cuando busca archivos fuente mediante el comando file, obtiene la ruta absoluta del archivo (la ruta correspondiente a cada archivo en la lista es un elemento, y todas son rutas absolutas), por lo que también debe elimínelo al eliminar Se debe especificar la ruta absoluta del archivo; de lo contrario, la operación de eliminación no se realizará correctamente.
Hay list
otras funciones del comando, pero no se usan comúnmente, por lo que no las presentaré una por una con ejemplos aquí.
-
Obtenga la longitud de la lista.
list(LENGTH <list> <output variable>)
-
LENGTH
: El subcomando LENGTH se utiliza para leer la longitud de la lista. -
<list>
: Lista de operaciones actuales -
<output variable>
: Variable recién creada que se utiliza para almacenar la longitud de la lista.
-
-
Lea el elemento en el índice especificado en la lista. Se pueden especificar varios índices.
list(GET <list> <element index> [<element index> ...] <output variable>)
-
<list>
: Lista de operaciones actuales -
<element index>
: Índice del elemento de la lista- La numeración comienza desde 0 y el elemento con índice 0 es el primer elemento de la lista;
- El índice también puede ser un número negativo,
-1
que significa el último elemento de la lista,-2
que significa el penúltimo elemento de la lista, y así sucesivamente. - Cuando el índice (ya sea positivo o negativo) excede la longitud de la lista, se informará un error durante la ejecución.
-
<output variable>
: Una variable recién creada que almacena el resultado devuelto del elemento de índice especificado, que también es una lista.
-
-
Une los elementos de la lista con un conector (cadena) para formar una cadena
list (JOIN <list> <glue> <output variable>)
-
<list>
: Lista de operaciones actuales -
<glue>
:Conector especificado (cadena) -
<output variable>
: Variable recién creada para almacenar la cadena devuelta
-
-
Encuentra si el elemento especificado existe en la lista; si no se encuentra, devuelve -1
list(FIND <list> <value> <output variable>)
-
<list>
: Lista de operaciones actuales -
<value>
: El elemento que debe buscarse en la lista. -
<output variable>
: Variable recién creada-
Si la lista
<list>
existe<value>
, devuelve<value>
el índice en la lista. -
Devuelve -1 si no se encuentra.
-
-
-
Agregar elementos a la lista
list (APPEND <list> [<element> ...])
-
Insertar varios elementos en la posición especificada en la lista.
list(INSERT <list> <element_index> <element> [<element> ...])
-
Insertar un elemento en la lista en el índice 0
list (PREPEND <list> [<element> ...])
-
Eliminar el último elemento de la lista.
list (POP_BACK <list> [<out-var>...])
-
Eliminar el primer elemento de la lista.
list (POP_FRONT <list> [<out-var>...])
-
Elimina el elemento especificado de la lista.
list (REMOVE_ITEM <list> <value> [<value> ...])
-
Elimina el elemento en el índice especificado de la lista.
list (REMOVE_AT <list> <index> [<index> ...])
-
Eliminar elementos duplicados de la lista
list (REMOVE_DUPLICATES <list>)
-
cambio de lista
list(REVERSE <list>)
-
Clasificación de listas
list (SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])
-
COMPARE
: Especifique el método de clasificación. Los siguientes valores están disponibles:STRING
: Ordenar en orden alfabético, que es el método de clasificación predeterminado.FILE_BASENAME
: Si se trata de una serie de nombres de ruta, se utilizará el nombre base para ordenar.NATURAL
: Ordenar usando el orden de los números naturales
-
CASE
: Indique si distingue entre mayúsculas y minúsculas. Los siguientes valores están disponibles:SENSITIVE
: Ordene distinguiendo entre mayúsculas y minúsculas, que es el valor predeterminado.INSENSITIVE
: Ordenar sin distinguir entre mayúsculas y minúsculas
-
ORDER
: especifique el orden de clasificación. Los siguientes valores están disponibles:-
ASCENDING
: Ordenar en orden ascendente, valor predeterminado -
DESCENDING
: Ordenar en orden descendente
-
-
2.9 Definición de macros
Al probar el programa, podemos agregar algunas definiciones de macro al código y usar estas macros para controlar si los códigos surten efecto, como se muestra a continuación:
#include <stdio.h>
#define NUMBER 3
int main()
{
int a = 10;
#ifdef DEBUG
printf("我是一个程序猿, 我不会爬树...\n");
#endif
for(int i=0; i<NUMBER; ++i)
{
printf("hello, GCC!!!\n");
}
return 0;
}
La macro se juzga en la séptima línea del programa DEBUG
. Si la macro está definida, la salida del registro se realizará en la octava línea. Si la macro no está definida, la octava línea equivale a estar comentada, por lo que no se puede visto al final para registrar entradas y salidas ( esta macro no está definida en el código anterior ).
Para que las pruebas sean más flexibles, no podemos definir esta macro en el código, sino definirla durante la prueba. Una forma es especificarla gcc/g++
en el comando, de la siguiente manera:
$ gcc test.c -DDEBUG -o app
Especifique el nombre de la macro que se definirá gcc/g++
mediante parámetros en el comando , lo que equivale a definir una macro en el código con el nombre .-D
DEBUG
CMake
También podemos hacer cosas similares en , y el comando correspondiente se llama add_definitions
:
add_definitions(-D宏名称)
Escriba uno para el archivo fuente anterior CMakeLists.txt
, el contenido es el siguiente:
cmake_minimum_required(VERSION 3.0)
project(TEST)
# 自定义 DEBUG 宏
add_definitions(-DDEBUG)
add_executable(app ./test.c)
De esta manera, se puede generar la octava línea de registro en el código anterior.
3. Macros predefinidas
La siguiente lista ha compilado algunas CMake
macros de uso común para usted:
Macro | Función |
---|---|
PROJECT_SOURCE_DIR | El directorio que sigue inmediatamente al comando cmake suele ser el directorio raíz del proyecto. |
PROJECT_BINARY_DIR | Directorio donde se ejecuta el comando cmake |
CMAKE_CURRENT_SOURCE_DIR | La ruta donde se encuentra el CMakeLists.txt actualmente procesado |
CMAKE_CURRENT_BINARY_DIR | directorio de compilación de destino |
EXECUTABLE_OUTPUT_PATH | Redefina la ubicación de almacenamiento del archivo ejecutable binario de destino [no apto para bibliotecas estáticas ] |
LIBRARY_OUTPUT_PATH | Redefinir la ubicación de almacenamiento del archivo de la biblioteca de enlaces de destino |
NOMBRE DEL PROYECTO | Devuelve el nombre del proyecto definido a través de la directiva PROJECT |
CMAKE_BINARY_DIR | La ruta de construcción real del proyecto, suponiendo que la construcción se realiza en build el directorio, luego se obtiene la ruta de este directorio |
Autor: Su Bingqu
Enlace: https://subingwen.cn/cmake/CMake-advanced/
Fuente: DaBing de iProgramming. Los derechos de autor pertenecen al autor. Para reimpresiones comerciales, comuníquese con el autor para obtener autorización. Para reimpresiones no comerciales, indique la fuente.