boost/config.hpp文件詳解

簡要概述

今天突發奇想想看一下boost/config.hpp的內部實現,以及他有哪些功能。

這個頭文件都有一個類似的結構,先包含一個頭文件,假設爲頭文件1,然後包含這個頭文件中定義的宏。對於頭文件中1中,有大量的#if..#endif,在這些指定的宏塊中定義一個頭文件宏,在這些大量的#if...#end中,頭文件宏有且只會被定義一次。具體的定義詳情在下面進行詳解。

根據上面的思路分析出了,config.hpp文件中主要包含幾個主要的頭文件:關於用戶配置的頭文件(User config)、編譯器配置文件(Compiler config)、C++標準庫配置文件(Standard library)、平臺配置文件(Platform config)、其他零碎的配置文件。接下來描述每個頭文件裏面的大概作用。

用戶配置文件(可控制的)

它是可選配置,可以通過定義BOOST_NO_USER_CONFIG宏來禁止包含用戶配置頭文件。如果沒有禁止的話,那麼這個頭文件就是boost/config/user.hpp。

如果你沒有禁止的話,那麼你可以在boost/config/user.hpp中定義一些關鍵的宏。這個文件中默認一些被註釋的宏,你可以根據需求取消這些註釋,並且定義自己的配置。主要有如下宏:

  • BOOST_COMPILER_CONFIG,這個宏用來指定編譯器配置的hpp文件,他是有一定標準的,他是和編譯器相關的,要定一些通用功能的宏,比如BOOST_SYMBOL_EXPORT,BOOST_SYMBOL_IMPORT,還有一些關於編譯器對於標準的支持,比如是否支持long long類型,是否支持pragma once,是否支持cxx11中的某些特性。。。,詳情請參考:boost/config/compiler/gcc.hpp。一般不要定義這個宏,因爲對於主流的編譯器,他都會有對應的編譯器配置頭文件(這個宏在下面還會介紹到)。一般是對於一種新的編譯器,如果你想讓他支持boost的話,那麼你需要重新定義這個宏,所以說,一般用戶是不會自己定義這個宏的。
  • BOOST_STDLIB_CONFIG,這個宏用來指定標準庫配置文件(hpp文件),主要描述一些標準庫對於某些標準的支持(後面會有詳細介紹的),因爲Boost都主流的標準庫都會自己定義對應這個hpp配置文件,所以一般用戶不用自己定義這個宏,只有一個新的標準庫的作者,可能纔要定義這個宏爲自己標準庫的配置文件。文件樣例可以參考:boost/config/stdlib/libstdcpp3.hpp(他是gnu自帶的標準庫配置文件),boost/config/stdlib/sgi.hpp(著名的sgi標準庫配置文件)。
  • BOOST_PLATFORM_CONFIG,平臺配置文件,普通用戶不用定義,只有新的系統作者,或者某個平臺作者纔會定義這個文件,樣例參考:boost/config/platform/win32.hpp(win32平臺),boost/config/platform/linux.hpp(linux平臺),boost/config/platform/bsd.hpp(bsd平臺)
  • BOOST_NO_COMPILER_CONFIG,定義這個宏可以取消編譯器配置
  • BOOST_NO_STDLIB_CONFIG,定義這個宏可以取消標準庫配置
  • BOOST_NO_PLATFORM_CONFIG,定義這個宏可以取消平臺配置
  • BOOST_NO_CONFIG,定義這個宏可以取消所有的配置
  • 。。。(詳情請參看boost/config/user.hpp)

編譯器配置文件(和每一個不同編譯器對應)

如果用戶定義了:BOOST_COMPILER_CONFIG,或者定義了BOOST_NO_COMPILER_CONFIG,或者定義了BOOST_NO_CONFIG的,這兒boost自己就不會包含編譯器配置文件。如果前面的說的條件都沒有發生,纔會發生下面的事情。

先包含一個頭文件boost/config/select_compiler_config.hpp,他會根據每一個編譯器自己定義的獨一無二的宏(一般vc編譯器會定義:_MSC_VER,gnu編譯器會定義__GNUC__。。。)來定義BOOST_COMPILER_CONFIG(這個宏在用戶配置那兒可以自己定義,只是那兒定義後,這兒就不會再定義了),這個宏指定了編譯器所對應的配置文件的路徑。然後在config.hpp中包含次路徑。

我選擇gnu編譯器所對應的配置文件來簡要描述一下里面定義的內容。

  • BOOST_GCC_VERSION、BOOST_GCC根據gcc的一些相關宏所一定的gcc版本號,至少是5位整數
  • BOOST_HAS_PRAGMA_ONCE 定義它來表明編譯器是否支持#pragma once指定,一般可以在頭文件中定義如下結構:#ifdef BOOST_HAS_PRAGMA_ONCE  #pragma once  #endif
  • BOOST_HAS_LONG_LONG 用來表明是否支持long long類型
  • BOOST_HAS_NRVO 用來表明編譯器是否有命名返回值優化
  • BOOST_HAS_DECLSPEC 用來表明是否支持特別聲明
  • BOOST_SYMBOL_IMPORT 導出簽名
  • BOOST_SYMBOL_EXPORT 導入簽名
  • 當然還有一些其他的工具宏
  • 還有一些對於cxx11的某些特性的支持,如果不支持某些特性,就會定義一些特定的宏,比如:BOOST_NO_CXX11_DECLTYPE表明編譯器不支持decltype操作符,BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS表明編譯器不支持函數魔板默認參數。BOOST_NO_CXX11_RVALUE_REFERENCES表明編譯器不支持右值引用。。。
  • 還有一些對於cxx14標準的支持。詳情請參考此hpp文件
  • BOOST_ATTRIBUTE_UNUSED,指定某些簽名爲未使用屬性
  • BOOST_COMPILER 表明某種編譯器類型的字符串,比如對於gnu編譯器,該字符串爲"GNU C++ version " __VERSION__

簡單小結:BOOST_HAS_PRAGMA_ONCE可以幫助你有選擇的使用#pragma once,BOOST_SYMBOL_IMPORT,BOOST_SYMBOL_EXPORT可以讓你不在忙於記住不同編譯器的導入導出簽名指令。BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS。。。這些類似宏,可以讓你有選擇地使用某些cxx11中的特性而不會出錯。


標準庫配置文件(和每一種標準庫對應)

如果用戶定義了:BOOST_STDLIB_CONFIG,或者定義了BOOST_NO_STDLIB_CONFIG,或者定義了BOOST_NO_CONFIG的,這兒boost自己就不會包含編譯器配置文件。如果前面的說的條件都沒有發生,纔會發生下面的事情。

先包含boost/config/select_stdlib_config.hpp,在這兒文件中和boost/config/select_compiler_config.hpp中結構比較類似,都含有大量的if endif預處理指定,只是這兒的用來作爲條件的宏是標準類型,比如如果使用__SGI_STL_PORT(即sgi標準庫)他會將BOOST_STDLIB_CONFIG設置爲 "boost/config/stdlib/stlport.hpp",如果使用__GLIBCPP__(gnu自帶標準庫),他會將BOOST_STDLIB_CONFIG宏定義爲: "boost/config/stdlib/libstdcpp3.hpp"。然後會包含#include BOOST_STDLIB_CONFIG。

接下來,我會選擇gnu標準庫配置文件(boost/config/stdlib/libstdcpp3.hpp)來進行簡要介紹配置文件裏面的內容:

  • BOOST_GNU_STDLIB 1 定義它來表明使用gnu標準庫
  • BOOST_STDLIB "GNU libstdc++ version " BOOST_STRINGIZE(__GLIBCXX__)定義BOOST_STDLIB 爲對應的標準庫字符串形式
  • BOOST_HAS_THREADS 表明支持線程
  • BOOST_STD_EXTENSION_NAMESPACE __gnu_cxx定義拓展命名空間
  • BOOST_HAS_SLIST 支持單向鏈表(拓展的,不在std庫中)
  • BOOST_HAS_HASH 支持hash表(拓展的,不在std庫中)
  • BOOST_SLIST_HEADER單向列表頭文件,可以用來被包含
  • BOOST_HASH_SET_HEADER <backward/hash_set>  hash表頭文件
  • BOOST_HASH_MAP_HEADER <backward/hash_map> hashmap頭文件
  • BOOST_LIBSTDCXX_VERSION cxx版本,是數字
  • 下面會有一些對於cxx11標準庫的支持,比如:BOOST_NO_CXX11_HDR_FORWARD_LIST,BOOST_NO_CXX11_HDR_INITIALIZER_LIST。。。詳情參考此文件(boost/config/stdlib/libstdcpp3.hpp)。
簡單小結一下:我上面標出的紅色的部分,在cxx11標準沒有出來之前,還是很重要的,但是現實隨着各大編譯器廠商對於cxx11標準的強有力支持中,這些特性已經可有可無了,當然對於那兒仍然在使用老的編譯器進行生產的項目中還是比較重要的。

平臺配置文件(和每一種平臺對應)

如果用戶定義了:BOOST_PLATFORM_CONFIG,或者定義了BOOST_NO_PLATFORM_CONFIG,或者定義了BOOST_NO_CONFIG的,這兒boost自己就不會包含編譯器配置文件。如果前面的說的條件都沒有發生,纔會發生下面的事情。

先包含boost/config/select_platform_config.hpp,結構和上面所描述的兩個hpp文件完全相同(boost/config/select_stdlib_config.hpp、boost/config/select_compiler_config.hpp)。邏輯就是在這個hpp文件中,根據每一種平臺所特別定義的宏來設置平臺配置文件路徑給BOOST_PLATFORM_CONFIG宏,然後在config.hpp文件中包含這個宏。

接下來,我選擇win32平臺所對應的配置文件(boost/config/platform/win32.hpp)進行描述。
  • BOOST_PLATFORM "Win32" 表明了平臺的字符串名稱
  • 如果編譯器支持__declspec(dllexport/import)的話,那麼會在這兒定義BOOST_SYMBOL_EXPORT/IMPORT
  • BOOST_HAS_STDINT_H、BOOST_HAS_DIRENT_H、BOOST_HAS_UNISTD_H表明有某些頭文件
  • BOOST_HAS_GETTIMEOFDAY、BOOST_HAS_WINTHREADS、BOOST_HAS_GETSYSTEMTIMEASFILETIME、BOOST_HAS_THREADEX。。。對於某些特性或者函數的支持
  • BOOST_WINDOWS 1 也可以用來標識win32平臺
  • 還有一些其他的東西,詳情請參閱boost/config/platform/win32.hpp。
簡單總結:利用BOOST_PLATFORM 宏,來打印平臺的名稱,可以使用BOOST_WINDOWS 來作爲#if的條件,來進行選擇編譯。

其他一些補充配置文件(固定的:boost/config/suffix.hpp)(包含了大量常用跨平臺(編譯器)宏

  • 有一些關於編譯器特性支持的宏,比如BOOST_NO_MS_INT64_NUMERIC_LIMITS 表明不支持numeric_limit<__int64>,BOOST_MSVC6_MEMBER_TEMPLATES 用來表明不支持成員函數模板,BOOST_HAS_PARTIAL_STD_ALLOCATOR 表明有一個局部的標準分配器。。。
  • 有一些工具宏:BOOST_USING_STD_MIN/MAX使用std::min/max來計算最小值和最大值,BOOST_STATIC_CONSTANT定義靜態常量
  • BOOST_STRINGIZE(X) 將x轉換爲字符串形式
  • BOOST_JOIN(X, Y) 可以講X和Y鏈接成一個符號比如BOOST_JOIN(My, Dog)會變成MyDog符號
  • 還有一些對於編譯器行爲的控制:比如:BOOST_FORCEINLINE強制內聯,BOOST_NOINLINE阻止函數內聯。BOOST_ALIGNMENT(x)設置內存對其方式
  • 還有一些描述cxx11的是否支持某些特性的宏
  • 詳情請看boost/config/suffix.hpp
簡單總結:這個hpp文件非常非常重要,他幾乎提供了80%以上的跨平臺的可以使用的宏。包含了編譯器對一些基本類型的支持,對於cxx11標準的支持。並且提供了一些統一的控制編譯器行爲的宏,和一些比較方便的工具宏。 值得看一下這個文件裏面所定義的宏,沒準以後就有類似的需求,可以使用裏面的宏來解決問題。

總體總結一下:

1)、以前打開文本編譯器看config.hpp這個頭文件,進入頭文件中,看到一大堆#if..#endif,頭就暈,其實藉助Ide的話,層次就非常清晰了,我使用eclipse,看一下他構建的Index索引數,1分鐘就知道他的結構了。
2)、就包含四個文件,也上面文章的4大部分:用戶配置文件(他只對 編譯器開發人員,標準庫設計人員,平臺設計人員),編譯器配置文件,平臺配置文件,補充文件(工具)。
3)、可以使用config來檢測編譯器對於某些特性的支持,比如是否支持pragma once指定,是否支持long long類型。也可以檢測標準庫是否支持某些cxx11中的標準特性。還可以檢測某個平臺對於某些基本類型的支持,某些函數的支持。可以利用他提供的工具宏來控制各種編譯器的行爲,是真正的編譯器啊!!!!。
4)、列出個人認爲比較有用的宏(基本上都是工具宏):
  • BOOST_SYMBOL_EXPORT
  • BOOST_SYMBOL_IMPORT
  • BOOST_PLATFORM
  • BOOST_STATIC_CONSTANT
  • BOOST_STRINGIZE
  • BOOST_JOIN
  • BOOST_FORCEINLINE
  • BOOST_NOINLINE
  • BOOST_ALIGNMENT
  • 。。。
開通CSDN賬號那麼久,還是第一次寫博客。寫他的目的很簡單,就是做一個簡單小結吧,以後忘記的時候,還能回過頭來看看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章