diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1616,6 +1616,8 @@ Flags<[CC1Option, NoArgumentUnused, HelpHidden]>; def fno_openmp_optimistic_collapse : Flag<["-"], "fno-openmp-optimistic-collapse">, Group, Flags<[NoArgumentUnused, HelpHidden]>; +def static_openmp: Flag<["-"], "static-openmp">, + HelpText<"Use the static host OpenMP runtime while linking.">; def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group; def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group; def fno_escaping_block_tail_calls : Flag<["-"], "fno-escaping-block-tail-calls">, Group, Flags<[CC1Option]>; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -84,7 +84,8 @@ /// Returns true, if an OpenMP runtime has been added. bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC, const llvm::opt::ArgList &Args, - bool IsOffloadingHost = false, bool GompNeedsRT = false); + bool IsOffloadingHost = false, bool GompNeedsRT = false, + bool StaticHostRuntime = false); llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args); llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -501,29 +501,38 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, const ArgList &Args, bool IsOffloadingHost, - bool GompNeedsRT) { + bool GompNeedsRT, bool StaticHostRuntime) { if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) return false; - switch (TC.getDriver().getOpenMPRuntime(Args)) { + Driver::OpenMPRuntimeKind RTKind = TC.getDriver().getOpenMPRuntime(Args); + + if (RTKind == Driver::OMPRT_Unknown) + // Already diagnosed. + return false; + + if (StaticHostRuntime) + CmdArgs.push_back("-Bstatic"); + + switch (RTKind) { case Driver::OMPRT_OMP: CmdArgs.push_back("-lomp"); break; case Driver::OMPRT_GOMP: CmdArgs.push_back("-lgomp"); - - if (GompNeedsRT) - CmdArgs.push_back("-lrt"); break; case Driver::OMPRT_IOMP5: CmdArgs.push_back("-liomp5"); break; - case Driver::OMPRT_Unknown: - // Already diagnosed. - return false; } + if (StaticHostRuntime) + CmdArgs.push_back("-Bdynamic"); + + if (RTKind == Driver::OMPRT_GOMP && GompNeedsRT) + CmdArgs.push_back("-lrt"); + if (IsOffloadingHost) CmdArgs.push_back("-lomptarget"); diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -555,11 +555,15 @@ bool WantPthread = Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads); + // Prefer the static OpenMP runtime with -static-openmp + bool StaticLibOpenMP = Args.hasArg(options::OPT_static_openmp) && + !Args.hasArg(options::OPT_static); + // FIXME: Only pass GompNeedsRT = true for platforms with libgomp that // require librt. Most modern Linux platforms do, but some may not. if (addOpenMPRuntime(CmdArgs, ToolChain, Args, JA.isHostOffloading(Action::OFK_OpenMP), - /* GompNeedsRT= */ true)) + /* GompNeedsRT= */ true, StaticLibOpenMP)) // OpenMP runtimes implies pthreads when using the GNU toolchain. // FIXME: Does this really make sense for all GNU toolchains? WantPthread = true; diff --git a/clang/test/Driver/fopenmp.c b/clang/test/Driver/fopenmp.c --- a/clang/test/Driver/fopenmp.c +++ b/clang/test/Driver/fopenmp.c @@ -31,6 +31,10 @@ // RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-RT // RUN: %clang -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5 // +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libomp -static-openmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-STATIC-OMP +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp -static-openmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-STATIC-GOMP --check-prefix=CHECK-LD-STATIC-GOMP-RT +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libiomp5 -static-openmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-STATIC-IOMP5 +// // RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OMP // RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-GOMP // RUN: %clang -nostdlib -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-IOMP5 @@ -93,6 +97,16 @@ // CHECK-NO-IOMP5MD: "{{.*}}ld{{(.exe)?}}" // CHECK-NO-IOMP5MD-NOT: "-liomp5md" // +// CHECK-LD-STATIC-OMP: "{{.*}}ld{{(.exe)?}}" +// CHECK-LD-STATIC-OMP: "-Bstatic" "-lomp" "-Bdynamic" +// +// CHECK-LD-STATIC-GOMP: "{{.*}}ld{{(.exe)?}}" +// CHECK-LD-STATIC-GOMP: "-Bstatic" "-lgomp" "-Bdynamic" +// CHECK-LD-STATIC-GOMP-RT: "-lrt" +// +// CHECK-LD-STATIC-IOMP5: "{{.*}}ld{{(.exe)?}}" +// CHECK-LD-STATIC-IOMP5: "-Bstatic" "-liomp5" "-Bdynamic" +// // We'd like to check that the default is sane, but until we have the ability // to *always* semantically analyze OpenMP without always generating runtime // calls (in the event of an unsupported runtime), we don't have a good way to