Learning CMake Cookbook Chapter02 Part01
平台检测以及与平台相关的代码
不同系统的检测与相关代码
#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}"
)