Skip to content

Commit ae58b94

Browse files
hjmjohnsonjcfr
authored andcommitted
feat: Add Apple Framework header support for __has_include
Apple frameworks store headers under: <Pkg.framework/Headers/MyHdr.h> This patch extends `openHeader(...)` so that `__has_include(<Pkg/MyHdr.h>)` resolves to the framework layout. A new test `appleFrameworkHasIncludeTest` verifies the behavior. Note: this applies only to `__has_include`; plain `#include` still uses the existing lookup logic. Co-authored-by: Jean-Christophe Fillion-Robin <jchris.fillionr@kitware.com>
1 parent 538c5c4 commit ae58b94

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

simplecpp.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3007,6 +3007,30 @@ static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const
30073007
if (!path.empty())
30083008
return path;
30093009
}
3010+
3011+
// a named lambda function to insert the ".framework/Headers" part for apple frameworks
3012+
auto get_apple_framework_relative_path= [](const std::string& appleFrameworkHeader) -> std::string {
3013+
// try the Framework path on apple OS, if there is a path in front
3014+
const size_t slashPos = appleFrameworkHeader.find('/');
3015+
if (slashPos == std::string::npos) {
3016+
return appleFrameworkHeader;
3017+
}
3018+
constexpr auto frameworkSuffix{ ".framework/Headers" };
3019+
return appleFrameworkHeader.substr(0, slashPos) + frameworkSuffix + appleFrameworkHeader.substr(slashPos);
3020+
};
3021+
// on Apple, try to find the header in the framework path
3022+
// Convert <includePath>/PKGNAME/myHeader -> <includePath>/PKGNAME.framework/Headers/myHeader
3023+
// Works on any platform, but only relevant when compiling against Apple SDKs.
3024+
const std::string appleFrameworkHeader = get_apple_framework_relative_path(header);
3025+
if (appleFrameworkHeader != header) {
3026+
for (const auto & includePath: dui.includePaths) {
3027+
const std::string frameworkCandidatePath = includePath + '/' + appleFrameworkHeader;
3028+
std::string simplePath = openHeaderDirect(f, simplecpp::simplifyPath(frameworkCandidatePath));
3029+
if (!simplePath.empty())
3030+
return simplePath;
3031+
}
3032+
}
3033+
30103034
return "";
30113035
}
30123036

test.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,6 +2131,36 @@ static void circularInclude()
21312131
ASSERT_EQUALS("", toString(outputList));
21322132
}
21332133

2134+
static void appleFrameworkHasIncludeTest()
2135+
{
2136+
const char code[] =
2137+
"#ifdef __has_include\n"
2138+
"#if __has_include(<Foundation/Foundation.h>)\n"
2139+
"A\n"
2140+
"#else\n"
2141+
"B\n"
2142+
"#endif\n"
2143+
"#endif\n";
2144+
2145+
std::vector<std::string> files;
2146+
const simplecpp::TokenList rawtokens = makeTokenList(code, files, "sourcecode.cpp");
2147+
2148+
simplecpp::FileDataCache cache;
2149+
simplecpp::TokenList tokens2(files);
2150+
simplecpp::DUI dui;
2151+
#ifdef SIMPLECPP_SOURCE_DIR
2152+
dui.includePaths.push_back(std::string(SIMPLECPP_SOURCE_DIR) + "/testsuite");
2153+
#else
2154+
dui.includePaths.push_back("./testsuite");
2155+
#endif
2156+
dui.std = "c++17"; // enable __has_include
2157+
2158+
simplecpp::OutputList outputList;
2159+
simplecpp::preprocess(tokens2, rawtokens, files, cache, dui, &outputList);
2160+
2161+
ASSERT_EQUALS("\n\nA", tokens2.stringify()); // should take the "A" branch
2162+
}
2163+
21342164
static void multiline1()
21352165
{
21362166
const char code[] = "#define A \\\n"
@@ -3359,6 +3389,7 @@ int main(int argc, char **argv)
33593389
TEST_CASE(nestedInclude);
33603390
TEST_CASE(systemInclude);
33613391
TEST_CASE(circularInclude);
3392+
TEST_CASE(appleFrameworkHasIncludeTest);
33623393

33633394
TEST_CASE(nullDirective1);
33643395
TEST_CASE(nullDirective2);

0 commit comments

Comments
 (0)