cmake与makefile的结合使用举例

1.工具类函数各自编译

cat /lysrv/eu/app/buildtools/cmake/config.cmake

#设置config_base变量
set(config_base ${CMAKE_CURRENT_LIST_DIR}/../../config)
#GLOB 会产生一个由所有匹配globbing表达式的文件组成的列表,并将其保存到变量中.Globbing 表达式与正则表达式类似,此处的Globbing 表达式为${config_base}/src/*.c
file(GLOB config_source ${config_base}/src/*.c)
#设置yaml_parser_source变量,内容为${yaml_parser_source} ${config_source}等,类似于export PATH=$PATH:/home/bin
set(yaml_parser_source ${yaml_parser_source} ${config_source})

cat /lysrv/eu/app/buildtools/cmake/utils.cmake

#设置utils_base变量
set(utils_base ${CMAKE_CURRENT_LIST_DIR}/../../utils)
#GLOB 会产生一个由所有匹配globbing表达式的文件组成的列表,并将其保存到变量中.Globbing 表达式与正则表达式类似,此处的Globbing 表达式为${utils_base}/src/*.c
file(GLOB utils_source ${utils_base}/src/*.c)
#设置yaml_parser_source变量,内容为${yaml_parser_source} ${utils_source}等,类似于export PATH=$PATH:/home/bin
set(yaml_parser_source ${yaml_parser_source} ${utils_source})

2.主函数CMakeLists.txt文件编写

#指定cmake的最低版本
cmake_minimum_required(VERSION 2.8.12)
#指定工程名以及开发语言,此处项目同时使用了c++与c
project(lids_monitor CXX C)
#更新系统变量EXECUTABLE_OUTPUT_PATH的内容,此处为目标文件的生成路径
#系统变量CMAKE_CURRENT_LIST_DIR对应的为CMakeLists.txt文件所在路径
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/bin)
#更新系统变量CMAKE_CXX_FLAGS的内容,此处为c++编译附加选项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#更新系统变量CMAKE_C_FLAGS的内容,此处为c编译附加选项
set(CMAKE_C_FLAGS "-g -Wall")

# 生成libyamlParser.a静态库
#相关文件导入,此处导入的为各模块追加内容的yaml_parser_source变量
include(${CMAKE_CURRENT_LIST_DIR}/../buildtools/cmake/config.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/../buildtools/cmake/utils.cmake)
#打印yaml_parser_source变量的值
MESSAGE(STATUS ${yaml_parser_source})
#指定编译所需的头文件路径
INCLUDE_DIRECTORIES(
    ${CMAKE_CURRENT_LIST_DIR}/../config/include
    ${CMAKE_CURRENT_LIST_DIR}/../utils/include
)
#更新系统变量LIBRARY_OUTPUT_PATH的内容,此处为库文件的生成路径
SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/lib)
#指定库文件名yamlParser并生成静态库
ADD_LIBRARY(yamlParser STATIC ${yaml_parser_source})

# 生成lids_monitor可执行程序
##GLOB 会产生一个由所有匹配globbing表达式的文件组成的列表,并将其保存到lids_monitor_source变量中.Globbing 表达式与正则表达式类似,此处的Globbing 表达式为${CMAKE_CURRENT_LIST_DIR}/src/*.cpp
file(GLOB lids_monitor_source ${CMAKE_CURRENT_LIST_DIR}/src/*.cpp)
#生成可执行文件lids_monitor
add_executable(lids_monitor ${lids_monitor_source})
#给当前项目lids_monitor对应的系统变量INCLUDE_DIRECTORIES追加头文件搜索路径(增加头文件搜索路径;必选项PROPERTY后面紧跟着要设置的属性的名字)
set_property(TARGET lids_monitor PROPERTY INCLUDE_DIRECTORIES
    ${CMAKE_CURRENT_LIST_DIR}/include
    ${CMAKE_CURRENT_LIST_DIR}/../config/include
    ${CMAKE_CURRENT_LIST_DIR}/../utils/include
)
#给当前项目lids_monitor对应的系统变量LINK_DIRECTORIES追加链接库搜索路径(增加链接库搜索路径;必选项PROPERTY后面紧跟着要设置的属性的名字)
set_property(TARGET lids_monitor PROPERTY LINK_DIRECTORIES
    ${CMAKE_CURRENT_LIST_DIR}/lib
)
#给当前项目lids_monitor对应的系统变量LINK_LIBRARIES追加链接库(增加链接库;必选项PROPERTY后面紧跟着要设置的属性的名字)
set_property(TARGET lids_monitor PROPERTY LINK_LIBRARIES yaml yamlParser pthread)

#上面添加库搜索路径的方式有时行不通(如:当lib和bin在各自的cmake中生成时),可以采用下述方式
# VAR变量代表找到的库全路径,包含库文件名(cmake会在目录中查找,如果所有目录中都没有,值VAR就会被赋为NO_DEFAULT_PATH)
#find_library( LIB_NAME LIB_PATH NO_DEFAULT_PATH)
##find_library(config_lib yamlParser ${CMAKE_CURRENT_LIST_DIR}/../../lib)
# 将库文件链接到可执行程序上(此时的${config_lib}为附带全路径的libyamlParser.a)
##target_link_libraries(lids_syn ${config_lib} yaml pthread)

3.自定义的Makefile生成(精髓:各取所长)

#返回(最近的)Makefile 真实绝对的路径
PROJECT_BASE:=$(abspath $(dir $(lastword $(MAKEFILE_LIST))))
#指定中间文件生成路径
OUTPUT_PATH:=$(PROJECT_BASE)/build
#指定目标文件
EXECUTALBE:=$(PROJECT_BASE)/bin/lids_monitor
#号称的动态编译:PHONY伪目标可以解决源文件不是最终目标直接依赖(实际上可以认为是间接依赖)带来的不能自动检查更新规则(Makefile中PHONY的用法可参考:https://www.cnblogs.com/amanlikethis/archive/2013/11/17/3427622.html)
.PHONY: build
# {
     {
     { build
#3.各取所长之利用cmake编译生成程序编译所需的Makefile(通过执行命令,由依赖文件生成目标文件(每条命令前必须有且仅有一个 tab 保持缩进,这是语法要求))
#此处用法特殊,缺省了以来文件,目标文件的生成无需依赖其他文件,直接执行命令即可生成
##命令行执行make build的流程3:生成$(OUTPUT_PATH)/Makefile
$(OUTPUT_PATH)/Makefile:
	mkdir -p $(OUTPUT_PATH) \
	&& cd $(OUTPUT_PATH) \
	&& cmake $(PROJECT_BASE) \
#2.各取所长之make编译(-C 是将当前工作目录移动到指定位置)
#理论上应该是:执行命令,由依赖文件$(OUTPUT_PATH)/Makefile生成目标文件$(EXECUTALBE)
#此处用法特殊,可理解为执行命令切换到$(OUTPUT_PATH)/Makefile文件所在目录,并通过$(EXECUTALBE):$(OUTPUT_PATH)/Makefile指定二者的依赖关系
#命令行执行make build的流程2:生成$(EXECUTALBE),但是发现$(EXECUTALBE)需要依赖$(OUTPUT_PATH)/Makefile,可是$(OUTPUT_PATH)/Makefile文件还没有,需要先执行其他分支生成
$(EXECUTALBE):$(OUTPUT_PATH)/Makefile
	$(MAKE_COMMAND) -C $(OUTPUT_PATH)
#1.生成可执行文件$(EXECUTALBE)(对应命令行执行命令:make build)(Makefile的用法可参考:https://www.jianshu.com/p/c61428b2d47e)
#此处.PHONY: build的含义是指:将目标build定义成伪目标(无论当前目录下是否存在“build”这个文件,输入“make build”后,后续命令都会被执行)
#此处用法特殊,缺省了需要执行的命令,仅通过build:$(EXECUTALBE)指定了二者的依赖关系
#命令行执行make build的流程起点1:执行build,但是发现build需要依赖$(EXECUTALBE),可是$(EXECUTALBE)文件还没有,需要先执行其他分支生成
.PHONY: build
build:$(EXECUTALBE)
#}}}

#临时文件清理(对应: make clean)
.PHONY: clean
clean:
	@rm -rvf $(PROJECT_BASE)/build
#临时文件全部清理(对应: make cleanAll)
cleanAll:
	@rm -rvf $(PROJECT_BASE)/build
	@rm -rvf $(PROJECT_BASE)/bin/lids_monitor
	@rm -rvf $(PROJECT_BASE)/lib/libyamlParser.a

你可能感兴趣的:(Linux命令,C语言,cmake,Makefile)