https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/91770
>From 291412a203ea60465d4ecae9317f3490c59bfb50 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida <cyndy_ish...@apple.com> Date: Thu, 2 May 2024 19:53:07 -0700 Subject: [PATCH 1/2] [InstallAPI] add JSON option to pass X<label> arguments --- .../clang/Basic/DiagnosticInstallAPIKinds.td | 2 +- clang/test/InstallAPI/alias_list.test | 2 +- clang/test/InstallAPI/exclusive-passes-2.test | 9 ++ clang/test/InstallAPI/exclusive-passes-3.test | 86 +++++++++++++++++++ clang/test/InstallAPI/exclusive-passes.test | 15 ++++ .../InstallAPI/invalid-exclusive-passes.test | 33 +++++++ .../tools/clang-installapi/InstallAPIOpts.td | 3 + clang/tools/clang-installapi/Options.cpp | 74 +++++++++++++++- clang/tools/clang-installapi/Options.h | 2 + 9 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 clang/test/InstallAPI/exclusive-passes-3.test diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 674742431dcb2..944b2a38b6e96 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -24,7 +24,7 @@ def err_no_matching_target : Error<"no matching target found for target variant def err_unsupported_vendor : Error<"vendor '%0' is not supported: '%1'">; def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'">; def err_unsupported_os : Error<"os '%0' is not supported: '%1'">; -def err_cannot_read_input_list : Error<"could not read %select{alias list|filelist}0 '%1': %2">; +def err_cannot_read_input_list : Error<"could not read %0 input list '%1': %2">; def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X<label>">; } // end of command line category. diff --git a/clang/test/InstallAPI/alias_list.test b/clang/test/InstallAPI/alias_list.test index 3e12221e088c4..aba7e395cca95 100644 --- a/clang/test/InstallAPI/alias_list.test +++ b/clang/test/InstallAPI/alias_list.test @@ -23,7 +23,7 @@ ; RUN: -o %t/AliasList.tbd 2>&1 | FileCheck -allow-empty %s \ ; RUN: --check-prefix=INVALID -; INVALID: error: could not read alias list {{.*}} missing alias for: _hidden +; INVALID: error: could not read symbol alias input list {{.*}}invalid.txt': invalid input format: missing alias for: _hidden ;--- Frameworks/AliasList.framework/Headers/AliasList.h // simple alias from one symbol to another. diff --git a/clang/test/InstallAPI/exclusive-passes-2.test b/clang/test/InstallAPI/exclusive-passes-2.test index 3e7a6d777d5af..132b27df383c4 100644 --- a/clang/test/InstallAPI/exclusive-passes-2.test +++ b/clang/test/InstallAPI/exclusive-passes-2.test @@ -11,6 +11,15 @@ ; RUN: -DFoo -XApple -DDarwin=1 -XElf -DNONDarwin=1 2>&1 | FileCheck -allow-empty %s ; RUN: llvm-readtapi --compare %t/output.tbd %t/expected.tbd 2>&1 | FileCheck -allow-empty %s +; RUN: clang-installapi -target arm64-apple-macos12 \ +; RUN: -install_name @rpath/libfoo.dylib \ +; RUN: -current_version 1 -compatibility_version 1 \ +; RUN: -I%S/Inputs/LibFoo/usr/include -dynamiclib \ +; RUN: -extra-public-header %S/Inputs/LibFoo/usr/include/foo.h \ +; RUN: -o %t/output2.tbd \ +; RUN: -DFoo -optionlist %t/options.json 2>&1 | FileCheck -allow-empty %s +; RUN: llvm-readtapi --compare %t/output.tbd %t/expected.tbd 2>&1 | FileCheck -allow-empty %s + ; CHECK-NOT: error ; CHECK-NOT: warning diff --git a/clang/test/InstallAPI/exclusive-passes-3.test b/clang/test/InstallAPI/exclusive-passes-3.test new file mode 100644 index 0000000000000..3a9b64c9f7b86 --- /dev/null +++ b/clang/test/InstallAPI/exclusive-passes-3.test @@ -0,0 +1,86 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t + +// "Apple" label has split options between the optionlist & command line. +; RUN: clang-installapi -target arm64-apple-macos12 \ +; RUN: -install_name @rpath/libfoo.dylib -current_version 1 \ +; RUN: -compatibility_version 1 \ +; RUN: -extra-public-header %t/usr/include/opts.h \ +; RUN: -optionlist %t/options.json -XApple -DCLI_OPT=1 \ +; RUN: -I%S/Inputs/LibFoo/usr/include \ +; RUN: -I%t/usr/include -dynamiclib -o %t/output.tbd 2>&1 | FileCheck %s -allow-empty +; RUN: llvm-readtapi --compare %t/output.tbd %t/expected.tbd 2>&1 | FileCheck -allow-empty %s + +// Validate duplicated options give same result. +; RUN: clang-installapi -target arm64-apple-macos12 \ +; RUN: -install_name @rpath/libfoo.dylib -current_version 1 \ +; RUN: -compatibility_version 1 \ +; RUN: -extra-public-header %t/usr/include/opts.h \ +; RUN: -optionlist %t/options.json -XApple -DCLI_OPT=1 \ +; RUN: -I%S/Inputs/LibFoo/usr/include \ +; RUN: -XApple -DDarwin -XElf -DNONDarwin \ +; RUN: -I%t/usr/include -dynamiclib -o %t/output2.tbd 2>&1 | FileCheck %s -allow-empty +; RUN: llvm-readtapi --compare %t/output2.tbd %t/expected.tbd 2>&1 | FileCheck -allow-empty %s + +; CHECK-NOT: error +; CHECK-NOT: warning + +;--- usr/include/opts.h +#ifndef OPTS_H +#define OPTS_H +#include <macro_defs.h> + +#if defined(CLI_OPT) && CLI_OPT + #define SUFFIX "$final" +#else + #define SUFFIX +#endif + + +#define __STRING(x) #x +#define PLATFORM_ALIAS(sym) __asm("_" __STRING(sym) DARWIN LINUX SUFFIX) +extern int foo() PLATFORM_ALIAS(foo); + +#endif + +;--- expected.tbd +{ + "main_library": { + "exported_symbols": [ + { + "text": { + "global": [ + "_foo$darwin$final", + "_foo$linux", + "_foo" + ] + } + } + ], + "flags": [ + { + "attributes": [ + "not_app_extension_safe" + ] + } + ], + "install_names": [ + { + "name": "@rpath/libfoo.dylib" + } + ], + "target_info": [ + { + "min_deployment": "12", + "target": "arm64-macos" + } + ] + }, + "tapi_tbd_version": 5 +} + +//--- options.json +{ + "Apple" : ["-DDarwin=1"], + "Elf" : ["-DNONDarwin=1"] +} diff --git a/clang/test/InstallAPI/exclusive-passes.test b/clang/test/InstallAPI/exclusive-passes.test index 29b0fc3d7a2aa..8e2d01ebaab19 100644 --- a/clang/test/InstallAPI/exclusive-passes.test +++ b/clang/test/InstallAPI/exclusive-passes.test @@ -10,6 +10,15 @@ ; RUN: -o %t/output.tbd -v 2>&1 | FileCheck %s --check-prefix=INSTALLAPI ; RUN: llvm-readtapi --compare %t/output.tbd %t/expected.tbd 2>&1 | FileCheck -allow-empty %s +// Try with -optionlist. +; RUN: clang-installapi \ +; RUN: -target arm64-apple-macos12 -install_name @rpath/libfoo.dylib \ +; RUN: -current_version 1 -compatibility_version 1 \ +; RUN: -I%S/Inputs/LibFoo/usr/include -dynamiclib \ +; RUN: -extra-public-header %S/Inputs/LibFoo/usr/include/public.h \ +; RUN: -optionlist %t/options.json -o %t/output2.tbd 2>&1 | FileCheck %s -allow-empty +; RUN: llvm-readtapi --compare %t/output2.tbd %t/expected.tbd 2>&1 | FileCheck -allow-empty %s + ; CHECK-NOT: error ; CHECK-NOT: warning @@ -17,6 +26,12 @@ ; INSTALLAPI: Apple Public Headers: ; INSTALLAPI: Elf Public Headers: +;--- options.json +{ + "Apple" : ["-DDarwin=1"], + "Elf" : ["-DNONDarwin=1"] +} + ;--- expected.tbd { "main_library": { diff --git a/clang/test/InstallAPI/invalid-exclusive-passes.test b/clang/test/InstallAPI/invalid-exclusive-passes.test index c23c918f0bfbb..24b3e3193866c 100644 --- a/clang/test/InstallAPI/invalid-exclusive-passes.test +++ b/clang/test/InstallAPI/invalid-exclusive-passes.test @@ -30,6 +30,39 @@ ; RUN: -o %t/output.tbd 2>&1 | FileCheck %s --check-prefix=INVALID_PROJECT_OPT ; INVALID_PROJECT_OPT: error: invalid argument '-Xproject' not allowed with '-fprofile-instr-generate' +// Validate arguments not allowed with -X passed via json +; RUN: not clang-installapi -target arm64-apple-macos12 \ +; RUN: -install_name @rpath/libfoo.dylib -current_version 1 -compatibility_version 1 \ +; RUN: -optionlist %t/options.json -I/fake/path \ +; RUN: -I%t -dynamiclib -o %t/output.tbd 2>&1 | FileCheck %s --check-prefix=INVALID_JSON_OPT +; INVALID_JSON_OPT: error: invalid argument '-XApple' not allowed with '-I/fake/path' + +// Validate invalid json path +; RUN: not clang-installapi -target arm64-apple-macos12 \ +; RUN: -install_name @rpath/libfoo.dylib -current_version 1 \ +; RUN: -compatibility_version 1 -optionlist %t/invalid_loc.json \ +; RUN: -I/fake/path -I%t -dynamiclib \ +; RUN: -o %t/output.tbd %t 2>&1 | FileCheck %s --check-prefix=INVALID_JSON_LOC +; INVALID_JSON_LOC: error: cannot open file {{.*}}invalid_loc.json': No such file or directory + +// Validate invalid json format +; RUN: not clang-installapi -target arm64-apple-macos12 \ +; RUN: -install_name @rpath/libfoo.dylib -current_version 1 \ +; RUN: -compatibility_version 1 -optionlist %t/invalid_format.json \ +; RUN: -I/fake/path -isysroot %sysroot -I%t -dynamiclib \ +; RUN: -o %t/output.tbd %t 2>&1 | FileCheck %s --check-prefix=INVALID_JSON_FORMAT +; INVALID_JSON_FORMAT: error: could not read option input list {{.*}}invalid_format.json': invalid input format + +;--- options.json +{ + "Apple" : ["-I/fake/path"] +} + +;--- invalid_format.json +{ + "Apple" : {"opt" : "-I/fake/path"} +} + ;--- inputs.json { "headers": [ ], diff --git a/clang/tools/clang-installapi/InstallAPIOpts.td b/clang/tools/clang-installapi/InstallAPIOpts.td index a95a7a80a9d20..fc0fbe929c887 100644 --- a/clang/tools/clang-installapi/InstallAPIOpts.td +++ b/clang/tools/clang-installapi/InstallAPIOpts.td @@ -99,6 +99,9 @@ def X__ : Joined<["-"], "X">, HelpText<"Pass <arg> to run unique clang invocation identified as <label>">, MetaVarName<"<label> <arg>">; +def option_list : Separate<["-"], "optionlist">, MetaVarName<"<path>">, + HelpText<"Specifies the <path> to a file that contains X<label> arguments to parse.">; + // /// Overidden clang options for different behavior. // diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp index 53340da704fc0..95d28b7b040d7 100644 --- a/clang/tools/clang-installapi/Options.cpp +++ b/clang/tools/clang-installapi/Options.cpp @@ -13,6 +13,7 @@ #include "clang/InstallAPI/HeaderFile.h" #include "clang/InstallAPI/InstallAPIDiagnostic.h" #include "llvm/BinaryFormat/Magic.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/Program.h" #include "llvm/TargetParser/Host.h" #include "llvm/TextAPI/DylibReader.h" @@ -82,6 +83,47 @@ static llvm::opt::OptTable *createDriverOptTable() { return new DriverOptTable(); } +/// Parse JSON input into argument list. +/// +/* Expected input format. + * { "label" : ["-ClangArg1", "-ClangArg2"] } + */ +/// +/// Input is interpreted as "-Xlabel ClangArg1 -XLabel ClangArg2". +static Expected<llvm::opt::InputArgList> +getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table, + std::vector<std::string> &Storage) { + using namespace json; + Expected<Value> ValOrErr = json::parse(Input); + if (!ValOrErr) + return ValOrErr.takeError(); + + const Object *Root = ValOrErr->getAsObject(); + if (!Root) + return llvm::opt::InputArgList(); + + for (const auto &KV : *Root) { + const Array *ArgList = KV.getSecond().getAsArray(); + std::string Label = "-X" + KV.getFirst().str(); + if (!ArgList) + return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat); + for (auto Arg : *ArgList) { + std::optional<StringRef> ArgStr = Arg.getAsString(); + if (!ArgStr) + return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat); + Storage.emplace_back(Label); + Storage.emplace_back(*ArgStr); + } + } + + std::vector<const char *> CArgs(Storage.size()); + llvm::for_each(Storage, + [&CArgs](StringRef Str) { CArgs.emplace_back(Str.data()); }); + + unsigned MissingArgIndex, MissingArgCount; + return Table->ParseArgs(CArgs, MissingArgIndex, MissingArgCount); +} + bool Options::processDriverOptions(InputArgList &Args) { // Handle inputs. llvm::append_range(DriverOpts.FileLists, @@ -348,6 +390,31 @@ bool Options::processXarchOption(InputArgList &Args, arg_iterator Curr) { return true; } +bool Options::processOptionList(InputArgList &Args, + llvm::opt::OptTable *Table) { + Arg *A = Args.getLastArg(OPT_option_list); + if (!A) + return true; + + const StringRef Path = A->getValue(0); + auto InputOrErr = FM->getBufferForFile(Path); + if (auto Err = InputOrErr.getError()) { + Diags->Report(diag::err_cannot_open_file) << Path << Err.message(); + return false; + } + // Backing storage referenced for argument processing. + std::vector<std::string> Storage; + auto ArgsOrErr = + getArgListFromJSON((*InputOrErr)->getBuffer(), Table, Storage); + + if (auto Err = ArgsOrErr.takeError()) { + Diags->Report(diag::err_cannot_read_input_list) + << "option" << Path << toString(std::move(Err)); + return false; + } + return processInstallAPIXOptions(*ArgsOrErr); +} + bool Options::processLinkerOptions(InputArgList &Args) { // Handle required arguments. if (const Arg *A = Args.getLastArg(drv::OPT_install__name)) @@ -510,6 +577,9 @@ Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) { if (!processInstallAPIXOptions(ParsedArgs)) return {}; + if (!processOptionList(ParsedArgs, Table.get())) + return {}; + DriverOpts.Demangle = ParsedArgs.hasArg(OPT_demangle); if (auto *A = ParsedArgs.getLastArg(OPT_filetype)) { @@ -818,7 +888,7 @@ InstallAPIContext Options::createContext() { Expected<AliasMap> Result = parseAliasList(Buffer.get()); if (!Result) { Diags->Report(diag::err_cannot_read_input_list) - << /*IsFileList=*/false << ListPath << toString(Result.takeError()); + << "symbol alias" << ListPath << toString(Result.takeError()); return Ctx; } Aliases.insert(Result.get().begin(), Result.get().end()); @@ -839,7 +909,7 @@ InstallAPIContext Options::createContext() { if (auto Err = FileListReader::loadHeaders(std::move(Buffer.get()), Ctx.InputHeaders, FM)) { Diags->Report(diag::err_cannot_read_input_list) - << /*IsFileList=*/true << ListPath << std::move(Err); + << "header file" << ListPath << std::move(Err); return Ctx; } } diff --git a/clang/tools/clang-installapi/Options.h b/clang/tools/clang-installapi/Options.h index fd1e10065d102..b37f91efbda72 100644 --- a/clang/tools/clang-installapi/Options.h +++ b/clang/tools/clang-installapi/Options.h @@ -161,6 +161,8 @@ class Options { bool processXarchOption(llvm::opt::InputArgList &Args, arg_iterator Curr); bool processXplatformOption(llvm::opt::InputArgList &Args, arg_iterator Curr); bool processXprojectOption(llvm::opt::InputArgList &Args, arg_iterator Curr); + bool processOptionList(llvm::opt::InputArgList &Args, + llvm::opt::OptTable *Table); public: /// The various options grouped together. >From ed86eb78207c881466e532ce810217a81e6a09fc Mon Sep 17 00:00:00 2001 From: Cyndy Ishida <cyndy_ish...@apple.com> Date: Mon, 20 May 2024 13:49:48 -0700 Subject: [PATCH 2/2] Fix windows test --- clang/test/InstallAPI/invalid-exclusive-passes.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/InstallAPI/invalid-exclusive-passes.test b/clang/test/InstallAPI/invalid-exclusive-passes.test index 24b3e3193866c..ef9dd857c0072 100644 --- a/clang/test/InstallAPI/invalid-exclusive-passes.test +++ b/clang/test/InstallAPI/invalid-exclusive-passes.test @@ -42,8 +42,8 @@ ; RUN: -install_name @rpath/libfoo.dylib -current_version 1 \ ; RUN: -compatibility_version 1 -optionlist %t/invalid_loc.json \ ; RUN: -I/fake/path -I%t -dynamiclib \ -; RUN: -o %t/output.tbd %t 2>&1 | FileCheck %s --check-prefix=INVALID_JSON_LOC -; INVALID_JSON_LOC: error: cannot open file {{.*}}invalid_loc.json': No such file or directory +; RUN: -o %t/output.tbd %t 2>&1 | FileCheck %s --check-prefix=INVALID_JSON_LOC -DMSG=%errc_ENOENT %s +; INVALID_JSON_LOC: error: cannot open file {{.*}}invalid_loc.json': [[MSG]] // Validate invalid json format ; RUN: not clang-installapi -target arm64-apple-macos12 \ _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits