cmake构建工程

1、两行命令帮你构建输出hello world的vs工程

      为了自动构建工程,需要在源文件所在的最上层目录写一个CMakeLists.txt文件,它是cmake的源文件,也可以看作是cmake的脚本文件,这个文件描述了cmake怎样帮我们自动构建工程。现在我们有一个hello.cpp文件,需要用这个文件来构建一个vs工程,手动的方法就是打开vs,新建一个工程hello,然后把hello.cpp添加到hello工程里面。而有了cmake,只需要在CMakeLists.txt写两行命令,第一行给自己工程命个名hello,第二行hello工程需要的源文件hello.cpp。然后通过下面几个步骤,就可以生成一个vs工程了,生成其它工程的步骤相同,只是在选择目标工程的时候不同。

1.1 编写CMakeLists.txt文件和hello.cpp文件

CMakeLists.txt

project(hello)

add_executable(hello hello.cpp)

hello.cpp

复制代码

#include <stdio.h>

int main (int argc, char *argv[])
{
    printf("hello world!");
    return 0;
}

复制代码

 

1.2 设置路径

 

 

 

 

 

 

 

 

 

 

 

1.3 设置目标工程为vs工程

1.4  产生vs工程

1.5 打开vs工程,编译运行程序

 

2 添加子模块

      对于比较大的工程来说,包含多个子模块是很常见的事,因为通常每个人只是负责他自己的模块。那么怎样将各个模块加入到主工程中呢?首先我们需要使用cmake来创建各个子模块的工程,然后再将这些模块加入到整个工程中。假设现在我们有一个子模块myhello,它提供了一个函数PrintHelloWorld来打印hello world!,主模块hello调用这个函数来打印。首先我们在hello.cpp所在目录创建myhello文件夹,将myhello.cpp和myhello.h放到里面,然后在这个文件夹中创建CMakeLists.txt。这三个文件的具体内容如下:

myhello/myhello.h:

void PrintHelloWorld();

myhello/myhello.cpp

复制代码

#include <stdio.h>

void PrintHelloWorld()
{
    printf("hello world!");
}

复制代码

myhello/CMakeLists.txt

add_library(myhello myhello.cpp)

这个CMakeLists.txt主要是告诉cmake,为myhello创建一个库工程。

hello.cpp

复制代码

#include "myhello/myhello.h"

int main (int argc, char *argv[])
{
    PrintHelloWorld();
    return 0;
}

复制代码

CMakeLists.txt

复制代码

cmake_minimum_required(VERSION 3.5)

project(hello)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)

add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})

复制代码

       add_subdirectory将myhello子工程加入到主工程,target_link_libraries将子模myhello链接到hello中。然后重新cmake下,打开vs就可以编译运行啦。

3 添加可配置的头文件

      cmake可以通过可配置的头文件来产生实际的头文件,如下面的可配置头文件hello.h.in,里面@@引用的变量可以通过CMakeLists.txt来设置,最后通过cmake来替换hello.h.in文件中的变量并生成hello.h内容。

hello.h.in

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@

CMakeLists.txt

复制代码

cmake_minimum_required(VERSION 3.5)

project(hello)

include_directories("${PROJECT_BINARY_DIR}")
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)
configure_file(
    "${PROJECT_SOURCE_DIR}/hello.h.in"
    "${PROJECT_BINARY_DIR}/hello.h"
)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)


add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})

复制代码

上面加红的命令主要用来设置hello.h.in中的两个变量,并且让cmake生成hello.h文件。生成的hello.h如下:

hello.h

#define VERSION_MAJOR 1
#define VERSION_MINOR 0

再修改下hello.cpp文件使用这两个变量,

hello.cpp

复制代码

#include "myhello/myhello.h"
#include "hello.h"
#include <stdio.h>

int main (int argc, char *argv[])
{
    printf("version:%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
    PrintHelloWorld();
    return 0;
}

复制代码

打开vs工程,编译运行输出者两个变量的值。这样就可以通过在CMakeLists.txt中设置变量的内容来动态修改.h文件,增加了代码的灵活性。

 

4 检测系统是否有支持工程需要的函数

      对于跨平台的工程来说,检查系统是否支持某些特性是很有必要的,这样程序中就可以通过系统的特性来选择具体执行哪些代码。其中检查是否支持某些函数是我们经常要做的事情,如epoll函数,可能有的linux系统就不支持,对于不支持的系统我们只能用poll来替代等。在cmake中检查系统是否支持某个函数也很简单,先包含一个CheckFunctionExists库,然后使用check_function_exists来判断就行了。

CMakeLists.txt

复制代码

cmake_minimum_required(VERSION 3.5)

project(hello)

include (CheckFunctionExists)
check_function_exists (printf HAVE_PRINTF)

include_directories("${PROJECT_BINARY_DIR}")
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)
configure_file(
    "${PROJECT_SOURCE_DIR}/hello.h.in"
    "${PROJECT_BINARY_DIR}/hello.h"
)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)


add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})

复制代码

在配置的头文件hello.h.in中加入#cmakedefine HAVE_PRINTF,这样如果系统中有printf函数,最终生成的hello.h中会定义HAVE_PRINTF这个宏,否则不会生成这个宏,在hello.cpp文件中可以根据这个宏来是否定义来判断是否应该使用printf函数。

hello.h.in

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@

#cmakedefine HAVE_PRINTF

hello.cpp

复制代码

#include "myhello/myhello.h"
#include "hello.h"
#include <stdio.h>

int main (int argc, char *argv[])
{
#ifdef HAVE_PRINTF
    printf("version:%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
#endif
    PrintHelloWorld();
    return 0;
}

复制代码

运行结果:

 

5 配置可选项

有时候代码可能包含了所有平台的模块代码,但是对于特定的目标平台,只需要配置该平台需要模块的代码,而不需要配置其它平台模块的代码。这种需求可以通过cmake的配置可选项来完成,配置可选项就是cmake在生成工程的时候提示你一些选项,根据你的选项来具体选择需要添加到工程中的模块代码。例如我现在需要提高是否使用myhello模块的选项,可以在CMakeLists.txt中加option命令来实现,代码如下:

复制代码

cmake_minimum_required(VERSION 3.5)

project(hello)

include (CheckFunctionExists)
check_function_exists (printf HAVE_PRINTF)

include_directories("${PROJECT_BINARY_DIR}")
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)

option (USE_MYHELLO 
        "Use myhello" ON) 
        
configure_file(
    "${PROJECT_SOURCE_DIR}/hello.h.in"
    "${PROJECT_BINARY_DIR}/hello.h"
)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)


add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})

复制代码

并且在hello.h.in中添加由cmake根据选项来定义USE_MYHELLO宏。

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@

#cmakedefine HAVE_PRINTF
#cmakedefine USE_MYHELLO

这样在运行cmake的时候,会提示我们一些选项来进行选择:

通过USE_MYHELLO是否被选择,cmake来确定是否要在hello.h中定义USE_MYHELLO宏,最终我们可以在hello.cpp中判断USE_MYHELLO宏是否定义来是否使用myhello模块中的PrintHelloWorld函数。

hello.cpp

复制代码

#include "myhello/myhello.h"
#include "hello.h"
#include <stdio.h>

int main (int argc, char *argv[])
{
#ifdef HAVE_PRINTF
    printf("version:%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
#endif
#ifdef USE_MYHELLO
    PrintHelloWorld();
#else
    printf("xx hello world!");
#endif
    return 0;
}

复制代码

最后通过选中或者不选中USE_MYHELLO选择,得到的结果会不同。

选中结果

没选中结果:

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个使用CMake构建C++工程的示例。 我们假设这个工程有如下目录结构: ``` . ├── CMakeLists.txt ├── include │ └── mylib.h ├── src │ ├── main.cpp │ └── mylib.cpp └── test ├── CMakeLists.txt └── mylib_test.cpp ``` 其中: - `include` 目录包含头文件 `mylib.h` - `src` 目录包含源文件 `main.cpp` 和 `mylib.cpp` - `test` 目录包含测试代码 `mylib_test.cpp` 下面是 `CMakeLists.txt` 文件的内容: ```cmake # 设置 CMake 最低版本需求 cmake_minimum_required(VERSION 3.10) # 设置项目名称和版本号 project(myproject VERSION 1.0) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) # 添加一个库 target,包含 mylib.cpp 和 mylib.h add_library(mylib src/mylib.cpp include/mylib.h) # 添加一个可执行文件 target,包含 main.cpp,以及 mylib 库 add_executable(myapp src/main.cpp) target_link_libraries(myapp PRIVATE mylib) # 添加一个测试 target,包含 mylib_test.cpp,以及 mylib 库 enable_testing() find_package(GTest REQUIRED) add_executable(mylib_test test/mylib_test.cpp) target_link_libraries(mylib_test PRIVATE mylib GTest::GTest GTest::Main) add_test(NAME mylib_test COMMAND mylib_test) ``` 其中: - `cmake_minimum_required(VERSION 3.10)` 声明了本工程需要 CMake 最低版本 3.10。 - `project(myproject VERSION 1.0)` 声明了本工程的名称和版本号。 - `set(CMAKE_CXX_STANDARD 11)` 设置了 C++ 标准为 C++11。 - `add_library(mylib src/mylib.cpp include/mylib.h)` 添加了一个名为 `mylib` 的库 target,包含 `mylib.cpp` 和 `mylib.h`。 - `add_executable(myapp src/main.cpp)` 添加了一个名为 `myapp` 的可执行文件 target,包含 `main.cpp` 和 `mylib` 库。 - `enable_testing()` 启用了测试功能。 - `find_package(GTest REQUIRED)` 查找 Google Test 库。 - `add_executable(mylib_test test/mylib_test.cpp)` 添加了一个名为 `mylib_test` 的测试 target,包含 `mylib_test.cpp` 和 `mylib` 库。 - `target_link_libraries(mylib_test PRIVATE mylib GTest::GTest GTest::Main)` 将 `mylib` 和 `GTest` 库链接到 `mylib_test` 中。 - `add_test(NAME mylib_test COMMAND mylib_test)` 添加了一个名为 `mylib_test` 的测试。 现在你可以使用以下命令构建和运行工程: ```bash mkdir build cd build cmake .. make ./myapp ctest ``` `make` 命令将编译所有 target,并生成可执行文件和库文件。`./myapp` 命令将运行 `myapp` 可执行文件。`ctest` 命令将运行所有测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值