工程描述
1、cmake 提供的 FindCURL 模块的使用
2、基于自己实现的libhello共享库,编写一个 FindHello.cmake模块
cmake 模块介绍
系统中提供了其他各种模块,一般情况需要使用INCLUDE指令显式的调用,FIND_PACKAGE指令是一
个特例,可以直接调用预定义的模块。其实使用纯粹依靠cmake 本身提供的基本指令来管理工程是一件非常复杂的事情,所以,cmake 设计成了可扩展的架构,可以通过编写一些通用的模块来扩展cmake。
对于系统预定义的Find<name>.cmake模块,使用方法一般如上例所示:
每一个模块都会定义以下几个变量
• <name>_FOUND
• <name>_INCLUDE_DIR or <name>_INCLUDES
• <name>_LIBRARY or <name>_LIBRARIES
你可以通过_FOUND来判断模块是否被找到,如果没有找到,按照工程的需要关闭
某些特性、给出提醒或者中止编译,下面的例子就是报出致命错误并终止构建。
如果<name>_FOUND为真,则将<name>_INCLUDE_DIR 加入INCLUDE_DIRECTORIES,
将<name>_LIBRARY 加入 TARGET_LINK_LIBRARIES中。
使用系统预定义好的FindCURL模块
工程结构
1.1 工程目录下CMakeLists.txt
# 指定工程名称
PROJECT(CURLTEST)
# 添加子目录,src下有编译源文件,CMakeLists.txt, 生成的可执行文件在output目录下
ADD_SUBDIRECTORY(src output)
1.2 src目录下的CMakeLists.txt
# 基于main.c生成目标程序curltest
ADD_EXECUTABLE(curltest main.c)
# 不使用FindCURL模块时,需要指定libcurl的头文件、链接库名称、链接路径
# 这里要注意库的信息放在ADD_EXECUTABLE后面,否则cmake报错,亲测。。
#INCLUDE_DIRECTORIES(/usr/include)
#LINK_DIRECTORIES(/usr/lib64)
#TARGET_LINK_LIBRARIES(curltest curl)
# 使用系统预定义的FindCURL模块
FIND_PACKAGE(CURL)
IF(CURL_FOUND)
INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(curltest ${CURL_LIBRARY})
ELSE(CURL_FOUND)
MESSAGE(FATAL_ERROR ”CURL library not found”)
ENDIF(CURL_FOUND)
1.3 src目录下的main.c
/*
功能:这段代码的作用是通过curl取回www.linux-ren.org 的首页并写入/tmp/curl-test
文件中。
*/
#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
FILE *fp;
int write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
int written = fwrite(ptr, size, nmemb, (FILE *)fp);
return written;
}
int main()
{
const char * path = "/tmp/curl-test";
const char * mode = "w";
fp = fopen(path,mode);
curl_global_init(CURL_GLOBAL_ALL);
CURLcode res;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL,"http://www.linux-ren.org");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
1.4 编译目录下执行cmake
1.4 编译完成后编译目录的结构
自定义 FindHello.cmake模块
工程结构
1.1 工程目录下的CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
# 指定工程名称
PROJECT(CURLTEST)
# 设置动态库的生成路径 下面2种语法都可以
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
#SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 生成libhello.so 动态库
SET(LIBHELLO_SRC ${PROJECT_SOURCE_DIR}/src/hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
# 指定工程目录下自定义的 .cmake 模块
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
# 添加子目录,src下有编译源文件,CMakeLists.txt, 生成的可执行文件在output目录下
ADD_SUBDIRECTORY(src output)
1.2 cmake 目录下自定义的FindHELLO模块 FindHELLO.cmake
# 搜索依赖库的头文件和依赖库的路径
FIND_PATH(HELLO_INCLUDE_DIR NAMES hello.h PATHS ${PROJECT_SOURCE_DIR}/include)
FIND_LIBRARY(HELLO_LIBRARY NAMES hello PATHS ${PROJECT_SOURCE_DIR}/lib)
# 日志打印 用以调试
MESSAGE(STATUS "include: ${HELLO_INCLUDE_DIR}")
MESSAGE(STATUS "lib: ${HELLO_LIBRARY}")
MESSAGE(STATUS "dir: ${PROJECT_SOURCE_DIR}")
# 设置HELLO_FOUND模块, 在src/CMakeLists.txt 中使用
IF (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
SET(HELLO_FOUND TRUE)
ENDIF (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
IF (HELLO_FOUND)
MESSAGE(STATUS "Found Hello: ${HELLO_LIBRARY}")
ELSE (HELLO_FOUND)
MESSAGE(FATAL_ERROR "Could not find hello library")
ENDIF (HELLO_FOUND)
1.3 src 目录下的CMakeLists.txt
# FIND_PACKAGE(HELLO QUIET) 指定 HELLO_FIND_QUIETLY FindHELLO.cmake中的控制逻辑
FIND_PACKAGE(HELLO)
IF(HELLO_FOUND)
ADD_EXECUTABLE(test main.c)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include)
TARGET_LINK_LIBRARIES(test hello)
ELSE(HELLO_FOUND)
MESSAGE(FATAL_ERROR "hello package not found")
ENDIF(HELLO_FOUND)
1.4 src目录下的main.c
#include <hello.h>
int main()
{
HelloFunc();
return 0;
}
1.5 src 目录下的hello.c
#include "../include/hello.h"
void HelloFunc()
{
printf("Hello World\n");
}
1.6 include 目录下的hello.h
#ifndef HELLO_H
#define HELLO_H
#include <stdio.h>
void HelloFunc();
#endif
1.7 编译目录下执行cmake
1.8 编译完成后的目录结构
问题:这里如果要加入自定义的FindHELLO模块,需要在lib下先生成libhello.so,不然cmake报错,
这里暂时没想到什么好的方法,只是把工程目录下CMakeLists.txt的 src包含 和 自动义FindHELLO模块屏蔽掉先生成libhello.so,然后再恢复编译