From 8a60d52be1bf0dcc2db9dfb1747458e02f54164f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Wed, 28 Nov 2018 16:32:54 +0100 Subject: [PATCH] Remove dependency on system include dir --- external/external.cmake | 15 ------------ include/cppast/libclang_parser.hpp | 4 ++- src/libclang/libclang_parser.cpp | 39 +++++++++++++++++++++++++++--- test/libclang_parser.cpp | 12 ++++++--- test/test_parser.hpp | 13 +++++++--- 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/external/external.cmake b/external/external.cmake index b6d9884..83e2c93 100644 --- a/external/external.cmake +++ b/external/external.cmake @@ -181,20 +181,6 @@ function(_cppast_find_libclang config_tool min_version force) endif() endif() - # find system header files in llvm_library_dir - if(${force}) - unset(LIBCLANG_SYSTEM_INCLUDE_DIR CACHE) - endif() - if(NOT LIBCLANG_SYSTEM_INCLUDE_DIR) - find_path(LIBCLANG_SYSTEM_INCLUDE_DIR "stddef.h" "${llvm_library_dir}/clang/${llvm_version}/include" NO_DEFAULT_PATH) - - if(NOT LIBCLANG_SYSTEM_INCLUDE_DIR) - message(FATAL_ERROR "libclang system header files not found") - else() - message(STATUS "Found libclang system header files at ${LIBCLANG_SYSTEM_INCLUDE_DIR}") - endif() - endif() - # find clang binary in llvm_binary_dir # note: never override that binary if(NOT CLANG_BINARY) @@ -238,6 +224,5 @@ add_library(_cppast_libclang INTERFACE) target_link_libraries(_cppast_libclang INTERFACE ${LIBCLANG_LIBRARY}) target_include_directories(_cppast_libclang INTERFACE ${LIBCLANG_INCLUDE_DIR}) target_compile_definitions(_cppast_libclang INTERFACE - CPPAST_LIBCLANG_SYSTEM_INCLUDE_DIR="${LIBCLANG_SYSTEM_INCLUDE_DIR}" CPPAST_CLANG_BINARY="${CLANG_BINARY}" CPPAST_CLANG_VERSION_STRING="${LLVM_VERSION}") diff --git a/include/cppast/libclang_parser.hpp b/include/cppast/libclang_parser.hpp index 6bac8c2..2d1fa52 100644 --- a/include/cppast/libclang_parser.hpp +++ b/include/cppast/libclang_parser.hpp @@ -120,7 +120,9 @@ public: /// binary. /// If the binary is not found, it will try and search for it. /// \returns `true` if the binary was found exactly as specified. - /// \notes It will be used for preprocessing. + /// \notes This binary will be used for preprocessing as well as determining the default include + /// directories. As such, if it is called after include directories have already been added, the + /// order might end up being wrong. bool set_clang_binary(std::string binary); /// \effects Sets whether or not the preprocessed file will be written out. diff --git a/src/libclang/libclang_parser.cpp b/src/libclang/libclang_parser.cpp index fb5bb7b..8590252 100644 --- a/src/libclang/libclang_parser.cpp +++ b/src/libclang/libclang_parser.cpp @@ -76,6 +76,9 @@ bool libclang_compilation_database::has_config(const char* file_name) const return true; } +namespace +{} // namespace + libclang_compile_config::libclang_compile_config() : compile_config({}), write_preprocessed_(false), fast_preprocessing_(false), remove_comments_in_macro_(false) @@ -83,9 +86,6 @@ libclang_compile_config::libclang_compile_config() // set given clang binary set_clang_binary(CPPAST_CLANG_BINARY); - // set system include dir - add_include_dir(CPPAST_LIBCLANG_SYSTEM_INCLUDE_DIR); - // set macros to detect cppast define_macro("__cppast__", "libclang"); define_macro("__cppast_version_major__", CPPAST_VERSION_MAJOR); @@ -252,6 +252,37 @@ bool is_valid_binary(const std::string& binary) [](const char*, std::size_t) {}); return process.get_exit_status() == 0; } + +void add_default_include_dirs(libclang_compile_config& config) +{ + std::string verbose_output; + tpl::Process process(detail::libclang_compile_config_access::clang_binary(config) + + " -x c++ -v -", + "", [](const char*, std::size_t) {}, + [&](const char* str, std::size_t n) { verbose_output.append(str, n); }, + true); + process.write("", 1); + process.close_stdin(); + process.get_exit_status(); + + auto pos = verbose_output.find("#include <...>"); + DEBUG_ASSERT(pos != std::string::npos, detail::assert_handler{}); + while (verbose_output[pos] != '\n') + ++pos; + ++pos; + + // now every line is an include path, starting with a space + while (verbose_output[pos] == ' ') + { + auto start = pos + 1; + while (verbose_output[pos] != '\n') + ++pos; + auto end = pos; + ++pos; + + config.add_include_dir(verbose_output.substr(start, end - start)); + } +} } // namespace bool libclang_compile_config::set_clang_binary(std::string binary) @@ -259,6 +290,7 @@ bool libclang_compile_config::set_clang_binary(std::string binary) if (is_valid_binary(binary)) { clang_binary_ = binary; + add_default_include_dirs(*this); return true; } else @@ -271,6 +303,7 @@ bool libclang_compile_config::set_clang_binary(std::string binary) if (is_valid_binary(p)) { clang_binary_ = p; + add_default_include_dirs(*this); return false; } diff --git a/test/libclang_parser.cpp b/test/libclang_parser.cpp index e4af768..c1762cb 100644 --- a/test/libclang_parser.cpp +++ b/test/libclang_parser.cpp @@ -23,9 +23,15 @@ void require_flags(const libclang_compile_config& config, const char* flags) { std::string result; auto config_flags = detail::libclang_compile_config_access::flags(config); - // skip first 4, those are the default options - for (auto iter = config_flags.begin() + 4; iter != config_flags.end(); ++iter) - result += *iter + ' '; + // skip until including __cppast_version__minor__, those are the default options + auto in_default = true; + for (auto iter = config_flags.begin(); iter != config_flags.end(); ++iter) + { + if (*iter == "-D__cppast_version_minor__=\"" CPPAST_VERSION_MINOR "\"") + in_default = false; + else if (!in_default) + result += *iter + ' '; + } result.pop_back(); REQUIRE(result == flags); } diff --git a/test/test_parser.hpp b/test/test_parser.hpp index fe6871c..79a18fe 100644 --- a/test/test_parser.hpp +++ b/test/test_parser.hpp @@ -23,14 +23,21 @@ inline void write_file(const char* name, const char* code) file << code; } -inline std::unique_ptr parse_file(const cppast::cpp_entity_index& idx, - const char* name, - bool fast_preprocessing = false) +inline cppast::libclang_compile_config make_test_config() { using namespace cppast; libclang_compile_config config; config.set_flags(cpp_standard::cpp_latest); + return config; +} + +inline std::unique_ptr parse_file(const cppast::cpp_entity_index& idx, + const char* name, + bool fast_preprocessing = false) +{ + using namespace cppast; + static auto config = make_test_config(); config.fast_preprocessing(fast_preprocessing); libclang_parser p(default_logger());