gollvm: fixes and new flags for linker invocation

Assorted fixes for linker invocation. Includes support for
-pthread/-pthreads, support for the -static-libgo flag, and
some general code cleanup.

Change-Id: Ib7413e41d06c6f06b72c88c296c39a3568b882b5
Reviewed-on: https://go-review.googlesource.com/112360
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/driver/GnuTools.cpp b/driver/GnuTools.cpp
index 67d10ac..9576c8c 100644
--- a/driver/GnuTools.cpp
+++ b/driver/GnuTools.cpp
@@ -241,6 +241,54 @@
       cmdArgs.push_back(args.MakeArgString(llvm::StringRef("-L") + fp));
 }
 
+void Linker::addSysLibsStatic(llvm::opt::ArgList &args,
+                              llvm::opt::ArgStringList &cmdArgs)
+{
+  // Go and pthread related libs.
+  cmdArgs.push_back("-lgobegin");
+  cmdArgs.push_back("-lgo");
+  cmdArgs.push_back("-lm");
+  cmdArgs.push_back("-u");
+  cmdArgs.push_back("pthread_create");
+  cmdArgs.push_back("--wrap=pthread_create");
+
+  // Libgcc and libc.
+  cmdArgs.push_back("--start-group");
+  cmdArgs.push_back("-lgcc");
+  cmdArgs.push_back("-lgcc_eh");
+  cmdArgs.push_back("-lpthread");
+  cmdArgs.push_back("-lc");
+  cmdArgs.push_back("--end-group");
+}
+
+void Linker::addSysLibsShared(llvm::opt::ArgList &args,
+                              llvm::opt::ArgStringList &cmdArgs)
+{
+  bool isStaticLibgo = args.hasArg(gollvm::options::OPT_static_libgo);
+  bool havePthreadFlag = args.hasArg(gollvm::options::OPT_pthreads);
+  cmdArgs.push_back("-lgobegin");
+  if (isStaticLibgo)
+    cmdArgs.push_back("-Bstatic");
+  cmdArgs.push_back("-lgo");
+  if (isStaticLibgo)
+    cmdArgs.push_back("-Bdynamic");
+
+  cmdArgs.push_back("-lm");
+  cmdArgs.push_back("--wrap=pthread_create");
+
+  // Libgcc and libc.
+  bool isShared = args.hasArg(gollvm::options::OPT_shared);
+  cmdArgs.push_back("-lgcc_s");
+  if (!isShared)
+    cmdArgs.push_back("-lgcc");
+  if (isStaticLibgo || havePthreadFlag)
+    cmdArgs.push_back("-lpthread");
+  cmdArgs.push_back("-lc");
+  cmdArgs.push_back("-lgcc_s");
+  if (!isShared)
+    cmdArgs.push_back("-lgcc");
+}
+
 bool Linker::constructCommand(Compilation &compilation,
                               const Action &jobAction,
                               const ArtifactList &inputArtifacts,
@@ -277,8 +325,6 @@
                            gollvm::options::OPT_Xlinker,
                            inputArtifacts, args, cmdArgs);
 
-  // FIXME: add "-dynamic-linker /lib64/ld-linux-x86-64.so.2"
-
   // Incorporate any -L, -l options from the user
   args.AddAllArgs(cmdArgs, gollvm::options::OPT_L, gollvm::options::OPT_l);
 
@@ -308,37 +354,11 @@
   cmdArgs.push_back(args.MakeArgString(golib.c_str()));
 
   // Incorporate linker arguments needed for Go.
-  cmdArgs.push_back("-lgobegin");
-  cmdArgs.push_back("-lgo");
-
-  // Pull in pthread and math library.
   bool isStatic = args.hasArg(gollvm::options::OPT_static);
   if (isStatic)
-    cmdArgs.push_back("-lpthread");
-  cmdArgs.push_back("-lm");
-  if (isStatic) {
-    cmdArgs.push_back("-u");
-    cmdArgs.push_back("pthread_create");
-  }
-  cmdArgs.push_back("--wrap=pthread_create");
-
-  // Libgcc and libc.
-  bool isShared = args.hasArg(gollvm::options::OPT_shared);
-  if (isStatic) {
-    cmdArgs.push_back("--start-group");
-    cmdArgs.push_back("-lgcc");
-    cmdArgs.push_back("-lgcc_eh");
-    cmdArgs.push_back("-lc");
-    cmdArgs.push_back("--end-group");
-  } else {
-    cmdArgs.push_back("-lgcc_s");
-    if (!isShared)
-      cmdArgs.push_back("-lgcc");
-    cmdArgs.push_back("-lc");
-    cmdArgs.push_back("-lgcc_s");
-    if (!isShared)
-      cmdArgs.push_back("-lgcc");
-  }
+    addSysLibsStatic(args, cmdArgs);
+  else
+    addSysLibsShared(args, cmdArgs);
 
   // crtend files.
   addEndFiles(cmdArgs);
diff --git a/driver/GnuTools.h b/driver/GnuTools.h
index da0f064..b3210b9 100644
--- a/driver/GnuTools.h
+++ b/driver/GnuTools.h
@@ -58,6 +58,10 @@
   void addBeginFiles(llvm::opt::ArgStringList &cmdArgs);
   void addEndFiles(llvm::opt::ArgStringList &cmdArgs);
   void addLDM(llvm::opt::ArgStringList &cmdArgs);
+  void addSysLibsStatic(llvm::opt::ArgList &args,
+                        llvm::opt::ArgStringList &cmdArgs);
+  void addSysLibsShared(llvm::opt::ArgList &args,
+                        llvm::opt::ArgStringList &cmdArgs);
   void addSharedAndOrStaticFlags(llvm::opt::ArgStringList &cmdArgs);
   void addFilePathArgs(llvm::opt::ArgStringList &cmdArgs);
 };
diff --git a/driver/GollvmOptions.td b/driver/GollvmOptions.td
index b0e2877..23e7760 100644
--- a/driver/GollvmOptions.td
+++ b/driver/GollvmOptions.td
@@ -196,6 +196,13 @@
 def shared : Flag<["-", "--"], "shared">;
 def static : Flag<["-", "--"], "static">;
 
+def static_libgo : Flag<["-", "--"], "static-libgo">;
+
+def pthreads : Flag<["-"], "pthreads">,
+  HelpText<"Support POSIX threads in generated code">;
+def pthread : Flag<["-"], "pthread">, Alias<pthreads>,
+  HelpText<"Support POSIX threads in generated code">;
+
 // Target-independent "-f" options.
 
 def fPIC : Flag<["-"], "fPIC">, Group<f_Group>;