[Entrada de CMake y avanzada (2)] Configuración de compilación de CMake: compilación de archivos de origen múltiple y generación de archivos de biblioteca (con código)

varios archivos de origen       

        En el último artículo, aprendimos sobre la compilación cmake de un solo archivo fuente, pero el ejemplo de un archivo fuente parece no tener sentido, así que agreguemos un archivo de encabezado hello.h y un archivo fuente hello.c. Se define una función hola en el archivo hello.c, y luego se llamará a la función en el archivo fuente main.c:

        ⚫ contenido del archivo hello.h

#ifndef __TEST_HELLO_
#define __TEST_HELLO_

void hello(const char *name);

#endif //__TEST_HELLO_

        ⚫ contenido del archivo hello.c

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

void hello(const char *name){
 printf("Hello %s!\n", name);
}

        ⚫ contenido del archivo main.c

#include "hello.h"

int main(void){
 hello("World");
 return 0;
}

        ⚫ Luego prepara el archivo CMakeLists.txt

project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST})

        La estructura del directorio del proyecto es la siguiente:

├── build //文件夹
├── CMakeLists.txt
├── hello.c
├── hello.h
└── main.c

        Del mismo modo, ingrese al directorio de compilación, ejecute cmake y luego ejecute make para compilar el proyecto, y finalmente se obtendrá el archivo ejecutable hello.

        En este ejemplo, el comando set se usa en el archivo CMakeLists.txt. El comando set se usa para configurar la variable. Si la variable no existe, cree la variable y configúrela; en este ejemplo, definimos una variable SRC_LIST, y la variable SRC_LIST es una lista de archivos de origen, registre los archivos de origen main.c y hello.c necesarios para generar el archivo ejecutable hello, y se hace referencia a esta variable en el comando add_executable; por supuesto, también podemos escribir directamente el archivo de origen list en add_executable sin definir la variable SRC_LIST en el comando, de la siguiente manera:

add_executable(hello main.c hello.c)

Generar archivos de biblioteca

       En este ejemplo, además de generar el archivo ejecutable hello, también necesitamos compilar hello.c en un archivo de biblioteca estática o en un archivo de biblioteca dinámica. Según el ejemplo anterior, modifique el archivo CMakeLists.txt de la siguiente manera:

project(HELLO)
add_library(libhello hello.c)
add_executable(hello main.c)
target_link_libraries(hello libhello)

        Ingrese al directorio de compilación, ejecute cmake y luego ejecute make para compilar el proyecto. Una vez completada la compilación, el archivo ejecutable hello y los archivos de biblioteca se generarán en el directorio de compilación, como se muestra a continuación:

         La estructura del directorio es la siguiente:

├── build
│ ├── hello
│ └── liblibhello.a
├── CMakeLists.txt
├── hello.c
├── hello.h
└── main.c

Explicación del archivo CMakeLists.txt

        En este ejemplo, usamos el comando add_library y el comando target_link_libraries. El comando add_library se utiliza para generar un archivo de biblioteca. En este ejemplo, pasamos dos parámetros. El primer parámetro indica el nombre del archivo de biblioteca. Cabe señalar que este nombre no incluye el prefijo y el sufijo; en Linux system , el prefijo del archivo de la biblioteca es lib, el sufijo del archivo de la biblioteca dinámica es .so y el sufijo del archivo de la biblioteca estática es .a; por lo tanto, significa que el nombre correspondiente al archivo de la biblioteca final generado automáticamente agregue el prefijo y el sufijo.

        El segundo parámetro indica el archivo de origen correspondiente al archivo de biblioteca.

        En este ejemplo, el comando add_library genera un archivo de biblioteca estática liblibhello.a, si desea generar un archivo de biblioteca dinámica, puede hacer esto:

add_library(libhello SHARED hello.c) #生成动态库文件
add_library(libhello STATIC hello.c) #生成静态库文件

El comando target_link_libraries especifica bibliotecas dependientes para el destino.En este ejemplo, hello.c se compila como un archivo de biblioteca y se vincula al programa hello.

Modificar el nombre del archivo de biblioteca generado

         En este ejemplo, una cosa es muy incómoda, la biblioteca generada es liblibhello.a, y el nombre es muy feo, ¿qué debo hacer si quiero generar liblibhello.a? ¿Es posible modificar directamente los parámetros del comando add_library como el siguiente?

add_library(hello hello.c)

        La respuesta es no, porque el objetivo hello ya existe (add_executable(hello main.c)), el nombre del objetivo es único para todo el proyecto y no puede aparecer ningún objetivo con el mismo nombre, por lo que este método definitivamente no es posible. Arriba, solo necesitamos agregar el siguiente comando al archivo CMakeLists.txt:

set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

        set_target_properties se usa para establecer las propiedades del destino Aquí, la propiedad OUTPUT_NAME del destino libhello se establece a través del comando set_target_properties, y se establece en hello.

        Realizamos experimentos y el contenido del archivo CMakeLists.txt es el siguiente:

cmake_minimum_required(VERSION 3.5)
project(HELLO)
add_library(libhello SHARED hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
add_executable(hello main.c)
target_link_libraries(hello libhello)

        Además de agregar el comando set_target_properties, también agregamos el comando cmake_minimum_required, que se usa para establecer el número mínimo de versión de cmake requerido para el proyecto actual. Por supuesto, esto no es obligatorio, pero es mejor agregarlo. Vaya al directorio de compilación y use cmake+make para compilar todo el proyecto. Una vez completada la compilación, encontrará que el archivo de biblioteca generado es libhello.a en lugar de liblibhello.a.

├── build
│ ├── hello
│ └── libhello.so
├── CMakeLists.txt
├── hello.c
├── hello.h
└── main.c

Organice los archivos de origen en diferentes directorios

        En el ejemplo anterior, hemos agregado varios archivos de origen, pero todos estos archivos de origen están ubicados en el mismo directorio, lo que no es muy formal. Deberíamos colocar estos archivos de origen en diferentes lugares según el tipo, la función y el directorio del módulo, por lo que el autor organizó el código fuente del proyecto.La estructura de directorios actual es la siguiente:

├── build #build 目录
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
 ├── CMakeLists.txt
 └── main.c

        En el directorio del proyecto, creamos los directorios src y libhello, y movimos los archivos hello.c y hello.h al directorio libhello, movimos el archivo main.c al directorio src, y en el directorio superior, el directorio libhello y src directorio Hay un archivo CMakeLists.txt debajo. El número de archivos CMakeLists.txt cambió de 1 a 3, ¡y de repente me sentí un poco desprevenido! ¡Afortunadamente, ninguno de ellos es complicado! Echemos un vistazo al contenido de cada archivo CMakeLists.txt.

        ⚫ Nivel superior CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(HELLO)
add_subdirectory(libhello)
add_subdirectory(src)

        ⚫ CMakeLists.txt en el directorio src

include_directories(${PROJECT_SOURCE_DIR}/libhello)
add_executable(hello main.c)
target_link_libraries(hello libhello)

        ⚫ CMakeLists.txt en el directorio libhello

add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

        El comando add_subdirectory se usa en el CMakeLists.txt de nivel superior, que le dice a cmake que busque un nuevo archivo CMakeLists.txt en el subdirectorio y lo analice, y en el archivo CMakeList.txt de src, se agrega un nuevo comando include_directories para indicar donde se encuentra el archivo de cabecera ruta, y se utiliza la variable PROJECT_SOURCE_DIR, que apunta a una ruta.Por el naming, esta variable representa el directorio del código fuente del proyecto.

        Como antes, vaya al directorio de compilación para compilar y compilar, y finalmente obtenga el archivo ejecutable hello (build/src/hello) y el archivo de biblioteca libhello.a (build/libhello/libhello.a):

├── build
│ ├── libhello
│ │ └── libhello.a
│ └── src
│   └── hello
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
 ├── CMakeLists.txt
 └── main.c

Coloque los archivos ejecutables y de biblioteca generados en directorios separados

        Todavía hay un poco de incomodidad en el frente.Por defecto, los archivos ejecutables y los archivos de biblioteca generados por make compilation se mezclarán con los archivos intermedios (CMakeCache.txt, CmakeFiles, cmake_install.cmake y Makefile, etc.) generados por cmake. comando, es decir, están en En el mismo directorio; si quiero que el archivo ejecutable se coloque por separado en el directorio bin, y el archivo de la biblioteca se coloque por separado en el directorio lib, así:

├── build
├── lib
│ └── libhello.a
└── bin
  └── hello

        Guarde los archivos de la biblioteca en el directorio lib del directorio de compilación y almacene los archivos ejecutables en el directorio bin del directorio de compilación. ¿Qué debo hacer en este momento? En este momento podemos realizarlo a través de dos variables, y modificar el archivo CMakeList.txt en el directorio src, de la siguiente manera:

include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello main.c)
target_link_libraries(hello libhello)

        Luego modifique el archivo CMakeList.txt en el directorio libhello, de la siguiente manera:

set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library(libhello hello.c)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

        Una vez completada la modificación, vuelva a compilar y compilar el proyecto de acuerdo con los pasos. En este momento, el archivo ejecutable generado hello se colocará en el directorio build/bin y el archivo de biblioteca libhello.a se colocará en build/lib. directorio de acuerdo a nuestros requerimientos. La estructura final del directorio se ve así:

├── build
│ ├── bin
│ │ └── hello
│ └── lib
│   └── libhello.a
├── CMakeLists.txt
├── libhello
│ ├── CMakeLists.txt
│ ├── hello.c
│ └── hello.h
└── src
  ├── CMakeLists.txt
  └── main.c

        De hecho, es muy sencillo realizar este requisito. Se puede hacer configurando las variables LIBRARY_OUTPUT_PATH y EXECUTABLE_OUTPUT_PATH; la variable EXECUTABLE_OUTPUT_PATH controla la ruta de salida de los archivos ejecutables, mientras que la variable LIBRARY_OUTPUT_PATH controla la ruta de salida de los archivos de la biblioteca.

Supongo que te gusta

Origin blog.csdn.net/cj_lsk/article/details/131001173
Recomendado
Clasificación