【Learning CMake Cookbook】第二章--第一部分

平台检测以及与平台相关的代码

不同系统的检测与相关代码

#include <cstdlib>
#include <iostream>
#include <string>

std::string say_hello() {
#ifdef IS_WINDOWS
  return std::string("Hello from Windows!");
#elif IS_LINUX //这种叫做条件编译
  return std::string("Hello from Linux!");
#elif IS_MACOS
  return std::string("Hello from macOS!");
#else
  return std::string("Hello from an unknown system!");
#endif
}

int main() {
  std::cout << say_hello() << std::endl;
  return EXIT_SUCCESS;
}

注意,以上我们对代码段进行条件编译,通过对是否定义了IS_WINDOWS、IS_LINUX、IS_MACOS决定是否对对应的语句段进行编译。并且输出不同的结果。

但是我们并没有在cpp文件中写入相应的定义,这部分定义我们在CMakeLists中可以找到。如下:

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(recipe-02 LANGUAGES CXX)

add_executable(hello-world hello-world.cpp)

if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
  target_compile_definitions(hello-world PUBLIC "IS_LINUX")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  target_compile_definitions(hello-world PUBLIC "IS_MACOS")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  target_compile_definitions(hello-world PUBLIC "IS_WINDOWS")
endif()

// target_compile_definitions() 指令。
// 就相当于在编译的过程中为将要编译的工程添加了一个宏定义。
// 在这个工程中用于处理不同平台下的不同代码,当然也可以有多种其他形式的使用方法。

以上通过在CMakeLists中使用与系统绑定的CMAKE_SYSTEM_NAME变量自动识别出系统环境,进而使用target_compile_definitions()为要编译的工程添加编译条件的宏定义。

不同编译器的检测与相关代码

#include <cstdlib>
#include <iostream>
#include <string>

std::string say_hello() {
#ifdef IS_INTEL_CXX_COMPILER
  // only compiled when Intel compiler is selected
  // such compiler will not compile the other branches
  return std::string("Hello Intel compiler!");
#elif IS_GNU_CXX_COMPILER
  // only compiled when GNU compiler is selected
  // such compiler will not compile the other branches
  return std::string("Hello GNU compiler!");
#elif IS_PGI_CXX_COMPILER
  // etc.
  return std::string("Hello PGI compiler!");
#elif IS_XL_CXX_COMPILER
  return std::string("Hello XL compiler!");
#else
  return std::string("Hello unknown compiler - have we met before?");
#endif
}

int main() {
  std::cout << say_hello() << std::endl;
  std::cout << "compiler name is " COMPILER_NAME << std::endl;
  return EXIT_SUCCESS;
}

同样的,我们这次检测的是编译器而非系统环境,根据编译器的不同种类定义不同的宏定义,执行不同的条件编译,输出不同的打印信息,CMakeLists文件如下:

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(recipe-03 LANGUAGES CXX)

add_executable(hello-world hello-world.cpp)

target_compile_definitions(hello-world PUBLIC "COMPILER_NAME=\"${CMAKE_CXX_COMPILER_ID}\"")
# 通过这里给COMPILER_NAME赋值, 使得对源文件和CmakeLists文件均可见
// 联系上下文,注意这里的COMPILER_NAME,实际映射到工程中的define, 而其宏定义的值由CMAKE_CXX_COMPILER_ID变量决定。
// 这样就建立了CMakeLists到源文件的映射关系,使得上文中的main函数可以打印出对应的COMPILER_NAME。


if(CMAKE_CXX_COMPILER_ID MATCHES Intel)
  target_compile_definitions(hello-world PUBLIC "IS_INTEL_CXX_COMPILER")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES GNU)
  target_compile_definitions(hello-world PUBLIC "IS_GNU_CXX_COMPILER")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES PGI)
  target_compile_definitions(hello-world PUBLIC "IS_PGI_CXX_COMPILER")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES XL)
  target_compile_definitions(hello-world PUBLIC "IS_XL_CXX_COMPILER")
endif()

不同处理器构架的检测与相关代码

大同小异,这里是处理器构架相关的检测与条件编译,看一下代码以及其中的注释即可,了解工程源码与CMakeLists中变量/宏定义之间的对应关系。

#include <cstdlib>
#include <iostream>
#include <string>

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)

std::string say_hello() {
  std::string arch_info(TOSTRING(ARCHITECTURE));
  arch_info += std::string(" architecture. ");
#ifdef IS_32_BIT_ARCH
  return arch_info + std::string("Compiled on a 32 bit host processor.");
#elif IS_64_BIT_ARCH
  return arch_info + std::string("Compiled on a 64 bit host processor.");
#else
  return arch_info + std::string("Neither 32 nor 64 bit, puzzling ...");
#endif
}

int main() {
  std::cout << say_hello() << std::endl;
  return EXIT_SUCCESS;
}
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(recipe-04 LANGUAGES CXX)

add_executable(arch-dependent arch-dependent.cpp)

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
// 通过 CMAKE_SIZEOF_VOID_P 这个参数检测void*是多少位的,从而判断构架:告知用户CPU是32位还是64位的
  target_compile_definitions(arch-dependent PUBLIC "IS_64_BIT_ARCH")
  // 相当于源码中 #define IS_64_BIT_ARCH
  message(STATUS "Target is 64 bits")
else()
  target_compile_definitions(arch-dependent PUBLIC "IS_32_BIT_ARCH")
  // 相当于源码中 #define IS_32_BIT_ARCH
  message(STATUS "Target is 32 bits")
endif()


// CMAKE_HOST_SYSTEM_PROCESSOR 这个参数告诉我们处理器的构架:我们这里应该是x86_64构架的
// 注意这里只是在cmake的时候使用massage语句输出信息对用户进行提醒,对实际编译结果没有什么效果
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "i386")
  message(STATUS "i386 architecture detected")
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "i686")
  message(STATUS "i686 architecture detected")
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86_64")
  message(STATUS "x86_64 architecture detected")
else()
  message(STATUS "host processor architecture is unknown")
endif()
// 其他的构架还有 AMD64 等
target_compile_definitions(arch-dependent
  PUBLIC "ARCHITECTURE=${CMAKE_HOST_SYSTEM_PROCESSOR}"
  )

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值