CMake
一、单个源文件的编译
//main.c
#incldue<stdio.h>
int main()
{
printf("Hello World!/n");
return 0;
}
在main.c相同目录下再编写一个CMakeLists.txt文件,内容如下:
project(HELLO)
set(SRC_LIST main.c)
add_executable(hello ${SRC_LIST})
同时,在相同目录下创建一个build子文件夹,用来进行外部编译(为什么这么做?兄弟,看后面就知道了)
进入build文件夹,调用cmake:
$ cmake ..
$ make
执行完编译命令之后,会在build文件中生成一系列文件,其中最重要的是一个名叫hello的可执行文件。
$ ./hello
继续调用该文件即可看到hello world!
当前的目录结构:
+-- main.c
+-- CMakeLists.txt
+-- /build
+--hello.exe
现在来看一下之前CMakeLists.txt中的内容:
project(HELLO)
set(SRC_LIST main.c)
add_executable(hello ${SRC_LIST})
第一行的project不是强制性的,但是最好始终都加上。
同时,cmake会自动定义两个变量:
PROJECT_BINARY_DIR
PROJECT_SOURCE_DIR
如果不做特殊声明,则这两个变量是相等的。可以通过语句:
message(“This is source dir :” ${PROJECT_SOURCE_DIR})
来显示PROJECT_SOURCE_DIR的默认目录。
使用
使用命令用来设置变量。
使用xecutable**则告诉cmake生成一个可执行文使用
二、多文件编译
通常来说,一个大型项目不会只有一个main.c文件,还会包含各种头文件,以及库文件。
现在将原来的main.c拆分成三个文件
//hello.h 头文件
void hello(const char * name);
//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()
{
hello("World!");
return 0;
}
然后准备CMakeLists.txt文件
project(HELLO)
set(SRC_LIST main.c)
message("This is PROJECT_BINARY_DIR :" ${PROJECT_BINARY_DIR})
message("This is PROJECT_SOURCE_DIR :" ${PROJECT_SOURCE_DIR})
add_executable(hello ${SRC_LIST})
按照之前的编译命令,同样在build中调用cmake。很简单,没什么特别的。
这时整个工程的目录结构变成了:
+-- main.c
+-- hello.h
+-- hello.c
+-- /build
+-- 中间产物
+-- hello.exe
想象一下,如果没有创建build子文件夹,直接在根部目下进行内部编译,编译之后生成的各种奇奇怪怪的文件将会淹没自己的源代码。
三、生成一个静态库,链接该库
现在将hello.c生成一个静态库。
修改CMakeLists.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_libraties(hello libhello)
相比之前,添加了一个新的目标libhello,并将其链接到hello.exe
同样在build目录中进行编译
现在的目录结构变为
+-- main.c
+-- hello.h
+-- hello.c
+-- CMakeLists.txt
+-- /build
+-- 中间产物
+-- hello.exe
+-- libhello.lib
四、将源文件、库文件、头文件放在不同的文件夹中
现在为根目录下的源文件、头文件以及库文件建立文件夹,使之看起来更像一个工程。这时需要为每一个文件夹都配置一个CMakeLists.txt文件。
为各个源代码创建文件夹之后的工程目录如下:
+-- CMakeLists.txt
+-- /src
+-- main.c
+-- CMakeLists.txt
+-- /libhello
+-- hello.c
+-- hello.h
+-- CMakeLists.txt
+-- /build
根目录下的CMakeLists.txt文件修改为:
project(HELLO)
add_subdirectory(src bin)
add_subdirectory(libhello lib)
src中的CMakeLists.txt
include_directories(${PROJECT_SOURCE_DIR/libhello})
set(APP_SRC main.c)
add_executable(hello ${APP_SRC})
target_link_libraries(hello libhello)
libhello中的CMakeLists.txt
set(LIB_SRC hello.c)
add_library(libhello ${LIB_SRC})
set_target_propeties(libhello PROPERTIES OUTPUT_NAME "hello")
在build目录中调用cmake,可以得到:
+-- /build
+-- /binhttps://blog.csdn.net/uxyheaven/article/details/49253757
+-- hello.exe
+-- 中间产物
+-- /lib
+-- hello.lib
+-- 中间产物
为了让bin、lib目录中只有.exe与.lib文件,进行如下修改:
src文件夹下的CMakeLists.txt:
include_directories(${PROJECT_SOURCE_DIR}/libhello)
set(APP_SRC main.c)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}\bin)
add_executable(hello ${APP_SRC})
hellolib下的CMakeLists.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")
五、使用动态库
修改头文件为:
对
对_
对_
#if defined _WIN32
#if LIBHELLO_BUILD
#define LIBHELLO_API_declspec(dllexport)
#else
#define LIBHELLO_API_declspec(dllimport)
#endif
#else
#define LIBHELLO_API
#endif对
LI对d hello(const char * name);
#endif对
修改libhello下的CMakeLists.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基本语法与命令
通过以上例子可以了解cmake的基本使用。下面讲解一下语法和常用命令。
简单语法
- 注释
- 命令语法
command(arg1 arg2 …) - 控制流结构
- 正则表达式
部分常用命令
INCLUDE_DIRECTORIES(“dir1” “dir2”…)
头文件路径LINK_DIRECTORIES(“dir1” “dir2”)
库文件路径ADD_LIBRARY( [name] [STATIC|SHARED|MODULE] [source1] [source2 …])
变量
工程路径:
工程的顶层目录
CMAKE_SOURCE_DIR
PROJECT_SOURCE_DIR
projectname_SOURCE_DIR
工程编译发生的目录
CMAKE_BINARY_DIR
PROJECT_BINARY_DIR
projectname——BINARY_DIR
如果是in source编译,则与工程的顶级目录相同,如果是out of source编译,则指得是工程编译发生的目录