cmake 学习指南

这篇文章主要介绍如何一步一步自己写cmake文件。

一,内部链接和外部链接

在总文件夹下新建main.c

//main.c
#include<stdio.h>
int main(){
    printf("hello world from t1 main!\n");
    return 0;
}

在同一目录下写好CMakeLists.txt(这个文件很重要,大小写有特殊要求,如果存在多个目录,要在每一个目录下面都要存在一个CMakeLists.txt)

PROJECT(HELLO)#新建项目
SET(SRC_LIST main.c)#把文件名指定为特殊字符 如果有多个,那么SET(SRC_LIST main.c t1.c t2.c)-->基本语法:参数之间用空格分开即可。
#指令是大小写无关的,但是参数和变量是大小写相关的。
MESSAGE(STATUS "this is BINARY dir" ${PROJECT_BINARY_DIR})#这里默认变量
MESSAGE(STATUS "this is  SOURCE dir" ${PROJECT_SOURCE_DIR})#这里是默认变量
#message 语法:SEND_ERROR:产生错误,生成过程被跳过。
#STATUS:输出前缀为-的信息。FATAL_ERROR:立刻终止cmake过程。
ADD_EXECUTABLE(hello ${SRC_LIST})#添加到编译生成的执行文件
#定义的这个工程会生成一个文件名字为hello的可执行文件
#对于变量的引用,只有在IF的情况下,变量才会被直接引用,其他时候都要加入${}才可以。

接下来输入:

cmake .
make

就生成执行文件.(以上为内部构建,比较冗长,容易生成很多无用的信息)

外部构建
mkdir build
cd build
cmake ..
make 

我们可以在当前目录下获得目标文件hello。最大的好处是对原有工程没有任何影响,所有动作都全部发生在编译目录。
此时默认变量:PROJECT_SOURCE_DIR 依然是工程目录
但是 PROJECT_BINARY_DIR 在外部编译之后从原来的工程目录转化为工程目录/build

二,多文件下的cmake与安装(外部构建)

文件分层:src--工程源码(main.c) doc--工程文档 COPYRIGHT/README 放在根目录 bin--构建后目标文件所在的子目录
安装:我们要把编译得到的内容安装到/tmp/usr/test2 中
src下的main.c文件:

#include<stdio.h>
int main(){
    printf("hello world from t1 main!\n");
    return 0;
}

src下的CMakeList.txt 文件

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
#设定变量的得到的编译执行文件输出到bin文件下。
#如果有编译好的lib文件,那么使用
#SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
#在哪里加入ADD_EXECUTABLE or ADD_LIBRARY,在哪里写这两句话
ADD_EXECUTABLE(hello main.c)
install(TARGETS hello RUNTIME DESTINATION bin)
#安装目标文件(三种类型)可执行文件-RUNTIME 动态库-LIBRARY 静态库-ARCHIVE 
#example:
#INSTALL(TARGETS myrun mylib mystaticlib
#              RUNTIME DESTINATION bin
#              LIBRARY DESTINATION lib
#              ARCHIVE DESTINATION libstatic
#)

根目录下的CMakeList.txt文件

cmake_minimum_required(VERSION 3.5)
#确定最小版本号
PROJECT(HELLO)
install(FILES COPYRIGHT README DESTINATION share/doc/cmake/test2)
#安装普通文件
install(PROGRAMS runhello.sh DESTINATION bin)
#安装非目标文件的可执行程序
install(DIRECTORY doc/ DESTINATION share/doc/cmake/test2)
#安装文件夹
add_subdirectory(src)
#向当前工程添加存放源文件的子目录,并可以指定编译输出的结果
#add_subdirectory(source_dir [binary_dir]) 如果编译输出目录为空,那么就是build下的相同目录

在安装之前,必须要定义安装的位置,否则将会默认为/usr/local
我们使用DCMAKE_INSTALL_PREFIX 定义

cmake  -DCMAKE_INSTALL_PREFIX=/tmp/test2/usr  ..
make 
make install

静态库与动态库的构建

首先建立lib文件夹,写入hello.c 和 hello.h

//hello.c
#include "hello.h"
void HelloFunc(){
    printf("hello world in test3!\n");
}
//hello.h
#ifndef HELLO_H
#define HELLO_H
#include <stdio.h>
void HelloFunc();
#endif

lib下的CMakeLists.txt:

set(LIBHELLO_SRC hello.c)
add_library(hello SHARED ${LIBHELLO_SRC})
#生成共享库
add_library(hello_static STATIC ${LIBHELLO_SRC})
#生成静态库(这里不能重名,否则只能生成一个),不需要写全名
#SHARED 动态库 STATIC 静态库
set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello")
#我希望输出的名字一样,所以要改变静态库的名字
set_target_properties(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
set_target_properties(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
#cmake会在构建新的target时候,尝试清理其他使用这个名字的库,我们要回避这个问题,所以要修改参数
set_target_properties(hello PROPERTIES VERSION 1.2 SOVERSION 1)
#设置动态库版本
get_target_property(OUTPUT_VALUE hello_static OUTPUT_NAME)
#获取输出名字的内容
message(STATUS "this is the hello_static output_name:"${OUTPUT_VALUE})
install(TARGETS hello hello_static 
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib)
#安装静态库和动态库
install(FILES hello.h DESTINATION include/hello)
#安装

主目录下的CMakeList.txt

project(HELLOLIB)
add_subdirectory(lib lib_HTF)
#如果要修改输出位置,可以在add_subdirectory 中设置或者在lib/CMakeList.txt中设置SET(LIBRARY_OUTPUT_PATH ...)中设置。

三,使用外部共享库和头文件

在src文件下写入源文件 main.c :

#include <hello.h>
int main(){
    HelloFunc();
    return 0;
}

编写src/CMakeLists.txt:

include_directories(/tmp/usr/test3/include/hello)
#添加包含目录
link_directories(/tmp/usr/test3/lib)
#添加库目录
add_executable(main hello.c)
#链接执行文件
target_link_libraries(main hello)
#添加执行文件下所需要的以来动态库

编写根目录下的CMakeList.txt

cmake_minimum_required(VERSION 3.5)
#设定cmake版本最小号
PROJECT(NEWHELLO)
EXEC_PROGRAM(ls ARGS "-l" OUTPUT_VARIABLE LS_OUTPUT RETUREN_VALUE LS_RVALUE)
#cmake中处理执行命令,args添加参数,output_variable为输出值,return_value为返回值
IF(NOT LS_RVALUE)
message(STATUS "ls result: "${LS_OUTPUT})
ENDIF(NOT LS_RVALUE)
aux_source_directory(. SRC_LIST)
#作用是发现一个目录下所有的源代码并将列表储存到一个变量中。
IF(NOT SRC_LIST)
message(STATUS "do not find any files")
ENDIF(NOT SRC_LIST)
foreach(F ${SRC_LIST})
    message(${F})
endforeach(F)
#foreach循环 ,使用方法:
#1,foreach(F  ${SRC_LIST})
#2,foreach(VAR RANGE 10)
#3, foreach (loop_var RANGE start stop [step])
add_subdirectory(src)

如果使用find的命令来查找,那么src/CMakeLists.txt 修改为:

#export CMAKE_INCLUDE_PATH=/tmp/usr/test3/include/hello
#export CMAKE_LIBRARY_PATH=/tmp/usr/test3/lib
这个两句都是外部命令,也可以用下面来指定
find_path(myHeader hello.h /tmp/usr/test3/include/hello)
#查找文件位置是否存在
IF(myHeader)
message(STATUS ${myHeader})
include_directories(${myHeader})
ENDIF(myHeader)

find_library(myLib hello /tmp/usr/test3/lib)
查找lib是否存在
IF(myLib)
message(STATUS ${myLib})
ELSEIF(NOT myLib)
MESSAGE(FAULT "libhello not found")
ENDIF(myLib)

add_executable(main hello.c)
target_link_libraries(main ${myLib})
#添加lib,这里应该是绝对路径了

四,cmake常用变量

1,引用方式 {} ,只有在IF情况下才直接用 2,常用变量 CMAKE_BINARY_DIR=PROJECT_BINARY_DIR=<projectname>_BINARY_DIR CMAKE_SOURCE_DIR=PROJECT_SOURCE_DIR=<projectname>_SOURCE_DIR CMAKE_CURRENT_SOURCE_DIR 当前处理的CMakeList所在路径 CMAKE_CURRENT_BINARY_DIR,out-of-source 中指的是target编译路径 3,cmake 调用环境变量ENV{NAME} 可以直接调用环境变量
message(STATUS "home dir: $ENV{HOME}")

五,自定义模块和模块使用

一般使用FIND_PACKAGE(XXX)来使用模块
每一个模块都有这几个变量:
1,<name>_FOUND
2,<name>_INCLUDE_DIR or <name>_INCLUDES
3,<name>_LIBRARY or <name>_LIBRARIES

编写属于自己的FindHello 模块

建立cmake文件夹,编写cmake/FindHELLO.cmake 模块

FIND_PATH(HELLO_INCLUDE_DIR hello.h /tmp/usr/test3/include/hello)
FIND_LIBRARY(HELLO_LIBRARY hello /tmp/usr/test3/lib)
IF(HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
    SET(HELLO_FOUND TRUE)
ELSE(HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
    message(STATUS "include: " ${HELLO_INCLUDE_DIR})
    message(STATUS "lib: " ${HELLO_LIBRARY})
ENDIF(HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
IF(HELLO_FOUND)
    IF(NOT HELLO_FIND_QUIETLY)
#REQUIRED 参数,就是确定共享库是否必须
        message(STATUS "Found Hello: ${HELLO_LIBRARY}")
    ENDIF(NOT HELLO_FIND_QUIETLY)
ELSE(HELLO_FOUND)
    IF(HELLO_FIND_REQUIRED)
        message(FATAL_ERROR "Could not find hello library")
    ELSE(HELLO_FIND_REQUIRED)
        message(STATUS "in find_hello.cmake,we do not find hello lib")
    ENDIF(HELLO_FIND_REQUIRED)
ENDIF(HELLO_FOUND)

定义src/CMakeLists.txt

set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
#注意确定cmake module的路径
FIND_PACKAGE(HELLO)
#这里可以改为 FIND_PACKAGE(HELLO QUIET) or FIND_PACKAGE(HELLO REQUIRED)
IF(HELLO_FOUND)
    ADD_EXECUTABLE(hello main.c)
    include_directories(${HELLO_INCLUDE_DIR})
    target_link_libraries(hello ${HELLO_LIBRARY})
    message(STATUS "include: " ${HELLO_INCLUDE_DIR})
    message(STATUS "lib: " ${HELLO_LIBRARY})
ELSEIF(HELLO_FOUND)
    message("do not find hello!")
ENDIF(HELLO_FOUND)

定义src/main.c

#include<hello.h>
int main(){
    HelloFunc();
    return 0;
}

主目录下的CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(HELLO)
add_subdirectory(src)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容