[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
https://github.com/cyndyishida created https://github.com/llvm/llvm-project/pull/86587 Umbrella headers are a concept for Darwin-based libraries. They allow framework authors to control the order in which their headers should be parsed and allow clients to access available headers by including a single header. InstallAPI will attempt to find the umbrella based on the name of the framework. Users can also specify this explicitly by using command line options specifying the umbrella header by file path. There can be an umbrella header per access level. >From 9b25b0486d8f3c8409ee199a9f4695da7780e6cb Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Mon, 25 Mar 2024 17:12:14 -0400 Subject: [PATCH] [InstallAPI] Add *umbrella-header options Umbrella headers are a concept for darwin based libraries. They allow framework authors control the order of which their headers should be parsed and allows clients to access available headers by including a single header. InstallAPI will attempt to find the umbrella based on the name of the framework. Users can also specify this explicitly by using command line options specifying the umbrella header by file path. --- .../clang/Basic/DiagnosticInstallAPIKinds.td | 1 + clang/include/clang/InstallAPI/HeaderFile.h | 12 ++- clang/test/InstallAPI/umbrella-headers.test | 59 +++ .../tools/clang-installapi/InstallAPIOpts.td | 12 +++ clang/tools/clang-installapi/Options.cpp | 74 +++ clang/tools/clang-installapi/Options.h| 9 +++ llvm/include/llvm/TextAPI/Utils.h | 3 + 7 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 clang/test/InstallAPI/umbrella-headers.test diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 27df731fa28627..d710688fc1fe20 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -18,6 +18,7 @@ def err_no_output_file: Error<"no output file specified">; def err_no_such_header_file : Error<"no such %select{public|private|project}1 header file: '%0'">; def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup; def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup; +def err_no_such_umbrella_header_file : Error<"no such %select{public|private|project}1 umbrella header file: '%0'">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h index 235b4da3add840..332cd415b39ae4 100644 --- a/clang/include/clang/InstallAPI/HeaderFile.h +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -62,6 +62,8 @@ class HeaderFile { bool Excluded{false}; /// Add header file to processing. bool Extra{false}; + /// Specify that header file is the umbrella header for library. + bool Umbrella{false}; public: HeaderFile() = delete; @@ -79,17 +81,21 @@ class HeaderFile { void setExtra(bool V = true) { Extra = V; } void setExcluded(bool V = true) { Excluded = V; } + void setUmbrellaHeader(bool V = true) { Umbrella = V; } bool isExtra() const { return Extra; } bool isExcluded() const { return Excluded; } + bool isUmbrellaHeader() const { return Umbrella; } bool useIncludeName() const { return Type != HeaderType::Project && !IncludeName.empty(); } bool operator==(const HeaderFile &Other) const { -return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra) == - std::tie(Other.Type, Other.FullPath, Other.IncludeName, -Other.Language, Other.Excluded, Other.Extra); +return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra, +Umbrella) == std::tie(Other.Type, Other.FullPath, + Other.IncludeName, Other.Language, + Other.Excluded, Other.Extra, + Other.Umbrella); } }; diff --git a/clang/test/InstallAPI/umbrella-headers.test b/clang/test/InstallAPI/umbrella-headers.test new file mode 100644 index 00..b91d3df25b38ec --- /dev/null +++ b/clang/test/InstallAPI/umbrella-headers.test @@ -0,0 +1,59 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json + +// Try umbrella header flags with different spellings. +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella2 \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=%t/Frameworks/Umbrella2.framework/Headers/SpecialUmbrella.h \ +; RUN: -private-umbrella-header \ +; RUN: %t/Frameworks/Umbrella2.framework/PrivateHeaders/SpecialPrivateU
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Cyndy Ishida (cyndyishida) Changes Umbrella headers are a concept for Darwin-based libraries. They allow framework authors to control the order in which their headers should be parsed and allow clients to access available headers by including a single header. InstallAPI will attempt to find the umbrella based on the name of the framework. Users can also specify this explicitly by using command line options specifying the umbrella header by file path. There can be an umbrella header per access level. --- Full diff: https://github.com/llvm/llvm-project/pull/86587.diff 7 Files Affected: - (modified) clang/include/clang/Basic/DiagnosticInstallAPIKinds.td (+1) - (modified) clang/include/clang/InstallAPI/HeaderFile.h (+9-3) - (added) clang/test/InstallAPI/umbrella-headers.test (+59) - (modified) clang/tools/clang-installapi/InstallAPIOpts.td (+12) - (modified) clang/tools/clang-installapi/Options.cpp (+74) - (modified) clang/tools/clang-installapi/Options.h (+9) - (modified) llvm/include/llvm/TextAPI/Utils.h (+3) ``diff diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 27df731fa28627..d710688fc1fe20 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -18,6 +18,7 @@ def err_no_output_file: Error<"no output file specified">; def err_no_such_header_file : Error<"no such %select{public|private|project}1 header file: '%0'">; def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup; def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup; +def err_no_such_umbrella_header_file : Error<"no such %select{public|private|project}1 umbrella header file: '%0'">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h index 235b4da3add840..332cd415b39ae4 100644 --- a/clang/include/clang/InstallAPI/HeaderFile.h +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -62,6 +62,8 @@ class HeaderFile { bool Excluded{false}; /// Add header file to processing. bool Extra{false}; + /// Specify that header file is the umbrella header for library. + bool Umbrella{false}; public: HeaderFile() = delete; @@ -79,17 +81,21 @@ class HeaderFile { void setExtra(bool V = true) { Extra = V; } void setExcluded(bool V = true) { Excluded = V; } + void setUmbrellaHeader(bool V = true) { Umbrella = V; } bool isExtra() const { return Extra; } bool isExcluded() const { return Excluded; } + bool isUmbrellaHeader() const { return Umbrella; } bool useIncludeName() const { return Type != HeaderType::Project && !IncludeName.empty(); } bool operator==(const HeaderFile &Other) const { -return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra) == - std::tie(Other.Type, Other.FullPath, Other.IncludeName, -Other.Language, Other.Excluded, Other.Extra); +return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra, +Umbrella) == std::tie(Other.Type, Other.FullPath, + Other.IncludeName, Other.Language, + Other.Excluded, Other.Extra, + Other.Umbrella); } }; diff --git a/clang/test/InstallAPI/umbrella-headers.test b/clang/test/InstallAPI/umbrella-headers.test new file mode 100644 index 00..b91d3df25b38ec --- /dev/null +++ b/clang/test/InstallAPI/umbrella-headers.test @@ -0,0 +1,59 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json + +// Try umbrella header flags with different spellings. +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella2 \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=%t/Frameworks/Umbrella2.framework/Headers/SpecialUmbrella.h \ +; RUN: -private-umbrella-header \ +; RUN: %t/Frameworks/Umbrella2.framework/PrivateHeaders/SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella2 \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=SpecialUmbrella.h \ +; RUN: --private-umbrella-header=SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +; CHECK-NOT: error +; CHECK-NOT: warning + +;--- Frameworks/Umbrella2.framework/Headers/SpecialUmbrella.h +#define PUBLIC_UMBRELLA_HEADER_FIRST + +;---
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
github-actions[bot] wrote: :white_check_mark: With the latest revision this PR passed the Python code formatter. https://github.com/llvm/llvm-project/pull/86587 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
github-actions[bot] wrote: :white_check_mark: With the latest revision this PR passed the C/C++ code formatter. https://github.com/llvm/llvm-project/pull/86587 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
@@ -424,6 +448,56 @@ InstallAPIContext Options::createContext() { if (!Glob->didMatch()) Diags->Report(diag::warn_glob_did_not_match) << Glob->str(); + // Mark any explicit or inferred umbrella headers. If one exists, move + // that to the beginning of the input headers. + auto MarkandMoveUmbrellaInHeaders = [&](Regex &Regex, + HeaderType Type) -> bool { +auto It = find_if(Ctx.InputHeaders, [&Regex, Type](const HeaderFile &H) { + return (H.getType() == Type) && Regex.match(H.getPath()); +}); + +if (It == Ctx.InputHeaders.end()) + return false; +It->setUmbrellaHeader(); + +// Because there can be an umbrella header per header type, +// find the first non umbrella header to swap position with. +auto BeginPos = find_if(Ctx.InputHeaders, [](const HeaderFile &H) { + return !H.isUmbrellaHeader(); +}); +if (BeginPos != Ctx.InputHeaders.end() && BeginPos < It) + std::swap(*BeginPos, *It); +return true; + }; + + auto FindUmbrellaHeader = [&](StringRef HeaderPath, HeaderType Type) -> bool { +if (!HeaderPath.empty()) { + auto EscapedString = Regex::escape(HeaderPath); + Regex UmbrellaRegex(EscapedString); + if (!MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type)) { +Diags->Report(diag::err_no_such_umbrella_header_file) +<< HeaderPath << (unsigned)Type - 1; ributzka wrote: Could the `HeaderType` enum be reshuffled so this arithmetic is not required? https://github.com/llvm/llvm-project/pull/86587 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
@@ -424,6 +448,56 @@ InstallAPIContext Options::createContext() { if (!Glob->didMatch()) Diags->Report(diag::warn_glob_did_not_match) << Glob->str(); + // Mark any explicit or inferred umbrella headers. If one exists, move + // that to the beginning of the input headers. + auto MarkandMoveUmbrellaInHeaders = [&](Regex &Regex, + HeaderType Type) -> bool { +auto It = find_if(Ctx.InputHeaders, [&Regex, Type](const HeaderFile &H) { + return (H.getType() == Type) && Regex.match(H.getPath()); +}); + +if (It == Ctx.InputHeaders.end()) + return false; +It->setUmbrellaHeader(); + +// Because there can be an umbrella header per header type, +// find the first non umbrella header to swap position with. +auto BeginPos = find_if(Ctx.InputHeaders, [](const HeaderFile &H) { + return !H.isUmbrellaHeader(); +}); +if (BeginPos != Ctx.InputHeaders.end() && BeginPos < It) + std::swap(*BeginPos, *It); +return true; + }; + + auto FindUmbrellaHeader = [&](StringRef HeaderPath, HeaderType Type) -> bool { +if (!HeaderPath.empty()) { + auto EscapedString = Regex::escape(HeaderPath); + Regex UmbrellaRegex(EscapedString); + if (!MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type)) { +Diags->Report(diag::err_no_such_umbrella_header_file) +<< HeaderPath << (unsigned)Type - 1; ributzka wrote: Could a header ever be of an `unknown` type? https://github.com/llvm/llvm-project/pull/86587 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/86587 >From 9b25b0486d8f3c8409ee199a9f4695da7780e6cb Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Mon, 25 Mar 2024 17:12:14 -0400 Subject: [PATCH 1/2] [InstallAPI] Add *umbrella-header options Umbrella headers are a concept for darwin based libraries. They allow framework authors control the order of which their headers should be parsed and allows clients to access available headers by including a single header. InstallAPI will attempt to find the umbrella based on the name of the framework. Users can also specify this explicitly by using command line options specifying the umbrella header by file path. --- .../clang/Basic/DiagnosticInstallAPIKinds.td | 1 + clang/include/clang/InstallAPI/HeaderFile.h | 12 ++- clang/test/InstallAPI/umbrella-headers.test | 59 +++ .../tools/clang-installapi/InstallAPIOpts.td | 12 +++ clang/tools/clang-installapi/Options.cpp | 74 +++ clang/tools/clang-installapi/Options.h| 9 +++ llvm/include/llvm/TextAPI/Utils.h | 3 + 7 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 clang/test/InstallAPI/umbrella-headers.test diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 27df731fa28627..d710688fc1fe20 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -18,6 +18,7 @@ def err_no_output_file: Error<"no output file specified">; def err_no_such_header_file : Error<"no such %select{public|private|project}1 header file: '%0'">; def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup; def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup; +def err_no_such_umbrella_header_file : Error<"no such %select{public|private|project}1 umbrella header file: '%0'">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h index 235b4da3add840..332cd415b39ae4 100644 --- a/clang/include/clang/InstallAPI/HeaderFile.h +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -62,6 +62,8 @@ class HeaderFile { bool Excluded{false}; /// Add header file to processing. bool Extra{false}; + /// Specify that header file is the umbrella header for library. + bool Umbrella{false}; public: HeaderFile() = delete; @@ -79,17 +81,21 @@ class HeaderFile { void setExtra(bool V = true) { Extra = V; } void setExcluded(bool V = true) { Excluded = V; } + void setUmbrellaHeader(bool V = true) { Umbrella = V; } bool isExtra() const { return Extra; } bool isExcluded() const { return Excluded; } + bool isUmbrellaHeader() const { return Umbrella; } bool useIncludeName() const { return Type != HeaderType::Project && !IncludeName.empty(); } bool operator==(const HeaderFile &Other) const { -return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra) == - std::tie(Other.Type, Other.FullPath, Other.IncludeName, -Other.Language, Other.Excluded, Other.Extra); +return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra, +Umbrella) == std::tie(Other.Type, Other.FullPath, + Other.IncludeName, Other.Language, + Other.Excluded, Other.Extra, + Other.Umbrella); } }; diff --git a/clang/test/InstallAPI/umbrella-headers.test b/clang/test/InstallAPI/umbrella-headers.test new file mode 100644 index 00..b91d3df25b38ec --- /dev/null +++ b/clang/test/InstallAPI/umbrella-headers.test @@ -0,0 +1,59 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json + +// Try umbrella header flags with different spellings. +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella2 \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=%t/Frameworks/Umbrella2.framework/Headers/SpecialUmbrella.h \ +; RUN: -private-umbrella-header \ +; RUN: %t/Frameworks/Umbrella2.framework/PrivateHeaders/SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella2 \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=SpecialUmbrella.h \ +; RUN: --private-umbrella-header=SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +; CHECK-NOT: error +; CHECK-N
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
@@ -424,6 +448,56 @@ InstallAPIContext Options::createContext() { if (!Glob->didMatch()) Diags->Report(diag::warn_glob_did_not_match) << Glob->str(); + // Mark any explicit or inferred umbrella headers. If one exists, move + // that to the beginning of the input headers. + auto MarkandMoveUmbrellaInHeaders = [&](Regex &Regex, + HeaderType Type) -> bool { +auto It = find_if(Ctx.InputHeaders, [&Regex, Type](const HeaderFile &H) { + return (H.getType() == Type) && Regex.match(H.getPath()); +}); + +if (It == Ctx.InputHeaders.end()) + return false; +It->setUmbrellaHeader(); + +// Because there can be an umbrella header per header type, +// find the first non umbrella header to swap position with. +auto BeginPos = find_if(Ctx.InputHeaders, [](const HeaderFile &H) { + return !H.isUmbrellaHeader(); +}); +if (BeginPos != Ctx.InputHeaders.end() && BeginPos < It) + std::swap(*BeginPos, *It); +return true; + }; + + auto FindUmbrellaHeader = [&](StringRef HeaderPath, HeaderType Type) -> bool { +if (!HeaderPath.empty()) { + auto EscapedString = Regex::escape(HeaderPath); + Regex UmbrellaRegex(EscapedString); + if (!MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type)) { +Diags->Report(diag::err_no_such_umbrella_header_file) +<< HeaderPath << (unsigned)Type - 1; cyndyishida wrote: No, added asserts. https://github.com/llvm/llvm-project/pull/86587 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/86587 >From 9b25b0486d8f3c8409ee199a9f4695da7780e6cb Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Mon, 25 Mar 2024 17:12:14 -0400 Subject: [PATCH 1/3] [InstallAPI] Add *umbrella-header options Umbrella headers are a concept for darwin based libraries. They allow framework authors control the order of which their headers should be parsed and allows clients to access available headers by including a single header. InstallAPI will attempt to find the umbrella based on the name of the framework. Users can also specify this explicitly by using command line options specifying the umbrella header by file path. --- .../clang/Basic/DiagnosticInstallAPIKinds.td | 1 + clang/include/clang/InstallAPI/HeaderFile.h | 12 ++- clang/test/InstallAPI/umbrella-headers.test | 59 +++ .../tools/clang-installapi/InstallAPIOpts.td | 12 +++ clang/tools/clang-installapi/Options.cpp | 74 +++ clang/tools/clang-installapi/Options.h| 9 +++ llvm/include/llvm/TextAPI/Utils.h | 3 + 7 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 clang/test/InstallAPI/umbrella-headers.test diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 27df731fa28627..d710688fc1fe20 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -18,6 +18,7 @@ def err_no_output_file: Error<"no output file specified">; def err_no_such_header_file : Error<"no such %select{public|private|project}1 header file: '%0'">; def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup; def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup; +def err_no_such_umbrella_header_file : Error<"no such %select{public|private|project}1 umbrella header file: '%0'">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h index 235b4da3add840..332cd415b39ae4 100644 --- a/clang/include/clang/InstallAPI/HeaderFile.h +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -62,6 +62,8 @@ class HeaderFile { bool Excluded{false}; /// Add header file to processing. bool Extra{false}; + /// Specify that header file is the umbrella header for library. + bool Umbrella{false}; public: HeaderFile() = delete; @@ -79,17 +81,21 @@ class HeaderFile { void setExtra(bool V = true) { Extra = V; } void setExcluded(bool V = true) { Excluded = V; } + void setUmbrellaHeader(bool V = true) { Umbrella = V; } bool isExtra() const { return Extra; } bool isExcluded() const { return Excluded; } + bool isUmbrellaHeader() const { return Umbrella; } bool useIncludeName() const { return Type != HeaderType::Project && !IncludeName.empty(); } bool operator==(const HeaderFile &Other) const { -return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra) == - std::tie(Other.Type, Other.FullPath, Other.IncludeName, -Other.Language, Other.Excluded, Other.Extra); +return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra, +Umbrella) == std::tie(Other.Type, Other.FullPath, + Other.IncludeName, Other.Language, + Other.Excluded, Other.Extra, + Other.Umbrella); } }; diff --git a/clang/test/InstallAPI/umbrella-headers.test b/clang/test/InstallAPI/umbrella-headers.test new file mode 100644 index 00..b91d3df25b38ec --- /dev/null +++ b/clang/test/InstallAPI/umbrella-headers.test @@ -0,0 +1,59 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json + +// Try umbrella header flags with different spellings. +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella2 \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=%t/Frameworks/Umbrella2.framework/Headers/SpecialUmbrella.h \ +; RUN: -private-umbrella-header \ +; RUN: %t/Frameworks/Umbrella2.framework/PrivateHeaders/SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella2 \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=SpecialUmbrella.h \ +; RUN: --private-umbrella-header=SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +; CHECK-NOT: error +; CHECK-N
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
@@ -424,6 +448,56 @@ InstallAPIContext Options::createContext() { if (!Glob->didMatch()) Diags->Report(diag::warn_glob_did_not_match) << Glob->str(); + // Mark any explicit or inferred umbrella headers. If one exists, move + // that to the beginning of the input headers. + auto MarkandMoveUmbrellaInHeaders = [&](Regex &Regex, + HeaderType Type) -> bool { +auto It = find_if(Ctx.InputHeaders, [&Regex, Type](const HeaderFile &H) { + return (H.getType() == Type) && Regex.match(H.getPath()); +}); + +if (It == Ctx.InputHeaders.end()) + return false; +It->setUmbrellaHeader(); + +// Because there can be an umbrella header per header type, +// find the first non umbrella header to swap position with. +auto BeginPos = find_if(Ctx.InputHeaders, [](const HeaderFile &H) { + return !H.isUmbrellaHeader(); +}); +if (BeginPos != Ctx.InputHeaders.end() && BeginPos < It) + std::swap(*BeginPos, *It); +return true; + }; + + auto FindUmbrellaHeader = [&](StringRef HeaderPath, HeaderType Type) -> bool { +if (!HeaderPath.empty()) { + auto EscapedString = Regex::escape(HeaderPath); + Regex UmbrellaRegex(EscapedString); + if (!MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type)) { +Diags->Report(diag::err_no_such_umbrella_header_file) +<< HeaderPath << (unsigned)Type - 1; ributzka wrote: If the type can never be `unknown`, then would it be possible to completely remove it? https://github.com/llvm/llvm-project/pull/86587 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
@@ -424,6 +448,56 @@ InstallAPIContext Options::createContext() { if (!Glob->didMatch()) Diags->Report(diag::warn_glob_did_not_match) << Glob->str(); + // Mark any explicit or inferred umbrella headers. If one exists, move + // that to the beginning of the input headers. + auto MarkandMoveUmbrellaInHeaders = [&](Regex &Regex, + HeaderType Type) -> bool { +auto It = find_if(Ctx.InputHeaders, [&Regex, Type](const HeaderFile &H) { + return (H.getType() == Type) && Regex.match(H.getPath()); +}); + +if (It == Ctx.InputHeaders.end()) + return false; +It->setUmbrellaHeader(); + +// Because there can be an umbrella header per header type, +// find the first non umbrella header to swap position with. +auto BeginPos = find_if(Ctx.InputHeaders, [](const HeaderFile &H) { + return !H.isUmbrellaHeader(); +}); +if (BeginPos != Ctx.InputHeaders.end() && BeginPos < It) + std::swap(*BeginPos, *It); +return true; + }; + + auto FindUmbrellaHeader = [&](StringRef HeaderPath, HeaderType Type) -> bool { +if (!HeaderPath.empty()) { + auto EscapedString = Regex::escape(HeaderPath); + Regex UmbrellaRegex(EscapedString); + if (!MarkandMoveUmbrellaInHeaders(UmbrellaRegex, Type)) { +Diags->Report(diag::err_no_such_umbrella_header_file) +<< HeaderPath << (unsigned)Type - 1; cyndyishida wrote: Oh sorry, I thought you meant for umbrella headers. In general, it's used as a default value. E.g. When non-input header files that are parsed through includes, cached then skipped over when picking up declarations during AST traversal. I think that's generally good to have a concept of null for enum values. https://github.com/llvm/llvm-project/pull/86587 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
https://github.com/cyndyishida edited https://github.com/llvm/llvm-project/pull/86587 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/86587 >From 9b25b0486d8f3c8409ee199a9f4695da7780e6cb Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Mon, 25 Mar 2024 17:12:14 -0400 Subject: [PATCH 1/3] [InstallAPI] Add *umbrella-header options Umbrella headers are a concept for darwin based libraries. They allow framework authors control the order of which their headers should be parsed and allows clients to access available headers by including a single header. InstallAPI will attempt to find the umbrella based on the name of the framework. Users can also specify this explicitly by using command line options specifying the umbrella header by file path. --- .../clang/Basic/DiagnosticInstallAPIKinds.td | 1 + clang/include/clang/InstallAPI/HeaderFile.h | 12 ++- clang/test/InstallAPI/umbrella-headers.test | 59 +++ .../tools/clang-installapi/InstallAPIOpts.td | 12 +++ clang/tools/clang-installapi/Options.cpp | 74 +++ clang/tools/clang-installapi/Options.h| 9 +++ llvm/include/llvm/TextAPI/Utils.h | 3 + 7 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 clang/test/InstallAPI/umbrella-headers.test diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 27df731fa28627..d710688fc1fe20 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -18,6 +18,7 @@ def err_no_output_file: Error<"no output file specified">; def err_no_such_header_file : Error<"no such %select{public|private|project}1 header file: '%0'">; def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup; def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup; +def err_no_such_umbrella_header_file : Error<"no such %select{public|private|project}1 umbrella header file: '%0'">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h index 235b4da3add840..332cd415b39ae4 100644 --- a/clang/include/clang/InstallAPI/HeaderFile.h +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -62,6 +62,8 @@ class HeaderFile { bool Excluded{false}; /// Add header file to processing. bool Extra{false}; + /// Specify that header file is the umbrella header for library. + bool Umbrella{false}; public: HeaderFile() = delete; @@ -79,17 +81,21 @@ class HeaderFile { void setExtra(bool V = true) { Extra = V; } void setExcluded(bool V = true) { Excluded = V; } + void setUmbrellaHeader(bool V = true) { Umbrella = V; } bool isExtra() const { return Extra; } bool isExcluded() const { return Excluded; } + bool isUmbrellaHeader() const { return Umbrella; } bool useIncludeName() const { return Type != HeaderType::Project && !IncludeName.empty(); } bool operator==(const HeaderFile &Other) const { -return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra) == - std::tie(Other.Type, Other.FullPath, Other.IncludeName, -Other.Language, Other.Excluded, Other.Extra); +return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra, +Umbrella) == std::tie(Other.Type, Other.FullPath, + Other.IncludeName, Other.Language, + Other.Excluded, Other.Extra, + Other.Umbrella); } }; diff --git a/clang/test/InstallAPI/umbrella-headers.test b/clang/test/InstallAPI/umbrella-headers.test new file mode 100644 index 00..b91d3df25b38ec --- /dev/null +++ b/clang/test/InstallAPI/umbrella-headers.test @@ -0,0 +1,59 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json + +// Try umbrella header flags with different spellings. +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella2 \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=%t/Frameworks/Umbrella2.framework/Headers/SpecialUmbrella.h \ +; RUN: -private-umbrella-header \ +; RUN: %t/Frameworks/Umbrella2.framework/PrivateHeaders/SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +; RUN: clang-installapi --target=arm64-apple-macosx13 \ +; RUN: -install_name /System/Library/Frameworks/Umbrella2.framework/Versions/A/Umbrella2 \ +; RUN: -ObjC -F%t/Frameworks/ %t/inputs.json \ +; RUN: --public-umbrella-header=SpecialUmbrella.h \ +; RUN: --private-umbrella-header=SpecialPrivateUmbrella.h \ +; RUN: -o %t/output.tbd 2>&1 | FileCheck -allow-empty %s + +; CHECK-NOT: error +; CHECK-N
[clang] [llvm] [InstallAPI] Add *umbrella-header options (PR #86587)
https://github.com/ributzka approved this pull request. https://github.com/llvm/llvm-project/pull/86587 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits