如何使用Cmake管理项目的跨平台C++应用程序

2023-05-17,

这篇文章给大家分享的是有关如何使用Cmake管理项目的跨平台C++应用程序的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

使用Cmake管理项目的跨平台C++应用程序

MSDN参考文档:https://docs.microsoft.com/zh-cn/cpp/build/cmake-projects-in-visual-studio?view=msvc-160

CMake对照VS参数修改总结:https://blog.csdn.net/xum2008/article/details/7268761?source=1

使用CMake管理项目,再使用标准C++作为开发语言,就可以创建完全跨平台的C++应用程序。

1)创建CMake项目

可以从IDE中创建一个新的cmake项目,也可以打开一个已经存在的cmake项目。

要打开存在的cmake项目,从【文件】【打开】【CMake】导入cmake配置:

新建cmake项目,从新建中选择cmake项目即可。从VS2019的项目解释可以看出,CMake是作为一个跨平台的管理工具存在,而不仅仅是Linux项目;

2)切换到CMake视图,这个很重要,因为默认为文件夹视图,不方便对子项目分别进行生成等操作:

切换到解决方案视图,找到这个按钮,单击一次:

出现选择视图,然后双击选中的视图类型,这里选择CMake目标视图,进入CMake开发视图:

这里就是CMake目标视图,右键单击项目,可以添加新的目标(即添加新的子项目),全部生成,清理等,同样单击某个项目也有类似的操作菜单:

这里解释下CMake缓存的意思:如果选择生成缓存,CMake会解析CMakeLists.txt文件,并生成CMake项目视图;必须这里有exe生成项目,也有dll生成项目,如果清除这些缓存,就只剩下CMakeLists.txt文件了。

需要注意的是,在输出栏需要选择不同的输出来源才能看到CMake过程,大多数默认都是生成输出来源,如果需要了解CMake的过程,可以切换到CMake来源。

3)添加一个名为Common的动态库项目:

//common.h

#pragma once

#ifdef _WIN32
#define COMMON_EXPORT _declspec(dllexport)
#else
#define COMMON_EXPORT
#endif // _WIN32

namespace BGI
{
	namespace Common
	{
		COMMON_EXPORT void add(int v1, int v2);
	}
}
//common.cpp

#include <iostream>
#include <chrono>
#include <thread>
#include "Common.h"

using namespace std;


namespace BGI
{
	namespace Common
	{
		static void threadproc(int* value)
		{
			for (int i = 0; i < 10; i++)
			{
				*value += 1;
				std::this_thread::sleep_for(std::chrono::milliseconds(100));
			}
		}

		void add(int v1, int v2)
		{
			thread t1(threadproc, &v1);
			thread t2(threadproc, &v2);
			t1.join();
			t2.join();
			cout << "Value[0] = " << v1 << endl;
			cout << "Value[1] = " << v2 << endl;
		}
	}
}

添加完成后选择生成试试。需要注意的是,如果要生成Windows下的动态库,还需要生成Common.lib文件,因此需要导出动态库接口:_declspec(dllexport);由于是跨平台项目,Linux项目无法设置导出接口,需要做宏限制。

注意!有时候当我们添加了宏来限制不同平台的宏输出,会发现在选择了Linux-GCC平台之后WIN32宏却被定义了。比如在common.h头文件中,WIN32显示已被定义,但是当你编译到Linux平台时却没有任何问题,甚至还可以调试,只是在某些地方代码和实际的可能对不上。那是因为IntelliSense(VS智能感知功能)没有被更新导致。简单说就是你的VS所在的Windows平台并没有得到最新的目标平台,也就是Linux平台的相关开发环境。找到【工具】【选项】【跨平台】,更新下设置的Linux远程电脑下的IntelliSense,重启一下VS即可。可打开【浏览】功能,找到VS从远程Linux同步过来的相关依赖文件。

4)在主项目上将Common子项目添加到引用,这一步会重新生成CMake缓存:

因为改变了主项目的CMakeLists.txt文件,增加了target_link_libraries(LinuxCmakeTest "Common")这一栏。这是CMake添加引用项目的方式。

5)完善cmake配置项

# CMakeList.txt: 顶层 CMake 项目文件,在此处执行全局配置
# 并包含子项目。
#

#最低cmake版本要求
cmake_minimum_required (VERSION 3.8)

#定义项目名称
project ("LinuxCmakeTest")

#设置C++编译器选项(Linux系统才需要设置)
IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
	MESSAGE(STATUS "Current platform: Linux ")
    add_compile_options(-std=c++11)
    SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
    SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 ")
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Windows")
	MESSAGE(STATUS "Current platform: Windows")
ELSE ()
	MESSAGE(STATUS "Other platform: ${CMAKE_SYSTEM_NAME}")
ENDIF()

#根据编译类型指定不同的库输出路径
IF (CMAKE_BUILD_TYPE MATCHES "Release")
    add_definitions(-DRELEASE -DCPP)
    set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/release)
ELSE()
    add_definitions(-DDEBUG -DCPP)
    set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/debug)
ENDIF()

#将程序输出指定到库输出路径
set(EXECUTABLE_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH})

#将链接库的搜寻目录设置为库输出目录
link_directories(${LIBRARY_OUTPUT_PATH})

#使用链接库相对路径(链接库寻找当前目录)
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TURE)
set(CMAKE_INSTALL_RPATH "$ORIGIN")

#添加当前目录为头文件包含目录(这里可以设置多个包含路径)
include_directories(.)

#添加子目录(自动加载目录下的子项目)
add_subdirectory("Common")
add_subdirectory ("LinuxCmakeTest")

#配置安装选项(设置后才能使用【安装】菜单功能)
install(TARGETS Common DESTINATION LinuxCmakeTest)
install(TARGETS LinuxCmakeTest DESTINATION LinuxCmakeTest)
# CMakeList.txt: LinuxCmakeTest 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)

# 将源代码添加到此项目的可执行文件。
add_executable (LinuxCmakeTest "LinuxCmakeTest.cpp" "LinuxCmakeTest.h")

# 平台差异化设置
IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
	# C++线程在Linux系统需要链接pthread库,使用动态库需要链接dl库
	target_link_libraries(LinuxCmakeTest Common pthread dl)
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Windows")
	target_link_libraries(LinuxCmakeTest Common)
ELSE ()
	MESSAGE(STATUS "Other platform: ${CMAKE_SYSTEM_NAME}")
ENDIF (CMAKE_SYSTEM_NAME MATCHES "Linux")
# CMakeList.txt: Common 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)

add_library(Common SHARED "Common.cpp" "Common.h")
  • 给debug和release指定不同的输出目录;

  • 将dll和exe都输出到同一个目录下,以免exe找不到dll的情况;

  • 将当前CMakeLists.txt文件所在目录设置为搜寻目录,就可以直接使用#include "Common/common.h";

  • 使用add_definitions(-DRELEASE -DCPP)预先定义好需要的宏,就可以在IDE中直接得到宏定义(通过IntelliSense智能感知);

  • 如果需要提供安装功能,添加install命令到CMakeLists.txt文件中,install安装后的文件少了.ink,.pdb,.exp等额外文件;

  • 如果要满足多平台一套代码,免不了需要在cmake中对不同平台做不同的设置,跨平台不是简单说说那么容易!

每次修改CMakeLists.txt文件之后VS都会自动解析,如果该文件很大,解析需要花费的时间也会越长(体验不好!!!)

可以通过CMake设置页面重定向安装目录路径:

到此为止,这个程序已经可以在Windows平台编译并输出结果。但配置到Linux仍需要一些额外的配置才能正确运行。

6)新建Linux平台下的CMake配置

这里选择通用的Linux-GCC-Debug,如果是Release则选择Linux-GCC-Release:

设置远程调试Linux平台:

如果远程没有安装高版本cmake文件,VS会自动提示,可以点击【是】让VS自动帮忙安装一个符合要求的cmake版本:

这里需要注意的是,CentOS默认安装cmake2.8,很旧很旧的版本。使用VS开发Linux至少需要cmake3.8版本以上。

如果一切顺利,应该就可以make成功通过并生成到Linux平台,可以调试运行了。

7)调试代码

利用VS2019调试Linux平台下的Release版本代码没有成功,应该是不行。

Debug模式下设置程序启动参数:

点击【添加调试配置】,会打开一个名叫launch.vs.json的配置文件,在args中配置启动参数即可,可以写成一行,也可以写成多行:

如果Linux平台安装了gdbserver的话(参考文档一的相关说明),可以更改gdb调试方式:"debuggerConfiguration": "gdbserver"为gdbserver类型。

8)其他一些注意事项(专门填坑)

  • Linux平台设置最好使用root账号,否则可能会出现一些和cmake,gcc相关的报错;

  • Linux平台要安装最新的cmake和gcc,cmake至少要3.8以上,gcc最好是6.0以上,可以通过cmake --version和gcc/g++ --version命令查看;

  • WIN32宏或者其他宏显示不正确,通常重新刷新下IntelliSense就正常了;

  • 如果使用【ln -f -s gcc新版 /usr/bin】配置重定向软链接的方式安装新版本g++,在编译时可能会出现“ GLIBCXX_3.4.20' not found ”的错误提示,那是因为使用了软链接重定向新版本gcc之后,相对应的lib/lib64库还未覆盖,仍然链接到了旧版本gcc中,参考下面的连接来处理https://my.oschina.net/u/3489228/blog/3082214 或者 https://blog.csdn.net/qingtingmeng/article/details/49863841

  • VS2019会将用户的平台配置写入到CMakeSettings.json文件中,可以直接修改这里的内容改变输出路径。参考MSDN上的说明:https://docs.microsoft.com/zh-cn/cpp/build/cmakesettings-reference?view=msvc-160 

  • 默认编译和安装的时候都会将原来的文件全部删除,如果不想这样做,尤其是安装了很多必要文件的时候,可以修改配置:将--delete --delete-excluded参数删除,只保留-t参数。

感谢各位的阅读!关于“如何使用Cmake管理项目的跨平台C++应用程序”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

《如何使用Cmake管理项目的跨平台C++应用程序.doc》

下载本文的Word格式文档,以方便收藏与打印。