CMakeLists.txt官网教程 , cmake命令配置等教程
CMakeLists.txt文件使用的是Cmake命令完成的,那么我们来了解下常用的命令使用, 这是必须要会的,否则静态库,动态库,都没法导入,而且项目文件管理等都靠这个文件, 就算你代码学的在好,这个不懂最后都不可能是一个完整的项目,只能在编译工具跑跑而已,不能发布出去
CMake是跨平台编译工具,比make更高级一些。其编译的主要工作是生成CMakeLists.txt文件,然后根据该文件生成Makefile,最后调用make来生成可执行程序或者动态库,具体流程如下:
以下教程都是基于Clion工具进行的, Clion极大地简化了我们构造C的难度,我们大部分情况只需要关注开发代码就行, 构建的部分在项目开始的时候配置一下就行, 下面就是讲解如何进行配置 , 前提需要将Clion-MinGW配置好具体教程: http://t.csdn.cn/FnTra
cmake_minimum_required(VERSION 3.20) # 声明了需要使用的cmake的最低版本
project(example1 VERSION 1.0.0 LANGUAGES C) # 项目的名字 版本 编译语言
set(CMAKE_C_STANDARD 11) #c编译器的版本
add_executable(example1 main.c) # 通过源文件main.c生成可执行文件demo.exe
当我们运行编译后,在cmake-build-debug目录下就会出现example1.exe
可执行文件了 ,当然如果只是学习C这点默认配置其实就够了
但是如果是自己开发项目,因为文件多了,同时还需要引入外部的各种库文件,那么这点配置就根本不行了, 在学习配置CMakeLists.txt前我么需要先学习下cmake的一些语法,因为CMakeLists.txt里面内容就是使用cmake编写的
因为我们又不用把CMake语法都学完,我们单纯的只是想打包项目而已,所以我们就将打包项目常用的语法说下(没用到的就不写了)
行注释使用#
;块注释使用#[[xxxxx]]
。比如:
# Multi line comments follow
#[[
xxxxx
]]
CMake中程序变量使用set和unset命令设置或者取消设置变量。作用域只是在CMakeLists.txt里
设置的变量可以是字符串,数字或者列表 ,语法: set(变量名 变量值
) 比如:
# Set variable
set(AUTHOR_NAME Farmer)
set(AUTHOR "Farmer Li")
set(AUTHOR Farmer\ Li)
# Set list
set(SLOGAN_ARR To be)
set(SLOGAN_ARR To;be)
set(SLOGAN_ARR "To;be")
set(NUM 30) # Saved as string, but can compare with other number string
set(FLAG ON) # Bool value
主要有以下要点:
${variable}
,在if()
条件判断中可以简化为只用变量名。unset(variable)
删除变量CMake允许设置环境变量,环境变量通过特殊的形式$ENV{varName}
获取,通过SET(ENV{变量名} "变量值")
设置环境变量
注意: 设置环境变量作用只是在CMakeLists.txt编译结束后就没了, 所以一般我们就来获取环境变量而已,和判断是否存在
提供信息的变量可以提供某种信息,通常只需要读取变量即可,而不需要对变量进行修改。
PROJECT_SOURCE_DIR
工程顶层目录,也就是顶层 CMakeLists.txt 源码所在目录PROJECT_BINARY_DIR
工 程 BINARY_DIR
, 也 就 是 顶 层 CMakeLists.txt 源 码 的BINARY_DIRCMAKE_SOURCE_DIR
与 PROJECT_SOURCE_DIR
等价CMAKE_BINARY_DIR
与 PROJECT_BINARY_DIR
等价CMAKE_CURRENT_SOURCE_DIR
当前源码所在路径CMAKE_CURRENT_BINARY_DIR
当前源码的 BINARY_DIRCMAKE_MAJOR_VERSION
cmake 的主版本号CMAKE_MINOR_VERSION
cmake 的次版本号CMAKE_VERSION
cmake 的版本号(主+次+修订)PROJECT_VERSION_MAJOR
工程的主版本号PROJECT_VERSION_MINOR
工程的次版本号PROJECT_VERSION
工程的版本号CMAKE_PROJECT_NAME
工程的名字PROJECT_NAME
工程名,与 CMAKE_PROJECT_NAME 等价
MESSAGE(打印内容)
MESSAGE( STATUS 打印内容)
执行shell命令
execute_process(COMMAND <一句shell命令> WORKING_DIRECTORY <这句shell命令执行的工作目录>)
如果命令不依赖于某个目录,而是全局的话那么可以直接使用
execute_process(COMMAND echo "Hello")
执行shell脚本
execute_process(COMMAND sh test.sh WORKING_DIRECTORY <test.sh所在目录> )
file(GLOB_RECURSE ALL_SRC
src/**.c
# module2/*.c
)
递归查询所有src下面所有后缀为.c
的文件,并且保存到ALL_SRC里(List方式)
execute_process( COMMAND ${CMAKE_COMMAND} -E make_directory 目录创建)
execute_process( COMMAND ${CMAKE_COMMAND} -E copy 文件/文件列表 目标目录)
execute_process( COMMAND ${CMAKE_COMMAND} -E copy_directory 目录/目录列表 目标地址)
list(LENGTH <list> <output variable>)
list(GET <list> <element index> [<element index> ...] <output variable>)
list(APPEND <list> <element> [<element> ...])
list(FIND <list> <value> <output variable>)
list(INSERT <list> <element_index> <element> [<element> ...])
list(REMOVE_ITEM <list> <value> [<value> ...])
list(REMOVE_AT <list> <index> [<index> ...])
list(REMOVE_DUPLICATES <list>)
list(REVERSE <list>)
list(SORT <list>)
注意: 在CMake中,一个list是一个由封号;分割的一组字符串。使用set命令可以创建一个list。例如,set(var a b c d e)命令将会创建一个list:a;b;c;d;e;而set(var “a b c d e”)命令创建的只是一个字符串,或者说是只有一个项的list。 当使用指定索引的命令格式时,如果是大于等于0的数,是从list第一个项开始的序号,list的第一项的索引是0。如果小于等于-1,这个索引是从结尾开始的逆向索引,其中-1表示的是list的最后一项。当使用负数索引时,注意它们不是从0开始!-0与0等价,它指向list的第一个成员。
foreach(var ${list})
# xxxx
endforeach()
连接库(静态和动态)有好几种方式,
记住唯一一种就行target_link_libraries,万能连接,要写在add_executable之后 ,可以和find_path搭配或者循环
target_link_libraries (${PROJECT_NAME} 动态库/动态库列表) # 将当前项目连接动态库 , 绝对路径方式
cmake_minimum_required(VERSION 3.20)# 声明了需要使用的cmake的最低版本 注意: 改为自己的cmake版本
project(demo1 C) # 项目名称 和 语言 注意: 项目名称需要改为你自己的
set(CMAKE_C_STANDARD 11) #改为自己C语言的编译版本
# 搜索.h文件
file(GLOB_RECURSE ALL_H
${PROJECT_SOURCE_DIR}/include_h/**.h
)
# 搜索include_h下所有包含.h的父级目录
foreach(file ${ALL_H})
# 获取父目录
string(REGEX REPLACE "/$" "" CURRENT_FOLDER_ABSOLUTE ${file})
string(REGEX REPLACE "(.*/)(.*)" "\\1" CURRENT_FOLDER ${CURRENT_FOLDER_ABSOLUTE})
list(APPEND include_h ${CURRENT_FOLDER})
endforeach()
# 目录去重
list(REMOVE_DUPLICATES include_h)
MESSAGE("include_directories" ${include_h})
# 指定.h头文件搜索路径
include_directories(${include_h})
# 递归查询文件
file(GLOB_RECURSE ALL_SRC
# 可以配置多个路径
${PROJECT_SOURCE_DIR}/src/**.c # 获取src下面的所有.c文件
# ${PROJECT_SOURCE_DIR}/module2/*.c
)
MESSAGE("add_executable" ${ALL_SRC})
# 手动添加ioc图标 ,等依赖文件
set(ICO ico/ico.o)
# 需要编译的文件 ,生成exe
add_executable(${PROJECT_NAME} ${ICO} ${ALL_SRC})
# 将环境变量路径下的所有库文件连接到项目里
if(DEFINED ENV{LIBRARY_CMAKE_PATH_FILES})
file(GLOB_RECURSE ALL_library
# 可以配置多个路径
$ENV{LIBRARY_CMAKE_PATH_FILES}/**.a # 获取lib下面的所有.a文件
$ENV{LIBRARY_CMAKE_PATH_FILES}/**.lib # 获取lib下面的所有.lib文件
$ENV{LIBRARY_CMAKE_PATH_FILES}/**.os # 获取lib下面的所有.lib文件
$ENV{LIBRARY_CMAKE_PATH_FILES}/**.dll # 获取lib下面的所有.lib文件
)
MESSAGE("target_link_libraries: " ${ALL_library})
# 链接静态库也可以链接动态库
target_link_libraries (${PROJECT_NAME} ${ALL_library})
endif()
# 将当前项目下lib所有的所有库文件(.os .dll .a .lib )连接到项目里
file(GLOB_RECURSE ALL_library
# 可以配置多个路径
${PROJECT_SOURCE_DIR}/lib/**.a # 获取lib下面的所有.a文件
${PROJECT_SOURCE_DIR}/lib/**.lib # 获取lib下面的所有.lib文件
${PROJECT_SOURCE_DIR}/lib/**.os # 获取lib下面的所有.lib文件
${PROJECT_SOURCE_DIR}/lib/**.dll # 获取lib下面的所有.lib文件
)
MESSAGE("target_link_libraries: " ${ALL_library})
# 链接静态库也可以链接动态库
target_link_libraries (${PROJECT_NAME} ${ALL_library})
如果有库文件在其他地方那么可以设置系统环境变量LIBRARY_CMAKE_PATH_FILES
, 来连接,默认会添加将当前项目lib下所有库文件
注意:
静态动态都可以使用下面写好的CMakeLists.txt,在文件中有说明,不同的库只需要改下就行
cmake_minimum_required(VERSION 3.20) # 声明了需要使用的cmake的最低版本
project(tool C) # 项目名称 和 语言
set(CMAKE_C_STANDARD 11) # C编译器版本
# 搜索全部的.c文件
file(GLOB_RECURSE ALL_SRC
${PROJECT_SOURCE_DIR}/src/**.c
${PROJECT_SOURCE_DIR}/*.c
)
MESSAGE("add_library" ${ALL_SRC})
# 静态打包库文件 (自行选择)
add_library(${PROJECT_NAME} ${ALL_SRC})
# 动态打包库文件 (自行选择)
# add_library(${PROJECT_NAME} SHARED ${ALL_SRC})
# 将库文件和头文件都复制到一个目录下
## 在项目根下创建 ${PROJECT_NAME} 文件夹
set( public_include ${PROJECT_SOURCE_DIR}/cmake-build-debug/${PROJECT_NAME})
execute_process( COMMAND ${CMAKE_COMMAND} -E make_directory ${public_include})
## 拷贝头部文件,到到${PROJECT_NAME}文件夹
file(GLOB_RECURSE ALL_SRC
${PROJECT_SOURCE_DIR}/src/**.h
${PROJECT_SOURCE_DIR}/**.h
)
MESSAGE("copy" ${ALL_SRC})
execute_process( COMMAND ${CMAKE_COMMAND} -E copy ${ALL_SRC} ${public_include})
最后当运行打包后, 只需要将库文件和头文件夹,复制到需要的地方就行了
静态库在编译的时候就会被打包到exe中
当我们项目使用的是动态库打包后,是运行不起来的 ,因为动态库打包的项目是在运行时候才会去找依赖 ,默认会去找exe当前目录下或者系统的PATH环境变量里的路径, 如果都没有那么就会报错
解决办法
如果当前是在本地开发代码那么直接在Clion的环境变量中配置就行了
如果当前需要打包项目的话,而dll文件和exe文件不是在同级目录下,那么以下有二种解决方案:
点赞 -收藏-关注-便于以后复习和收到最新内容有其他问题在评论区讨论-或者私信我-收到会在第一时间回复感谢,配合,希望我的努力对你有帮助^_^
免责声明:本文部分素材来源于网络,版权归原创者所有,如存在文章/图片/音视频等使用不当的情况,请随时私信联系我。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://huanmin.blog.csdn.net/article/details/125635790
内容来源于网络,如有侵权,请联系作者删除!