cmake笔记

注:cmake .   当前文件夹(一个点)

    cmake .. 父目录(两个点)编程

例子一

一个经典的C程序,如何用cmake来进行构建程序呢?windows

//main.c
#include <stdio.h>
int main(void) { printf("Hello World!/n"); return 0; }

编写一个 CMakeList.txt 文件(可看作cmake的工程文件):ui

project(HELLO)
set(SRC_LIST main.c)
add_executable(hello ${SRC_LIST})

而后,创建一个任意目录(好比本目录下建立一个build子目录),在该build目录下调用cmakespa

  • 注意:为了简单起见,咱们从一开始就采用cmake的 out-of-source 方式来构建(即生成中间产物与源代码分离),并始终坚持这种方法,这也就是此处为何单首创建一个目录,而后在该目录下执行 cmake 的缘由
cmake .. -G"NMake Makefiles"
nmake

或者code

cmake .. -G"MinGW Makefiles"
make

便可生成可执行程序 hello(.exe)blog

目录结构get

+
| 
+--- main.c
+--- CMakeList.txt
|
/--+ build/
   |
   +--- hello.exe

cmake 真的不太好用哈,使用cmake的过程,自己也就是一个编程的过程,只有多练才行。it

咱们先看看:前面提到的这些都是什么呢?io

CMakeList.txt

第一行 project 不是强制性的,但最好始终都加上。这一行会引入两个变量table

  • HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR

同时,cmake自动定义了两个等价的变量

  • PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR

由于是out-of-source方式构建,因此咱们要时刻区分这两个变量对应的目录

能够经过message来输出变量的值

message(${PROJECT_SOURCE_DIR})

set 命令用来设置变量

add_exectuable 告诉工程生成一个可执行文件。

add_library 则告诉生成一个库文件。

  • 注意:CMakeList.txt 文件中,命令名字是不区分大小写的,而参数和变量是大小写相关的。

cmake命令

cmake 命令后跟一个路径(..),用来指出 CMakeList.txt 所在的位置。

因为系统中可能有多套构建环境,咱们能够经过-G来制定生成哪一种工程文件,经过 cmake -h 可获得详细信息。

要显示执行构建过程当中详细的信息(好比为了获得更详细的出错信息),能够在CMakeList.txt内加入:SET( CMAKE_VERBOSE_MAKEFILE on )

或者执行make时

  • $ make VERBOSE=1

或者

  • $ export VERBOSE=1
    $ make

例子二

一个源文件的例子一彷佛没什么意思,拆成3个文件再试试看:

  • hello.h 头文件
#ifndef DBZHANG_HELLO_
#define DBZHANG_HELLO_
void hello(const char* name);
#endif //DBZHANG_HELLO_
  • hello.c
#include <stdio.h>
#include "hello.h"

void hello(const char * name)
{
        printf ("Hello %s!/n", name);
}
  • main.c
#include "hello.h"

int main(void)
{
    hello("World");
    return 0;
}
  • 而后准备好CMakeList.txt 文件
project(HELLO)
set(SRC_LIST main.c hello.c)
add_executable(hello ${SRC_LIST})

执行cmake的过程同上,目录结构

+
| 
+--- main.c
+--- hello.h
+--- hello.c
+--- CMakeList.txt
|
/--+ build/
   |
   +--- hello.exe

例子很简单,没什么可说的。

例子三

接前面的例子,咱们将 hello.c 生成一个库,而后再使用会怎么样?

改写一下前面的CMakeList.txt文件试试:

project(HELLO)
set(LIB_SRC hello.c)
set(APP_SRC main.c)
add_library(libhello ${LIB_SRC})
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)

和前面相比,咱们添加了一个新的目标 libhello,并将其连接进hello程序

而后想前面同样,运行cmake,获得

+
| 
+--- main.c
+--- hello.h
+--- hello.c
+--- CMakeList.txt
|
/--+ build/
   |
   +--- hello.exe
   +--- libhello.lib

里面有一点不爽,对不?

  • 由于个人可执行程序(add_executable)占据了 hello 这个名字,因此 add_library 就不能使用这个名字了
  • 而后,咱们去了个libhello 的名字,这将致使生成的库为 libhello.lib(或 liblibhello.a),很不爽
  • 想生成 hello.lib(或libhello.a) 怎么办?

添加一行

set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

就能够了

例子四

在前面,咱们成功地使用了库,但是源代码放在同一个路径下,仍是不太正规,怎么办呢?分开放呗

咱们期待是这样一种结构

+
|
+--- CMakeList.txt
+--+ src/
|  |
|  +--- main.c
|  /--- CMakeList.txt
|
+--+ libhello/
|  |
|  +--- hello.h
|  +--- hello.c
|  /--- CMakeList.txt
|
/--+ build/

哇,如今须要3个CMakeList.txt 文件了,每一个源文件目录都须要一个,还好,每个都不是太复杂

  • 顶层的CMakeList.txt 文件
project(HELLO)
add_subdirectory(src)
add_subdirectory(libhello)
  • src 中的 CMakeList.txt 文件
include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(APP_SRC main.c)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)
  • libhello 中的 CMakeList.txt 文件
set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

恩,和前面同样,创建一个build目录,在其内运行cmake,而后能够获得

  • build/src/hello.exe
  • build/libhello/hello.lib

回头看看,此次多了点什么,顶层的 CMakeList.txt 文件中使用 add_subdirectory 告诉cmake去子目录寻找新的CMakeList.txt 子文件

在 src 的 CMakeList.txt 文件中,新增长了include_directories,用来指明头文件所在的路径。

例子五

前面仍是有一点不爽:若是想让可执行文件在 bin 目录,库文件在 lib 目录怎么办?

就像下面显示的同样:

   + build/
   |
   +--+ bin/
   |  |
   |  /--- hello.exe
   |
   /--+ lib/
      |
      /--- hello.lib
  • 一种办法:修改顶级的 CMakeList.txt 文件
project(HELLO)
add_subdirectory(src bin)
add_subdirectory(libhello lib)

不是build中的目录默认和源代码中结构同样么,咱们能够指定其对应的目录在build中的名字。

这样一来:build/src 就成了 build/bin 了,但是除了 hello.exe,中间产物也进来了。还不是咱们最想要的。

  • 另外一种方法:不修改顶级的文件,修改其余两个文件

src/CMakeList.txt 文件

include_directories(${PROJECT_SOURCE_DIR}/libhello)
#link_directories(${PROJECT_BINARY_DIR}/lib)
set(APP_SRC main.c)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)

 

libhello/CMakeList.txt 文件

set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

 

例子六

在例子三至五中,咱们始终用的静态库,那么用动态库应该更酷一点吧。 试着写一下

若是不考虑windows下,这个例子应该是很简单的,只须要在上个例子的 libhello/CMakeList.txt 文件中的add_library命令中加入一个SHARED参数:

add_library(libhello SHARED ${LIB_SRC})

但是,咱们既然用cmake了,仍是兼顾不一样的平台吧,因而,事情有点复杂:

  • 修改 hello.h 文件
#ifndef DBZHANG_HELLO_
#define DBZHANG_HELLO_

#if defined _WIN32
    #if LIBHELLO_BUILD
        #define LIBHELLO_API __declspec(dllexport)
    #else
        #define LIBHELLO_API __declspec(dllimport)
    #endif
#else
    #define LIBHELLO_API
#endif

LIBHELLO_API void hello(const char* name);

#endif //DBZHANG_HELLO_
  • 修改 libhello/CMakeList.txt 文件
set(LIB_SRC hello.c)
add_definitions("-DLIBHELLO_BUILD")
add_library(libhello SHARED ${LIB_SRC})
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

接下来就跟别的同样

cmake ..

make

相关文章
相关标签/搜索