[llvm] [llvm] get cl::opt instantiations working with MSVC DLL build (PR #147810)
Andrew Rogers via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 22 09:55:58 PDT 2025
https://github.com/andrurogerz updated https://github.com/llvm/llvm-project/pull/147810
>From b6afd5e6533cfa717e1fe2b06909cc7c729e207a Mon Sep 17 00:00:00 2001
From: Andrew Rogers <andrurogerz at gmail.com>
Date: Wed, 9 Jul 2025 12:03:59 -0700
Subject: [PATCH 1/2] [llvm] get cl::opt instantiations working with MSVC DLL
build
---
llvm/include/llvm/Support/CommandLine.h | 19 +++++++++++-----
llvm/lib/Support/CommandLine.cpp | 29 ++++++++++++++++++++-----
2 files changed, 38 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h
index adaa75cc6c348..ab3ab9b52ac12 100644
--- a/llvm/include/llvm/Support/CommandLine.h
+++ b/llvm/include/llvm/Support/CommandLine.h
@@ -1518,11 +1518,20 @@ class opt
[](const typename ParserClass::parser_data_type &) {};
};
-extern template class opt<unsigned>;
-extern template class opt<int>;
-extern template class opt<std::string>;
-extern template class opt<char>;
-extern template class opt<bool>;
+#if !defined(LLVM_ENABLE_LLVM_EXPORT_ANNOTATIONS) || \
+ !(defined(_MSC_VER) && !defined(__clang__))
+// Only instantiate opt<std::string> when not building a Windows DLL with MSVC.
+// When exporting opt<std::string>, MSVC cl implicitly exports symbols for
+// std::basic_string through transitive inheritance via std::string. These
+// symbols may appear in other TUs with different linkage, leading to duplicate
+// symbol conflicts.
+extern template class LLVM_TEMPLATE_ABI opt<std::string>;
+#endif
+
+extern template class LLVM_TEMPLATE_ABI opt<unsigned>;
+extern template class LLVM_TEMPLATE_ABI opt<int>;
+extern template class LLVM_TEMPLATE_ABI opt<char>;
+extern template class LLVM_TEMPLATE_ABI opt<bool>;
//===----------------------------------------------------------------------===//
// Default storage class definition: external storage. This implementation
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp
index d5c3cba13e030..c9541289aa3bd 100644
--- a/llvm/lib/Support/CommandLine.cpp
+++ b/llvm/lib/Support/CommandLine.cpp
@@ -68,11 +68,21 @@ template class LLVM_EXPORT_TEMPLATE basic_parser<float>;
template class LLVM_EXPORT_TEMPLATE basic_parser<std::string>;
template class LLVM_EXPORT_TEMPLATE basic_parser<char>;
-template class opt<unsigned>;
-template class opt<int>;
-template class opt<std::string>;
-template class opt<char>;
-template class opt<bool>;
+#if !defined(LLVM_ENABLE_LLVM_EXPORT_ANNOTATIONS) || \
+ !(defined(_MSC_VER) && !defined(__clang__))
+// Only instantiate opt<std::string> when not building a Windows DLL with MSVC.
+// When exporting opt<std::string>, MSVC cl implicitly exports symbols for
+// std::basic_string through transitive inheritance via std::string. These
+// symbols may appear in other TUs with different linkage, leading to duplicate
+// symbol conflicts.
+template class LLVM_EXPORT_TEMPLATE opt<std::string>;
+#endif
+
+template class LLVM_EXPORT_TEMPLATE opt<bool>;
+template class LLVM_EXPORT_TEMPLATE opt<char>;
+template class LLVM_EXPORT_TEMPLATE opt<int>;
+template class LLVM_EXPORT_TEMPLATE opt<unsigned>;
+
} // namespace cl
} // namespace llvm
@@ -95,6 +105,15 @@ void parser<float>::anchor() {}
void parser<std::string>::anchor() {}
void parser<char>::anchor() {}
+// These anchor functions instantiate opt<T> and reference its virtual
+// destructor to ensure MSVC exports the corresponding vtable and typeinfo when
+// building a Windows DLL. Without an explicit reference, MSVC may omit the
+// instantiation at link time even if it is marked DLL-export.
+void opt_bool_anchor() { opt<bool> anchor{""}; }
+void opt_char_anchor() { opt<char> anchor{""}; }
+void opt_int_anchor() { opt<int> anchor{""}; }
+void opt_unsigned_anchor() { opt<unsigned> anchor{""}; }
+
//===----------------------------------------------------------------------===//
const static size_t DefaultPad = 2;
>From d61eda7c4ac0f1ad9ff4eccf570556bdbde27e7a Mon Sep 17 00:00:00 2001
From: Andrew Rogers <andrurogerz at gmail.com>
Date: Tue, 22 Jul 2025 09:55:46 -0700
Subject: [PATCH 2/2] also exclude exporting cl::opt with Clang
---
llvm/include/llvm/Support/CommandLine.h | 10 ++++------
llvm/lib/Support/CommandLine.cpp | 10 ++++------
2 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h
index ab3ab9b52ac12..ca725b8ac8712 100644
--- a/llvm/include/llvm/Support/CommandLine.h
+++ b/llvm/include/llvm/Support/CommandLine.h
@@ -1518,13 +1518,11 @@ class opt
[](const typename ParserClass::parser_data_type &) {};
};
-#if !defined(LLVM_ENABLE_LLVM_EXPORT_ANNOTATIONS) || \
- !(defined(_MSC_VER) && !defined(__clang__))
-// Only instantiate opt<std::string> when not building a Windows DLL with MSVC.
-// When exporting opt<std::string>, MSVC cl implicitly exports symbols for
+#if !(defined(LLVM_ENABLE_LLVM_EXPORT_ANNOTATIONS) && defined(_MSC_VER))
+// Only instantiate opt<std::string> when not building a Windows DLL. When
+// exporting opt<std::string>, MSVC implicitly exports symbols for
// std::basic_string through transitive inheritance via std::string. These
-// symbols may appear in other TUs with different linkage, leading to duplicate
-// symbol conflicts.
+// symbols may appear in clients, leading to duplicate symbol conflicts.
extern template class LLVM_TEMPLATE_ABI opt<std::string>;
#endif
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp
index c9541289aa3bd..8491633df97e8 100644
--- a/llvm/lib/Support/CommandLine.cpp
+++ b/llvm/lib/Support/CommandLine.cpp
@@ -68,13 +68,11 @@ template class LLVM_EXPORT_TEMPLATE basic_parser<float>;
template class LLVM_EXPORT_TEMPLATE basic_parser<std::string>;
template class LLVM_EXPORT_TEMPLATE basic_parser<char>;
-#if !defined(LLVM_ENABLE_LLVM_EXPORT_ANNOTATIONS) || \
- !(defined(_MSC_VER) && !defined(__clang__))
-// Only instantiate opt<std::string> when not building a Windows DLL with MSVC.
-// When exporting opt<std::string>, MSVC cl implicitly exports symbols for
+#if !(defined(LLVM_ENABLE_LLVM_EXPORT_ANNOTATIONS) && defined(_MSC_VER))
+// Only instantiate opt<std::string> when not building a Windows DLL. When
+// exporting opt<std::string>, MSVC implicitly exports symbols for
// std::basic_string through transitive inheritance via std::string. These
-// symbols may appear in other TUs with different linkage, leading to duplicate
-// symbol conflicts.
+// symbols may appear in clients, leading to duplicate symbol conflicts.
template class LLVM_EXPORT_TEMPLATE opt<std::string>;
#endif
More information about the llvm-commits
mailing list