cpp_include_paths.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*=============================================================================
  2. Boost.Wave: A Standard compliant C++ preprocessor library
  3. http://www.boost.org/
  4. Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
  5. Software License, Version 1.0. (See accompanying file
  6. LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #if !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED)
  9. #define CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED
  10. #include <string>
  11. #include <list>
  12. #include <utility>
  13. #include <boost/assert.hpp>
  14. #include <boost/wave/wave_config.hpp>
  15. #include <boost/wave/util/filesystem_compatibility.hpp>
  16. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  17. #include <boost/multi_index_container.hpp>
  18. #include <boost/multi_index/member.hpp>
  19. #include <boost/multi_index/ordered_index.hpp>
  20. #endif
  21. #if BOOST_WAVE_SERIALIZATION != 0
  22. #include <boost/serialization/serialization.hpp>
  23. #include <boost/serialization/utility.hpp>
  24. #include <boost/serialization/collections_save_imp.hpp>
  25. #include <boost/serialization/collections_load_imp.hpp>
  26. #include <boost/serialization/split_free.hpp>
  27. #endif
  28. #include <boost/filesystem/path.hpp>
  29. #include <boost/filesystem/operations.hpp>
  30. // this must occur after all of the includes and before any code appears
  31. #ifdef BOOST_HAS_ABI_HEADERS
  32. #include BOOST_ABI_PREFIX
  33. #endif
  34. ///////////////////////////////////////////////////////////////////////////////
  35. namespace boost { namespace wave { namespace util {
  36. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  37. ///////////////////////////////////////////////////////////////////////////////
  38. // Tags for accessing both sides of a bidirectional map
  39. struct from {};
  40. struct to {};
  41. ///////////////////////////////////////////////////////////////////////////////
  42. // The class template bidirectional_map wraps the specification
  43. // of a bidirectional map based on multi_index_container.
  44. template<typename FromType, typename ToType>
  45. struct bidirectional_map
  46. {
  47. typedef std::pair<FromType, ToType> value_type;
  48. #if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) || \
  49. (defined(BOOST_MSVC) && (BOOST_MSVC == 1600) ) || \
  50. (defined(BOOST_INTEL_CXX_VERSION) && \
  51. (defined(_MSC_VER) && (BOOST_INTEL_CXX_VERSION <= 700)))
  52. BOOST_STATIC_CONSTANT(unsigned, from_offset = offsetof(value_type, first));
  53. BOOST_STATIC_CONSTANT(unsigned, to_offset = offsetof(value_type, second));
  54. typedef boost::multi_index::multi_index_container<
  55. value_type,
  56. boost::multi_index::indexed_by<
  57. boost::multi_index::ordered_unique<
  58. boost::multi_index::tag<from>,
  59. boost::multi_index::member_offset<value_type, FromType, from_offset>
  60. >,
  61. boost::multi_index::ordered_non_unique<
  62. boost::multi_index::tag<to>,
  63. boost::multi_index::member_offset<value_type, ToType, to_offset>
  64. >
  65. >
  66. > type;
  67. #else
  68. typedef boost::multi_index::multi_index_container<
  69. value_type,
  70. boost::multi_index::indexed_by<
  71. boost::multi_index::ordered_unique<
  72. boost::multi_index::tag<from>,
  73. boost::multi_index::member<value_type, FromType, &value_type::first>
  74. >,
  75. boost::multi_index::ordered_non_unique<
  76. boost::multi_index::tag<to>,
  77. boost::multi_index::member<value_type, ToType, &value_type::second>
  78. >
  79. >
  80. > type;
  81. #endif
  82. };
  83. #endif // BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  84. #if BOOST_WAVE_SERIALIZATION != 0
  85. struct load_filepos
  86. {
  87. static unsigned int get_line() { return 0; }
  88. static unsigned int get_column() { return 0; }
  89. static std::string get_file() { return "<loading-state>"; }
  90. };
  91. #endif
  92. ///////////////////////////////////////////////////////////////////////////////
  93. //
  94. // include_paths - controlling the include path search order
  95. //
  96. // General notes:
  97. //
  98. // Any directories specified with the 'add_include_path()' function before
  99. // the function 'set_sys_include_delimiter()' is called are searched only
  100. // for the case of '#include "file"' directives, they are not searched for
  101. // '#include <file>' directives. If additional directories are specified
  102. // with the 'add_include_path()' function after a call to the function
  103. // 'set_sys_include_delimiter()', these directories are searched for all
  104. // '#include' directives.
  105. //
  106. // In addition, a call to the function 'set_sys_include_delimiter()'
  107. // inhibits the use of the current directory as the first search directory
  108. // for '#include "file"' directives. Therefore, the current directory is
  109. // searched only if it is requested explicitly with a call to the function
  110. // 'add_include_path(".")'.
  111. //
  112. // Calling both functions, the 'set_sys_include_delimiter()' and
  113. // 'add_include_path(".")' allows you to control precisely which
  114. // directories are searched before the current one and which are searched
  115. // after.
  116. //
  117. ///////////////////////////////////////////////////////////////////////////////
  118. class include_paths
  119. {
  120. private:
  121. typedef std::list<std::pair<boost::filesystem::path, std::string> >
  122. include_list_type;
  123. typedef include_list_type::value_type include_value_type;
  124. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  125. typedef bidirectional_map<std::string, std::string>::type
  126. pragma_once_set_type;
  127. #endif
  128. public:
  129. include_paths()
  130. : was_sys_include_path(false),
  131. current_dir(initial_path()),
  132. current_rel_dir(initial_path())
  133. {}
  134. bool add_include_path(char const *path_, bool is_system = false)
  135. {
  136. return add_include_path(path_, (is_system || was_sys_include_path) ?
  137. system_include_paths : user_include_paths);
  138. }
  139. void set_sys_include_delimiter() { was_sys_include_path = true; }
  140. bool find_include_file (std::string &s, std::string &dir, bool is_system,
  141. char const *current_file) const;
  142. void set_current_directory(char const *path_);
  143. boost::filesystem::path get_current_directory() const
  144. { return current_dir; }
  145. protected:
  146. bool find_include_file (std::string &s, std::string &dir,
  147. include_list_type const &pathes, char const *) const;
  148. bool add_include_path(char const *path_, include_list_type &pathes_);
  149. private:
  150. include_list_type user_include_paths;
  151. include_list_type system_include_paths;
  152. bool was_sys_include_path; // saw a set_sys_include_delimiter()
  153. boost::filesystem::path current_dir;
  154. boost::filesystem::path current_rel_dir;
  155. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  156. public:
  157. bool has_pragma_once(std::string const &filename)
  158. {
  159. using boost::multi_index::get;
  160. return get<from>(pragma_once_files).find(filename) != pragma_once_files.end();
  161. }
  162. bool add_pragma_once_header(std::string const &filename,
  163. std::string const& guard_name)
  164. {
  165. typedef pragma_once_set_type::value_type value_type;
  166. return pragma_once_files.insert(value_type(filename, guard_name)).second;
  167. }
  168. bool remove_pragma_once_header(std::string const& guard_name)
  169. {
  170. typedef pragma_once_set_type::index_iterator<to>::type to_iterator;
  171. typedef std::pair<to_iterator, to_iterator> range_type;
  172. range_type r = pragma_once_files.get<to>().equal_range(guard_name);
  173. if (r.first != r.second) {
  174. using boost::multi_index::get;
  175. get<to>(pragma_once_files).erase(r.first, r.second);
  176. return true;
  177. }
  178. return false;
  179. }
  180. private:
  181. pragma_once_set_type pragma_once_files;
  182. #endif
  183. #if BOOST_WAVE_SERIALIZATION != 0
  184. public:
  185. BOOST_STATIC_CONSTANT(unsigned int, version = 0x10);
  186. BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f);
  187. private:
  188. friend class boost::serialization::access;
  189. template<typename Archive>
  190. void save(Archive & ar, const unsigned int version) const
  191. {
  192. using namespace boost::serialization;
  193. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  194. ar & make_nvp("pragma_once_files", pragma_once_files);
  195. #endif
  196. ar & make_nvp("user_include_paths", user_include_paths);
  197. ar & make_nvp("system_include_paths", system_include_paths);
  198. ar & make_nvp("was_sys_include_path", was_sys_include_path);
  199. }
  200. template<typename Archive>
  201. void load(Archive & ar, const unsigned int loaded_version)
  202. {
  203. using namespace boost::serialization;
  204. if (version != (loaded_version & ~version_mask)) {
  205. BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
  206. "cpp_include_path state version", load_filepos());
  207. return;
  208. }
  209. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  210. ar & make_nvp("pragma_once_files", pragma_once_files);
  211. #endif
  212. // verify that the old include paths match the current ones
  213. include_list_type user_paths, system_paths;
  214. ar & make_nvp("user_include_paths", user_paths);
  215. ar & make_nvp("system_include_paths", system_paths);
  216. if (user_paths != user_include_paths)
  217. {
  218. BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
  219. "user include paths", load_filepos());
  220. return;
  221. }
  222. if (system_paths != system_include_paths)
  223. {
  224. BOOST_WAVE_THROW(preprocess_exception, incompatible_config,
  225. "system include paths", load_filepos());
  226. return;
  227. }
  228. ar & make_nvp("was_sys_include_path", was_sys_include_path);
  229. }
  230. BOOST_SERIALIZATION_SPLIT_MEMBER()
  231. #endif
  232. };
  233. ///////////////////////////////////////////////////////////////////////////////
  234. // Add an include path to one of the search lists (user include path or system
  235. // include path).
  236. inline
  237. bool include_paths::add_include_path (
  238. char const *path_, include_list_type &pathes_)
  239. {
  240. namespace fs = boost::filesystem;
  241. if (path_) {
  242. fs::path newpath = util::complete_path(create_path(path_), current_dir);
  243. if (!fs::exists(newpath) || !fs::is_directory(newpath)) {
  244. // the given path does not form a name of a valid file system directory
  245. // item
  246. return false;
  247. }
  248. pathes_.push_back (include_value_type(newpath, path_));
  249. return true;
  250. }
  251. return false;
  252. }
  253. ///////////////////////////////////////////////////////////////////////////////
  254. // Find an include file by traversing the list of include directories
  255. inline
  256. bool include_paths::find_include_file (std::string &s, std::string &dir,
  257. include_list_type const &pathes, char const *current_file) const
  258. {
  259. namespace fs = boost::filesystem;
  260. typedef include_list_type::const_iterator const_include_list_iter_t;
  261. const_include_list_iter_t it = pathes.begin();
  262. const_include_list_iter_t include_paths_end = pathes.end();
  263. #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
  264. if (0 != current_file) {
  265. // re-locate the directory of the current file (#include_next handling)
  266. // #include_next does not distinguish between <file> and "file"
  267. // inclusion, nor does it check that the file you specify has the same
  268. // name as the current file. It simply looks for the file named, starting
  269. // with the directory in the search path after the one where the current
  270. // file was found.
  271. fs::path file_path (create_path(current_file));
  272. for (/**/; it != include_paths_end; ++it) {
  273. fs::path currpath (create_path((*it).first.string()));
  274. if (std::equal(currpath.begin(), currpath.end(), file_path.begin()))
  275. {
  276. ++it; // start searching with the next directory
  277. break;
  278. }
  279. }
  280. }
  281. #endif
  282. for (/**/; it != include_paths_end; ++it) {
  283. fs::path currpath (create_path(s));
  284. if (!currpath.has_root_directory()) {
  285. currpath = create_path((*it).first.string());
  286. currpath /= create_path(s); // append filename
  287. }
  288. if (fs::exists(currpath)) {
  289. fs::path dirpath (create_path(s));
  290. if (!dirpath.has_root_directory()) {
  291. dirpath = create_path((*it).second);
  292. dirpath /= create_path(s);
  293. }
  294. dir = dirpath.string();
  295. s = normalize(currpath).string(); // found the required file
  296. return true;
  297. }
  298. }
  299. return false;
  300. }
  301. ///////////////////////////////////////////////////////////////////////////////
  302. // Find an include file by searching the user and system includes in the
  303. // correct sequence (as it was configured by the user of the driver program)
  304. inline bool
  305. include_paths::find_include_file (std::string &s, std::string &dir,
  306. bool is_system, char const *current_file) const
  307. {
  308. namespace fs = boost::filesystem;
  309. // if not system include (<...>), then search current directory first
  310. if (!is_system) {
  311. if (!was_sys_include_path) { // set_sys_include_delimiter() not called
  312. // first have a look at the current directory
  313. fs::path currpath (create_path(s));
  314. if (!currpath.has_root_directory()) {
  315. currpath = create_path(current_dir.string());
  316. currpath /= create_path(s);
  317. }
  318. if (fs::exists(currpath) && 0 == current_file) {
  319. // if 0 != current_path (#include_next handling) it can't be
  320. // the file in the current directory
  321. fs::path dirpath (create_path(s));
  322. if (!dirpath.has_root_directory()) {
  323. dirpath = create_path(current_rel_dir.string());
  324. dirpath /= create_path(s);
  325. }
  326. dir = dirpath.string();
  327. s = normalize(currpath).string(); // found in local directory
  328. return true;
  329. }
  330. // iterate all user include file directories to find the file
  331. if (find_include_file(s, dir, user_include_paths, current_file))
  332. return true;
  333. // ... fall through
  334. }
  335. else {
  336. // if set_sys_include_delimiter() was called, then user include files
  337. // are searched in the user search path only
  338. return find_include_file(s, dir, user_include_paths, current_file);
  339. }
  340. // if nothing found, fall through
  341. // ...
  342. }
  343. // iterate all system include file directories to find the file
  344. return find_include_file (s, dir, system_include_paths, current_file);
  345. }
  346. ///////////////////////////////////////////////////////////////////////////////
  347. // Set current directory from a given file name
  348. inline bool
  349. as_relative_to(boost::filesystem::path const& path,
  350. boost::filesystem::path const& base, boost::filesystem::path& result)
  351. {
  352. if (path.has_root_path()) {
  353. if (path.root_path() == base.root_path())
  354. return as_relative_to(path.relative_path(), base.relative_path(), result);
  355. result = path; // that's our result
  356. }
  357. else {
  358. if (base.has_root_path()) {
  359. // cannot find relative path from a relative path and a rooted base
  360. return false;
  361. }
  362. else {
  363. typedef boost::filesystem::path::const_iterator path_iterator;
  364. path_iterator path_it = path.begin();
  365. path_iterator base_it = base.begin();
  366. while (path_it != path.end() && base_it != base.end() ) {
  367. if (*path_it != *base_it)
  368. break;
  369. ++path_it; ++base_it;
  370. }
  371. for (/**/; base_it != base.end(); ++base_it)
  372. result /= "..";
  373. for (/**/; path_it != path.end(); ++path_it)
  374. result /= *path_it;
  375. }
  376. }
  377. return true;
  378. }
  379. ///////////////////////////////////////////////////////////////////////////////
  380. inline
  381. void include_paths::set_current_directory(char const *path_)
  382. {
  383. namespace fs = boost::filesystem;
  384. fs::path filepath (create_path(path_));
  385. fs::path filename = util::complete_path(filepath, current_dir);
  386. BOOST_ASSERT(!(fs::exists(filename) && fs::is_directory(filename)));
  387. current_rel_dir.clear();
  388. if (!as_relative_to(branch_path(filepath), current_dir, current_rel_dir))
  389. current_rel_dir = branch_path(filepath);
  390. current_dir = branch_path(filename);
  391. }
  392. ///////////////////////////////////////////////////////////////////////////////
  393. }}} // namespace boost::wave::util
  394. #if BOOST_WAVE_SERIALIZATION != 0
  395. ///////////////////////////////////////////////////////////////////////////////
  396. namespace boost { namespace serialization {
  397. ///////////////////////////////////////////////////////////////////////////////
  398. // Serialization support for boost::filesystem::path
  399. template<class Archive>
  400. inline void save (Archive & ar, boost::filesystem::path const& p,
  401. const unsigned int /* file_version */)
  402. {
  403. using namespace boost::serialization;
  404. std::string path_str(p.native_file_string());
  405. ar & make_nvp("filepath", path_str);
  406. }
  407. template<class Archive>
  408. inline void load (Archive & ar, boost::filesystem::path &p,
  409. const unsigned int /* file_version */)
  410. {
  411. using namespace boost::serialization;
  412. std::string path_str;
  413. ar & make_nvp("filepath", path_str);
  414. p = wave::util::create_path(path_str);
  415. }
  416. // split non-intrusive serialization function member into separate
  417. // non intrusive save/load member functions
  418. template<class Archive>
  419. inline void serialize (Archive & ar, boost::filesystem::path &p,
  420. const unsigned int file_version)
  421. {
  422. boost::serialization::split_free(ar, p, file_version);
  423. }
  424. ///////////////////////////////////////////////////////////////////////////////
  425. // Serialization support for the used multi_index
  426. template<class Archive>
  427. inline void save (Archive & ar,
  428. const typename boost::wave::util::bidirectional_map<
  429. std::string, std::string
  430. >::type &t,
  431. const unsigned int /* file_version */)
  432. {
  433. boost::serialization::stl::save_collection<
  434. Archive,
  435. typename boost::wave::util::bidirectional_map<
  436. std::string, std::string
  437. >::type
  438. >(ar, t);
  439. }
  440. template<class Archive>
  441. inline void load (Archive & ar,
  442. typename boost::wave::util::bidirectional_map<std::string, std::string>::type &t,
  443. const unsigned int /* file_version */)
  444. {
  445. typedef typename boost::wave::util::bidirectional_map<
  446. std::string, std::string
  447. >::type map_type;
  448. boost::serialization::stl::load_collection<
  449. Archive, map_type,
  450. boost::serialization::stl::archive_input_unique<Archive, map_type>,
  451. boost::serialization::stl::no_reserve_imp<map_type>
  452. >(ar, t);
  453. }
  454. // split non-intrusive serialization function member into separate
  455. // non intrusive save/load member functions
  456. template<class Archive>
  457. inline void serialize (Archive & ar,
  458. typename boost::wave::util::bidirectional_map<
  459. std::string, std::string
  460. >::type &t,
  461. const unsigned int file_version)
  462. {
  463. boost::serialization::split_free(ar, t, file_version);
  464. }
  465. ///////////////////////////////////////////////////////////////////////////////
  466. }} // namespace boost::serialization
  467. BOOST_CLASS_VERSION(boost::wave::util::include_paths,
  468. boost::wave::util::include_paths::version);
  469. #endif // BOOST_WAVE_SERIALIZATION != 0
  470. // the suffix header occurs after all of the code
  471. #ifdef BOOST_HAS_ABI_HEADERS
  472. #include BOOST_ABI_SUFFIX
  473. #endif
  474. #endif // !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED)