我们构建自己的项目工程时,通常会引入第三库。比价简单的做法是用自己的编译工具链编译好对应的动态/静态库后再通过 TARGET_LINK_LIBRARIES 等函数链接到本地工程中。但将库放在自己的工程中,push到云端进行代码托管时就显得不优雅,并且自己编译的库所用到的工具链别人未必会用,这样上传的库就只能自己用了。
有没有一种方法可以在 cmake 的时候就把库从 github 中下载到本地,并make的时候一并编译到执行文件当中。
以下是从github中下载paho-mqtt库到本地路径并进行编译的例子。
mqtt.cmake
# mqtt library cmake function.
# 从当前可用的环境变量中移除< variable > 后续调用 $ENV{< variable >} 将返回空字符串
UNSET(LOCAL_MQTT_TAR_GZ CACHE)
UNSET(LOCAL_MQTT_DIR CACHE)
UNSET(LOCAL_LIBRARIES_PATH CACHE)
# MQTT文件夹名称
SET(MQTT_DIR_NAME "paho.mqtt.c-1.3.12")
# MQTT库压缩包名称
SET(MQTT_TAR_GZ_NAME "paho.mqtt.c-1.3.12.tar.gz")
# MQTT远程下载地址URL
SET(MQTT_DOWNLOAD_URL "https://codeload.github.com/eclipse/paho.mqtt.c/tar.gz/refs/tags/v1.3.12")
# 设置库远程下载超时时间
SET(DOWNLOAD_MQTT_TIMEOUT 300 CACHE STRING "Timeout in seconds when downloading mqtt_lib.")
MESSAGE(STATUS "Checking ${MQTT_TAR_GZ_NAME}...")
# 判断压缩包是否已经存在
FIND_FILE(LOCAL_MQTT_TAR_GZ
NAMES ${MQTT_TAR_GZ_NAME}
HINTS "${PROJECT_SOURCE_DIR}/libraries_path"
NO_DEFAULT_PATH)
# 判断压缩包在文件夹libraries_path下是否已经解压
FIND_FILE(LOCAL_MQTT_DIR
NAMES ${MQTT_DIR_NAME}
HINTS "${PROJECT_SOURCE_DIR}/libraries_path"
NO_DEFAULT_PATH)
FIND_FILE(LOCAL_LIBRARIES_PATH
NAMES ""
HINTS "libraries_path"
NO_DEFAULT_PATH)
MESSAGE(STATUS "Checking url link ${MQTT_DOWNLOAD_URL} ...")
# 如果路径下没有压缩文件
IF(NOT LOCAL_MQTT_TAR_GZ)
MESSAGE(STATUS "Downloading ${MQTT_TAR_GZ_NAME} to ${LOCAL_LIBRARIES_PATH} ...")
# 从设定的 URL 地址下载相应的压缩包
FILE(DOWNLOAD ${MQTT_DOWNLOAD_URL}
${LOCAL_LIBRARIES_PATH}/${MQTT_TAR_GZ_NAME}
TIMEOUT ${DOWNLOAD_MQTT_TIMEOUT}
STATUS ERR
SHOW_PROGRESS)
# 判断下载是否存在错误
IF(ERR EQUAL 0)
# 如果下载无错误则设置压缩包名称标记下载成功
SET(LOCAL_MQTT_TAR_GZ "${LOCAL_LIBRARIES_PATH}/${MQTT_TAR_GZ_NAME}")
#下载错误输出相关的提示信息
ELSE()
MESSAGE(STATUS "Download failed, error: ${ERR}")
MESSAGE(FATAL_ERROR
"You can try downloading ${MQTT_DOWNLOAD_URL} manually"
"using curl/wget or a similar tool")
ENDIF()
ENDIF()
# 如果路径下存在压缩文件
IF(LOCAL_MQTT_TAR_GZ)
# 输出相应的提示信息校验解压路径等
MESSAGE(STATUS "Checking the direction of ${LOCAL_LIBRARIES_PATH}/${MQTT_DIR_NAME}")
# 如果路径下没有减压文件
IF(NOT EXISTS "${LOCAL_LIBRARIES_PATH}/${MQTT_DIR_NAME}")
# 输出提示信息准备进行解压缩
MESSAGE(STATUS "cd ${LOCAL_LIBRARIES_PATH} && tar -zxvf ${MQTT_TAR_GZ_NAME}")
# 获取已下载的压缩包大小做基本的判断
FILE(SIZE ${LOCAL_MQTT_TAR_GZ} MQTT_TAR_GZ_SIZE)
MESSAGE(STATUS "${LOCAL_MQTT_TAR_GZ} size is ${MQTT_TAR_GZ_SIZE}")
# 如果压缩包大小为0则输出对应的错误信息
IF(${MQTT_TAR_GZ_SIZE} EQUAL 0)
# 移除损坏压缩包,重置相应的参数
FILE(REMOVE ${LOCAL_MQTT_TAR_GZ})
MESSAGE(FATAL_ERROR "${MQTT_TAR_GZ_SIZE} is zero length. it had been deleted.")
# 下载文件无问题,进入解压路径开始解压压缩包
ELSE()
# 解压文件
EXECUTE_PROCESS(COMMAND tar -zxvf ${LOCAL_MQTT_TAR_GZ} -C ${LOCAL_LIBRARIES_PATH}/
WORKING_DIRECTORY "${LOCAL_LIBRARIES_PATH}"
RESULT_VARIABLE 10
RESULT_VARIABLE RESULT_TAR)
# 如果解压操作返回值为0,说明解压成功
IF(RESULT_TAR MATCHES 0)
MESSAGE(STATUS "tar -zxvf ${LOCAL_MQTT_TAR_GZ} -C ${LOCAL_LIBRARIES_PATH}/")
# 如果解压操作返回值非0,说明解压失败
ELSE()
MESSAGE(FATAL_ERROR "[ERROR] tar -zxvf ${LOCAL_MQTT_TAR_GZ} -C ${LOCAL_LIBRARIES_PATH}/ failed.\n")
ENDIF()
UNSET(RESULT_TAR)
ENDIF()
ENDIF()
ENDIF()
在 CMakeLists 将 mqtt.cmke 使用 INCLUDE 函数 包含进去即可。