[InstallAPI] Set InstallAPI as a standalone tool instead of CC1 action (#82293)

Installapi has important distinctions when compared to the clang driver,
so much that, it doesn't make much sense to try to integrate into it.

This patch partially reverts the CC1 action & driver support to replace
with its own driver as a clang tool.

For distribution, we could use `LLVM_TOOL_LLVM_DRIVER_BUILD` mechanism
for integrating the functionality into clang such that the toolchain
size is less impacted.
This commit is contained in:
Cyndy Ishida 2024-02-21 09:39:31 -08:00 committed by GitHub
parent cc13f3ba45
commit 0a518db99e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 408 additions and 271 deletions

View File

@ -804,7 +804,4 @@ def warn_android_unversioned_fallback : Warning<
def err_drv_triple_version_invalid : Error<
"version '%0' in target triple '%1' is invalid">;
def err_drv_installapi_unsupported : Error<
"InstallAPI is not supported for '%0'">;
}

View File

@ -59,7 +59,6 @@ public:
PreprocessJobClass,
PrecompileJobClass,
ExtractAPIJobClass,
InstallAPIJobClass,
AnalyzeJobClass,
MigrateJobClass,
CompileJobClass,
@ -449,17 +448,6 @@ public:
void addHeaderInput(Action *Input) { getInputs().push_back(Input); }
};
class InstallAPIJobAction : public JobAction {
void anchor() override;
public:
InstallAPIJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == InstallAPIJobClass;
}
};
class AnalyzeJobAction : public JobAction {
void anchor() override;

View File

@ -336,8 +336,6 @@ class AnalyzerOpts<string base>
: KeyPathAndMacro<"AnalyzerOpts->", base, "ANALYZER_"> {}
class MigratorOpts<string base>
: KeyPathAndMacro<"MigratorOpts.", base, "MIGRATOR_"> {}
class InstallAPIOpts<string base>
: KeyPathAndMacro<"InstallAPIOpts.", base, "INSTALLAPI_"> {}
// A boolean option which is opt-in in CC1. The positive option exists in CC1 and
// Args.hasArg(OPT_ffoo) can be used to check that the flag is enabled.
@ -1143,8 +1141,7 @@ def config_user_dir_EQ : Joined<["--"], "config-user-dir=">,
def coverage : Flag<["-", "--"], "coverage">, Group<Link_Group>,
Visibility<[ClangOption, CLOption]>;
def cpp_precomp : Flag<["-"], "cpp-precomp">, Group<clang_ignored_f_Group>;
def current__version : JoinedOrSeparate<["-"], "current_version">,
Visibility<[ClangOption, CC1Option]>;
def current__version : JoinedOrSeparate<["-"], "current_version">;
def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>,
HelpText<"Add directory to the C++ SYSTEM include search path">,
Visibility<[ClangOption, CC1Option]>,
@ -1559,9 +1556,6 @@ def static_libsan : Flag<["-"], "static-libsan">,
HelpText<"Statically link the sanitizer runtime (Not supported for ASan, TSan or UBSan on darwin)">;
def : Flag<["-"], "shared-libasan">, Alias<shared_libsan>;
def fasm : Flag<["-"], "fasm">, Group<f_Group>;
def installapi : Flag<["-"], "installapi">,
Visibility<[ClangOption, CC1Option]>, Group<Action_Group>,
HelpText<"Create a text-based stub file by scanning header files">;
defm assume_unique_vtables : BoolFOption<"assume-unique-vtables",
CodeGenOpts<"AssumeUniqueVTables">, DefaultTrue,
@ -4320,9 +4314,7 @@ def verify_pch : Flag<["-"], "verify-pch">, Group<Action_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Load and verify that a pre-compiled header file is not stale">;
def init : Separate<["-"], "init">;
def install__name : Separate<["-"], "install_name">,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoString<InstallAPIOpts<"InstallName">>;
def install__name : Separate<["-"], "install_name">;
def iprefix : JoinedOrSeparate<["-"], "iprefix">, Group<clang_i_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">, MetaVarName<"<dir>">;

View File

@ -94,7 +94,6 @@ TYPE("lto-bc", LTO_BC, INVALID, "o", phases
TYPE("ast", AST, INVALID, "ast", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("ifs", IFS, INVALID, "ifs", phases::IfsMerge)
TYPE("ifs-cpp", IFS_CPP, INVALID, "ifs", phases::Compile, phases::IfsMerge)
TYPE("tbd", TextAPI, INVALID, "tbd", phases::Precompile)
TYPE("pcm", ModuleFile, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("header-unit", HeaderUnit, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("plist", Plist, INVALID, "plist", phases::Compile, phases::Backend, phases::Assemble, phases::Link)

View File

@ -294,13 +294,6 @@ public:
return Invocation->getFrontendOpts();
}
InstallAPIOptions &getInstallAPIOpts() {
return Invocation->getInstallAPIOpts();
}
const InstallAPIOptions &getInstallAPIOpts() const {
return Invocation->getInstallAPIOpts();
}
HeaderSearchOptions &getHeaderSearchOpts() {
return Invocation->getHeaderSearchOpts();
}

View File

@ -18,12 +18,11 @@
#include "clang/Basic/LangStandard.h"
#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/InstallAPIOptions.h"
#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/ArrayRef.h"
#include <memory>
#include <string>
@ -112,9 +111,6 @@ protected:
/// Options controlling preprocessed output.
std::shared_ptr<PreprocessorOutputOptions> PreprocessorOutputOpts;
/// Options controlling InstallAPI operations and output.
std::shared_ptr<InstallAPIOptions> InstallAPIOpts;
/// Dummy tag type whose instance can be passed into the constructor to
/// prevent creation of the reference-counted option objects.
struct EmptyConstructor {};
@ -149,7 +145,6 @@ public:
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
return *PreprocessorOutputOpts;
}
const InstallAPIOptions &getInstallAPIOpts() const { return *InstallAPIOpts; }
/// @}
/// Command line generation.
@ -242,7 +237,6 @@ public:
using CompilerInvocationBase::getFrontendOpts;
using CompilerInvocationBase::getDependencyOutputOpts;
using CompilerInvocationBase::getPreprocessorOutputOpts;
using CompilerInvocationBase::getInstallAPIOpts;
/// @}
/// Mutable getters.
@ -264,7 +258,6 @@ public:
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
return *PreprocessorOutputOpts;
}
InstallAPIOptions &getInstallAPIOpts() { return *InstallAPIOpts; }
/// @}
/// Base class internals.

View File

@ -130,16 +130,6 @@ protected:
bool shouldEraseOutputFiles() override;
};
class InstallAPIAction : public ASTFrontendAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
public:
static std::unique_ptr<llvm::raw_pwrite_stream>
CreateOutputFile(CompilerInstance &CI, StringRef InFile);
};
class GenerateInterfaceStubsAction : public ASTFrontendAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,

View File

@ -100,9 +100,6 @@ enum ActionKind {
/// Only execute frontend initialization.
InitOnly,
// Create TextAPI stub.
InstallAPI,
/// Dump information about a module file.
ModuleFileInfo,

View File

@ -1,28 +0,0 @@
//===--- InstallAPIOptions.h ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_FRONTEND_INSTALLAPIOPTIONS_H
#define LLVM_CLANG_FRONTEND_INSTALLAPIOPTIONS_H
#include "llvm/TextAPI/PackedVersion.h"
namespace clang {
/// InstallAPIOptions - Options for controlling InstallAPI verification and
/// TextAPI output.
class InstallAPIOptions {
public:
/// The install name which is apart of the library's ID.
std::string InstallName;
/// The current version which is apart of the library's ID.
llvm::MachO::PackedVersion CurrentVersion;
};
} // namespace clang
#endif

View File

@ -5,18 +5,10 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Top level types for interacting with the generic clang driver and frontend
// for InstallAPI operations.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_INSTALLAPI_CONTEXT_H
#define LLVM_CLANG_INSTALLAPI_CONTEXT_H
#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/TextAPI/InterfaceFile.h"
#include "llvm/TextAPI/RecordVisitor.h"
#include "llvm/TextAPI/RecordsSlice.h"
@ -35,12 +27,6 @@ struct InstallAPIContext {
/// Active target triple to parse.
llvm::Triple TargetTriple{};
/// Output stream to write TextAPI file to.
std::unique_ptr<llvm::raw_pwrite_stream> OS = nullptr;
/// DiagnosticsEngine to report errors.
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags = nullptr;
/// File Path of output location.
StringRef OutputLoc{};
@ -48,17 +34,6 @@ struct InstallAPIContext {
llvm::MachO::FileType FT = llvm::MachO::FileType::TBD_V5;
};
class InstallAPIConsumer : public ASTConsumer {
public:
InstallAPIConsumer(InstallAPIContext InstallAPICtx)
: Ctx(std::move(InstallAPICtx)) {}
void HandleTranslationUnit(ASTContext &ASTContext) override;
private:
InstallAPIContext Ctx;
};
} // namespace installapi
} // namespace clang

View File

@ -32,8 +32,6 @@ const char *Action::getClassName(ActionClass AC) {
case CompileJobClass: return "compiler";
case BackendJobClass: return "backend";
case AssembleJobClass: return "assembler";
case InstallAPIJobClass:
return "installapi";
case IfsMergeJobClass: return "interface-stub-merger";
case LinkJobClass: return "linker";
case LipoJobClass: return "lipo";
@ -364,11 +362,6 @@ void ExtractAPIJobAction::anchor() {}
ExtractAPIJobAction::ExtractAPIJobAction(Action *Inputs, types::ID OutputType)
: JobAction(ExtractAPIJobClass, Inputs, OutputType) {}
void InstallAPIJobAction::anchor() {}
InstallAPIJobAction::InstallAPIJobAction(Action *Inputs, types::ID OutputType)
: JobAction(InstallAPIJobClass, Inputs, OutputType) {}
void AnalyzeJobAction::anchor() {}
AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)

View File

@ -4189,11 +4189,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
break;
}
if (isa<InstallAPIJobAction>(Current)) {
Current = nullptr;
break;
}
// FIXME: Should we include any prior module file outputs as inputs of
// later actions in the same command line?
@ -4324,13 +4319,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
if (!MergerInputs.empty())
Actions.push_back(
C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image));
} else if (Args.hasArg(options::OPT_installapi)) {
// TODO: Lift restriction once operation can handle multiple inputs.
assert(Inputs.size() == 1 && "InstallAPI action can only handle 1 input");
const auto [InputType, InputArg] = Inputs.front();
Action *Current = C.MakeAction<InputAction>(*InputArg, InputType);
Actions.push_back(
C.MakeAction<InstallAPIJobAction>(Current, types::TY_TextAPI));
}
for (auto Opt : {options::OPT_print_supported_cpus,
@ -4774,8 +4762,6 @@ Action *Driver::ConstructPhaseAction(
return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
if (Args.hasArg(options::OPT_extract_api))
return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO);
if (Args.hasArg(options::OPT_installapi))
return C.MakeAction<InstallAPIJobAction>(Input, types::TY_TextAPI);
return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
}
case phases::Backend: {
@ -6455,7 +6441,7 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const {
// And say "no" if this is not a kind of action clang understands.
if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) &&
!isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA) &&
!isa<ExtractAPIJobAction>(JA) && !isa<InstallAPIJobAction>(JA))
!isa<ExtractAPIJobAction>(JA))
return false;
return true;

View File

@ -532,7 +532,6 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::PrecompileJobClass:
case Action::PreprocessJobClass:
case Action::ExtractAPIJobClass:
case Action::InstallAPIJobClass:
case Action::AnalyzeJobClass:
case Action::MigrateJobClass:
case Action::VerifyPCHJobClass:

View File

@ -4939,17 +4939,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Arg *ExtractAPIIgnoresFileArg =
Args.getLastArg(options::OPT_extract_api_ignores_EQ))
ExtractAPIIgnoresFileArg->render(Args, CmdArgs);
} else if (isa<InstallAPIJobAction>(JA)) {
if (!Triple.isOSDarwin())
D.Diag(diag::err_drv_installapi_unsupported) << Triple.str();
CmdArgs.push_back("-installapi");
// Add necessary library arguments for InstallAPI.
if (const Arg *A = Args.getLastArg(options::OPT_install__name))
A->render(Args, CmdArgs);
if (const Arg *A = Args.getLastArg(options::OPT_current__version))
A->render(Args, CmdArgs);
} else {
assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
"Invalid action for clang tool.");

View File

@ -7,7 +7,6 @@ set(LLVM_LINK_COMPONENTS
ProfileData
Support
TargetParser
TextAPI
)
add_clang_library(clangFrontend
@ -28,7 +27,6 @@ add_clang_library(clangFrontend
HeaderIncludeGen.cpp
InitPreprocessor.cpp
LayoutOverrideSource.cpp
InstallAPIConsumer.cpp
LogDiagnosticPrinter.cpp
ModuleDependencyCollector.cpp
MultiplexConsumer.cpp
@ -55,7 +53,6 @@ add_clang_library(clangFrontend
clangBasic
clangDriver
clangEdit
clangInstallAPI
clangLex
clangParse
clangSema

View File

@ -149,8 +149,7 @@ CompilerInvocationBase::CompilerInvocationBase()
FSOpts(std::make_shared<FileSystemOptions>()),
FrontendOpts(std::make_shared<FrontendOptions>()),
DependencyOutputOpts(std::make_shared<DependencyOutputOptions>()),
PreprocessorOutputOpts(std::make_shared<PreprocessorOutputOptions>()),
InstallAPIOpts(std::make_shared<InstallAPIOptions>()) {}
PreprocessorOutputOpts(std::make_shared<PreprocessorOutputOptions>()) {}
CompilerInvocationBase &
CompilerInvocationBase::deep_copy_assign(const CompilerInvocationBase &X) {
@ -168,7 +167,6 @@ CompilerInvocationBase::deep_copy_assign(const CompilerInvocationBase &X) {
FrontendOpts = make_shared_copy(X.getFrontendOpts());
DependencyOutputOpts = make_shared_copy(X.getDependencyOutputOpts());
PreprocessorOutputOpts = make_shared_copy(X.getPreprocessorOutputOpts());
InstallAPIOpts = make_shared_copy(X.getInstallAPIOpts());
}
return *this;
}
@ -189,7 +187,6 @@ CompilerInvocationBase::shallow_copy_assign(const CompilerInvocationBase &X) {
FrontendOpts = X.FrontendOpts;
DependencyOutputOpts = X.DependencyOutputOpts;
PreprocessorOutputOpts = X.PreprocessorOutputOpts;
InstallAPIOpts = X.InstallAPIOpts;
}
return *this;
}
@ -2161,34 +2158,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
return Diags.getNumErrors() == NumErrorsBefore;
}
static bool ParseInstallAPIArgs(InstallAPIOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags,
frontend::ActionKind Action) {
unsigned NumErrorsBefore = Diags.getNumErrors();
InstallAPIOptions &InstallAPIOpts = Opts;
#define INSTALLAPI_OPTION_WITH_MARSHALLING(...) \
PARSE_OPTION_WITH_MARSHALLING(Args, Diags, __VA_ARGS__)
#include "clang/Driver/Options.inc"
#undef INSTALLAPI_OPTION_WITH_MARSHALLING
if (Arg *A = Args.getLastArg(options::OPT_current__version))
Opts.CurrentVersion.parse64(A->getValue());
return Diags.getNumErrors() == NumErrorsBefore;
}
static void GenerateInstallAPIArgs(const InstallAPIOptions &Opts,
ArgumentConsumer Consumer) {
const InstallAPIOptions &InstallAPIOpts = Opts;
#define INSTALLAPI_OPTION_WITH_MARSHALLING(...) \
GENERATE_OPTION_WITH_MARSHALLING(Consumer, __VA_ARGS__)
#include "clang/Driver/Options.inc"
#undef INSTALLAPI_OPTION_WITH_MARSHALLING
if (!Opts.CurrentVersion.empty())
GenerateArg(Consumer, OPT_current__version,
std::string(Opts.CurrentVersion));
}
static void GenerateDependencyOutputArgs(const DependencyOutputOptions &Opts,
ArgumentConsumer Consumer) {
const DependencyOutputOptions &DependencyOutputOpts = Opts;
@ -2588,7 +2557,6 @@ static const auto &getFrontendActionTable() {
{frontend::GeneratePCH, OPT_emit_pch},
{frontend::GenerateInterfaceStubs, OPT_emit_interface_stubs},
{frontend::InitOnly, OPT_init_only},
{frontend::InstallAPI, OPT_installapi},
{frontend::ParseSyntaxOnly, OPT_fsyntax_only},
{frontend::ModuleFileInfo, OPT_module_file_info},
{frontend::VerifyPCH, OPT_verify_pch},
@ -4312,7 +4280,6 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
case frontend::GenerateHeaderUnit:
case frontend::GeneratePCH:
case frontend::GenerateInterfaceStubs:
case frontend::InstallAPI:
case frontend::ParseSyntaxOnly:
case frontend::ModuleFileInfo:
case frontend::VerifyPCH:
@ -4687,11 +4654,6 @@ bool CompilerInvocation::CreateFromArgsImpl(
Res.getDependencyOutputOpts().Targets.empty())
Diags.Report(diag::err_fe_dependency_file_requires_MT);
if (Args.hasArg(OPT_installapi)) {
ParseInstallAPIArgs(Res.getInstallAPIOpts(), Args, Diags,
Res.getFrontendOpts().ProgramAction);
}
// If sanitizer is enabled, disable OPT_ffine_grained_bitfield_accesses.
if (Res.getCodeGenOpts().FineGrainedBitfieldAccesses &&
!Res.getLangOpts().Sanitize.empty()) {
@ -4882,7 +4844,6 @@ void CompilerInvocationBase::generateCC1CommandLine(
GeneratePreprocessorOutputArgs(getPreprocessorOutputOpts(), Consumer,
getFrontendOpts().ProgramAction);
GenerateDependencyOutputArgs(getDependencyOutputOpts(), Consumer);
GenerateInstallAPIArgs(getInstallAPIOpts(), Consumer);
}
std::vector<std::string> CompilerInvocationBase::getCC1CommandLine() const {

View File

@ -1,43 +0,0 @@
//===--- InstallAPIConsumer.cpp -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/InstallAPI/Context.h"
using namespace clang;
using namespace clang::installapi;
std::unique_ptr<ASTConsumer>
InstallAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
const InstallAPIOptions &Opts = CI.getInstallAPIOpts();
InstallAPIContext Ctx;
Ctx.BA.InstallName = Opts.InstallName;
Ctx.BA.AppExtensionSafe = CI.getLangOpts().AppExt;
Ctx.BA.CurrentVersion = Opts.CurrentVersion;
// InstallAPI requires two level namespacing.
Ctx.BA.TwoLevelNamespace = true;
Ctx.TargetTriple = CI.getTarget().getTriple();
Ctx.Diags = &CI.getDiagnostics();
Ctx.OutputLoc = CI.getFrontendOpts().OutputFile;
Ctx.OS = CreateOutputFile(CI, InFile);
if (!Ctx.OS)
return nullptr;
return std::make_unique<InstallAPIConsumer>(std::move(Ctx));
}
std::unique_ptr<llvm::raw_pwrite_stream>
InstallAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
std::unique_ptr<raw_pwrite_stream> OS =
CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"tbd",
/*RemoveFileOnSignal=*/false);
if (!OS)
return nullptr;
return OS;
}

View File

@ -71,8 +71,6 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
case GenerateInterfaceStubs:
return std::make_unique<GenerateInterfaceStubsAction>();
case InitOnly: return std::make_unique<InitOnlyAction>();
case InstallAPI:
return std::make_unique<InstallAPIAction>();
case ParseSyntaxOnly: return std::make_unique<SyntaxOnlyAction>();
case ModuleFileInfo: return std::make_unique<DumpModuleInfoAction>();
case VerifyPCH: return std::make_unique<VerifyPCHAction>();

View File

@ -4,7 +4,6 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangInstallAPI
Context.cpp
FileList.cpp
HeaderFile.cpp

View File

@ -1,27 +0,0 @@
//===--- InstallAPI/Context.cpp -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/InstallAPI/Context.h"
#include "clang/AST/ASTContext.h"
#include "llvm/TextAPI/TextAPIWriter.h"
using namespace clang;
using namespace clang::installapi;
using namespace llvm::MachO;
void InstallAPIConsumer::HandleTranslationUnit(ASTContext &Context) {
if (Context.getDiagnostics().hasErrorOccurred())
return;
InterfaceFile IF;
// Set library attributes captured through cc1 args.
Target T(Ctx.TargetTriple);
IF.addTarget(T);
IF.setFromBinaryAttrs(Ctx.BA, T);
if (auto Err = TextAPIWriter::writeToStream(*Ctx.OS, IF, Ctx.FT))
Ctx.Diags->Report(diag::err_cannot_open_file) << Ctx.OutputLoc;
}

View File

@ -71,6 +71,7 @@ list(APPEND CLANG_TEST_DEPS
clang-rename
clang-refactor
clang-diff
clang-installapi
clang-scan-deps
clang-linker-wrapper
clang-offload-bundler

View File

@ -1,13 +0,0 @@
// Check non-darwin triple is rejected.
// RUN: not %clang -target x86_64-unknown-unknown -installapi %s 2> %t
// RUN: FileCheck --check-prefix INVALID_INSTALLAPI -input-file %t %s
// INVALID_INSTALLAPI: error: InstallAPI is not supported for 'x86_64-unknown-unknown'
// Check installapi phases.
// RUN: %clang -target x86_64-apple-macos11 -ccc-print-phases -installapi %s 2> %t
// RUN: FileCheck --check-prefix INSTALLAPI_PHASES -input-file %t %s
// INSTALLAPI_PHASES: 0: input,
// INSTALLAPI_PHASES: installapi,
// INSTALLAPI_PHASES-SAME: tbd

View File

@ -1,10 +1,17 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: %clang_cc1 -x objective-c -triple arm64-apple-ios13.0.0 -installapi \
/// Check basic arguments are captured.
// RUN: clang-installapi -x objective-c -target arm64-apple-ios13.0.0 \
// RUN: -fapplication-extension -current_version 1 -install_name /usr/lib/basic.dylib \
// RUN: %t/basic_inputs.json -o %t/basic.tbd 2>&1 | FileCheck %s --allow-empty
// RUN: llvm-readtapi -compare %t/basic.tbd %t/expected.tbd 2>&1 | FileCheck %s --allow-empty
/// Check multiple targets are captured.
// RUN: clang-installapi -x objective-c -target arm64-apple-ios14.1 -target arm64e-apple-ios14.1 \
// RUN: -fapplication-extension -install_name /usr/lib/basic.dylib \
// RUN: %t/basic_inputs.json -o %t/multi-targets.tbd 2>&1 | FileCheck %s --allow-empty
// RUN: llvm-readtapi -compare %t/multi-targets.tbd %t/expected-multi.tbd 2>&1 | FileCheck %s --allow-empty
// CHECK-NOT: error:
// CHECK-NOT: warning:
@ -32,3 +39,33 @@
},
"tapi_tbd_version": 5
}
//--- expected-multi.tbd
{
"main_library": {
"compatibility_versions": [
{
"version": "0"
}],
"current_versions": [
{
"version": "0"
}],
"install_names": [
{
"name": "/usr/lib/basic.dylib"
}
],
"target_info": [
{
"min_deployment": "14.1",
"target": "arm64-ios"
},
{
"min_deployment": "14.1",
"target": "arm64e-ios"
}
]
},
"tapi_tbd_version": 5
}

View File

@ -0,0 +1,4 @@
/// Check non-darwin triple is rejected.
// RUN: not clang-installapi -target x86_64-unknown-unknown %s 2> %t
// RUN: FileCheck --check-prefix INVALID_INSTALLAPI -input-file %t %s
// INVALID_INSTALLAPI: error: unsupported option 'installapi' for target 'x86_64-unknown-unknown'

View File

@ -90,6 +90,7 @@ tools = [
"clang-offload-packager",
"clang-tblgen",
"clang-scan-deps",
"clang-installapi",
"opt",
"llvm-ifs",
"yaml2obj",

View File

@ -12,6 +12,7 @@ add_clang_subdirectory(clang-linker-wrapper)
add_clang_subdirectory(clang-offload-packager)
add_clang_subdirectory(clang-offload-bundler)
add_clang_subdirectory(clang-scan-deps)
add_clang_subdirectory(clang-installapi)
if(HAVE_CLANG_REPL_SUPPORT)
add_clang_subdirectory(clang-repl)
endif()

View File

@ -0,0 +1,20 @@
set(LLVM_LINK_COMPONENTS
Support
TargetParser
TextAPI
)
add_clang_tool(clang-installapi
ClangInstallAPI.cpp
Options.cpp
GENERATE_DRIVER
)
clang_target_link_libraries(clang-installapi
PRIVATE
clangInstallAPI
clangDriver
clangFrontend
clangTooling
)

View File

@ -0,0 +1,121 @@
//===-- ClangInstallAPI.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is the entry point to clang-installapi; it is a wrapper
// for functionality in the InstallAPI clang library.
//
//===----------------------------------------------------------------------===//
#include "Options.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/InstallAPI/Context.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/LLVMDriver.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TextAPI/TextAPIWriter.h"
using namespace clang;
using namespace clang::installapi;
using namespace clang::driver::options;
using namespace llvm::opt;
using namespace llvm::MachO;
static bool run(ArrayRef<const char *> Args, const char *ProgName) {
// Setup Diagnostics engine.
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
const llvm::opt::OptTable &ClangOpts = clang::driver::getDriverOptTable();
unsigned MissingArgIndex, MissingArgCount;
llvm::opt::InputArgList ParsedArgs = ClangOpts.ParseArgs(
ArrayRef(Args).slice(1), MissingArgIndex, MissingArgCount);
ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
IntrusiveRefCntPtr<DiagnosticsEngine> Diag = new clang::DiagnosticsEngine(
new clang::DiagnosticIDs(), DiagOpts.get(),
new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts.get()));
// Create file manager for all file operations.
IntrusiveRefCntPtr<clang::FileManager> FM(
new FileManager(clang::FileSystemOptions()));
// Set up driver to parse input arguments.
auto DriverArgs = llvm::ArrayRef(Args).slice(1);
clang::driver::Driver Driver(ProgName, llvm::sys::getDefaultTargetTriple(),
*Diag, "clang installapi tool");
Driver.setInstalledDir(llvm::sys::path::parent_path(ProgName));
auto TargetAndMode =
clang::driver::ToolChain::getTargetAndModeFromProgramName(ProgName);
Driver.setTargetAndMode(TargetAndMode);
bool HasError = false;
llvm::opt::InputArgList ArgList =
Driver.ParseArgStrings(DriverArgs, /*UseDriverMode=*/true, HasError);
if (HasError)
return EXIT_FAILURE;
Driver.setCheckInputsExist(false);
// Capture InstallAPI specific options and diagnose any option errors.
Options Opts(*Diag, FM.get(), ArgList);
if (Diag->hasErrorOccurred())
return EXIT_FAILURE;
InstallAPIContext Ctx = Opts.createContext();
// Set up compilation.
std::unique_ptr<CompilerInstance> CI(new CompilerInstance());
CI->setFileManager(FM.get());
CI->createDiagnostics();
if (!CI->hasDiagnostics())
return EXIT_FAILURE;
auto Out = CI->createOutputFile(Ctx.OutputLoc, /*Binary=*/false,
/*RemoveFileOnSignal=*/false,
/*UseTemporary=*/false,
/*CreateMissingDirectories=*/false);
if (!Out)
return EXIT_FAILURE;
// Assign attributes for serialization.
InterfaceFile IF;
for (const auto &TargetInfo : Opts.DriverOpts.Targets) {
IF.addTarget(TargetInfo.first);
IF.setFromBinaryAttrs(Ctx.BA, TargetInfo.first);
}
// Write output file and perform CI cleanup.
if (auto Err = TextAPIWriter::writeToStream(*Out, IF, Ctx.FT)) {
Diag->Report(diag::err_cannot_open_file) << Ctx.OutputLoc;
CI->clearOutputFiles(/*EraseFiles=*/true);
return EXIT_FAILURE;
}
CI->clearOutputFiles(/*EraseFiles=*/false);
return EXIT_SUCCESS;
}
int clang_installapi_main(int argc, char **argv,
const llvm::ToolContext &ToolContext) {
// Standard set up, so program fails gracefully.
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
llvm::llvm_shutdown_obj Shutdown;
if (llvm::sys::Process::FixupStandardFileDescriptors())
return EXIT_FAILURE;
const char *ProgName =
ToolContext.NeedsPrependArg ? ToolContext.PrependArg : ToolContext.Path;
return run(llvm::ArrayRef(argv, argc), ProgName);
}

View File

@ -0,0 +1,129 @@
//===-- Options.cpp -------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Options.h"
#include "clang/Driver/Driver.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Support/Program.h"
#include "llvm/TargetParser/Host.h"
using namespace clang::driver;
using namespace clang::driver::options;
using namespace llvm::opt;
using namespace llvm::MachO;
namespace clang {
namespace installapi {
bool Options::processDriverOptions(InputArgList &Args) {
// Handle inputs.
llvm::vfs::Status Stat;
for (const auto &Path : Args.getAllArgValues(OPT_INPUT)) {
if (FM->getNoncachedStatValue(Path, Stat) || !Stat.exists()) {
Diags->Report(clang::diag::err_drv_no_such_file) << Path;
return false;
}
DriverOpts.FileLists.push_back(std::move(Path));
}
// Handle output.
SmallString<PATH_MAX> OutputPath;
if (auto *Arg = Args.getLastArg(OPT_o)) {
OutputPath = Arg->getValue();
if (OutputPath != "-")
FM->makeAbsolutePath(OutputPath);
DriverOpts.OutputPath = std::string(OutputPath);
}
// Do basic error checking first for mixing -target and -arch options.
auto *ArgArch = Args.getLastArgNoClaim(OPT_arch);
auto *ArgTarget = Args.getLastArgNoClaim(OPT_target);
auto *ArgTargetVariant =
Args.getLastArgNoClaim(OPT_darwin_target_variant_triple);
if (ArgArch && (ArgTarget || ArgTargetVariant)) {
Diags->Report(clang::diag::err_drv_argument_not_allowed_with)
<< ArgArch->getAsString(Args)
<< (ArgTarget ? ArgTarget : ArgTargetVariant)->getAsString(Args);
return false;
}
auto *ArgMinTargetOS = Args.getLastArgNoClaim(OPT_mtargetos_EQ);
if ((ArgTarget || ArgTargetVariant) && ArgMinTargetOS) {
Diags->Report(clang::diag::err_drv_cannot_mix_options)
<< ArgTarget->getAsString(Args) << ArgMinTargetOS->getAsString(Args);
return false;
}
// Capture target triples first.
if (ArgTarget) {
for (auto *Arg : Args.filtered(OPT_target)) {
llvm::Triple TargetTriple(Arg->getValue());
Target TAPITarget = Target(TargetTriple);
if ((TAPITarget.Arch == AK_unknown) ||
(TAPITarget.Platform == PLATFORM_UNKNOWN)) {
Diags->Report(clang::diag::err_drv_unsupported_opt_for_target)
<< "installapi" << TargetTriple.str();
return false;
}
DriverOpts.Targets[TAPITarget] = TargetTriple;
}
}
return true;
}
bool Options::processLinkerOptions(InputArgList &Args) {
// TODO: add error handling.
// Required arguments.
if (const Arg *A = Args.getLastArg(options::OPT_install__name))
LinkerOpts.InstallName = A->getValue();
// Defaulted or optional arguments.
if (auto *Arg = Args.getLastArg(OPT_current__version))
LinkerOpts.CurrentVersion.parse64(Arg->getValue());
LinkerOpts.IsDylib = Args.hasArg(OPT_dynamiclib);
LinkerOpts.AppExtensionSafe =
Args.hasFlag(OPT_fapplication_extension, OPT_fno_application_extension,
/*Default=*/LinkerOpts.AppExtensionSafe);
if (::getenv("LD_NO_ENCRYPT") != nullptr)
LinkerOpts.AppExtensionSafe = true;
if (::getenv("LD_APPLICATION_EXTENSION_SAFE") != nullptr)
LinkerOpts.AppExtensionSafe = true;
return true;
}
Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
InputArgList &ArgList)
: Diags(&Diag), FM(FM) {
if (!processDriverOptions(ArgList))
return;
if (!processLinkerOptions(ArgList))
return;
}
InstallAPIContext Options::createContext() {
InstallAPIContext Ctx;
// InstallAPI requires two level namespacing.
Ctx.BA.TwoLevelNamespace = true;
Ctx.BA.InstallName = LinkerOpts.InstallName;
Ctx.BA.CurrentVersion = LinkerOpts.CurrentVersion;
Ctx.BA.AppExtensionSafe = LinkerOpts.AppExtensionSafe;
Ctx.FT = DriverOpts.OutFT;
Ctx.OutputLoc = DriverOpts.OutputPath;
return Ctx;
}
} // namespace installapi
} // namespace clang

View File

@ -0,0 +1,88 @@
//===--- clang-installapi/Options.h - Options -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_CLANG_INSTALLAPI_OPTIONS_H
#define LLVM_CLANG_TOOLS_CLANG_INSTALLAPI_OPTIONS_H
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/InstallAPI/Context.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Program.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/TextAPI/Architecture.h"
#include "llvm/TextAPI/InterfaceFile.h"
#include "llvm/TextAPI/PackedVersion.h"
#include "llvm/TextAPI/Platform.h"
#include "llvm/TextAPI/Target.h"
#include "llvm/TextAPI/Utils.h"
#include <set>
#include <string>
#include <vector>
namespace clang {
namespace installapi {
using Macro = std::pair<std::string, bool /*isUndef*/>;
struct DriverOptions {
/// \brief Path to input file lists (JSON).
llvm::MachO::PathSeq FileLists;
/// \brief Mappings of target triples & tapi targets to build for.
std::map<llvm::MachO::Target, llvm::Triple> Targets;
/// \brief Output path.
std::string OutputPath;
/// \brief File encoding to print.
llvm::MachO::FileType OutFT = llvm::MachO::FileType::TBD_V5;
};
struct LinkerOptions {
/// \brief The install name to use for the dynamic library.
std::string InstallName;
/// \brief The current version to use for the dynamic library.
llvm::MachO::PackedVersion CurrentVersion;
/// \brief Is application extension safe.
bool AppExtensionSafe = false;
/// \brief Set if we should scan for a dynamic library and not a framework.
bool IsDylib = false;
};
class Options {
private:
bool processDriverOptions(llvm::opt::InputArgList &Args);
bool processLinkerOptions(llvm::opt::InputArgList &Args);
public:
/// The various options grouped together.
DriverOptions DriverOpts;
LinkerOptions LinkerOpts;
Options() = delete;
/// \brief Create InstallAPIContext from processed options.
InstallAPIContext createContext();
/// \brief Constructor for options.
Options(clang::DiagnosticsEngine &Diag, FileManager *FM,
llvm::opt::InputArgList &Args);
private:
DiagnosticsEngine *Diags;
FileManager *FM;
};
} // namespace installapi
} // namespace clang
#endif