<div dir="ltr">Hmm, I'm not able to reproduce this with upstream. Sorry for the noise.<div><br clear="all"><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">- Michael Spencer</div></div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jun 6, 2022 at 2:44 PM Michael Spencer <<a href="mailto:bigcheesegs@gmail.com">bigcheesegs@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">I believe this broke the shared library build. CMake complains with a cycle:<div><br></div><div><pre style="color:rgb(0,0,0);white-space:pre-wrap">CMake Error: The inter-target dependency graph contains the following strongly connected component (cycle):</pre><pre style="color:rgb(0,0,0);white-space:pre-wrap"><br></pre><pre style="color:rgb(0,0,0);white-space:pre-wrap"><span style="color:rgb(34,34,34);font-family:Arial,Helvetica,sans-serif;white-space:normal">I'm verifying that this occurs with a clean upstream build.</span></pre><div><div dir="ltr">- Michael Spencer</div></div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Jun 5, 2022 at 9:28 PM Alex Brachet via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
Author: Chris Bieneman<br>
Date: 2022-06-06T04:27:32Z<br>
New Revision: f06abbb393800b0d466c88e283c06f75561c432c<br>
<br>
URL: <a href="https://github.com/llvm/llvm-project/commit/f06abbb393800b0d466c88e283c06f75561c432c" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/f06abbb393800b0d466c88e283c06f75561c432c</a><br>
DIFF: <a href="https://github.com/llvm/llvm-project/commit/f06abbb393800b0d466c88e283c06f75561c432c.diff" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/commit/f06abbb393800b0d466c88e283c06f75561c432c.diff</a><br>
<br>
LOG: LLVM Driver Multicall tool<br>
<br>
This patch adds an llvm-driver multicall tool that can combine multiple<br>
LLVM-based tools. The build infrastructure is enabled for a tool by<br>
adding the GENERATE_DRIVER option to the add_llvm_executable CMake<br>
call, and changing the tool's main function to a canonicalized<br>
tool_name_main format (i.e. llvm_ar_main, clang_main, etc...).<br>
<br>
As currently implemented llvm-driver contains dsymutil, llvm-ar,<br>
llvm-cxxfilt, llvm-objcopy, and clang (if clang is included in the<br>
build).<br>
<br>
llvm-driver can be enabled from builds by setting<br>
LLVM_TOOL_LLVM_DRIVER_BUILD=On.<br>
<br>
There are several limitations in the current implementation, which can<br>
be addressed in subsequent patches:<br>
<br>
(1) the multicall binary cannot currently properly handle<br>
multi-dispatch tools. This means symlinking llvm-ranlib to llvm-driver<br>
will not properly result in llvm-ar's main being called.<br>
(2) the multicall binary cannot be comprised of tools containing<br>
conflicting cl::opt options as the global cl::opt option list cannot<br>
contain duplicates.<br>
<br>
These limitations can be addressed in subsequent patches.<br>
<br>
Differential revision: <a href="https://reviews.llvm.org/D109977" rel="noreferrer" target="_blank">https://reviews.llvm.org/D109977</a><br>
<br>
Added: <br>
    llvm/cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a><br>
    llvm/test/tools/llvm-driver/help-passthrough.test<br>
    llvm/test/tools/llvm-driver/help.test<br>
    llvm/test/tools/llvm-driver/symlink-call.test<br>
    llvm/tools/llvm-driver/CMakeLists.txt<br>
    llvm/tools/llvm-driver/llvm-driver.cpp<br>
<br>
Modified: <br>
    clang/cmake/modules/AddClang.cmake<br>
    clang/tools/driver/CMakeLists.txt<br>
    clang/tools/driver/driver.cpp<br>
    llvm/CMakeLists.txt<br>
    llvm/cmake/modules/AddLLVM.cmake<br>
    llvm/lib/Support/Path.cpp<br>
    llvm/lib/Support/Unix/Path.inc<br>
    llvm/lib/Support/Windows/Path.inc<br>
    llvm/test/CMakeLists.txt<br>
    llvm/test/<a href="http://lit.cfg.py" rel="noreferrer" target="_blank">lit.cfg.py</a><br>
    llvm/test/<a href="http://lit.site.cfg.py.in" rel="noreferrer" target="_blank">lit.site.cfg.py.in</a><br>
    llvm/tools/CMakeLists.txt<br>
    llvm/tools/dsymutil/CMakeLists.txt<br>
    llvm/tools/dsymutil/dsymutil.cpp<br>
    llvm/tools/llvm-ar/CMakeLists.txt<br>
    llvm/tools/llvm-ar/llvm-ar.cpp<br>
    llvm/tools/llvm-cxxfilt/CMakeLists.txt<br>
    llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp<br>
    llvm/tools/llvm-objcopy/CMakeLists.txt<br>
    llvm/tools/llvm-objcopy/llvm-objcopy.cpp<br>
    utils/bazel/llvm-project-overlay/clang/BUILD.bazel<br>
    utils/bazel/llvm-project-overlay/llvm/BUILD.bazel<br>
<br>
Removed: <br>
<br>
<br>
<br>
################################################################################<br>
diff  --git a/clang/cmake/modules/AddClang.cmake b/clang/cmake/modules/AddClang.cmake<br>
index 9bbbfc032b7df..299f8ce6e2fb4 100644<br>
--- a/clang/cmake/modules/AddClang.cmake<br>
+++ b/clang/cmake/modules/AddClang.cmake<br>
@@ -184,5 +184,8 @@ function(clang_target_link_libraries target type)<br>
   else()<br>
     target_link_libraries(${target} ${type} ${ARGN})<br>
   endif()<br>
+  if (TARGET obj.${target})<br>
+    target_link_libraries(obj.${target} ${ARGN})<br>
+  endif()<br>
<br>
 endfunction()<br>
<br>
diff  --git a/clang/tools/driver/CMakeLists.txt b/clang/tools/driver/CMakeLists.txt<br>
index 6b3e159d1b648..d05b71db13f21 100644<br>
--- a/clang/tools/driver/CMakeLists.txt<br>
+++ b/clang/tools/driver/CMakeLists.txt<br>
@@ -31,6 +31,7 @@ add_clang_tool(clang<br>
   DEPENDS<br>
   intrinsics_gen<br>
   ${support_plugins}<br>
+  GENERATE_DRIVER<br>
   )<br>
<br>
 clang_target_link_libraries(clang<br>
<br>
diff  --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp<br>
index d361457f8cecd..fa1f09b44f4da 100644<br>
--- a/clang/tools/driver/driver.cpp<br>
+++ b/clang/tools/driver/driver.cpp<br>
@@ -327,7 +327,7 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {<br>
   return 1;<br>
 }<br>
<br>
-int main(int Argc, const char **Argv) {<br>
+int clang_main(int Argc, char **Argv) {<br>
   noteBottomOfStack();<br>
   llvm::InitLLVM X(Argc, Argv);<br>
   llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL<br>
<br>
diff  --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt<br>
index 1effbde06b80e..fab16edd7d532 100644<br>
--- a/llvm/CMakeLists.txt<br>
+++ b/llvm/CMakeLists.txt<br>
@@ -269,6 +269,8 @@ include(VersionFromVCS)<br>
 option(LLVM_APPEND_VC_REV<br>
   "Embed the version control system revision in LLVM" ON)<br>
<br>
+option(LLVM_TOOL_LLVM_DRIVER_BUILD "Enables building the llvm multicall tool" OFF)<br>
+<br>
 set(PACKAGE_NAME LLVM)<br>
 set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")<br>
 set(PACKAGE_BUGREPORT "<a href="https://github.com/llvm/llvm-project/issues/" rel="noreferrer" target="_blank">https://github.com/llvm/llvm-project/issues/</a>")<br>
<br>
diff  --git a/llvm/cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a> b/llvm/cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a><br>
new file mode 100644<br>
index 0000000000000..2164fb00d168f<br>
--- /dev/null<br>
+++ b/llvm/cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a><br>
@@ -0,0 +1,11 @@<br>
+//===-- driver-template.cpp -----------------------------------------------===//<br>
+//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+int @TOOL_NAME@_main(int argc, char **argv);<br>
+<br>
+int main(int argc, char **argv) { return @TOOL_NAME@_main(argc, argv); }<br>
<br>
diff  --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake<br>
index f798243a80b22..64d719f2626c9 100644<br>
--- a/llvm/cmake/modules/AddLLVM.cmake<br>
+++ b/llvm/cmake/modules/AddLLVM.cmake<br>
@@ -859,7 +859,7 @@ endmacro(add_llvm_library name)<br>
<br>
 macro(add_llvm_executable name)<br>
   cmake_parse_arguments(ARG<br>
-    "DISABLE_LLVM_LINK_LLVM_DYLIB;IGNORE_EXTERNALIZE_DEBUGINFO;NO_INSTALL_RPATH;SUPPORT_PLUGINS"<br>
+    "DISABLE_LLVM_LINK_LLVM_DYLIB;IGNORE_EXTERNALIZE_DEBUGINFO;NO_INSTALL_RPATH;SUPPORT_PLUGINS;GENERATE_DRIVER"<br>
     "ENTITLEMENTS;BUNDLE_PATH"<br>
     "DEPENDS"<br>
     ${ARGN})<br>
@@ -869,7 +869,7 @@ macro(add_llvm_executable name)<br>
   list(APPEND LLVM_COMMON_DEPENDS ${ARG_DEPENDS})<br>
<br>
   # Generate objlib<br>
-  if(LLVM_ENABLE_OBJLIB)<br>
+  if(LLVM_ENABLE_OBJLIB OR ARG_GENERATE_DRIVER)<br>
     # Generate an obj library for both targets.<br>
     set(obj_name "obj.${name}")<br>
     add_library(${obj_name} OBJECT EXCLUDE_FROM_ALL<br>
@@ -884,6 +884,23 @@ macro(add_llvm_executable name)<br>
     set_target_properties(${obj_name} PROPERTIES FOLDER "Object Libraries")<br>
   endif()<br>
<br>
+  if (ARG_GENERATE_DRIVER)<br>
+    string(REPLACE "-" "_" TOOL_NAME ${name})<br>
+    configure_file(<br>
+      ${LLVM_MAIN_SRC_DIR}/cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a><br>
+      ${CMAKE_CURRENT_BINARY_DIR}/${name}-driver.cpp)<br>
+<br>
+    list(APPEND ALL_FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}-driver.cpp)<br>
+<br>
+    set_property(GLOBAL APPEND PROPERTY LLVM_DRIVER_COMPONENTS ${LLVM_LINK_COMPONENTS})<br>
+    set_property(GLOBAL APPEND PROPERTY LLVM_DRIVER_DEPS ${ARG_DEPENDS} ${LLVM_COMMON_DEPENDS})<br>
+    set_property(GLOBAL APPEND PROPERTY LLVM_DRIVER_OBJLIBS "${obj_name}")<br>
+    <br>
+    set_property(GLOBAL APPEND PROPERTY LLVM_DRIVER_TOOLS ${name})<br>
+    target_link_libraries(${obj_name} ${LLVM_PTHREAD_LIB})<br>
+    llvm_config(${obj_name} ${USE_SHARED} ${LLVM_LINK_COMPONENTS} )<br>
+  endif()<br>
+<br>
   add_windows_version_resource_file(ALL_FILES ${ALL_FILES})<br>
<br>
   if(XCODE)<br>
@@ -1449,6 +1466,12 @@ function(llvm_add_implicit_projects project)<br>
   foreach(dir ${sub-dirs})<br>
     if(IS_DIRECTORY "${dir}" AND EXISTS "${dir}/CMakeLists.txt")<br>
       canonicalize_tool_name(${dir} name)<br>
+      # I don't like special casing things by order, but the llvm-driver ends up<br>
+      # linking the object libraries from all the tools that opt-in, so adding<br>
+      # it separately at the end is probably the simplest case.<br>
+      if("${name}" STREQUAL "LLVM_DRIVER")<br>
+        continue()<br>
+      endif()<br>
       if (${project}_TOOL_${name}_BUILD)<br>
         get_filename_component(fn "${dir}" NAME)<br>
         list(APPEND list_of_implicit_subdirs "${fn}")<br>
@@ -1998,6 +2021,16 @@ endfunction()<br>
<br>
 function(add_llvm_tool_symlink link_name target)<br>
   cmake_parse_arguments(ARG "ALWAYS_GENERATE" "OUTPUT_DIR" "" ${ARGN})<br>
+<br>
+  get_property(LLVM_DRIVER_TOOLS GLOBAL PROPERTY LLVM_DRIVER_TOOLS)<br>
+<br>
+  if (${target} IN_LIST LLVM_DRIVER_TOOLS)<br>
+    string(REPLACE "-" "_" tool_entry ${target})<br>
+    string(REPLACE "-" "_" key ${link_name})<br>
+    string(REPLACE "llvm-" "" tool_name ${link_name})<br>
+    set_property(GLOBAL APPEND_STRING PROPERTY<br>
+                 LLVM_EXTRA_DRIVER_ENTRIES "LLVM_DRIVER_TOOL(\"${tool_name}\", ${tool_entry})\n")<br>
+  endif()<br>
   set(dest_binary "$<TARGET_FILE:${target}>")<br>
<br>
   # This got a bit gross... For multi-configuration generators the target<br>
<br>
diff  --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp<br>
index 9575e34b81c63..283dc70f2bc9a 100644<br>
--- a/llvm/lib/Support/Path.cpp<br>
+++ b/llvm/lib/Support/Path.cpp<br>
@@ -1202,9 +1202,18 @@ Error readNativeFileToEOF(file_t FileHandle, SmallVectorImpl<char> &Buffer,<br>
 #include "Windows/Path.inc"<br>
 #endif<br>
<br>
+bool IsLLVMDriver = false;<br>
+<br>
 namespace llvm {<br>
 namespace sys {<br>
 namespace fs {<br>
+<br>
+std::string getMainExecutable(const char *Argv0, void *MainAddr) {<br>
+  if (IsLLVMDriver)<br>
+    return sys::path::stem(Argv0).str();<br>
+  return getMainExecutableImpl(Argv0, MainAddr);<br>
+}<br>
+<br>
 TempFile::TempFile(StringRef Name, int FD)<br>
     : TmpName(std::string(Name)), FD(FD) {}<br>
 TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); }<br>
<br>
diff  --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc<br>
index c4345f13f0a6e..2ae7c6dc47e07 100644<br>
--- a/llvm/lib/Support/Unix/Path.inc<br>
+++ b/llvm/lib/Support/Unix/Path.inc<br>
@@ -194,7 +194,7 @@ getprogpath(char ret[PATH_MAX], const char *bin)<br>
<br>
 /// GetMainExecutable - Return the path to the main executable, given the<br>
 /// value of argv[0] from program startup.<br>
-std::string getMainExecutable(const char *argv0, void *MainAddr) {<br>
+std::string getMainExecutableImpl(const char *argv0, void *MainAddr) {<br>
 #if defined(__APPLE__)<br>
   // On OS X the executable path is saved to the stack by dyld. Reading it<br>
   // from there is much faster than calling dladdr, especially for large<br>
<br>
diff  --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc<br>
index 5f1a364ea1a8e..433c62900a3f6 100644<br>
--- a/llvm/lib/Support/Windows/Path.inc<br>
+++ b/llvm/lib/Support/Windows/Path.inc<br>
@@ -130,7 +130,7 @@ namespace fs {<br>
<br>
 const file_t kInvalidFile = INVALID_HANDLE_VALUE;<br>
<br>
-std::string getMainExecutable(const char *argv0, void *MainExecAddr) {<br>
+std::string getMainExecutableImpl(const char *argv0, void *MainExecAddr) {<br>
   SmallVector<wchar_t, MAX_PATH> PathName;<br>
   PathName.resize_for_overwrite(PathName.capacity());<br>
   DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.size());<br>
<br>
diff  --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt<br>
index 50a4a982ec4d2..bc2869dc536b5 100644<br>
--- a/llvm/test/CMakeLists.txt<br>
+++ b/llvm/test/CMakeLists.txt<br>
@@ -21,6 +21,7 @@ llvm_canonicalize_cmake_booleans(<br>
   LLVM_RAEVICT_MODEL_AUTOGENERATED<br>
   LLVM_ENABLE_EXPENSIVE_CHECKS<br>
   LLVM_INCLUDE_DXIL_TESTS<br>
+  LLVM_TOOL_LLVM_DRIVER_BUILD<br>
   )<br>
<br>
 configure_lit_site_cfg(<br>
@@ -144,6 +145,10 @@ if(TARGET llvm-lto)<br>
   set(LLVM_TEST_DEPENDS ${LLVM_TEST_DEPENDS} llvm-lto)<br>
 endif()<br>
<br>
+if(TARGET llvm-driver)<br>
+  set(LLVM_TEST_DEPENDS ${LLVM_TEST_DEPENDS} llvm-driver)<br>
+endif()<br>
+<br>
 # If Intel JIT events are supported, depend on a tool that tests the listener.<br>
 if( LLVM_USE_INTEL_JITEVENTS )<br>
   set(LLVM_TEST_DEPENDS ${LLVM_TEST_DEPENDS} llvm-jitlistener)<br>
<br>
diff  --git a/llvm/test/<a href="http://lit.cfg.py" rel="noreferrer" target="_blank">lit.cfg.py</a> b/llvm/test/<a href="http://lit.cfg.py" rel="noreferrer" target="_blank">lit.cfg.py</a><br>
index b6fb8aa9fab76..a1f4f86b84562 100644<br>
--- a/llvm/test/<a href="http://lit.cfg.py" rel="noreferrer" target="_blank">lit.cfg.py</a><br>
+++ b/llvm/test/<a href="http://lit.cfg.py" rel="noreferrer" target="_blank">lit.cfg.py</a><br>
@@ -139,6 +139,7 @@ def get_asan_rtlib():<br>
 config.llvm_locstats_used = os.path.exists(llvm_locstats_tool)<br>
<br>
 tools = [<br>
+    ToolSubst('%llvm', FindTool('llvm')),<br>
     ToolSubst('%lli', FindTool('lli'), post='.', extra_args=lli_args),<br>
     ToolSubst('%llc_dwarf', FindTool('llc'), extra_args=llc_args),<br>
     ToolSubst('%go', config.go_executable, unresolved='ignore'),<br>
@@ -350,6 +351,9 @@ def have_cxx_shared_library():<br>
     if not config.target_triple.startswith(("nvptx", "xcore")):<br>
         config.available_features.add('object-emission')<br>
<br>
+if config.have_llvm_driver:<br>
+  config.available_features.add('llvm-driver')<br>
+<br>
 import subprocess<br>
<br>
<br>
<br>
diff  --git a/llvm/test/<a href="http://lit.site.cfg.py.in" rel="noreferrer" target="_blank">lit.site.cfg.py.in</a> b/llvm/test/<a href="http://lit.site.cfg.py.in" rel="noreferrer" target="_blank">lit.site.cfg.py.in</a><br>
index 266f93232ed61..c3f6cb6dd3ca1 100644<br>
--- a/llvm/test/<a href="http://lit.site.cfg.py.in" rel="noreferrer" target="_blank">lit.site.cfg.py.in</a><br>
+++ b/llvm/test/<a href="http://lit.site.cfg.py.in" rel="noreferrer" target="_blank">lit.site.cfg.py.in</a><br>
@@ -59,6 +59,7 @@ config.llvm_inliner_model_autogenerated = @LLVM_INLINER_MODEL_AUTOGENERATED@<br>
 config.llvm_raevict_model_autogenerated = @LLVM_RAEVICT_MODEL_AUTOGENERATED@<br>
 config.expensive_checks = @LLVM_ENABLE_EXPENSIVE_CHECKS@<br>
 config.dxil_tests = @LLVM_INCLUDE_DXIL_TESTS@<br>
+config.have_llvm_driver = @LLVM_TOOL_LLVM_DRIVER_BUILD@<br>
<br>
 import lit.llvm<br>
 lit.llvm.initialize(lit_config, config)<br>
<br>
diff  --git a/llvm/test/tools/llvm-driver/help-passthrough.test b/llvm/test/tools/llvm-driver/help-passthrough.test<br>
new file mode 100644<br>
index 0000000000000..93f6146cdbbbe<br>
--- /dev/null<br>
+++ b/llvm/test/tools/llvm-driver/help-passthrough.test<br>
@@ -0,0 +1,3 @@<br>
+# REQUIRES: llvm-driver<br>
+# RUN: %llvm cxxfilt --help | FileCheck %s <br>
+# CHECK: USAGE: cxxfilt<br>
<br>
diff  --git a/llvm/test/tools/llvm-driver/help.test b/llvm/test/tools/llvm-driver/help.test<br>
new file mode 100644<br>
index 0000000000000..c16a30833c65d<br>
--- /dev/null<br>
+++ b/llvm/test/tools/llvm-driver/help.test<br>
@@ -0,0 +1,3 @@<br>
+# REQUIRES: llvm-driver<br>
+# RUN: %llvm --help | FileCheck %s<br>
+# CHECK: USAGE: llvm [subcommand]<br>
<br>
diff  --git a/llvm/test/tools/llvm-driver/symlink-call.test b/llvm/test/tools/llvm-driver/symlink-call.test<br>
new file mode 100644<br>
index 0000000000000..eeedf9edc73f2<br>
--- /dev/null<br>
+++ b/llvm/test/tools/llvm-driver/symlink-call.test<br>
@@ -0,0 +1,23 @@<br>
+## Don't make symlinks on Windows.<br>
+# UNSUPPORTED: system-windows<br>
+# REQUIRES: llvm-driver<br>
+<br>
+# RUN: rm -rf %t<br>
+# RUN: mkdir %t<br>
+# RUN: ln -s %llvm %t/llvm-cxxfilt<br>
+# RUN: %t/llvm-cxxfilt --help | FileCheck %s<br>
+# RUN: ln -s %llvm %t/llvm-cxxfilt-15<br>
+# RUN: %t/llvm-cxxfilt-15 --help | FileCheck %s<br>
+# RUN: ln -s %llvm %t/cxxfilt<br>
+# RUN: %t/cxxfilt --help | FileCheck %s<br>
+# RUN: ln -s %llvm %t/cxxfilt-15<br>
+# RUN: %t/cxxfilt-15 --help | FileCheck %s<br>
+# RUN: ln -s %llvm %t/cxxfilt-15.exe<br>
+# RUN: %t/cxxfilt-15.exe --help | FileCheck %s<br>
+<br>
+# RUN: ln -s %llvm %t/llvm-15<br>
+# RUN: %t/llvm-15 cxxfilt --help | FileCheck %s<br>
+# RUN: ln -s %llvm %t/llvm-15.exe<br>
+# RUN: %t/llvm-15.exe cxxfilt --help | FileCheck %s<br>
+<br>
+# CHECK: OVERVIEW: LLVM symbol undecoration tool<br>
<br>
diff  --git a/llvm/tools/CMakeLists.txt b/llvm/tools/CMakeLists.txt<br>
index 770e46c4806f5..ef5edb195317b 100644<br>
--- a/llvm/tools/CMakeLists.txt<br>
+++ b/llvm/tools/CMakeLists.txt<br>
@@ -53,3 +53,9 @@ foreach(p ${LLVM_EXTERNAL_PROJECTS})<br>
 endforeach(p)<br>
<br>
 set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE)<br>
+<br>
+if (LLVM_TOOL_LLVM_DRIVER_BUILD)<br>
+  # This is explicitly added at the end _after_ all tool projects so that it can<br>
+  # scrape up tools from other projects into itself.<br>
+  add_subdirectory(llvm-driver)<br>
+endif()<br>
<br>
diff  --git a/llvm/tools/dsymutil/CMakeLists.txt b/llvm/tools/dsymutil/CMakeLists.txt<br>
index 1efc58d19e92c..a255c1c5daf51 100644<br>
--- a/llvm/tools/dsymutil/CMakeLists.txt<br>
+++ b/llvm/tools/dsymutil/CMakeLists.txt<br>
@@ -32,6 +32,8 @@ add_llvm_tool(dsymutil<br>
   DEPENDS<br>
   intrinsics_gen<br>
   ${tablegen_deps}<br>
+  DsymutilTableGen<br>
+  GENERATE_DRIVER<br>
   )<br>
<br>
 if(APPLE)<br>
<br>
diff  --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp<br>
index df50432368471..abdb4ca4d48ce 100644<br>
--- a/llvm/tools/dsymutil/dsymutil.cpp<br>
+++ b/llvm/tools/dsymutil/dsymutil.cpp<br>
@@ -521,7 +521,7 @@ getOutputFileName(StringRef InputFile, const DsymutilOptions &Options) {<br>
   return OutputLocation(std::string(Path.str()), ResourceDir);<br>
 }<br>
<br>
-int main(int argc, char **argv) {<br>
+int dsymutil_main(int argc, char **argv) {<br>
   InitLLVM X(argc, argv);<br>
<br>
   // Parse arguments.<br>
<br>
diff  --git a/llvm/tools/llvm-ar/CMakeLists.txt b/llvm/tools/llvm-ar/CMakeLists.txt<br>
index 602b4a46ea055..166d670017159 100644<br>
--- a/llvm/tools/llvm-ar/CMakeLists.txt<br>
+++ b/llvm/tools/llvm-ar/CMakeLists.txt<br>
@@ -15,6 +15,7 @@ add_llvm_tool(llvm-ar<br>
<br>
   DEPENDS<br>
   intrinsics_gen<br>
+  GENERATE_DRIVER<br>
   )<br>
<br>
 add_llvm_tool_symlink(llvm-ranlib llvm-ar)<br>
<br>
diff  --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp<br>
index a93943295cf93..abd10f1b500b0 100644<br>
--- a/llvm/tools/llvm-ar/llvm-ar.cpp<br>
+++ b/llvm/tools/llvm-ar/llvm-ar.cpp<br>
@@ -1265,7 +1265,7 @@ static int ranlib_main(int argc, char **argv) {<br>
   return performOperation(CreateSymTab, nullptr);<br>
 }<br>
<br>
-int main(int argc, char **argv) {<br>
+int llvm_ar_main(int argc, char **argv) {<br>
   InitLLVM X(argc, argv);<br>
   ToolName = argv[0];<br>
<br>
<br>
diff  --git a/llvm/tools/llvm-cxxfilt/CMakeLists.txt b/llvm/tools/llvm-cxxfilt/CMakeLists.txt<br>
index 07ba9f9e9b1d0..367744beb9b60 100644<br>
--- a/llvm/tools/llvm-cxxfilt/CMakeLists.txt<br>
+++ b/llvm/tools/llvm-cxxfilt/CMakeLists.txt<br>
@@ -13,6 +13,7 @@ add_llvm_tool(llvm-cxxfilt<br>
<br>
   DEPENDS<br>
   CxxfiltOptsTableGen<br>
+  GENERATE_DRIVER<br>
   )<br>
<br>
 if(LLVM_INSTALL_BINUTILS_SYMLINKS)<br>
<br>
diff  --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp<br>
index ccfaaa96deb21..1cea9e29faa4f 100644<br>
--- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp<br>
+++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp<br>
@@ -140,7 +140,7 @@ static void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) {<br>
   OS.flush();<br>
 }<br>
<br>
-int main(int argc, char **argv) {<br>
+int llvm_cxxfilt_main(int argc, char **argv) {<br>
   InitLLVM X(argc, argv);<br>
   BumpPtrAllocator A;<br>
   StringSaver Saver(A);<br>
<br>
diff  --git a/llvm/tools/llvm-driver/CMakeLists.txt b/llvm/tools/llvm-driver/CMakeLists.txt<br>
new file mode 100644<br>
index 0000000000000..7cbeaf398eb4b<br>
--- /dev/null<br>
+++ b/llvm/tools/llvm-driver/CMakeLists.txt<br>
@@ -0,0 +1,31 @@<br>
+get_property(LLVM_COMMON_DEPENDS GLOBAL PROPERTY LLVM_DRIVER_DEPS)<br>
+get_property(LLVM_DRIVER_OBJLIBS GLOBAL PROPERTY LLVM_DRIVER_OBJLIBS)<br>
+<br>
+get_property(LLVM_DRIVER_TOOLS GLOBAL PROPERTY LLVM_DRIVER_TOOLS)<br>
+<br>
+foreach(tool ${LLVM_DRIVER_TOOLS})<br>
+  string(REPLACE "-" "_" tool_entry ${tool})<br>
+  string(REPLACE "llvm-" "" tool ${tool})<br>
+  set(def_decl "${def_decl}LLVM_DRIVER_TOOL(\"${tool}\", ${tool_entry})\n")<br>
+endforeach()<br>
+<br>
+get_property(LLVM_EXTRA_DRIVER_ENTRIES GLOBAL PROPERTY LLVM_EXTRA_DRIVER_ENTRIES)<br>
+<br>
+file(WRITE<br>
+          "${CMAKE_CURRENT_BINARY_DIR}/LLVMDriverTools.def"<br>
+          "${def_decl}${LLVM_EXTRA_DRIVER_ENTRIES}#undef LLVM_DRIVER_TOOL\n")<br>
+<br>
+include_directories(${CMAKE_CURRENT_BINARY_DIR})<br>
+<br>
+add_llvm_tool(llvm-driver<br>
+  llvm-driver.cpp<br>
+  )<br>
+<br>
+set_target_properties(llvm-driver PROPERTIES OUTPUT_NAME llvm)<br>
+<br>
+target_link_libraries(llvm-driver PUBLIC ${LLVM_DRIVER_OBJLIBS})<br>
+<br>
+if(APPLE)<br>
+  # dsymutil uses some CoreFoundation stuff on Darwin...<br>
+  target_link_libraries(llvm-driver PRIVATE "-framework CoreFoundation")<br>
+endif(APPLE)<br>
<br>
diff  --git a/llvm/tools/llvm-driver/llvm-driver.cpp b/llvm/tools/llvm-driver/llvm-driver.cpp<br>
new file mode 100644<br>
index 0000000000000..3f543360ffbc4<br>
--- /dev/null<br>
+++ b/llvm/tools/llvm-driver/llvm-driver.cpp<br>
@@ -0,0 +1,74 @@<br>
+//===-- llvm-driver.cpp ---------------------------------------------------===//<br>
+//<br>
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>
+// See <a href="https://llvm.org/LICENSE.txt" rel="noreferrer" target="_blank">https://llvm.org/LICENSE.txt</a> for license information.<br>
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "llvm/ADT/StringExtras.h"<br>
+#include "llvm/ADT/StringRef.h"<br>
+#include "llvm/ADT/StringSwitch.h"<br>
+#include "llvm/Support/CommandLine.h"<br>
+#include "llvm/Support/ErrorHandling.h"<br>
+#include "llvm/Support/Path.h"<br>
+#include "llvm/Support/WithColor.h"<br>
+<br>
+using namespace llvm;<br>
+<br>
+#define LLVM_DRIVER_TOOL(tool, entry) int entry##_main(int argc, char **argv);<br>
+#include "LLVMDriverTools.def"<br>
+<br>
+constexpr char subcommands[] =<br>
+#define LLVM_DRIVER_TOOL(tool, entry) "  " tool "\n"<br>
+#include "LLVMDriverTools.def"<br>
+    ;<br>
+<br>
+static void printHelpMessage() {<br>
+  llvm::outs() << "OVERVIEW: llvm toolchain driver\n\n"<br>
+               << "USAGE: llvm [subcommand] [options]\n\n"<br>
+               << "SUBCOMMANDS:\n\n"<br>
+               << subcommands<br>
+               << "\n  Type \"llvm <subcommand> --help\" to get more help on a "<br>
+                  "specific subcommand\n\n"<br>
+               << "OPTIONS:\n\n  --help - Display this message";<br>
+}<br>
+<br>
+static int findTool(int Argc, char **Argv) {<br>
+  if (!Argc) {<br>
+    printHelpMessage();<br>
+    return 1;<br>
+  }<br>
+<br>
+  StringRef ToolName = Argv[0];<br>
+<br>
+  if (ToolName == "--help") {<br>
+    printHelpMessage();<br>
+    return 0;<br>
+  }<br>
+<br>
+  StringRef Stem = sys::path::stem(ToolName);<br>
+  auto Is = [=](StringRef Tool) {<br>
+    auto I = Stem.rfind_insensitive(Tool);<br>
+    return I != StringRef::npos && (I + Tool.size() == Stem.size() ||<br>
+                                    !llvm::isAlnum(Stem[I + Tool.size()]));<br>
+  };<br>
+<br>
+#define LLVM_DRIVER_TOOL(tool, entry)                                          \<br>
+  if (Is(tool))                                                                \<br>
+    return entry##_main(Argc, Argv);<br>
+#include "LLVMDriverTools.def"<br>
+<br>
+  if (Is("llvm"))<br>
+    return findTool(Argc - 1, Argv + 1);<br>
+<br>
+  printHelpMessage();<br>
+  return 1;<br>
+}<br>
+<br>
+extern bool IsLLVMDriver;<br>
+<br>
+int main(int Argc, char **Argv) {<br>
+  IsLLVMDriver = true;<br>
+  return findTool(Argc, Argv);<br>
+}<br>
<br>
diff  --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt<br>
index 493cc87b0768c..ca94d4a477406 100644<br>
--- a/llvm/tools/llvm-objcopy/CMakeLists.txt<br>
+++ b/llvm/tools/llvm-objcopy/CMakeLists.txt<br>
@@ -30,6 +30,7 @@ add_llvm_tool(llvm-objcopy<br>
   ObjcopyOptsTableGen<br>
   InstallNameToolOptsTableGen<br>
   StripOptsTableGen<br>
+  GENERATE_DRIVER<br>
   )<br>
<br>
 add_llvm_tool_symlink(llvm-install-name-tool llvm-objcopy)<br>
<br>
diff  --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp<br>
index 117a63cd9d8fb..aa262152ed646 100644<br>
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp<br>
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp<br>
@@ -223,7 +223,7 @@ static Error executeObjcopy(ConfigManager &ConfigMgr) {<br>
   return Error::success();<br>
 }<br>
<br>
-int main(int argc, char **argv) {<br>
+int llvm_objcopy_main(int argc, char **argv) {<br>
   InitLLVM X(argc, argv);<br>
   ToolName = argv[0];<br>
<br>
<br>
diff  --git a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel<br>
index 702547e87df37..5e93d9ebe71be 100644<br>
--- a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel<br>
+++ b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel<br>
@@ -5,6 +5,7 @@<br>
 load("//llvm:tblgen.bzl", "gentbl")<br>
 load("//llvm:binary_alias.bzl", "binary_alias")<br>
 load("//llvm:cc_plugin_library.bzl", "cc_plugin_library")<br>
+load("//llvm:template_rule.bzl", "template_rule")<br>
<br>
 package(<br>
     default_visibility = ["//visibility:public"],<br>
@@ -1925,12 +1926,21 @@ cc_binary(<br>
     ],<br>
 )<br>
<br>
+template_rule(<br>
+    name = "clang_main",<br>
+    src = "//llvm:cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a>",<br>
+    out = "clang_main.cpp",<br>
+    substitutions = {<br>
+        "@TOOL_NAME@": "clang"<br>
+    },<br>
+)<br>
+<br>
 cc_library(<br>
     name = "clang-driver",<br>
     srcs = glob([<br>
         "tools/driver/*.cpp",<br>
         "tools/driver/*.h",<br>
-    ]),<br>
+    ]) + ["clang_main.cpp"],<br>
     copts = [<br>
         # Disable stack frame size checks in the driver because<br>
         # clang::ensureStackAddressSpace allocates a large array on the stack.<br>
<br>
diff  --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel<br>
index 2e9faad29af96..8ffd63b4bd996 100644<br>
--- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel<br>
+++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel<br>
@@ -2594,12 +2594,21 @@ gentbl(<br>
     td_srcs = ["include/llvm/Option/OptParser.td"],<br>
 )<br>
<br>
+template_rule(<br>
+    name = "dsymutil_main",<br>
+    src = "cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a>",<br>
+    out = "dsymutil_main.cpp",<br>
+    substitutions = {<br>
+        "@TOOL_NAME@": "dsymutil"<br>
+    },<br>
+)<br>
+<br>
 cc_binary(<br>
     name = "dsymutil",<br>
     srcs = glob([<br>
         "tools/dsymutil/*.cpp",<br>
         "tools/dsymutil/*.h",<br>
-    ]),<br>
+    ]) + ["dsymutil_main.cpp"],<br>
     copts = llvm_copts,<br>
     stamp = 0,<br>
     deps = [<br>
@@ -2689,12 +2698,21 @@ cc_binary(<br>
     ],<br>
 )<br>
<br>
+template_rule(<br>
+    name = "ar_main",<br>
+    src = "cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a>",<br>
+    out = "ar_main.cpp",<br>
+    substitutions = {<br>
+        "@TOOL_NAME@": "llvm_ar"<br>
+    },<br>
+)<br>
+<br>
 cc_binary(<br>
     name = "llvm-ar",<br>
     srcs = glob([<br>
         "tools/llvm-ar/*.cpp",<br>
         "tools/llvm-ar/*.h",<br>
-    ]),<br>
+    ]) + ["ar_main.cpp"],<br>
     copts = llvm_copts,<br>
     stamp = 0,<br>
     deps = [<br>
@@ -2882,12 +2900,21 @@ gentbl(<br>
     td_srcs = ["include/llvm/Option/OptParser.td"],<br>
 )<br>
<br>
+template_rule(<br>
+    name = "cxxfilt_main",<br>
+    src = "cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a>",<br>
+    out = "cxxfilt_main.cpp",<br>
+    substitutions = {<br>
+        "@TOOL_NAME@": "llvm_cxxfilt"<br>
+    },<br>
+)<br>
+<br>
 cc_binary(<br>
     name = "llvm-cxxfilt",<br>
     srcs = glob([<br>
         "tools/llvm-cxxfilt/*.cpp",<br>
         "tools/llvm-cxxfilt/*.h",<br>
-    ]),<br>
+    ]) + ["cxxfilt_main.cpp"],<br>
     copts = llvm_copts,<br>
     stamp = 0,<br>
     deps = [<br>
@@ -3416,12 +3443,22 @@ cc_binary(<br>
     ],<br>
 )<br>
<br>
+template_rule(<br>
+    name = "objcopy_main",<br>
+    src = "cmake/<a href="http://driver-template.cpp.in" rel="noreferrer" target="_blank">driver-template.cpp.in</a>",<br>
+    out = "objcopy_main.cpp",<br>
+    substitutions = {<br>
+        "@TOOL_NAME@": "llvm_objcopy"<br>
+    },<br>
+)<br>
+<br>
+<br>
 cc_binary(<br>
     name = "llvm-objcopy",<br>
     srcs = glob([<br>
         "tools/llvm-objcopy/*.cpp",<br>
         "tools/llvm-objcopy/*.h",<br>
-    ]),<br>
+    ]) + ["objcopy_main.cpp"],<br>
     copts = llvm_copts,<br>
     stamp = 0,<br>
     deps = [<br>
<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>
</blockquote></div>