Skip to content

Commit 4bafb0a

Browse files
committed
Add Statically Linked Libraries
Add GNU Static Lib Tool, which supports the --emit-static-lib flag. For HIP, a static library archive will be created and consist of HIP Fat Binary host object with the device images embedded. Using llvm-ar to create the static archive. Also, delete existing output file to ensure a new archive is created each time. Reviewers: yaxunl, tra, rjmccall, echristo Subscribers: echristo, JonChesterfield, scchan, msearles Differential Revision: https://reviews.llvm.org/D78759
1 parent 77df5a8 commit 4bafb0a

File tree

15 files changed

+254
-2
lines changed

15 files changed

+254
-2
lines changed

clang/include/clang/Driver/Action.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,10 @@ class Action {
7373
OffloadBundlingJobClass,
7474
OffloadUnbundlingJobClass,
7575
OffloadWrapperJobClass,
76+
StaticLibJobClass,
7677

7778
JobClassFirst = PreprocessJobClass,
78-
JobClassLast = OffloadWrapperJobClass
79+
JobClassLast = StaticLibJobClass
7980
};
8081

8182
// The offloading kind determines if this action is binded to a particular
@@ -637,6 +638,17 @@ class OffloadWrapperJobAction : public JobAction {
637638
}
638639
};
639640

641+
class StaticLibJobAction : public JobAction {
642+
void anchor() override;
643+
644+
public:
645+
StaticLibJobAction(ActionList &Inputs, types::ID Type);
646+
647+
static bool classof(const Action *A) {
648+
return A->getKind() == StaticLibJobClass;
649+
}
650+
};
651+
640652
} // namespace driver
641653
} // namespace clang
642654

clang/include/clang/Driver/Driver.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,9 @@ class Driver {
548548
/// handle this action.
549549
bool ShouldUseFlangCompiler(const JobAction &JA) const;
550550

551+
/// ShouldEmitStaticLibrary - Should the linker emit a static library.
552+
bool ShouldEmitStaticLibrary(const llvm::opt::ArgList &Args) const;
553+
551554
/// Returns true if we are performing any kind of LTO.
552555
bool isUsingLTO() const { return LTOMode != LTOK_None; }
553556

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,8 @@ def hip_link : Flag<["--"], "hip-link">,
605605
def no_offload_arch_EQ : Joined<["--"], "no-offload-arch=">, Flags<[DriverOption]>,
606606
HelpText<"Remove CUDA/HIP offloading device architecture (e.g. sm_35, gfx906) from the list of devices to compile for. "
607607
"'all' resets the list to its default value.">;
608+
def emit_static_lib : Flag<["--"], "emit-static-lib">,
609+
HelpText<"Enable linker job to emit a static library.">;
608610
def no_cuda_gpu_arch_EQ : Joined<["--"], "no-cuda-gpu-arch=">, Flags<[DriverOption]>,
609611
Alias<no_offload_arch_EQ>;
610612
def cuda_noopt_device_debug : Flag<["--"], "cuda-noopt-device-debug">,

clang/include/clang/Driver/ToolChain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class ToolChain {
139139
mutable std::unique_ptr<Tool> Flang;
140140
mutable std::unique_ptr<Tool> Assemble;
141141
mutable std::unique_ptr<Tool> Link;
142+
mutable std::unique_ptr<Tool> StaticLibTool;
142143
mutable std::unique_ptr<Tool> IfsMerge;
143144
mutable std::unique_ptr<Tool> OffloadBundler;
144145
mutable std::unique_ptr<Tool> OffloadWrapper;
@@ -147,6 +148,7 @@ class ToolChain {
147148
Tool *getFlang() const;
148149
Tool *getAssemble() const;
149150
Tool *getLink() const;
151+
Tool *getStaticLibTool() const;
150152
Tool *getIfsMerge() const;
151153
Tool *getClangAs() const;
152154
Tool *getOffloadBundler() const;
@@ -174,6 +176,7 @@ class ToolChain {
174176

175177
virtual Tool *buildAssembler() const;
176178
virtual Tool *buildLinker() const;
179+
virtual Tool *buildStaticLibTool() const;
177180
virtual Tool *getTool(Action::ActionClass AC) const;
178181

179182
/// \name Utilities for implementing subclasses.
@@ -326,6 +329,9 @@ class ToolChain {
326329
/// the linker suffix or name.
327330
std::string GetLinkerPath() const;
328331

332+
/// Returns the linker path for emitting a static library.
333+
std::string GetStaticLibToolPath() const;
334+
329335
/// Dispatch to the specific toolchain for verbose printing.
330336
///
331337
/// This is used when handling the verbose option to print detailed,

clang/lib/Driver/Action.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const char *Action::getClassName(ActionClass AC) {
4343
return "clang-offload-unbundler";
4444
case OffloadWrapperJobClass:
4545
return "clang-offload-wrapper";
46+
case StaticLibJobClass:
47+
return "static-lib-linker";
4648
}
4749

4850
llvm_unreachable("invalid class");
@@ -415,3 +417,8 @@ void OffloadWrapperJobAction::anchor() {}
415417
OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs,
416418
types::ID Type)
417419
: JobAction(OffloadWrapperJobClass, Inputs, Type) {}
420+
421+
void StaticLibJobAction::anchor() {}
422+
423+
StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type)
424+
: JobAction(StaticLibJobClass, Inputs, Type) {}

clang/lib/Driver/Driver.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3542,7 +3542,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
35423542
if (!LinkerInputs.empty()) {
35433543
if (Action *Wrapper = OffloadBuilder.makeHostLinkAction())
35443544
LinkerInputs.push_back(Wrapper);
3545-
Action *LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image);
3545+
Action *LA;
3546+
// Check if this Linker Job should emit a static library.
3547+
if (ShouldEmitStaticLibrary(Args)) {
3548+
LA = C.MakeAction<StaticLibJobAction>(LinkerInputs, types::TY_Image);
3549+
} else {
3550+
LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image);
3551+
}
35463552
LA = OffloadBuilder.processHostLinkAction(LA);
35473553
Actions.push_back(LA);
35483554
}
@@ -5044,6 +5050,13 @@ bool Driver::ShouldUseFlangCompiler(const JobAction &JA) const {
50445050
return true;
50455051
}
50465052

5053+
bool Driver::ShouldEmitStaticLibrary(const ArgList &Args) const {
5054+
// Only emit static library if the flag is set explicitly.
5055+
if (Args.hasArg(options::OPT_emit_static_lib))
5056+
return true;
5057+
return false;
5058+
}
5059+
50475060
/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
50485061
/// grouped values as integers. Numbers which are not provided are set to 0.
50495062
///

clang/lib/Driver/ToolChain.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ Tool *ToolChain::buildLinker() const {
275275
llvm_unreachable("Linking is not supported by this toolchain");
276276
}
277277

278+
Tool *ToolChain::buildStaticLibTool() const {
279+
llvm_unreachable("Creating static lib is not supported by this toolchain");
280+
}
281+
278282
Tool *ToolChain::getAssemble() const {
279283
if (!Assemble)
280284
Assemble.reset(buildAssembler());
@@ -293,6 +297,12 @@ Tool *ToolChain::getLink() const {
293297
return Link.get();
294298
}
295299

300+
Tool *ToolChain::getStaticLibTool() const {
301+
if (!StaticLibTool)
302+
StaticLibTool.reset(buildStaticLibTool());
303+
return StaticLibTool.get();
304+
}
305+
296306
Tool *ToolChain::getIfsMerge() const {
297307
if (!IfsMerge)
298308
IfsMerge.reset(new tools::ifstool::Merger(*this));
@@ -322,6 +332,9 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
322332
case Action::LinkJobClass:
323333
return getLink();
324334

335+
case Action::StaticLibJobClass:
336+
return getStaticLibTool();
337+
325338
case Action::InputClass:
326339
case Action::BindArchClass:
327340
case Action::OffloadClass:
@@ -565,6 +578,11 @@ std::string ToolChain::GetLinkerPath() const {
565578
return GetProgramPath(getDefaultLinker());
566579
}
567580

581+
std::string ToolChain::GetStaticLibToolPath() const {
582+
// TODO: Add support for static lib archiving on Windows
583+
return GetProgramPath("llvm-ar");
584+
}
585+
568586
types::ID ToolChain::LookupTypeForExtension(StringRef Ext) const {
569587
types::ID id = types::lookupTypeForExtension(Ext);
570588

clang/lib/Driver/ToolChains/Gnu.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,43 @@ static bool getStatic(const ArgList &Args) {
341341
!Args.hasArg(options::OPT_static_pie);
342342
}
343343

344+
void tools::gnutools::StaticLibTool::ConstructJob(
345+
Compilation &C, const JobAction &JA, const InputInfo &Output,
346+
const InputInfoList &Inputs, const ArgList &Args,
347+
const char *LinkingOutput) const {
348+
const Driver &D = getToolChain().getDriver();
349+
350+
// Silence warning for "clang -g foo.o -o foo"
351+
Args.ClaimAllArgs(options::OPT_g_Group);
352+
// and "clang -emit-llvm foo.o -o foo"
353+
Args.ClaimAllArgs(options::OPT_emit_llvm);
354+
// and for "clang -w foo.o -o foo". Other warning options are already
355+
// handled somewhere else.
356+
Args.ClaimAllArgs(options::OPT_w);
357+
// Silence warnings when linking C code with a C++ '-stdlib' argument.
358+
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
359+
360+
// GNU ar tool command "ar <options> <output_file> <input_files>".
361+
ArgStringList CmdArgs;
362+
// Create and insert file members with a deterministic index.
363+
CmdArgs.push_back("rcsD");
364+
CmdArgs.push_back(Output.getFilename());
365+
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
366+
367+
// Delete old output archive file if it already exists before generating a new
368+
// archive file.
369+
auto OutputFileName = Output.getFilename();
370+
if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {
371+
if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
372+
D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
373+
return;
374+
}
375+
}
376+
377+
const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
378+
C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
379+
}
380+
344381
void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
345382
const InputInfo &Output,
346383
const InputInfoList &Inputs,

clang/lib/Driver/ToolChains/Gnu.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,20 @@ class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
7272
const llvm::opt::ArgList &TCArgs,
7373
const char *LinkingOutput) const override;
7474
};
75+
76+
class LLVM_LIBRARY_VISIBILITY StaticLibTool : public GnuTool {
77+
public:
78+
StaticLibTool(const ToolChain &TC)
79+
: GnuTool("GNU::StaticLibTool", "static-lib-linker", TC) {}
80+
81+
bool hasIntegratedCPP() const override { return false; }
82+
bool isLinkJob() const override { return true; }
83+
84+
void ConstructJob(Compilation &C, const JobAction &JA,
85+
const InputInfo &Output, const InputInfoList &Inputs,
86+
const llvm::opt::ArgList &TCArgs,
87+
const char *LinkingOutput) const override;
88+
};
7589
} // end namespace gnutools
7690

7791
/// gcc - Generic GCC tool implementations.

clang/lib/Driver/ToolChains/Linux.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,10 @@ bool Linux::HasNativeLLVMSupport() const { return true; }
363363

364364
Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); }
365365

366+
Tool *Linux::buildStaticLibTool() const {
367+
return new tools::gnutools::StaticLibTool(*this);
368+
}
369+
366370
Tool *Linux::buildAssembler() const {
367371
return new tools::gnutools::Assembler(*this);
368372
}

0 commit comments

Comments
 (0)