Explicación detallada de la construcción del proyecto CMake.

Tabla de contenido

1. Introducción e instalación de CMake

1.1 Instalar CMake en Ubuntu

1.2 Instalar CMake en el entorno VScode

1.3 Estructura del directorio de construcción del proyecto CMake

1.4 Recopilación y vinculación del proyecto

1.5 CMake variables predefinidas de uso común

1.6 tipos de compilación de CMake

2. Uso sencillo de la construcción CMake: Helloworld

3. Compilación de CMake: múltiples archivos fuente en el directorio raíz

Elemental: pocos archivos fuente usan add_executable()

Avanzado: más archivos fuente usan aux_source_directory() o set()

Cuarto, compilación de CMake: archivos multidirectorio y de múltiples fuentes

5. Construcción de CMake: estructura organizativa formal

Método 1: dos CMakeLists.txt

Método 2: un CMakeLists.txt

Seis, compilación de CMake: compilar biblioteca dinámica y biblioteca estática

Siete, compilación de CMake: biblioteca de enlaces

Ocho, compilación de CMake: agregue opciones de compilación

Nueve, compilación de CMake: agregue opciones de control

9.1 Originalmente quería generar varios archivos bin o biblioteca, pero ahora solo quiero generar algunos archivos bin o biblioteca específicos

 9.2 Para el mismo archivo bin, solo desea compilar parte del código (use macro para controlar)

10. Resumen


1. Introducción e instalación de CMake

CMake: es simple y conveniente de usar y puede crear un entorno de compilación de proyectos en todas las plataformas. Es más simple que escribir Makefile directamente (al compilar un proyecto a gran escala, necesita escribir una gran cantidad de dependencias de archivos), puede generar un Makefile local responsable a través de una configuración simple de CMake, y un comando compilará el archivo ejecutable y biblioteca estática que queremos compilar. , Se compilan las bibliotecas dinámicas. Además, el archivo de configuración se puede utilizar directamente en otras plataformas sin modificaciones, lo cual es muy conveniente.


1.1 Instalar CMake en Ubuntu

Instale CMake usando el comando:

sudo apt install cmake

cmake -versionUna vez completada la instalación, ingrese la versión de cmake en la terminal :

fff@ubuntu:~$ cmake -version
cmake version 3.22.1

CMake suite maintained and supported by Kitware (kitware.com/cmake).

1.2 Instalar CMake en el entorno VScode

1.2.1 vscode descarga el complemento correspondiente.

1.2.2 Encuentre la ubicación de cmake debajo del terminal shell, la ruta en nuestro sistema es /usr/bin/camke.

fff@ubuntu:~$ whereis cmake
cmake: /usr/bin/cmake /usr/share/cmake /opt/cmake-3.23.0-linux-x86_64/bin/cmake /usr/share/man/man1/cmake.1.gz

1.2.3 Haga clic en la configuración extendida de CMake Tools.

 1.2.4 Seleccione la configuración del host remoto, busque Cmake: Build Environment y agregue las variables de entorno correspondientes.


1.3 Estructura del directorio de construcción del proyecto CMake

Generalmente, durante el desarrollo real, distinguiremos claramente los directorios correspondientes, para que la estructura del proyecto parezca más clara. Por ejemplo, la siguiente estructura de directorios:

bin: archivo ejecutable generado (  archivo .elf
) lib: archivo de biblioteca intermedia generado
incluye: archivo de encabezado
src: archivo fuente
build: archivo intermedio temporal generado durante la compilación del proyecto
test: archivo de prueba
3rd: biblioteca de terceros dependiente (como .a. entonces archivos .la, etc.)
CMakeLists.txt: archivo de configuración de CMake
autobuild.sh: script de compilación con un solo clic

1.4 Recopilación y vinculación del proyecto

Cuando normalmente usamos comandos para compilar archivos de enlace en Linux, los siguientes elementos pueden estar involucrados:

 Por ejemplo, tenemos un archivo muduo_server.cpp, el comando es el siguiente:

fff@ubuntu:~/home/Desktop/muduocode$ g++ -o server moduo_server.cpp -lmuduo_net -lmuduo_base -lpthread

Podemos usar el archivo de configuración de CMake para realizar la misma función: cree un archivo CMakeList.txt en el directorio raíz del proyecto y el comando cmake lo encontrará en el directorio raíz del proyecto.

fff@ubuntu:~/home/Desktop/muduocode$ árbol
.
├── CMakeLists.txt
├── muduo_server
├── muduo_server.cpp

 El comando cmake ejecutará los elementos de configuración en el archivo de configuración CMakeLists.txt en el directorio. El contenido de un archivo de configuración CMakeLists.txt simple es el siguiente:


1.5 CMake variables predefinidas de uso común

1. PROJECT_NAME : especifique el nombre del proyecto a través de project();
2. PROJECT_SOURCE_DIR : el directorio raíz del proyecto;
3. PROJECT_BINARY_DIR : el directorio donde se ejecuta el comando cmake;
4. CMAKE_CURRENT_SOURCE_DIR : el directorio donde se encuentra el archivo CMakeList.txt actual se encuentra;
5. CMAKE_CURRENT_BIN ARY_DIR : directorio de compilación, se puede modificar usando agregar subdirectorio;
6. EXECUTABLE_OUTPUT_PATH : ubicación de salida del archivo ejecutable binario;
7. LIBRARY_OUTPUT_PATH : ubicación de salida del archivo de biblioteca;
8. BUILD_SHARED_LIBS : método de compilación de biblioteca predeterminado (compartido o estático) ), el valor predeterminado es estático;
9, CMAKE_C_FLAGS : establece las opciones de compilación de C;
10, CMAKE_CXX_FLAGS : establece las opciones de compilación de C++;
11, CMAKE_CXX_FLAGS_DEBUG: Opciones de compilación al configurar el tipo de compilación Debug;
12. CMAKE_CXX_FLAGS_RELEASE : Opciones de compilación al configurar el tipo de compilación Release;
13. CMAKE_GENERATOR : Nombre del compilador;
14. CMAKE_COMMAND : La ruta completa del archivo ejecutable de CMake;
15. CMAKE_BUILD_TYPE : Compilación del proyecto Versión generada, Depuración/Liberación;

1.6 tipos de compilación de CMake

La diferencia entre establecer el tipo de compilación en Lanzar y Depurar se refleja principalmente en el nivel de optimización del compilador y las características del archivo ejecutable generado.

1. Nivel de optimización :

  • Modo de lanzamiento : en el modo de lanzamiento, el compilador realizará optimizaciones de nivel superior para mejorar la eficiencia y el rendimiento de la ejecución del código. Esto incluye, entre otras, técnicas de optimización como inserción de funciones, desenrollado de bucles y plegado constante para reducir el tiempo de ejecución del código y el uso de memoria. Sin embargo, esto puede aumentar el tiempo de compilación y hacer que el código sea menos legible.
  • Modo de depuración : en el modo de depuración, el compilador generalmente no realiza optimizaciones para comprender y rastrear mejor el código durante la depuración. Esto significa que el ejecutable resultante será más grande, pero más conveniente para depurar y solucionar problemas.

2. Información de depuración :

  • Modo de lanzamiento : en el modo de lanzamiento, el compilador normalmente elimina la información de depuración para reducir el tamaño del ejecutable resultante. Esto significa que es posible que la información completa de los símbolos no esté disponible durante la depuración, lo que dificulta el proceso de depuración.
  • Modo de depuración : en el modo de depuración, el compilador retendrá la información de depuración completa para que el código pueda ubicarse y rastrearse con precisión en el depurador. Esto hace que el proceso de depuración sea más fácil y preciso.

En resumen , el modo de lanzamiento es adecuado para la versión final lanzada, centrándose en el rendimiento y el tamaño del archivo ejecutable, mientras que el modo de depuración es adecuado para las fases de depuración y desarrollo, centrándose en la depuración y resolución de problemas convenientes.

 El tipo de compilación es Release, escrito de la siguiente manera :

SET(CMAKE_BUILD_TYPE "Release")
SET(CMAKE_C_FLAGS_RELEASE "$ENV{CXXFLAGS} -Os -s -Wall -std=gnu11  -Werror")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -Os  -s -Wall -std=c++1y -Werror")

Los parámetros específicos se explican a continuación:

1. SET(CMAKE_BUILD_TYPE "Release")  Establezca el tipo de compilación en Release , lo que significa que el código se compilará de forma optimizada para mejorar el rendimiento.

2.SET(CMAKE_C_FLAGS_RELEASE "$ENV{CXXFLAGS} -Os -s -Wall -std=gnu11 -Werror")  Configure los parámetros de compilación del compilador de C en modo de lanzamiento . Los parámetros específicos se explican a continuación:

  • $ENV{CXXFLAGS} es una variable de entorno para obtener parámetros adicionales para el compilador de C++ para que pueda usarse con otros parámetros.
  • -Os Indica optimizar la compilación para reducir el tamaño del ejecutable resultante.
  • -s Indica que la información de depuración se elimina para reducir el tamaño del ejecutable resultante.
  • -Wall Indica que todos los mensajes de advertencia están activados.
  • -std=gnu11 Indica compilación utilizando el estándar GNU C11.
  • -Werror Indica tratar todas las advertencias como errores.

3. Configure los parámetros de compilación del SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -Os -s -Wall -std=c++1y -Werror") compilador de C++ en modo de lanzamiento . Similar a los parámetros del compilador de C anteriores, excepto que se utiliza el estándar C++ 11 para la compilación.

Al configurar estos parámetros, puede realizar una compilación optimizada en el modo de lanzamiento y tratar las advertencias como errores durante la compilación para garantizar la calidad y el rendimiento del ejecutable generado.

El tipo de compilación es Debug, escrito de la siguiente manera:

SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_C_FLAGS_DEBUG "$ENV{CXXFLAGS} -g -Wall -std=gnu11 -Werror")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -g -Wall -std=c++1y -Werror")

Los parámetros específicos se explican a continuación:

1.SET(CMAKE_BUILD_TYPE "Debug") Establezca el tipo de compilación en Depurar para compilar en modo de depuración.

2.SET(CMAKE_C_FLAGS_DEBUG "$ENV{CXXFLAGS} -g -Wall -std=gnu11 -Werror")Establezca los parámetros de compilación del  compilador de C en modo de depuración . Los parámetros específicos se explican a continuación:

  • $ENV{CXXFLAGS} es una variable de entorno para obtener parámetros adicionales para el compilador de C++ para que pueda usarse con otros parámetros.
  • -g Indica conservar la información de depuración en el ejecutable para depurar en un depurador.
  • -Wall Indica que todos los mensajes de advertencia están activados.
  • -std=gnu11 Indica compilación utilizando el estándar GNU C11.
  • -Werror Indica tratar todas las advertencias como errores.

3.SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -g -Wall -std=c++1y -Werror")Establezca los parámetros de compilación del  compilador de C++ en modo de depuración . Similar a los parámetros del compilador de C anteriores, excepto que se utiliza el estándar C++ 11 para la compilación.

Al configurar estos parámetros, se pueden generar archivos ejecutables con información de depuración en el modo de depuración y las advertencias se tratan como errores para ayudar en la depuración y la resolución de problemas.


2. Uso sencillo de la construcción CMake: Helloworld

2.1 Escribe un hello.c:

#include "stdio.h"

int main(void)
{       
    printf("Hello World!\r\n");
    return 0;
}

2.2 Escribir en el mismo directorio CMakeLists.txt:

cmake_minimum_required (VERSION 2.8)
        
project (demo)
        
add_executable(hello hello.c)

2.3 Para ejecutar CMake en el mismo directorio, debe ingresar el comando:

fff@ubuntu:~/Desktop/cmake_test$ 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/liefyuan/Desktop/cmake_test

2.4 se generará en el mismo directorio:

fff@ubuntu:~/Desktop/cmake_test$ ls -l
总用量 36
-rw-rw-r-- 1 liefyuan liefyuan 11542 Nov  7 14:50 CMakeCache.txt
drwxrwxr-x 5 liefyuan liefyuan  4096 Nov  7 14:50 CMakeFiles
-rw-rw-r-- 1 liefyuan liefyuan  1377 Nov  7 14:50 cmake_install.cmake
-rw-rw-r-- 1 liefyuan liefyuan    84 Nov  7 14:45 CMakeLists.txt
-rw-rw-r-- 1 liefyuan liefyuan    80 Nov  7 14:44 hello.c
-rw-rw-r-- 1 liefyuan liefyuan  4734 Nov  7 14:50 Makefile

2.5 Como se muestra arriba, el archivo Makefile se ha generado y también hay archivos generados automáticamente al ejecutar cmake.
Luego puedes usar makeel comando para compilar.

fff@ubuntu:~/Desktop/cmake_test$ make
Scanning dependencies of target hello
[ 50%] Building C object CMakeFiles/hello.dir/hello.c.o
[100%] Linking C executable hello
[100%] Built target hello

2.6 Mire el archivo generado nuevamente:

fff@ubuntu:~/Desktop/cmake_test$ ls -l
总用量 48
-rw-rw-r-- 1 liefyuan liefyuan 11542 Nov  7 14:50 CMakeCache.txt
drwxrwxr-x 5 liefyuan liefyuan  4096 Nov  7 14:53 CMakeFiles
-rw-rw-r-- 1 liefyuan liefyuan  1377 Nov  7 14:50 cmake_install.cmake
-rw-rw-r-- 1 liefyuan liefyuan    84 Nov  7 14:45 CMakeLists.txt
-rwxrwxr-x 1 liefyuan liefyuan  8600 Nov  7 14:53 hello
-rw-rw-r-- 1 liefyuan liefyuan    80 Nov  7 14:44 hello.c
-rw-rw-r-- 1 liefyuan liefyuan  4734 Nov  7 14:50 Makefile

2.7 Puede ver que se ha generado un archivo de saludo ejecutable, ingrese y ./helloejecute el archivo ejecutable:

fff@ubuntu:~/Desktop/cmake_test$ ./hello
Hello World!

2.8 ¡Ejecutar exitosamente!

PD: si necesita volver a compilar, puede usar make cleanel comando para limpiar (eliminar el ejecutable anterior).


3. Compilación de CMake: múltiples archivos fuente en el directorio raíz

Elemental: pocos archivos fuente usan add_executable()

3.1 Directorio de archivos:

fff@ubuntu:~/Desktop/cmake_multi_test$ ls -l
rw-rw-r-- 1   fff fff    93 Nov   7 16:41 CMakeLists.txt
-rw-rw-r-- 1  fff fff    107 Nov  7 16:34 function.c
-rw-rw-r-- 1  fff fff    86 Nov   7 16:38 function.h
-rw-rw-r-- 1  fff fff    85 Nov   7 16:30 main.c

3.2 función.h

#ifndef __FUNCTION_H__
#define __FUNCTION_H__

void func(unsigned int var);

#endif

3.3 función.c

#include <stdio.h>
#include "function.h"

void func(unsigned int var)
{
	printf("para var:%d\r\n", var);
}

3.4 principal.c

#include <stdio.h>
#include "function.h"

int main(void)
{
	func(200);
	return 0;
}

CMakeLists .txt

cmake_minimum_required (VERSION 2.8)

project (demo)

add_executable(main main.c function.c)

3.5 Ejecutar cmake .para generar Makefile y ejecutar make

fff@ubuntu:~/Desktop/cmake_multi_test$ 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/fff/Desktop/cmake_multi_test
fff@ubuntu:~/Desktop/cmake_multi_test$ make
Scanning dependencies of target main
[ 33%] Building C object CMakeFiles/main.dir/main.c.o
[ 66%] Building C object CMakeFiles/main.dir/function.c.o
[100%] Linking C executable main
[100%] Built target main

3.6 Puede ver que se ha generado un archivo principal ejecutable, ingrese y ./mainejecute el archivo ejecutable:

fff@ubuntu:~/Desktop/cmake_multi_test$ ./main
para var:200

3.7 ¡Ejecutar exitosamente!

PD: resumen

Por analogía, si hay varios archivos fuente en el mismo directorio, simplemente agregue todos los archivos fuente en add_executable.


Avanzado: más archivos fuente usan aux_source_directory() o set()

PD: Pero si hay cien archivos fuente, sería un poco complicado hacer esto nuevamente y no puede reflejar la superioridad de cmake. cmake proporciona un comando para almacenar todos los archivos fuente en un directorio específico en una variable. Este comando es aux_source_directory(dir  var).
El primer parámetro dir es el directorio especificado y el segundo parámetro var es la variable utilizada para almacenar la lista de archivos fuente.

3.8 Agregar archivos nuevamentefunction2.c

#include <stdio.h>
#include "function2.h"

void func2(unsigned int var)
{
	printf("para var2:%d\r\n", var);
}

3.9 Función Agregar archivo 2.h

#ifndef __FUNCTION2_H__
#define __FUNCTION2_H__

void func2(unsigned int var);

#endif

3.10 Modificar principal.c

#include <stdio.h>
#include "function.h"
#include "function2.h"

int main(void)
{
	func(200);
	func2(100);
	
	return 0;
}

3.11 Modificar CMakeLists.txt

cmake_minimum_required (VERSION 2.8)

project (demo)

aux_source_directory(. SRC_LIST)

add_executable(main ${SRC_LIST})

3.12 Luego corre cmake .y make

fff@ubuntu:~/Desktop/cmake_multi_test$ cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/fff/Desktop/cmake_multi_test
fff@ubuntu:~/Desktop/cmake_multi_test$ make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/function.c.o
[ 50%] Building C object CMakeFiles/main.dir/function2.c.o
[ 75%] Building C object CMakeFiles/main.dir/main.c.o
[100%] Linking C executable main
[100%] Built target main

3.13 Ejecutar ejecutables./main

liefyuan@ubuntu:~/Desktop/cmake_multi_test$ ./main
para var:200
para var2:100

3.14 ¡Ejecutar exitosamente!

PD: En resumen ,
aux_source_directory() también tiene desventajas. Agregará todos los archivos fuente en el directorio especificado y puede agregar algunos archivos que no necesitamos. En este momento, podemos usar el comando set para crear variables para almacene los archivos fuente requeridos, de la siguiente manera:

cmake_minimum_required (VERISON 2.8)

project (demo)

set(SRC_LIST 
		./main.c
		./function.c
		./function2.c)

add_executable(main ${SRC_LIST})

Cuarto, compilación de CMake: archivos multidirectorio y de múltiples fuentes

 En general, cuando hay muchos archivos de programa, los administraremos por categoría y colocaremos los códigos en diferentes directorios según sus funciones, para que sea fácil de encontrar. Entonces, ¿cómo escribir CMakeLists.txt en este caso?

4.1 Clasifiquemos los archivos fuente anteriores (creemos 2 directorios function y function2 ), y la estructura general del archivo es la siguiente:

fff@ubuntu:~/Desktop/cmake_multi_dir_test$ tree
.
├── CMakeLists.txt
├── function
│   ├── function.c
│   └── function.h
├── function2
│   ├── function2.c
│   └── function2.h
└── main.c

4.2 Modificar el archivo CmakeLists.txt

cmake_minimum_required (VERSION 2.8)

project (demo)

include_directories (function function2)
        
aux_source_directory(function SRC_LIST)
aux_source_directory(function2 SRC_LIST2)

add_executable(main main.c ${SRC_LIST} ${SRC_LIST2})

Como anteriormente:

  • El aux_source_directory se usa 2 veces, porque los archivos fuente se distribuyen en 2 directorios, así que agregue 2 veces.

o:

  • Almacenar ambas sumas en la misma variable.
cmake_minimum_required (VERSION 2.8)

project (demo)

include_directories (function function2)
        
aux_source_directory(function SRC_LIST)
aux_source_directory(function2 SRC_LIST)

add_executable(main main.c ${SRC_LIST})

4.3 Luego ejecuta cmake .de nuevomake./main

fff@ubuntu:~/Desktop/cmake_multi_dir_test$ 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/fff/Desktop/cmake_multi_dir_test
fff@ubuntu:~/Desktop/cmake_multi_dir_test$ make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/main.c.o
[ 50%] Building C object CMakeFiles/main.dir/function/function.c.o
[ 75%] Building C object CMakeFiles/main.dir/function2/function2.c.o
[100%] Linking C executable main
[100%] Built target main
fff@ubuntu:~/Desktop/cmake_multi_dir_test$ ./main
para var:200
para var2:100

¡operación normal!

PD: nuevo comando: include_directories()

Aquí viene un nuevo comando: include_directories() . Este comando se utiliza para agregar rutas de búsqueda para varios archivos de encabezado especificados al proyecto, y las rutas están separadas por espacios.

 Debido a que function.h y function2.h están incluidos en main.c, si no hay un comando para especificar la ubicación del archivo de encabezado, no podrá compilarse. Por supuesto, también puedes usar include para especificar la ruta en main.c, de la siguiente manera:

#include "function/function.h"
#include "function2/function2.h"

¡Esta forma de escribir no es bonita!

5. Construcción de CMake: estructura organizativa formal

Primero cree un árbol de directorios, de la siguiente manera:

fff@ubuntu:~/Desktop/cmake_dir$ tree
.
├── bin
├── build
├── include
│   ├── function2.h
│   └── function.h
└── src
    ├── function2.c
    ├── function.c
    └── main.c

Método 1: dos CMakeLists.txt

Cree un nuevo archivo en el directorio raízCMakeLists.txt con el siguiente contenido:

cmake_minimum_required (VERSION 2.8)

project (demo)

add_subdirectory (src)

También necesita crear un nuevo archivo en el directorio srcCMakeLists.txt , el contenido es el siguiente:

aux_source_directory (. SRC_LIST)

include_directories (../include)

add_executable (main ${SRC_LIST})

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

Aquí se utiliza un nuevo conjunto de comandos, que se utiliza para definir variables, EXECUTABLE_OUT_PATHy es una variable predefinidaPROJECT_SOURCE_DIR que viene con CMake . Su significado es el siguiente:

  • EXECUTABLE_OUTPUT_PATH : la ubicación donde se almacena el ejecutable binario de destino.
  • PROJECT_SOURCE_DIR : el directorio raíz del proyecto

Por lo tanto, establecer aquí significa establecer la ubicación donde se almacena el archivo elf en el directorio bin en el directorio raíz del proyecto . (cmake tiene muchas variables predefinidas, puede buscar detalles en línea)

Después de agregar los dos CMakeLists.txt anteriores, la estructura general del archivo es la siguiente:

fff@ubuntu:~/Desktop/cmake_dir$ tree
.
├── bin
├── build
├── CMakeLists.txt
├── include
│   ├── function2.h
│   └── function.h
└── src
    ├── CMakeLists.txt
    ├── function2.c
    ├── function.c
    └── main.c

construir, compilar, ejecutar

  • Paso 1: vaya a la carpeta de compilación y ejecute el comando:cmake ..
  • Paso 2: Después del paso anterior, el Makefile se generará en el directorio de compilación y luego se ejecutará para compilar y se generará un archivo ejecutable en el directorio binmake del directorio raíz.main
  • Paso 3: Ingrese el archivo bin en el directorio raíz para ejecutar el archivo ejecutable./main
fff@ubuntu:~/Desktop/cmake_dir/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/fff/Desktop/cmake_dir/build
fff@ubuntu:~/Desktop/cmake_dir/build$ make
Scanning dependencies of target main
[ 25%] Building C object src/CMakeFiles/main.dir/function.c.o
[ 50%] Building C object src/CMakeFiles/main.dir/function2.c.o
[ 75%] Building C object src/CMakeFiles/main.dir/main.c.o
[100%] Linking C executable ../../bin/main
[100%] Built target main
fff@ubuntu:~/Desktop/cmake_dir/build$ cd ..
fff@ubuntu:~/Desktop/cmake_dir$ cd bin
fff@ubuntu:~/Desktop/cmake_dir/bin$ ls
main
fff@ubuntu:~/Desktop/cmake_dir/bin$ ./main
para var:200
para var2:100

¡operación normal!

PD: ¿Por qué ejecutar cmake en el directorio de compilación? Como se puede ver en los ejemplos anteriores, si no se hace esto, los archivos adjuntos generados cuando se ejecuta cmake se mezclarán con los archivos de código fuente, lo que contaminará la estructura de directorios del programa y ejecutará cmake en el directorio de compilación. los generados Los archivos adjuntos solo permanecerán en el directorio de compilación. Si no queremos estos archivos, podemos borrar directamente el directorio de compilación, lo cual es muy conveniente.


Método 2: un CMakeLists.txt

El proyecto anterior usó 2 CMakeLists.txt, el CMakeLists.txt más externo se usa para controlar la situación general y add_subdirectory se usa para controlar el funcionamiento de CMakeLists.txt en otros directorios.

 El ejemplo anterior también puede usar solo un CMakeLists.txt y cambiar el contenido del CMakeLists.txt más externo de la siguiente manera:

cmake_minimum_required (VERSION 2.8)

project (demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

aux_source_directory (src SRC_LIST)

include_directories (include)

add_executable (main ${SRC_LIST})

Luego elimine CMakeLists.txt en el directorio src . El directorio es el siguiente:

fff@ubuntu:~/Desktop/cmake_dir2$ tree
.
├── bin
├── build
├── CMakeLists.txt
├── include
│   ├── function2.h
│   └── function.h
└── src
    ├── function2.c
    ├── function.c
    └── main.c

construir, compilar, ejecutar

  • Paso 1: primero ingrese la carpeta de compilación y luego ejecute el comando:cmake ..
  • Paso 2: Después del paso anterior, el Makefile se generará en el directorio de compilación y luego se ejecutará para compilar y se generará un archivo ejecutable en el directorio binmake del directorio raíz.main
  • Paso 3: Ingrese el archivo bin en el directorio raíz para ejecutar el archivo ejecutable./main
fff@ubuntu:~/Desktop/cmake_dir2/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/fff/Desktop/cmake_dir2/build
liefyuan@ubuntu:~/Desktop/cmake_dir2/build$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile
fff@ubuntu:~/Desktop/cmake_dir2/build$ make
Scanning dependencies of target main
[ 25%] Building C object CMakeFiles/main.dir/src/function.c.o
[ 50%] Building C object CMakeFiles/main.dir/src/function2.c.o
[ 75%] Building C object CMakeFiles/main.dir/src/main.c.o
[100%] Linking C executable ../bin/main
[100%] Built target main
fff@ubuntu:~/Desktop/cmake_dir2/build$ cd ..
fff@ubuntu:~/Desktop/cmake_dir2$ cd bin
fff@ubuntu:~/Desktop/cmake_dir2/bin$ ls
main
fff@ubuntu:~/Desktop/cmake_dir2/bin$ ./main
para var:200
para var2:100

¡operación normal!


Seis, compilación de CMake: compilar biblioteca dinámica y biblioteca estática

6.1 Construya una estructura de archivos:

fff@ubuntu:~/Desktop/cmake_lib$ tree
.
├── build
├── CMakeLists.txt
├── function
│   ├── function.c
│   └── function.h
└── lib

Ejecute cmake en el directorio de compilación y almacene los archivos de biblioteca generados en el directorio lib .

6.2 El contenido del CMakeLists.txt recién creado es:

cmake_minimum_required (VERSION 2.8)
        
project (demo)
        
set (SRC_LIST ${PROJECT_SOURCE_DIR}/function/function.c)
        
add_library (function_shared SHARED ${SRC_LIST})
add_library (function_static STATIC ${SRC_LIST})
        
set_target_properties (function_shared PROPERTIES OUTPUT_NAME "function")
set_target_properties (function_static PROPERTIES OUTPUT_NAME "function")
        
set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

PD: Aquí aparecen nuevos comandos y variables predefinidas:

  • add_library : genera una biblioteca dinámica o una biblioteca estática (el primer parámetro especifica el nombre de la biblioteca; el segundo parámetro determina si es dinámica o estática; de lo contrario, el valor predeterminado es estático; el tercer parámetro especifica el archivo fuente del archivo generado biblioteca)
  • set_target_properties : establece el nombre de la biblioteca generada final y otras funciones, como configurar el número de versión de la biblioteca, etc.
  • LIBRARY_OUTPUT_PATH : la ruta de salida predeterminada del archivo de la biblioteca, aquí se establece en el directorio lib en el directorio del proyecto.

6.3 Ingrese al directorio de compilación para ejecutar el comando cmake .., genere el Makefile y luego ejecútelo make.

fff@ubuntu:~/Desktop/cmake_lib/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/fff/Desktop/cmake_lib/build
fff@ubuntu:~/Desktop/cmake_lib/build$ make
Scanning dependencies of target function_static
[ 25%] Building C object CMakeFiles/function_static.dir/function/function.c.o
[ 50%] Linking C static library ../lib/libfunction.a
[ 50%] Built target function_static
Scanning dependencies of target function_shared
[ 75%] Building C object CMakeFiles/function_shared.dir/function/function.c.o
[100%] Linking C shared library ../lib/libfunction.so
[100%] Built target function_shared

6.4 Una vez que la compilación sea exitosa, ingrese al directorio lib para verificar y descubra que la biblioteca dinámica y la biblioteca estática se han generado exitosamente.

fff@ubuntu:~/Desktop/cmake_lib/build$ cd ..
fff@ubuntu:~/Desktop/cmake_lib$ cd lib
fff@ubuntu:~/Desktop/cmake_lib/lib$ ls
libfunction.a  libfunction.so

PD: Set_target_properties se usó para redefinir el nombre de salida de la biblioteca. Si no usa set_target_properties , entonces el nombre de la biblioteca es el nombre definido en add_library , pero cuando usa add_library para especificar el nombre de la biblioteca (el primer parámetro) dos veces En una fila , el nombre no puede ser el mismo, pero set_target_properties puede configurar los nombres para que sean iguales, pero los sufijos de los archivos de biblioteca generados finales son diferentes (uno es .so, el otro es .a), lo que se verá relativamente bueno.


Siete, compilación de CMake: biblioteca de enlaces

La biblioteca se generó antes y ahora se realiza el enlace de la biblioteca.

fff@ubuntu:~/Desktop/cmake_lib_link$ tree
.
├── bin
├── build
├── CMakeLists.txt
├── function
│   ├── inc
│   │   └── function.h
│   └── lib
│       ├── libfunction.a
│       └── libfunction.so
└── src
    └── main.c

7.1 principal.c

#include <stdio.h>
#include "function.h"

int main(void)
{       
    func(300);

    return 0;
} 

7.2 CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
        
project (demo)
        
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
        
set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.c)
        
include_directories (${PROJECT_SOURCE_DIR}/function/inc)
        
find_library(FUNCTION_LIB function HINTS ${PROJECT_SOURCE_DIR}/function/lib)
        
add_executable (main ${SRC_LIST})
        
target_link_libraries (main ${FUNCTION_LIB})

Explicación de los nuevos comandos:

  • find_library : busque la biblioteca especificada en el directorio especificado y almacene la ruta absoluta de la biblioteca en una variable. El primer parámetro es el nombre de la variable, el segundo parámetro es el nombre de la biblioteca, el tercer parámetro es HINTS y ​​el cuarto parámetro es Ruta, otros usos pueden consultar la documentación de cmake
  • target_link_libraries : vincula archivos de destino con archivos de biblioteca

 La ventaja de usar find_library es que cmake ..verificará si la biblioteca existe durante la ejecución, de modo que se puedan encontrar errores con anticipación sin esperar hasta el momento del enlace.

 cd al directorio de compilación, luego ejecútelo cmake .. && makey finalmente ingrese al directorio bin para verificar, y descubrió que se ha generado el principal, simplemente ejecútelo.

fff@ubuntu:~/Desktop/cmake_lib_link/build$ cmake ..&& make
-- 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/fff/Desktop/cmake_lib_link/build
Scanning dependencies of target main
[ 50%] Building C object CMakeFiles/main.dir/src/main.c.o
[100%] Linking C executable ../bin/main
[100%] Built target main

7.3 Ejecutar:

fff@ubuntu:~/Desktop/cmake_lib_link/build$ cd ..
fff@ubuntu:~/Desktop/cmake_lib_link$ cd bin
fff@ubuntu:~/Desktop/cmake_lib_link/bin$ ./main
para var:300

¡Ejecute con éxito! PD:

Hay bibliotecas estáticas y bibliotecas dinámicas de funciones en el directorio lib, find_library (la función FUNCTION_LIB ... es buscar la biblioteca dinámica de forma predeterminada, si desea especificar directamente si usar la biblioteca dinámica o la biblioteca estática, puede escribir find_library(FUNCTION_LIB libfunction.so ...o find_library(FUNCTION_LIB libfunction. a…

Ocho, compilación de CMake: agregue opciones de compilación

A veces es necesario agregar algunas opciones de compilación al compilar el programa, como -Wall, -std=c++11etc., puede usarlo add_compile_optionpara operar.

8.1 principal.cpp

#include <iostream>

int main(void)
{
	auto data = 100;
	std::cout << "data:" << data << "\n";
	return 0;
}

8.2 CMakeLists.txt

cmake_minimum_required (VERSION 2.8)

project (demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

add_compile_options(-std=c++11 -Wall)

add_executable(main main.cpp)

El árbol de directorios es el siguiente:

fff@ubuntu:~/Desktop/cmake_cpp$ tree
.
├── bin
├── build
├── CMakeLists.txt
└── main.cpp

Luego vaya al directorio de compilación , ejecute el comando cmake... && make , puede obtener el archivo elf principal en el directorio bin


Nueve, compilación de CMake: agregue opciones de control

A veces, al compilar el código, solo se compilan algunos códigos específicos. Puede usar el comando de opción de cmake. Se encuentran principalmente dos tipos de situaciones:

  • Originalmente quería generar varios archivos bin o biblioteca, pero ahora solo quiero generar algunos archivos bin o biblioteca específicos
  • Para el mismo archivo bin, solo quiero compilar parte del código (usando macros para controlar)

9.1 Originalmente quería generar varios archivos bin o biblioteca, pero ahora solo quiero generar algunos archivos bin o biblioteca específicos

Suponiendo que nuestro proyecto actual generará dos archivos bin, main1 y main2, la estructura general ahora es la siguiente:

fff@ubuntu:~/Desktop/cmake_2bin$ tree
.
├── bin
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── main1.c
    └── main2.c

El contenido de main1.c y main2.c es el siguiente,

// main1.c
#include <stdio.h>

int main(void)
{
    printf("hello, this main1\n");
    
    return 0;
}
// main2.c
#include <stdio.h>

int main(void)
{
    printf("hello, this main2\n");
    
    return 0;
}

El contenido del CMakeLists.txt externo es el siguiente,

cmake_minimum_required(VERSION 3.5)

project(demo)

option(MYDEBUG "enable debug compilation" OFF)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

add_subdirectory(src)

El comando de opción se usa aquí , el primer parámetro es el nombre de la opción, el segundo parámetro es una cadena, que se usa para describir para qué sirve la opción, y el tercero es el valor de la opción, ENCENDIDO o APAGADO, usted También puede No escribir, no escribir es el valor predeterminado APAGADO.

Luego escriba CMakeLists.txt en el directorio src , de la siguiente manera

cmake_minimum_required (VERSION 3.5)

add_executable(main1 main1.c)

if (MYDEBUG)
    add_executable(main2 main2.c)
else()
    message(STATUS "Currently is not in debug mode")    
endif()

Nota : aquí se usa if-else para decidir si compilar main2.c según la opción

Luego vaya al directorio de compilación e ingrese cmake .. && makepara compilar solo main1. Si desea compilar main2, configure MYDEBUG en ON y ingrese nuevamente cmake .. && makepara volver a compilar.

PD: Cada vez que desee cambiar MYDEBUG, debe modificar CMakeLists.txt, lo cual es un poco problemático. De hecho, puede operarlo a través de la línea de comando de cmake. Por ejemplo, si queremos configurar MYDEBUG en APAGADO, primero cd al directorio de compilación y luego ingrese cmake .. - DMYDEBUG=ON , para que main1 y main2 puedan compilarse (en el directorio bin )

 9.2 Para el mismo archivo bin, solo desea compilar parte del código (use macro para controlar)

La estructura general del proyecto es la siguiente,

fff@ubuntu:~/Desktop/cmake_1mian_define$ tree
.
├── bin
├── build
├── CMakeLists.txt
└── main.c

Supongamos que tenemos un main.c cuyo contenido es el siguiente,

#include <stdio.h>

int main(void)
{
#ifdef WWW1
    printf("hello world1\n");
#endif    

#ifdef WWW2     
    printf("hello world2\n");
#endif

    return 0;
}

Puede controlar la información impresa definiendo macros. El contenido de nuestro CMakeLists.txt es el siguiente,

cmake_minimum_required(VERSION 3.5)

project(demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

option(WWW1 "print one message" OFF)
option(WWW2 "print another message" OFF)

if (WWW1)
    add_definitions(-DWWW1)
endif()

if (WWW2)
    add_definitions(-DWWW2)
endif()

add_executable(main main.c)

Aquí, el nombre de la opción se mantiene igual que el nombre de la macro en main.c, que es más intuitivo y también puede elegir un nombre diferente. Al cooperar con add_definitions() , puede controlar la impresión de un único archivo bin.

cd al directorio de compilación para ejecutar cmake .. && make, y luego al directorio bin para ejecutar ./main, puede ver que la impresión está vacía,
luego siga las instrucciones a continuación para ejecutar y luego verifique el efecto de impresión,

  • cmake .. -DWWW1=ON -DWWW2=OFF && make
  • cmake .. -DWWW1=OFF -DWWW2=ON && make
  • cmake .. -DWWW1=ON -DWWW2=ON && make

Aviso:

Aquí hay un pequeño problema al que prestar atención: supongamos que hay dos opciones llamadas A y B, primero llame a cmake para configurar A y luego llame a cmake para configurar B la próxima vez, si el archivo de caché generado cuando se ejecutó cmake la última vez no es eliminado, entonces esto Aunque A no está configurado esta vez, el último valor de opción de A se usará de forma predeterminada.

Entonces, si la opción cambia, elimine el archivo de caché generado cuando se ejecutó cmake la última vez o especifique explícitamente su valor para todas las opciones.

10. Resumen

Lo anterior son algunas notas de estudio para aprender CMake . A través de ejemplos simples, puedo comenzar rápidamente con CMake . También leo muchos blogs de internautas mientras estudio. Todavía hay muchos puntos de conocimiento sobre CMake y se pueden buscar detalles específicos en línea. En resumen, CMake puede salvarnos de escribir Makefiles complejos , y es multiplataforma, es una herramienta muy poderosa que vale la pena aprender.

Si hay algún problema, espero que puedas dejar un mensaje para corregirme, ¡gracias por leer!

Supongo que te gusta

Origin blog.csdn.net/FLM19990626/article/details/132408320
Recomendado
Clasificación