cmake-使用


title: cmake 使用
tags: [cmake,项目构建]
categories:

  • tools
  • cmake
    date: 2021-07-13 13:47:11

CMmake

简介

简单来讲,cmake是一个跨平台的makefile生成器。大型项目的额makefile实在是太繁琐了。学习cmake就是在学习其语法。一般来讲,只有在使用c/c++做一个大项目的时候才用得到cmake

基本命令简介

project

PROJECT(<projectname> [CXX] [C] [Java])

指定生成项目的名字,可选项目语言(默认位全选)
同时 cmake 系统也帮助我们预定义了
PROJECT_BINARY_DIR 指向生成的项目的路径(build) 和
PROJECT_SOURCE_DIR 指向项目源文件的路径(source)

MESSAGE

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display")

这个指令用于向终端输出用户定义的信息,包含了三种类型:

  1. SEND_ERROR,产生错误,生成过程被跳过。
  2. SATUS,输出前缀为—的信息。
  3. FATAL_ERROR,立即终止所有 cmake 过程.
MESSAGE(STATUS "build " ${PROJECT_BINARY_DIR} " source " ${PROJECT_SOURCE_DIR})

SET

显式地定义变量

SET(SRC_LIST main.c t1.c t2.c)

将 main.c t1.c t2.c 定义为源文件列表

ADD_EXECUTABLE

生成可执行文件

ADD_EXECUTABLE(hello ${SRC_LIST})

ADD_SUBDIRECTORY

位当前目录添加一个子目录

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

INSTALL

CMAKE_INSTALL_PREFIX

DESTINATION 定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候
CMAKE_INSTALL_PREFIX 其实就无效了。如果你希望使用 CMAKE_INSTALL_PREFIX 来定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是
${CMAKE_INSTALL_PREFIX}/<DESTINATION 定义的路径>

INSTALL(TARGETS myrun mylib mystaticlib
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION libstatic )

上面的例子会将: 
可执行二进制 myrun 安装到${CMAKE_INSTALL_PREFIX}/bin 目录 
动态库 libmylib 安装到${CMAKE_INSTALL_PREFIX}/lib 目录 
静态库 libmystaticlib 安装到${CMAKE_INSTALL_PREFIX}/libstatic 目录

普通文件的安装

INSTALL(FILES files... DESTINATION <dir>
 [PERMISSIONS permissions...]
 [CONFIGURATIONS [Debug|Release|...]]
 [COMPONENT <component>]
 [RENAME <name>] [OPTIONAL])

ADD_LIBRARY

ADD_LIBRARY(libname [SHARED|STATIC|MODULE]
 [EXCLUDE_FROM_ALL]
 source1 source2 ... sourceN)

SET_TARGET_PROPERTIES

SET_TARGET_PROPERTIES(target1 target2 ...
 PROPERTIES prop1 value1
 prop2 value2 ...)

GET_TARGET_PROPERTY

与他对应的指令是:
GET_TARGET_PROPERTY(VAR target property)
具体用法如下例,我们向 lib/CMakeListst.txt 中添加:
GET_TARGET_PROPERTY(OUTPUT_VALUE hello_static OUTPUT_NAME)
MESSAGE(STATUS “This is the hello_static
OUTPUT_NAME:”${OUTPUT_VALUE})
如果没有这个属性定义,则返回 NOTFOUND.

INCLUDE_DIRECTORIES

现在我们在 src/CMakeLists.txt 中添加一个头文件搜索路径,方式很简单,加入:
INCLUDE_DIRECTORIES(/usr/include/hello)

LINK_DIRECTORIES

LINK_DIRECTORIES(directory1 directory2 ...)

这个指令非常简单,添加非标准的共享库搜索路径,比如,在工程内部同时存在共享库和可 执行二进制,在编译时就需要指定一下这些共享库的路径。这个例子中我们没有用到这个指 令。

TARGET_LINK_LIBRARIES

TARGET_LINK_LIBRARIES(target library1
 <debug | optimized> library2
 ...)
这个指令可以用来为 target 添加需要链接的共享库,本例中是一个可执行文件,但是同样
可以用于为自己编写的共享库添加共享库链接。

cmake 学习 assimp的经验

项目文件目录

code
    --项目的各种代码文件夹
    --CMakeLists.txt
contrib
    --各种依赖的文件夹
doc
include
    --项目的头文件,对外的接口
samples
tests
tools
readme.md
CMakeLists.txt

特点:

  1. 对别的项目的依赖不使用自己编译好的lib或者dll,而是直接使用源文件。估计编译assimp的时候把这些源文件都编译了一遍
  2. code文件夹就放自己的代码。
  3. include文件夹就负责对外提供接口。
  4. 只使用两个CMakeLists.txt,根目录下的负责项目的整体信息描述,code目录下的负责对文件的编译。

cmake 编写

太复杂了,我现在并看不懂。但并不像我这样每一个模块编写一个CMakeLists.txt进行cmake,而是根目录下的负责项目的整体信息描述,code目录下的负责对文件的编译。

项目编译

  1. 首先按照上面的文件目录进行编排。
  2. 编写CMakeLists.txt 文件
    1. 最好编译成动态链接库,不然没有办法将项目的静态依赖库lib文件包含在内。
    2. 若项目的依赖中存在动态库,比如assimp 时,就没办法将其包含在内了,只能让用户显式地使用assimp.
  3. 将项目的头文件列举出来保存到include文件夹中,这里面的就是提供给用户的接口,将不想提供给用户的接口删除即可。
  4. 记得cmake中进行install,将所有需要提供给用户的文件全部放在最显眼的地方。

CMakeLists.txt 编写

我现在对编译有关的知识了解甚少,所以现在只能使用一些最基础的东西,日后会对编译有更深得了解。

  1. cmake的最下版本要求

  2. 确定项目的名称

  3. 确定项目的目录安排

  4. 确定项目的包含目录和库目录

  5. 确定项目生成目标位置

  6. 确定项目的额依赖

  7. 确定目标使用的文件并安排成组

  8. 确定目标工程的筛选器

  9. 编译项目

  10. 安装项目

Demo list

XYY_Game_Engine 的构建示例

# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.20)

# 项目信息
project(XYY_Game_Engine)


#变量设置   主要是目录变量
#CMAKE_INSTALL_PREFIX
set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_LIST_DIR})
#code目录
set(CODE_ROOT_PATH ${CMAKE_CURRENT_LIST_DIR}/code/)
#build目录
set(BUILD_PATH ${CMAKE_CURRENT_LIST_DIR}/build/)
#存放生成的lib的目录
set(LIB_PATH ${BUILD_PATH}/../lib/)
#存放生成的dll的目录
set(DLL_PATH ${BUILD_PATH}/../dll/)
#编译所需包含目录
set(INCLUDE_PATH_CODE ${CMAKE_CURRENT_LIST_DIR}/include/)
set(INCLUDE_PATH_CONTRIB ${CMAKE_CURRENT_LIST_DIR}/contrib/include/)
#编译所需库目录
set(LIBRARY_PATH_CONTRIB ${CMAKE_CURRENT_LIST_DIR}/contrib/lib/)
#设置test路径
set(TEST_PATH ${CMAKE_CURRENT_LIST_DIR}/build/test/)
#指定程序的包含目录 库目录
#引用目录
#INCLUDE_DIRECTORIES(${INCLUDE_PATH_CODE})
INCLUDE_DIRECTORIES(${INCLUDE_PATH_CONTRIB})
INCLUDE_DIRECTORIES(${TEST_PATH}/include)
#库目录 将生成的lib 目录也包含在内,为了给test使用
LINK_DIRECTORIES(${LIBRARY_PATH_CONTRIB})
LINK_DIRECTORIES(${LIB_PATH})

#设置目标的属性 
function(SetDefaultTargetProperties target)
	#程序生成文件的目录   
	set_target_properties(${target} PROPERTIES
		ARCHIVE_OUTPUT_DIRECTORY ${LIB_PATH}
		LIBRARY_OUTPUT_DIRECTORY ${LIB_PATH}
		RUNTIME_OUTPUT_DIRECTORY ${DLL_PATH}
	)
endfunction()

#MESSAGE(STATUS ${LIB_PATH})

#code的编译  得到 XYY_Game_Engine.lib XYY_Game_Engine.dll 
add_subdirectory(${CODE_ROOT_PATH})


#放入 lib 文件夹
INSTALL(TARGETS
    XYY_Game_Engine
    LIBRARY DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/lib/
)

#放入 bin 中

if(EXISTS   ${CMAKE_CURRENT_LIST_DIR}/dll/Debug/XYY_Game_Engine.dll)
INSTALL(FILES
    ${CMAKE_CURRENT_LIST_DIR}/dll/Debug/XYY_Game_Engine.dll
    DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/bin/
)
endif()

if(EXISTS    ${CMAKE_CURRENT_LIST_DIR}/dll/assimp-vc142-mt.dll)
INSTALL(FILES
    ${CMAKE_CURRENT_LIST_DIR}/dll/assimp-vc142-mt.dll
    DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/bin
)
endif()


#对 test 增加支持   dll  release  test 所有的引用都来原来自include中的
INSTALL(FILES
    ${CMAKE_CURRENT_LIST_DIR}/bin/assimp-vc142-mt.dll
    DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/build/test/Release
)

INSTALL(FILES
    ${CMAKE_CURRENT_LIST_DIR}/bin/XYY_Game_Engine.dll
    DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/build/test/Release
)
INSTALL(FILES
    ${CMAKE_CURRENT_LIST_DIR}/bin/assimp-vc142-mt.dll
    DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/build/test/Debug
)
INSTALL(FILES
    ${CMAKE_CURRENT_LIST_DIR}/bin/XYY_Game_Engine.dll
    DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/build/test/Debug
)

FILE(
    GLOB_RECURSE Header_Driver
    ${CODE_ROOT_PATH}/Driver/*.hpp
)
FILE(
    GLOB_RECURSE Header_Driver_LocalDriver
    ${CODE_ROOT_PATH}/Driver/LocalDriver/*.h
)
FILE(
    GLOB_RECURSE Header_Driver_Global
    ${CODE_ROOT_PATH}/Driver/GlobalDriver/*.h
)
#SRC_Element
FILE(
    GLOB_RECURSE Header_Element
    ${CODE_ROOT_PATH}/Element/*.h
)
#SRC_Resource
FILE(
    GLOB_RECURSE Header_Resource
    ${CODE_ROOT_PATH}/Resource/*.h
)
#SRC_Resource
FILE(
    GLOB_RECURSE Header_Scene
    ${CODE_ROOT_PATH}/Scene/*.h
)
#SRC_Sync
FILE(
    GLOB_RECURSE Header_Sync
    ${CODE_ROOT_PATH}/Sync/*.h
)
INSTALL(
    FILES
    ${Header_Driver}
    DESTINATION
    ${INCLUDE_PATH_CODE}/Driver/
)
INSTALL(
    FILES
    ${Header_Driver_LocalDriver}
    DESTINATION
    ${INCLUDE_PATH_CODE}/Driver/LocalDriver/
)
INSTALL(
    FILES
    ${Header_Driver_Global}
    DESTINATION
    ${INCLUDE_PATH_CODE}/Driver/GlobalDriver/
)
INSTALL(
    FILES
    ${Header_Element}
    DESTINATION
    ${INCLUDE_PATH_CODE}/Element/
)
INSTALL(
    FILES
    ${Header_Resource}
    DESTINATION
    ${INCLUDE_PATH_CODE}/Resource/
)
INSTALL(
    FILES
    ${Header_Scene}
    DESTINATION
    ${INCLUDE_PATH_CODE}/Scene/
)
INSTALL(
    FILES
    ${Header_Sync}
    DESTINATION
    ${INCLUDE_PATH_CODE}/Sync/
)
INSTALL(
    DIRECTORY
    ${CMAKE_CURRENT_LIST_DIR}/code/Scxmlexample
    DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/include/
)
INSTALL(
    DIRECTORY
    ${CMAKE_CURRENT_LIST_DIR}/code/resources
    DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/include/
)
INSTALL(
    DIRECTORY
    ${CMAKE_CURRENT_LIST_DIR}/code/GLSL
    DESTINATION
    ${CMAKE_CURRENT_LIST_DIR}/include/
)
# example 
INSTALL(
    DIRECTORY
    ${CMAKE_CURRENT_LIST_DIR}/include/Scxmlexample
    DESTINATION
    ${TEST_PATH}/
)
# resources
INSTALL(
    DIRECTORY
    ${CMAKE_CURRENT_LIST_DIR}/include/resources
    DESTINATION
    ${TEST_PATH}/
)
# header
INSTALL(
    DIRECTORY
    ${CMAKE_CURRENT_LIST_DIR}/include
    DESTINATION
    ${TEST_PATH}/
)


#target 测试
add_subdirectory(test)
#code 

#code 中的所有文件
FILE(GLOB_RECURSE SOURCE_CODE       
    Driver/*
    Driver/LocalDriver/*
    Driver/GlobalDriver/*
    Element/*
    Resource/*
    Scene/*
    Sync/*
    ${INCLUDE_PATH_CONTRIB}/*.c
)

#组织 file 
#Driver
FILE(
    GLOB_RECURSE SRC_Driver
    Driver/*.hpp
)
source_group(Driver FILES ${SRC_Driver})
FILE(
    GLOB_RECURSE SRC_Driver_LocalDriver
    Driver/LocalDriver/*
)
source_group(Driver//LocalDriver FILES ${SRC_Driver_LocalDriver})
FILE(
    GLOB_RECURSE SRC_Driver_Global
    Driver/GlobalDriver/*
)
source_group(Driver//GlobalDriver FILES ${SRC_Driver_Global})
#SRC_Element
FILE(
    GLOB_RECURSE SRC_Element
    Element/*
)
source_group(Element FILES ${SRC_Element})
#SRC_Resource
FILE(
    GLOB_RECURSE SRC_Resource
    Resource/*
)
source_group(Resource FILES ${SRC_Resource})
#SRC_Resource
FILE(
    GLOB_RECURSE SRC_Scene
    Scene/*
)
source_group(Scene FILES ${SRC_Scene})
#SRC_Sync
FILE(
    GLOB_RECURSE SRC_Sync
    Sync/*
)
source_group(Sync FILES ${SRC_Sync})
#xml
FILE(
    GLOB_RECURSE SRC_Scxmlexample
    ${CODE_ROOT_PATH}/Scxmlexample/*.xml
)
source_group(Scxmlexample FILES ${SRC_Scxmlexample})




FILE(
    GLOB DEPENDENCE_LIB
    ${LIBRARY_PATH_CONTRIB}/*.lib
)

#生成链接库
add_library(XYY_Game_Engine SHARED ${SOURCE_CODE} ${SRC_Scxmlexample})
SetDefaultTargetProperties(XYY_Game_Engine)
#  应该还要加上 opengl32.lib
target_link_libraries(XYY_Game_Engine   
opengl32  
glfw3.lib 
assimp-vc142-mt.lib  
tinyxml.lib  
kernel32.lib
user32.lib
gdi32.lib
winspool.lib
comdlg32.lib
advapi32.lib
shell32.lib
ole32.lib
oleaut32.lib
uuid.lib
odbc32.lib
odbccp32.lib
)
#对于每一个项目,其相对路径的起始位置是 vs 那一对文件的位置

#xml
FILE(
    GLOB_RECURSE SRC_Scxmlexample_test
    ${CODE_ROOT_PATH}/Scxmlexample/*.xml
)
source_group(Scxmlexample FILES ${SRC_Scxmlexample_test})

#test1
add_executable(test1 test1.cpp ${SRC_Scxmlexample_test})
ADD_DEPENDENCIES(test1 XYY_Game_Engine)
target_link_libraries(test1 XYY_Game_Engine)

#test1
add_executable(test2 test2.cpp ${SRC_Scxmlexample_test})
ADD_DEPENDENCIES(test1 XYY_Game_Engine)
target_link_libraries(test2 XYY_Game_Engine)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值