通過分析一個非常簡單的函數:resize_file,來初步瞭解boost的源代碼佈局。
filesystem庫是需要編譯成庫才能使用的。要使用filesystem庫,首先需要包含頭文件boost/filesystem.hpp,然後需要鏈接庫文件,windows下的 vs2010比較智能,能夠自動鏈接,linux則需要指定鏈接庫文件libboost_filesystem.a,在這裏vs2010用到的庫文件是boost_filesystem-vc100-mt-1_44.lib。
boost/filesystem.hpp是一個純粹引用其他頭文件的頭文件。代碼如下:
#ifndef BOOST_FILESYSTEM_FILESYSTEM_HPP
#define BOOST_FILESYSTEM_FILESYSTEM_HPP
# if defined(BOOST_FILESYSTEM_VERSION) \
&& BOOST_FILESYSTEM_VERSION != 2 && BOOST_FILESYSTEM_VERSION != 3
# error BOOST_FILESYSTEM_VERSION defined, but not as 2 or 3
# endif
# if !defined(BOOST_FILESYSTEM_VERSION)
# define BOOST_FILESYSTEM_VERSION 2
# endif
#if BOOST_FILESYSTEM_VERSION == 2
# include <boost/filesystem/v2/config.hpp>
# include <boost/filesystem/v2/path.hpp>
# include <boost/filesystem/v2/operations.hpp>
# include <boost/filesystem/v2/convenience.hpp>
# else
# include <boost/filesystem/v3/config.hpp>
# include <boost/filesystem/v3/path.hpp>
# include <boost/filesystem/v3/operations.hpp>
# include <boost/filesystem/v3/convenience.hpp>
# endif
#endif // BOOST_FILESYSTEM_FILESYSTEM_HPP
在這裏可以看到boost 1_44_0的filesystem庫包含了兩個版本,V2和V3,其中只有V3版本纔有resize_file接口,所以要使用resize_file必須先在自己的工程中定義宏:
#define BOOST_FILESYSTEM_VERSION
在boost\filesystem\v3\operations.hpp 中:
inline // name suggested by Scott McMurray
void resize_file(const path& p, uintmax_t size) {detail::resize_file(p, size);}
inline
void resize_file(const path& p, uintmax_t size, system::error_code& ec)
{detail::resize_file(p, size, &ec);}
然後再看detail命名空間的resize_file,它的實現則在libs\filesystem\v3\src\operations.cpp
進入到這個文件中看到如下代碼:
BOOST_FILESYSTEM_DECL
void resize_file(const path& p, uintmax_t size, system::error_code* ec)
{
error(!BOOST_RESIZE_FILE(p.c_str(), size), p, ec, "boost::filesystem::resize_file");
}
這裏定義了一個BOOST_RESIZE_FILE的宏,再看operations.cpp中代碼片段:
# if defined(BOOST_POSIX_API)
...
# define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0)
...
# else // BOOST_WINDOWS_API
...
# define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0)
...
# endif
這裏根據宏BOOST_POSIX_API來區分支持posix api的操作系統和windows操作系統。
注:POSIX 表示可移植操作系統接口(Portable Operating System Interface) ,一般類unix內核的操作系統都支持,例如unix,linux,freebsd,mac。
其中類unix平臺的實現比較簡單,直接調用truncate函數。windows下稍微複雜,調用了自定義的resize_file_api函數,再進一步分析代碼:
BOOL resize_file_api(const wchar_t* p, boost::uintmax_t size)
{
HANDLE handle = CreateFileW(p, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
LARGE_INTEGER sz;
sz.QuadPart = size;
return handle != INVALID_HANDLE_VALUE
&& ::SetFilePointerEx(handle, sz, 0, FILE_BEGIN)
&& ::SetEndOfFile(handle)
&& ::CloseHandle(handle);
}
終於看到windows下的resize_file的廬山真面目了,這裏調用了4個windows api函數才實現了函數功能。
順便也可以瞭解下,有的boost庫的大部分接口不用事先編譯成庫,只需包含頭文件就可以直接使用,比如data_time庫,而有的庫必需先編譯成庫文件,然後纔可以使用,比如filesystem庫。這是因爲 data_time庫的大部分接口實現都在boost_1_44_0\boost\date_time目錄下的頭文件中,而filesystem庫除了boost_1_44_0\boost\目錄下的頭文件實現了部分接口外,其他大部分都放在libs\filesystem\v3\src\目錄下。這個目錄下的文件都是cpp文件,正常情況下是需要編譯成庫才能使用的。當然特殊情況下也可以把這些cpp文件包含到自己的工程中去,直接在自己的工程中編譯實現,這樣的好處是完全跨平臺(因爲都不用事先編譯成相應平臺的庫了)但這樣也會付出代價,編譯時間會很長、工程的代碼量非常大且很多接口是用不上的。