1313#include " simplecpp.h"
1414
1515#include < algorithm>
16+ #include < array>
1617#include < cassert>
1718#include < cctype>
1819#include < climits>
@@ -2429,6 +2430,27 @@ static bool isAbsolutePath(const std::string &path)
24292430}
24302431#endif
24312432
2433+ namespace {
2434+ // "<Pkg/Hdr.h>" -> "<Pkg.framework/Headers/Hdr.h>" (and PrivateHeaders variant).
2435+ // Returns candidates in priority order (Headers, then PrivateHeaders).
2436+ inline std::array<std::string,2 >
2437+ toAppleFrameworkRelatives (const std::string& header)
2438+ {
2439+ const std::size_t slash = header.find (' /' );
2440+ if (slash == std::string::npos)
2441+ return { header, header }; // no transformation applicable
2442+ const std::string pkg = header.substr (0 , slash);
2443+ const std::string tail = header.substr (slash); // includes '/'
2444+ return { pkg + " .framework/Headers" + tail,
2445+ pkg + " .framework/PrivateHeaders" + tail };
2446+ }
2447+
2448+ inline void push_unique (std::vector<std::string> &v, std::string p) {
2449+ if (!p.empty () && (v.empty () || v.back () != p))
2450+ v.push_back (std::move (p));
2451+ }
2452+ }
2453+
24322454namespace simplecpp {
24332455 /* *
24342456 * perform path simplifications for . and ..
@@ -2999,12 +3021,61 @@ static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const
29993021 }
30003022 }
30013023
3002- // search the header on the include paths (provided by the flags "-I...")
3003- for (const auto &includePath : dui.includePaths ) {
3004- std::string path = openHeaderDirect (f, simplecpp::simplifyPath (includePath + " /" + header));
3005- if (!path.empty ())
3006- return path;
3024+ // Build an ordered, typed path list:
3025+ // - Prefer DUI::searchPaths when provided (interleaved -I/-F/-iframework).
3026+ // - Otherwise mirror legacy includePaths into Include entries (back-compat).
3027+ std::vector<simplecpp::DUI::SearchPath> searchPaths;
3028+ if (!dui.searchPaths .empty ()) {
3029+ searchPaths = dui.searchPaths ;
3030+ } else {
3031+ searchPaths.reserve (dui.includePaths .size ());
3032+ for (const auto &includePath : dui.includePaths )
3033+ searchPaths.push_back ({includePath, simplecpp::DUI::PathKind::Include});
30073034 }
3035+
3036+ // Interleave -I and -F in CLI order
3037+ for (const auto &searchPath : searchPaths) {
3038+ if (searchPath.kind == simplecpp::DUI::PathKind::Include) {
3039+ const std::string path = openHeaderDirect (f, simplecpp::simplifyPath (searchPath.path + " /" + header));
3040+ if (!path.empty ())
3041+ return path;
3042+ } else if (searchPath.kind == simplecpp::DUI::PathKind::Framework) {
3043+ // try Headers then PrivateHeaders
3044+ const auto relatives = toAppleFrameworkRelatives (header);
3045+ if (relatives[0 ] != header) { // Skip if no framework rewrite was applied.
3046+ for (const auto &rel : relatives) {
3047+ const std::string frameworkPath = openHeaderDirect (f, simplecpp::simplifyPath (searchPath.path + " /" + rel));
3048+ if (!frameworkPath.empty ())
3049+ return frameworkPath;
3050+ }
3051+ }
3052+ }
3053+ }
3054+
3055+ // -isystem
3056+ for (const auto &searchPath : searchPaths) {
3057+ if (searchPath.kind == simplecpp::DUI::PathKind::SystemInclude) {
3058+ std::string path = openHeaderDirect (f, simplecpp::simplifyPath (searchPath.path + " /" + header));
3059+ if (!path.empty ())
3060+ return path;
3061+ }
3062+ }
3063+
3064+ // -iframework
3065+ for (const auto &searchPath : searchPaths) {
3066+ if (searchPath.kind == simplecpp::DUI::PathKind::SystemFramework) {
3067+ const auto relatives = toAppleFrameworkRelatives (header);
3068+ if (relatives[0 ] != header) { // Skip if no framework rewrite was applied.
3069+ // Try Headers then PrivateHeaders
3070+ for (const auto &rel : relatives) {
3071+ const std::string frameworkPath = openHeaderDirect (f, simplecpp::simplifyPath (searchPath.path + " /" + rel));
3072+ if (!frameworkPath.empty ())
3073+ return frameworkPath;
3074+ }
3075+ }
3076+ }
3077+ }
3078+
30083079 return " " ;
30093080}
30103081
@@ -3036,6 +3107,7 @@ std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::tryload(FileDat
30363107
30373108std::pair<simplecpp::FileData *, bool > simplecpp::FileDataCache::get (const std::string &sourcefile, const std::string &header, const simplecpp::DUI &dui, bool systemheader, std::vector<std::string> &filenames, simplecpp::OutputList *outputList)
30383109{
3110+ // Absolute path: load directly
30393111 if (isAbsolutePath (header)) {
30403112 auto ins = mNameMap .emplace (simplecpp::simplifyPath (header), nullptr );
30413113
@@ -3051,32 +3123,78 @@ std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::get(const std::
30513123 return {nullptr , false };
30523124 }
30533125
3126+ // Build ordered candidates.
3127+ std::vector<std::string> candidates;
3128+
3129+ // Prefer first to search the header relatively to source file if found, when not a system header
30543130 if (!systemheader) {
3055- auto ins = mNameMap .emplace (simplecpp::simplifyPath (dirPath (sourcefile) + header), nullptr );
3131+ push_unique (candidates, simplecpp::simplifyPath (dirPath (sourcefile) + header));
3132+ }
30563133
3057- if (ins.second ) {
3058- const auto ret = tryload (ins.first , dui, filenames, outputList);
3059- if (ret.first != nullptr ) {
3060- return ret;
3134+ // Build an ordered, typed path list:
3135+ // - Prefer DUI::searchPaths when provided (interleaved -I/-F/-iframework).
3136+ // - Otherwise mirror legacy includePaths into Include entries (back-compat).
3137+ std::vector<simplecpp::DUI::SearchPath> searchPaths;
3138+ if (!dui.searchPaths .empty ()) {
3139+ searchPaths = dui.searchPaths ;
3140+ } else {
3141+ searchPaths.reserve (dui.includePaths .size ());
3142+ for (const auto &p : dui.includePaths )
3143+ searchPaths.push_back ({p, simplecpp::DUI::PathKind::Include});
3144+ }
3145+
3146+ // Interleave -I and -F in CLI order
3147+ for (const auto &searchPath : searchPaths) {
3148+ if (searchPath.kind == simplecpp::DUI::PathKind::Include) {
3149+ push_unique (candidates, simplecpp::simplifyPath (searchPath.path + " /" + header));
3150+ } else if (searchPath.kind == simplecpp::DUI::PathKind::Framework) {
3151+ // Try Headers then PrivateHeaders
3152+ const auto relatives = toAppleFrameworkRelatives (header);
3153+ if (relatives[0 ] != header) { // Skip if no framework rewrite was applied.
3154+ push_unique (candidates, simplecpp::simplifyPath (searchPath.path + " /" + relatives[0 ]));
3155+ push_unique (candidates, simplecpp::simplifyPath (searchPath.path + " /" + relatives[1 ]));
30613156 }
3062- } else if (ins.first ->second != nullptr ) {
3063- return {ins.first ->second , false };
30643157 }
30653158 }
30663159
3067- for (const auto &includePath : dui.includePaths ) {
3068- auto ins = mNameMap .emplace (simplecpp::simplifyPath (includePath + " /" + header), nullptr );
3160+ // -isystem
3161+ for (const auto &searchPath : searchPaths) {
3162+ if (searchPath.kind == DUI::PathKind::SystemInclude) {
3163+ push_unique (candidates, simplecpp::simplifyPath (searchPath.path + " /" + header));
3164+ }
3165+ }
30693166
3070- if (ins.second ) {
3071- const auto ret = tryload (ins.first , dui, filenames, outputList);
3072- if (ret.first != nullptr ) {
3073- return ret;
3167+ // -iframework
3168+ for (const auto &searchPath : searchPaths) {
3169+ if (searchPath.kind == simplecpp::DUI::PathKind::SystemFramework) {
3170+ // Try Headers then PrivateHeaders
3171+ const auto relatives = toAppleFrameworkRelatives (header);
3172+ if (relatives[0 ] != header) { // Skip if no framework rewrite was applied.
3173+ push_unique (candidates, simplecpp::simplifyPath (searchPath.path + " /" + relatives[0 ]));
3174+ push_unique (candidates, simplecpp::simplifyPath (searchPath.path + " /" + relatives[1 ]));
30743175 }
3075- } else if (ins.first ->second != nullptr ) {
3076- return {ins.first ->second , false };
30773176 }
30783177 }
30793178
3179+ // Try loading each candidate path (left-to-right).
3180+ for (const std::string &candidate : candidates) {
3181+ // Already loaded?
3182+ auto it = mNameMap .find (candidate);
3183+ if (it != mNameMap .end ()) {
3184+ return {it->second , false };
3185+ }
3186+
3187+ auto ins = mNameMap .emplace (candidate, static_cast <FileData *>(nullptr ));
3188+ const auto ret = tryload (ins.first , dui, filenames, outputList);
3189+ if (ret.first != nullptr ) {
3190+ return ret;
3191+ }
3192+
3193+ // Failed: remove placeholder so we can retry later if needed.
3194+ mNameMap .erase (ins.first );
3195+ }
3196+
3197+ // Not found.
30803198 return {nullptr , false };
30813199}
30823200
0 commit comments