diff --git a/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/a.cpp b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/a.cpp new file mode 100644 index 00000000..102612d5 --- /dev/null +++ b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/a.cpp @@ -0,0 +1 @@ +#include "a.h" \ No newline at end of file diff --git a/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/include_a/a.h b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/include_a/a.h new file mode 100644 index 00000000..15de28cc --- /dev/null +++ b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/include_a/a.h @@ -0,0 +1 @@ +#include "b.h" \ No newline at end of file diff --git a/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/include_b/b.h b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/include_b/b.h new file mode 100644 index 00000000..e69de29b diff --git a/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/a.cpp b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/a.cpp new file mode 100644 index 00000000..102612d5 --- /dev/null +++ b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/a.cpp @@ -0,0 +1 @@ +#include "a.h" \ No newline at end of file diff --git a/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/include_a/a.h b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/include_a/a.h new file mode 100644 index 00000000..15de28cc --- /dev/null +++ b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/include_a/a.h @@ -0,0 +1 @@ +#include "b.h" \ No newline at end of file diff --git a/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/include_b/b.h b/bin/test/data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/include_b/b.h new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index b1ad27f3..120b8eea 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -356,6 +356,8 @@ add_files( utility/file/FileRegisterStateData.h utility/file/FileSystem.cpp utility/file/FileSystem.h + utility/file/FileTree.cpp + utility/file/FileTree.h utility/interprocess/SharedMemory.cpp utility/interprocess/SharedMemory.h diff --git a/src/lib/utility/file/FileTree.cpp b/src/lib/utility/file/FileTree.cpp new file mode 100644 index 00000000..9b26f708 --- /dev/null +++ b/src/lib/utility/file/FileTree.cpp @@ -0,0 +1,86 @@ +#include "utility/file/FileTree.h" + +#include "utility/file/FileSystem.h" + +FileTree::FileTree(const FilePath& rootPath) + : m_rootPath(rootPath.getAbsolute().makeCanonical()) +{ + if (m_rootPath.exists()) + { + if (m_rootPath.isDirectory()) + { + for (const FilePath& filePath : FileSystem::getFilePathsFromDirectory(m_rootPath)) + { + m_files[filePath.fileName()].insert(filePath); + } + } + else + { + m_files[m_rootPath.fileName()].insert(m_rootPath); + } + } +} + +FilePath FileTree::getAbsoluteRootPathForRelativeFilePath(const FilePath& relativeFilePath) +{ + std::vector rootPaths = doGetAbsoluteRootPathsForRelativeFilePath(relativeFilePath, false); + if (!rootPaths.empty()) + { + return rootPaths.front(); + } + return FilePath(); +} + +std::vector FileTree::getAbsoluteRootPathsForRelativeFilePath(const FilePath& relativeFilePath) +{ + return doGetAbsoluteRootPathsForRelativeFilePath(relativeFilePath, true); +} + +std::vector FileTree::doGetAbsoluteRootPathsForRelativeFilePath(const FilePath& relativeFilePath, bool allowMultipleResults) +{ + std::vector rootPaths; + + std::unordered_map>::const_iterator it = m_files.find(relativeFilePath.fileName()); + if (it != m_files.end()) + { + for (FilePath existingFilePath : it->second) + { + existingFilePath = existingFilePath.getParentDirectory(); + bool ok = true; + { + FilePath temp = relativeFilePath.getParentDirectory(); + while (!temp.empty()) + { + if (temp.fileName() == "..") + { + std::vector subDirectories = FileSystem::getDirectSubDirectories(existingFilePath); + if (!subDirectories.empty()) + { + existingFilePath = subDirectories.front(); + } + else + { + ok = false; + break; + } + } + else + { + existingFilePath = existingFilePath.getParentDirectory(); + } + temp = temp.getParentDirectory(); + } + } + if (ok) + { + rootPaths.push_back(existingFilePath); + if (!allowMultipleResults) + { + break; + } + } + } + } + return rootPaths; +} + diff --git a/src/lib/utility/file/FileTree.h b/src/lib/utility/file/FileTree.h new file mode 100644 index 00000000..d9bb8747 --- /dev/null +++ b/src/lib/utility/file/FileTree.h @@ -0,0 +1,25 @@ +#ifndef FILE_TREE_H +#define FILE_TREE_H + +#include +#include +#include + +#include "utility/file/FilePath.h" + +class FileTree +{ +public: + FileTree(const FilePath& rootPath); + + FilePath getAbsoluteRootPathForRelativeFilePath(const FilePath& relativeFilePath); + std::vector getAbsoluteRootPathsForRelativeFilePath(const FilePath& relativeFilePath); + +private: + std::vector doGetAbsoluteRootPathsForRelativeFilePath(const FilePath& relativeFilePath, bool allowMultipleResults); + + FilePath m_rootPath; + std::unordered_map> m_files; +}; + +#endif // FILE_TREE_H diff --git a/src/lib_cxx/utility/IncludeProcessing.cpp b/src/lib_cxx/utility/IncludeProcessing.cpp index a67aafe2..c2cb4581 100644 --- a/src/lib_cxx/utility/IncludeProcessing.cpp +++ b/src/lib_cxx/utility/IncludeProcessing.cpp @@ -5,7 +5,7 @@ #include "utility/IncludeDirective.h" #include "utility/file/FilePath.h" -#include "utility/file/FileSystem.h" +#include "utility/file/FileTree.h" #include "utility/text/TextAccess.h" #include "utility/utility.h" #include "utility/utilityString.h" @@ -57,47 +57,15 @@ std::vector IncludeProcessing::getUnresolvedIncludeDirectives( for (size_t i = 0; i < quantiles.size(); i++) { - const std::vector& quantile = quantiles[i]; - progress(float(i) / quantiles.size()); - std::set unprocessedFilePaths(quantile.begin(), quantile.end()); - - while (!unprocessedFilePaths.empty()) - { - std::transform( - unprocessedFilePaths.begin(), unprocessedFilePaths.end(), - std::inserter(processedFilePaths, processedFilePaths.begin()), - [](const FilePath& p){ return p.str(); } - ); - - std::set unprocessedFilePathsForNextIteration; - - for (const FilePath& filePath: unprocessedFilePaths) - { - for (const IncludeDirective& includeDirective: getIncludeDirectives(filePath)) - { - const FilePath resolvedIncludePath = resolveIncludeDirective(includeDirective, headerSearchDirectories).makeCanonical(); - if (resolvedIncludePath.empty()) - { - unresolvedIncludeDirectives.insert(includeDirective); - } - else if (processedFilePaths.find(resolvedIncludePath.str()) == processedFilePaths.end()) - { - for (const FilePath& indexedPath: indexedPaths) - { - if (indexedPath.contains(resolvedIncludePath)) - { - unprocessedFilePathsForNextIteration.insert(resolvedIncludePath); - break; - } - } - } - } - } - - unprocessedFilePaths = unprocessedFilePathsForNextIteration; - } + const std::vector directives = doGetUnresolvedIncludeDirectives( + utility::toSet(quantiles[i]), + processedFilePaths, + indexedPaths, + headerSearchDirectories + ); + std::copy(directives.begin(), directives.end(), std::inserter(unresolvedIncludeDirectives, unresolvedIncludeDirectives.end())); } std::vector ret; @@ -115,25 +83,16 @@ std::vector IncludeProcessing::getUnresolvedIncludeDirectives( std::set IncludeProcessing::getHeaderSearchDirectories( const std::set& sourceFilePaths, const std::set& searchedPaths, + const std::set& currentHeaderSearchDirectories, const size_t desiredQuantileCount, std::function progress ) { progress(0.0f); - std::map> existingFilePaths; + std::vector> existingFileTrees; for (const FilePath& searchedPath : searchedPaths) { - if (searchedPath.isDirectory()) - { - for (const FilePath& filePath : FileSystem::getFilePathsFromDirectory(searchedPath.getCanonical())) - { - existingFilePaths[filePath.fileName()].insert(filePath); - } - } - else - { - existingFilePaths[searchedPath.fileName()].insert(searchedPath); - } + existingFileTrees.push_back(std::make_shared(searchedPath)); } std::set headerSearchDirectories; @@ -142,18 +101,16 @@ std::set IncludeProcessing::getHeaderSearchDirectories( for (size_t i = 0; i < quantiles.size(); i++) { - const std::vector& quantile = quantiles[i]; - progress(float(i) / quantiles.size()); - std::set unprocessedFilePaths(quantile.begin(), quantile.end()); + std::set unprocessedFilePaths(quantiles[i].begin(), quantiles[i].end()); while (!unprocessedFilePaths.empty()) { std::transform( unprocessedFilePaths.begin(), unprocessedFilePaths.end(), std::inserter(processedFilePaths, processedFilePaths.begin()), - [](const FilePath& p) { return p.str(); } + [](const FilePath& p) { return p.getAbsolute().str(); } ); std::set unprocessedFilePathsForNextIteration; @@ -164,61 +121,20 @@ std::set IncludeProcessing::getHeaderSearchDirectories( { const FilePath includedFilePath = includeDirective.getIncludedFile(); - FilePath foundIncludedPath; - if (includedFilePath.isAbsolute()) + FilePath foundIncludedPath = resolveIncludeDirective(includeDirective, currentHeaderSearchDirectories); + if (foundIncludedPath.empty()) { - foundIncludedPath = includedFilePath; - } - else - { - const FilePath relativeToIncludingPath = includeDirective.getIncludingFile().getParentDirectory().concatenate(includedFilePath); - if (relativeToIncludingPath.exists()) + for (std::shared_ptr existingFileTree : existingFileTrees) { - foundIncludedPath = relativeToIncludingPath; - } - else - { - std::map>::const_iterator it = existingFilePaths.find(includedFilePath.fileName()); - if (it != existingFilePaths.end()) + // TODO: handle the case where a file can be found by two different paths + const FilePath rootPath = existingFileTree->getAbsoluteRootPathForRelativeFilePath(includedFilePath); + if (!rootPath.empty()) { - // TODO: handle the case where a file can be found by two different paths - for (FilePath existingFilePath : it->second) + foundIncludedPath = rootPath.getConcatenated(includedFilePath); + if (foundIncludedPath.exists()) { - existingFilePath = existingFilePath.getParentDirectory(); - bool ok = true; - { - FilePath tempIncludedFilePath = includedFilePath.getParentDirectory(); - while (!tempIncludedFilePath.empty()) - { - if (tempIncludedFilePath.fileName() == "..") - { - std::vector subDirectories = FileSystem::getDirectSubDirectories(existingFilePath); - if (!subDirectories.empty()) - { - existingFilePath = subDirectories.front(); - } - else - { - ok = false; - break; - } - } - else - { - existingFilePath = existingFilePath.getParentDirectory(); - } - tempIncludedFilePath = tempIncludedFilePath.getParentDirectory(); - } - } - if (ok) - { - foundIncludedPath = existingFilePath.getConcatenated(includedFilePath); - if (foundIncludedPath.exists()) - { - headerSearchDirectories.insert(existingFilePath); - break; - } - } + headerSearchDirectories.insert(rootPath); + break; } } } @@ -227,14 +143,7 @@ std::set IncludeProcessing::getHeaderSearchDirectories( { if (processedFilePaths.find(foundIncludedPath.str()) == processedFilePaths.end()) { - for (const FilePath& searchedPath : searchedPaths) - { - if (searchedPath.contains(foundIncludedPath)) - { - unprocessedFilePathsForNextIteration.insert(foundIncludedPath); - break; - } - } + unprocessedFilePathsForNextIteration.insert(foundIncludedPath); } } } @@ -291,6 +200,54 @@ std::vector IncludeProcessing::getIncludeDirectives(std::share return includeDirectives; } +std::vector IncludeProcessing::doGetUnresolvedIncludeDirectives( + std::set filePathsToProcess, + std::unordered_set& processedFilePaths, + const std::set& indexedPaths, + const std::set& headerSearchDirectories +) +{ + std::vector unresolvedIncludeDirectives; + + while (!filePathsToProcess.empty()) + { + std::transform( + filePathsToProcess.begin(), filePathsToProcess.end(), + std::inserter(processedFilePaths, processedFilePaths.begin()), + [](const FilePath& p) { return p.getAbsolute().makeCanonical().str(); } + ); + + std::set filePathsToProcessForNextIteration; + + for (const FilePath& filePath : filePathsToProcess) + { + for (const IncludeDirective& includeDirective : getIncludeDirectives(filePath)) + { + const FilePath resolvedIncludePath = resolveIncludeDirective(includeDirective, headerSearchDirectories).makeCanonical(); + if (resolvedIncludePath.empty()) + { + unresolvedIncludeDirectives.push_back(includeDirective); + } + else if (processedFilePaths.find(resolvedIncludePath.str()) == processedFilePaths.end()) + { + for (const FilePath& indexedPath : indexedPaths) + { + if (indexedPath.contains(resolvedIncludePath)) + { + filePathsToProcessForNextIteration.insert(resolvedIncludePath); + break; + } + } + } + } + } + filePathsToProcess.clear(); + filePathsToProcess.swap(filePathsToProcessForNextIteration); + } + + return unresolvedIncludeDirectives; +} + FilePath IncludeProcessing::resolveIncludeDirective( const IncludeDirective& includeDirective, const std::set& headerSearchDirectories diff --git a/src/lib_cxx/utility/IncludeProcessing.h b/src/lib_cxx/utility/IncludeProcessing.h index 1b0d6ecd..c8379005 100644 --- a/src/lib_cxx/utility/IncludeProcessing.h +++ b/src/lib_cxx/utility/IncludeProcessing.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "utility/OrderedCache.h" @@ -24,6 +25,7 @@ public: static std::set getHeaderSearchDirectories( const std::set& sourceFilePaths, const std::set& searchedPaths, + const std::set& currentHeaderSearchDirectories, const size_t desiredQuantileCount, std::function progress ); @@ -32,6 +34,13 @@ public: static std::vector getIncludeDirectives(std::shared_ptr textAccess); private: + static std::vector doGetUnresolvedIncludeDirectives( + std::set filePathsToProcess, + std::unordered_set& processedFilePaths, + const std::set& indexedPaths, + const std::set& headerSearchDirectories + ); + static FilePath resolveIncludeDirective( const IncludeDirective& includeDirective, const std::set& headerSearchDirectories diff --git a/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPaths.cpp b/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPaths.cpp index 6b1cefc0..cb1dba7c 100644 --- a/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPaths.cpp +++ b/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPaths.cpp @@ -589,7 +589,6 @@ void QtProjectWizzardContentPathsHeaderSearch::finishedSelectDetectIncludesRootP { // TODO: regard Force Includes here, too! const std::vector searchedPaths = m_settings->makePathsExpandedAndAbsolute(m_pathsDialog->getPaths()); - closedPathsDialog(); std::thread([=]() @@ -599,7 +598,7 @@ void QtProjectWizzardContentPathsHeaderSearch::finishedSelectDetectIncludesRootP std::shared_ptr dialogView = std::dynamic_pointer_cast(Application::getInstance()->getDialogView()); std::set sourceFilePaths; - + std::vector headerSearchPaths; { dialogView->setParentWindow(m_window); dialogView->showUnknownProgressDialog("Processing", "Gathering Source Files"); @@ -614,6 +613,13 @@ void QtProjectWizzardContentPathsHeaderSearch::finishedSelectDetectIncludesRootP m_settings->getSourceExtensions() ); sourceFilePaths = fileManager.getAllSourceFilePaths(); + + headerSearchPaths = ApplicationSettings::getInstance()->getHeaderSearchPathsExpanded(); + if (std::shared_ptr cxxSettings = + std::dynamic_pointer_cast(m_settings)) + { + utility::append(headerSearchPaths, cxxSettings->getHeaderSearchPathsExpandedAndAbsolute()); + } } { dialogView->setParentWindow(m_window); @@ -624,6 +630,7 @@ void QtProjectWizzardContentPathsHeaderSearch::finishedSelectDetectIncludesRootP detectedHeaderSearchPaths = IncludeProcessing::getHeaderSearchDirectories( sourceFilePaths, utility::toSet(searchedPaths), + utility::toSet(headerSearchPaths), log2(sourceFilePaths.size()), [&](const float progress) { diff --git a/src/test/CxxIncludeProcessingTestSuite.h b/src/test/CxxIncludeProcessingTestSuite.h index 05c3cd29..1415dc8e 100644 --- a/src/test/CxxIncludeProcessingTestSuite.h +++ b/src/test/CxxIncludeProcessingTestSuite.h @@ -3,6 +3,7 @@ #include "utility/text/TextAccess.h" #include "utility/IncludeDirective.h" #include "utility/IncludeProcessing.h" +#include "utility/utility.h" class CxxIncludeProcessingTestSuite: public CxxTest::TestSuite { @@ -71,48 +72,78 @@ public: void test_header_search_path_detection_does_not_find_path_relative_to_including_file() { - std::set headerSearchDirectories = IncludeProcessing::getHeaderSearchDirectories( - { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_does_not_find_path_relative_to_including_file/a.cpp") }, - { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_does_not_find_path_relative_to_including_file") }, - 1, [&](float) {} - ); + std::vector headerSearchDirectories = utility::toVector(IncludeProcessing::getHeaderSearchDirectories( + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_does_not_find_path_relative_to_including_file/a.cpp") }, + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_does_not_find_path_relative_to_including_file") }, + { }, + 1, [](float) {} + )); TS_ASSERT(headerSearchDirectories.empty()); } void test_header_search_path_detection_finds_path_inside_sub_directory() { - std::set headerSearchDirectories = IncludeProcessing::getHeaderSearchDirectories( - { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_inside_sub_directory/a.cpp") }, - { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_inside_sub_directory") }, - 1, [&](float) {} - ); + std::vector headerSearchDirectories = utility::toVector(IncludeProcessing::getHeaderSearchDirectories( + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_inside_sub_directory/a.cpp") }, + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_inside_sub_directory") }, + {}, + 1, [](float) {} + )); - TS_ASSERT(!headerSearchDirectories.empty()); - if (!headerSearchDirectories.empty()) - { - TS_ASSERT_EQUALS( - "CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_inside_sub_directory/include", - headerSearchDirectories.begin()->getRelativeTo(FilePath("data").getAbsolute()).str() - ); - } + TS_ASSERT(utility::containsElement( + headerSearchDirectories, + FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_inside_sub_directory/include").makeAbsolute() + )); } void test_header_search_path_detection_finds_path_relative_to_sub_directory() { - std::set headerSearchDirectories = IncludeProcessing::getHeaderSearchDirectories( - { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_relative_to_sub_directory/a.cpp") }, - { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_relative_to_sub_directory") }, - 1, [&](float) {} - ); + std::vector headerSearchDirectories = utility::toVector(IncludeProcessing::getHeaderSearchDirectories( + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_relative_to_sub_directory/a.cpp") }, + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_relative_to_sub_directory") }, + {}, + 1, [](float) {} + )); - TS_ASSERT(!headerSearchDirectories.empty()); - if (!headerSearchDirectories.empty()) - { - TS_ASSERT_EQUALS( - "CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_relative_to_sub_directory/include", - headerSearchDirectories.begin()->getRelativeTo(FilePath("data").getAbsolute()).str() - ); - } + TS_ASSERT(utility::containsElement( + headerSearchDirectories, + FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_relative_to_sub_directory/include").makeAbsolute() + )); + } + + void test_header_search_path_detection_finds_path_included_in_header_search_path() + { + std::vector headerSearchDirectories = utility::toVector(IncludeProcessing::getHeaderSearchDirectories( + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/a.cpp") }, + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/include_b") }, + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/include_a") }, + 1, [](float) {} + )); + + + TS_ASSERT(utility::containsElement( + headerSearchDirectories, + FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_header_search_path/include_b").makeAbsolute() + )); + } + + void test_header_search_path_detection_finds_path_included_in_future_header_search_path() + { + std::vector headerSearchDirectories = utility::toVector(IncludeProcessing::getHeaderSearchDirectories( + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/a.cpp") }, + { FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path") }, + { }, + 1, [](float) {} + )); + + TS_ASSERT(utility::containsElement( + headerSearchDirectories, + FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/include_a").makeAbsolute() + )); + TS_ASSERT(utility::containsElement( + headerSearchDirectories, + FilePath("data/CxxIncludeProcessingTestSuite/test_header_search_path_detection_finds_path_included_in_future_header_search_path/include_b").makeAbsolute() + )); } };