Skip to content

Commit eb5a734

Browse files
committed
[llvm] get cl::opt instantiations working with MSVC DLL build
1 parent 62f8377 commit eb5a734

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

llvm/include/llvm/Support/CommandLine.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,11 +1518,20 @@ class opt
15181518
[](const typename ParserClass::parser_data_type &) {};
15191519
};
15201520

1521-
extern template class opt<unsigned>;
1522-
extern template class opt<int>;
1523-
extern template class opt<std::string>;
1524-
extern template class opt<char>;
1525-
extern template class opt<bool>;
1521+
#if !defined(LLVM_ENABLE_LLVM_EXPORT_ANNOTATIONS) || \
1522+
!(defined(_MSC_VER) && !defined(__clang__))
1523+
// Only instantiate opt<std::string> when not building a Windows DLL with MSVC.
1524+
// When exporting opt<std::string>, MSVC cl implicitly exports symbols for
1525+
// std::basic_string through transitive inheritance via std::string. These
1526+
// symbols may appear in other TUs with different linkage, leading to duplicate
1527+
// symbol conflicts.
1528+
extern template class LLVM_TEMPLATE_ABI opt<std::string>;
1529+
#endif
1530+
1531+
extern template class LLVM_TEMPLATE_ABI opt<unsigned>;
1532+
extern template class LLVM_TEMPLATE_ABI opt<int>;
1533+
extern template class LLVM_TEMPLATE_ABI opt<char>;
1534+
extern template class LLVM_TEMPLATE_ABI opt<bool>;
15261535

15271536
//===----------------------------------------------------------------------===//
15281537
// Default storage class definition: external storage. This implementation

llvm/lib/Support/CommandLine.cpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,21 @@ template class LLVM_EXPORT_TEMPLATE basic_parser<float>;
6868
template class LLVM_EXPORT_TEMPLATE basic_parser<std::string>;
6969
template class LLVM_EXPORT_TEMPLATE basic_parser<char>;
7070

71-
template class opt<unsigned>;
72-
template class opt<int>;
73-
template class opt<std::string>;
74-
template class opt<char>;
75-
template class opt<bool>;
71+
#if !defined(LLVM_ENABLE_LLVM_EXPORT_ANNOTATIONS) || \
72+
!(defined(_MSC_VER) && !defined(__clang__))
73+
// Only instantiate opt<std::string> when not building a Windows DLL with MSVC.
74+
// When exporting opt<std::string>, MSVC cl implicitly exports symbols for
75+
// std::basic_string through transitive inheritance via std::string. These
76+
// symbols may appear in other TUs with different linkage, leading to duplicate
77+
// symbol conflicts.
78+
template class LLVM_EXPORT_TEMPLATE opt<std::string>;
79+
#endif
80+
81+
template class LLVM_EXPORT_TEMPLATE opt<bool>;
82+
template class LLVM_EXPORT_TEMPLATE opt<char>;
83+
template class LLVM_EXPORT_TEMPLATE opt<int>;
84+
template class LLVM_EXPORT_TEMPLATE opt<unsigned>;
85+
7686
} // namespace cl
7787
} // namespace llvm
7888

@@ -95,6 +105,15 @@ void parser<float>::anchor() {}
95105
void parser<std::string>::anchor() {}
96106
void parser<char>::anchor() {}
97107

108+
// These anchor functions instantiate opt<T> and reference its virtual
109+
// destructor to ensure MSVC exports the corresponding vtable and typeinfo when
110+
// building a Windows DLL. Without an explicit reference, MSVC may omit the
111+
// instantiation at link time even if it is marked DLL-export.
112+
void opt_bool_anchor() { opt<bool> anchor{""}; }
113+
void opt_char_anchor() { opt<char> anchor{""}; }
114+
void opt_int_anchor() { opt<int> anchor{""}; }
115+
void opt_unsigned_anchor() { opt<unsigned> anchor{""}; }
116+
98117
//===----------------------------------------------------------------------===//
99118

100119
const static size_t DefaultPad = 2;

0 commit comments

Comments
 (0)