¿Posibilidades de uso de CMake junto a Make? #11
-
Sé que el ideal es el uso del
Lo hice para parecerse lo más posible al Makefile original que nos pasan en cuanto a funcionalidad y escritura de variables, pero con soporte para arrays multilinea y búsqueda recursiva de archivos Ejemplo de uso:
# Bajo el supuesto de que estoy en la carpeta junto a `CMakeLists.txt` y la carpeta `src`
mkdir build ; cd build
a. Generar cmake -DCMAKE_BUILD_TYPE="debug" .. b. Generar cmake -DCMAKE_BUILD_TYPE="dev" .. c. Generar un # También sirve
# cmake -DCMAKE_BUILD_TYPE="production" ..
cmake ..
make
# También sirven los comandos
# make nombre_del_binario_especifico_que_quiero_compilar
# make clean
# make all Los binarios quedaría en la carpeta Ejemplo del manejo de carpetas y archivo de variables.
Para compilar este proyecto, en vez de listar cada archivo
project(A-Name-For-My-Project C)
set(COMMON_FOLDERS
cts
utils
debug
data_structures
)
set(MAIN_EXECUTABLES
my_binary_1
my_binary_2
tests
)
set(LIBS
m
) En base a eso se realizan todas las búsquedas recursivas y crea los binarios:
Para lograr eso con el Makefile tendría que ajustarlo cada vez que cambie un archivo y quedaría algo más o menos así:
cmake_minimum_required(VERSION 3.22)
set(VARIABLES_FILE ${CMAKE_SOURCE_DIR}/variables.cmake) # <--------------------------------------------- IMPORTANTE
set(SIGNATURE_FILE ${CMAKE_SOURCE_DIR}/signature.cmake) # Firma
set(COLORS_FILE ${CMAKE_SOURCE_DIR}/colors.cmake) # Soporte para colores
### Opciones de compilación
# Incluir el archivo de variables solo si existe
if(EXISTS ${VARIABLES_FILE})
include(${VARIABLES_FILE})
else()
message(STATUS "Archivo variables.cmake no encontrado. Usando valores por defecto.")
endif()
# Nombre del proyecto por defecto
if(NOT PROJECT_NAME)
project(defaultProject VERSION 1.0 DESCRIPTION "Proyecto Por Defecto" LANGUAGES C)
endif()
# Forzar opciones del compilador
if(NOT FORCE_SETUP)
set(FORCE_SETUP FALSE)
endif()
if(NOT VERBOSE)
set(VERBOSE FALSE)
endif()
if(NOT SRC_DIR)
set(SRC_DIR "src")
endif()
if(NOT COMMON_FOLDERS)
set(COMMON_FOLDERS
*
)
endif()
# Array de ejecutables de salida
if(NOT MAIN_EXECUTABLES)
set(MAIN_EXECUTABLES
main
)
endif()
#-------------------------
# Librerías de C para esta compilación
if(NOT LIBS)
set(LIBS )
endif()
############################################################################
# Bases compilador
include(CMakePrintHelpers)
set(CMAKE_C_STANDARD 99)
#-------------------------
# Parametros para el makefile
set(CMAKE_USE_RELATIVE_PATHS TRUE)
set(CMAKE_VERBOSE_MAKEFILE ${VERBOSE})
#-------------------------
# Modo Release por defecto
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif()
if(NOT CMAKE_C_COMPILER_ID OR FORCE_SETUP)
# El compilador a usar: Gnu C Compiler, Standard 2011 with GNU extensions
set(CMAKE_C_COMPILER_ID "gcc-11")
#set(CMAKE_C_COMPILER_ID "gcc")
endif()
if(NOT CMAKE_C_COMPILER_VERSION OR FORCE_SETUP)
set(CMAKE_C_COMPILER_VERSION "11")
endif()
if(CMAKE_BUILD_TYPE MATCHES "Debug" OR
CMAKE_BUILD_TYPE MATCHES "debug")
set(CMAKE_FLAGS -std=gnu11 -Og -g -Wall -Wextra -Wpedantic)
set(CMAKE_LINKER_FLAGS "")
elseif(CMAKE_BUILD_TYPE MATCHES "Devel" OR
CMAKE_BUILD_TYPE MATCHES "devel" OR
CMAKE_BUILD_TYPE MATCHES "dev" OR
CMAKE_BUILD_TYPE MATCHES "Dev" OR
CMAKE_BUILD_TYPE MATCHES "Development" OR
CMAKE_BUILD_TYPE MATCHES "development")
set(CMAKE_FLAGS -std=gnu11 -Og -g -Wall)
set(CMAKE_LINKER_FLAGS "")
elseif(CMAKE_BUILD_TYPE MATCHES "Release" OR
CMAKE_BUILD_TYPE MATCHES "release" OR
CMAKE_BUILD_TYPE MATCHES "production" OR
CMAKE_BUILD_TYPE MATCHES "Production" OR
CMAKE_BUILD_TYPE MATCHES "Prod" OR
CMAKE_BUILD_TYPE MATCHES "prod")
set(CMAKE_FLAGS -std=gnu11 -O3 -w)
set(CMAKE_LINKER_FLAGS -s)
else()
set(CMAKE_FLAGS -std=gnu11 -O3 -w)
set(CMAKE_LINKER_FLAGS "")
endif()
#-------------------------
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${CMAKE_FLAGS}")
set(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS} ${CMAKE_FLAGS}")
############################################################################
if(EXISTS ${COLORS_FILE})
include(${COLORS_FILE})
endif()
# Incluir el archivo de firma
if(EXISTS ${SIGNATURE_FILE})
include(${SIGNATURE_FILE})
else()
message(" ${ColourBold}${Green}CMAKE_BUILD_TYPE${Yellow}=${Magenta}\"${CMAKE_BUILD_TYPE}\"${ColourReset}
${ColourBold}${Green}CMAKE_C_COMPILER_ID${Yellow}=${Magenta}\"${CMAKE_C_COMPILER_ID}\"${ColourReset}
${ColourBold}${Green}CMAKE_C_COMPILER_VERSION${Yellow}=${Magenta}\"${CMAKE_C_COMPILER_VERSION}\"${ColourReset}
${ColourBold}${Green}CMAKE_Fortran_FLAGS${Yellow}=${Magenta}\"${CMAKE_Fortran_FLAGS}\"${ColourReset}
${ColourBold}${Green}CMAKE_SYSTEM_NAME${Yellow}=${Magenta}\"${CMAKE_SYSTEM_NAME}\"${ColourReset}
${ColourBold}${Green}CMAKE_SYSTEM_PROCESSOR${Yellow}=${Magenta}\"${CMAKE_SYSTEM_PROCESSOR}\"${ColourReset}
")
endif()
############################################################################
function(create_makefile_for main_executable)
set(sources)
message(STATUS "${ColourBold}${Cyan}Finding sources...${ColourReset}")
foreach (common_folder ${COMMON_FOLDERS})
file(GLOB_RECURSE folder_deps ${SRC_DIR}/${common_folder}/*.c
${SRC_DIR}/${common_folder}/*.h)
list (APPEND sources ${folder_deps})
endforeach()
file(GLOB_RECURSE folder_deps ${SRC_DIR}/${main_executable}/*.c ${SRC_DIR}/${main_executable}/*.h)
list (APPEND sources ${folder_deps})
foreach (source ${sources})
message(STATUS "${Cyan}Found${ColourReset}: ${ColourItalic}${source}${ColourReset}")
endforeach()
message(STATUS "${ColourBold}${Cyan}Adding sources to executable...${ColourReset}")
add_executable(${main_executable} ${sources})
# Flags y opciones
message(STATUS "${ColourBold}${Cyan}Setting flags... (${CMAKE_FLAGS}) ${ColourReset}")
target_compile_options(${main_executable} PUBLIC ${CMAKE_FLAGS})
# Enlazar las librerías especificadas en LIBS
message(STATUS "${ColourBold}${Cyan}Linking libraries... (${LIBS}) ${ColourReset}")
target_link_libraries(${main_executable} PRIVATE ${LIBS})
# Agregar opciones del enlazador
target_link_options(${main_executable} PRIVATE ${CMAKE_LINKER_FLAGS})
message(STATUS "${ColourBold}${Green}Binary configured${ColourReset}")
message("")
endfunction()
function(create_makefile)
foreach(executable IN LISTS MAIN_EXECUTABLES)
create_makefile_for(${executable})
endforeach()
endfunction()
############################################################################
# Genera el output para el makefile
create_makefile()
# Variable de entorno para habilitar/deshabilitar colores
if(NOT DEFINED ENV{ENABLE_COLORS})
set(ENABLE_COLORS TRUE)
else()
set(ENABLE_COLORS $ENV{ENABLE_COLORS})
endif()
# Función para verificar si la terminal soporta secuencias de escape ANSI
function(CHECK_ANSI_SUPPORT result)
if(DEFINED ENV{TERM})
string(REGEX MATCH "^(xterm|screen|tmux|vt100|linux|cygwin|ansi|rxvt|alacritty|konsole|gnome|iterm2)" _match "$ENV{TERM}")
if(_match)
set(${result} TRUE PARENT_SCOPE)
return()
endif()
endif()
set(${result} FALSE PARENT_SCOPE)
endfunction()
# Uso de la función
CHECK_ANSI_SUPPORT(ANSI_SUPPORTED)
# Definir los códigos de color ANSI
if(NOT WIN32 AND ANSI_SUPPORTED AND ENABLE_COLORS)
string(ASCII 27 Esc)
set(ColourReset "${Esc}[m")
set(ColourBold "${Esc}[1m")
set(ColourItalic "${Esc}[3m")
set(Red "${Esc}[31m")
set(Green "${Esc}[32m")
set(Yellow "${Esc}[33m")
set(Blue "${Esc}[34m")
set(Magenta "${Esc}[35m")
set(Cyan "${Esc}[36m")
set(White "${Esc}[37m")
set(BlackBG "${Esc}[40m")
else()
set(ColourReset "")
set(ColourBold "")
set(ColourItalic "")
set(Red "")
set(Green "")
set(Yellow "")
set(Blue "")
set(Magenta "")
set(Cyan "")
set(White "")
set(BlackBG "")
endif()
# Firma. Es bonita :D
message("${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀${ColourReset}
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀${ColourReset} _ _ _
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠶⢚⣉⡉⠀⠀⠀⠀⠈⠹⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀${ColourReset} | |(_) __ _ ___ _ __ ______ _| | ___ ____
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⢀⡞⢡⣾⣿⣿⣛⣷⣀⣀⣀⣀⠀⣿⡄⠙⢷⣄⠀⠀⠀⠀⠀⠀${ColourReset} | || |/ _` |/ _ \\| '_ \\|_ / _` | |/ _ \\_ /
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⢸⣧⢾⣿⡿⠿⠿⠿⠷⠾⠯⢭⣝⡛⢷⣤⡀⢻⣄⠀⠀⠀⠀⠀${ColourReset} | || | (_| | (_) | | | |/ / (_| | | __// /
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⣶⣯⣻⢷⡿⠀⠀⠀⠀⠀${ColourReset} |_|/ |\\__, |\\___/|_| |_/___\\__,_|_|\\___/___|
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⣸⡟⠀⠀⠀⠀⢀⡀⠀⠀⠀⣾⡷⠀⢻⣿⡿⠿⣇⠀⠀⠀⠀⠀${ColourReset} |__/ |___/
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⢀⣠⠞⠉⠉⠓⠒⠚⠋⣿⠁⠀⠀⠀⠉⠁⠀⠘⣿⠃⠀⠈⠳⢄⡀⠀⠀${ColourReset} ${ColourBold}${Green}CMAKE_BUILD_TYPE${Yellow}=${Magenta}\"${CMAKE_BUILD_TYPE}\"${ColourReset}
${Yellow}${ColourBold}⠀⠀⠀⣠⠴⠋⠁⠀⠀⠀⠀⠀⠀⠀⢸⡀⠀⠀⠀⠀⠀⠀⢀⡇⠀⠀⠀⠀⠈⣻⡄⠀${ColourReset} ${ColourBold}${Green}CMAKE_C_COMPILER_ID${Yellow}=${Magenta}\"${CMAKE_C_COMPILER_ID}\"${ColourReset}
${Yellow}${ColourBold}⠀⢰⣏⡁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⡽⠒⠀⠀⠀⠀⠀⣸⣧⣤⣤⡶⠶⠟⠋⠁⠀${ColourReset} ${ColourBold}${Green}CMAKE_C_COMPILER_VERSION${Yellow}=${Magenta}\"${CMAKE_C_COMPILER_VERSION}\"${ColourReset}
${Yellow}${ColourBold}⠀⠀⠈⠙⠓⠲⠶⠶⠤⠤⠶⣶⠛⠉⠁⠀⠀⠀⠀⠀⠀⢀⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀${ColourReset} ${ColourBold}${Green}CMAKE_Fortran_FLAGS${Yellow}=${Magenta}\"${CMAKE_Fortran_FLAGS}\"${ColourReset}
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢧⠀⠀⠀⠀⠀⠀⠀⠀⢸⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀${ColourReset} ${ColourBold}${Green}CMAKE_SYSTEM_NAME${Yellow}=${Magenta}\"${CMAKE_SYSTEM_NAME}\"${ColourReset}
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡇⠀⠀⠀⠀⠀⠀⠀⣾⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀${ColourReset} ${ColourBold}${Green}CMAKE_SYSTEM_PROCESSOR${Yellow}=${Magenta}\"${CMAKE_SYSTEM_PROCESSOR}\"${ColourReset}
${Yellow}${ColourBold}⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀${ColourReset}")
# Usar `cmake -DCMAKE_BUILD_TYPE="Production" ..` para entrega <---- IMPORTANTE
# Usar `cmake -DCMAKE_BUILD_TYPE="Devel" ..` para desarrollo <------ IMPORTANTE
# Usar `cmake -DCMAKE_BUILD_TYPE="Debug" ..` para debug <----------- IMPORTANTE
project(T0-EDD-Luis-Gonzalez C) # <---------------------------------- MODIFICAR
set(FORCE_SETUP FALSE) # Fuerza el setup del ambiente de trabajo
set(VERBOSE FALSE) # Mas output... (para debug)
set(SRC_DIR "src") # <----------------------------------------------- MODIFICAR
# Carpeta común (para dependencias)
set(COMMON_FOLDERS
# AÑADIR MÁS CARPETAS DENTRO DE `src` COMUNES DISTINTAS DE `*` AQUÍ
# <---------------------------------------------------------- MODIFICAR
cts
utils
debug
data_structures
)
# Array de ejecutables de salida
set(MAIN_EXECUTABLES
# AÑADIR UN ELEMENTO POR CADA EJECUTABLE DE SALIDA
# <---------------------------------------------------------- MODIFICAR
my_binary_1
my_binary_2
tests
)
#-------------------------
# Librerías de C para esta compilación
set(LIBS
# <---------------------------------------------------------- MODIFICAR
m # Matemáticas
#pthread # POSIX Threads
#glib-2.0 # libglib2.0-dev GLib
#cjson # libcjson-dev JSON-C (C JSON library)
#OpenGL # libgl1-mesa-dev Open Graphics Library
#png # libpng-dev Portable Network Graphics
#jpeg # libjpeg-dev JPEG image format handling library
) Ejemplo de ejecución
Creo haber cubierto la mayoría de los casos borde. Puede que me falte alguno siendo que es búsqueda recursiva. Sé que no revisé los casos de enlaces simbólicos, límites de profundidad o archivos y carpetas ocultos. Todo puede ser condensado a un puro archivo, pero decidí modularizarlo para mayor claridad. ¿Por qué surgió todo este código? ¿Debí haber avanzado en la tarea 0 en vez de hacer esto? tl;dr |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Corrijo mi respuesta anterior: No se admitirán otras formas de compilar como cmake, ya que añadiría complejidad para el cuerpo docente (corrección) y para los alumnos, que se enfrentarían a algo distinto de lo que se enseña. Las tareas no están pensadas para tener una complejidad a nivel de código o "casos bordes" que requieran hacer uso de algo distinto al Makefile que se entrega. Si tienes errores debido a las limitaciones del Makefile, te recomendamos pedir ayuda para simplificar el código. |
Beta Was this translation helpful? Give feedback.
Corrijo mi respuesta anterior:
No se admitirán otras formas de compilar como cmake, ya que añadiría complejidad para el cuerpo docente (corrección) y para los alumnos, que se enfrentarían a algo distinto de lo que se enseña.
Las tareas no están pensadas para tener una complejidad a nivel de código o "casos bordes" que requieran hacer uso de algo distinto al Makefile que se entrega. Si tienes errores debido a las limitaciones del Makefile, te recomendamos pedir ayuda para simplificar el código.