c++ - 如何从共享库可移植地导出模板实例
问题描述
我有这个标题:
#pragma once
#if _MSC_VER
# ifdef mylib_EXPORTS
# define MYLIB_EXPORT __declspec(dllexport)
# else
# define MYLIB_EXPORT __declspec(dllimport)
# endif
#else
# ifdef mylib_EXPORTS
# define MYLIB_EXPORT __attribute__((visibility("default")))
# else
# define MYLIB_EXPORT
# endif
#endif
template<typename T>
class Templ
{
public:
T getNum() const;
T getAnotherNum() const;
};
#ifndef mylib_EXPORTS
extern template class MYLIB_EXPORT Templ<int>;
#endif
有了这个实现:
#include "mylib.h"
template<typename T>
T Templ<T>::getNum() const
{
return 7;
}
template<typename T>
T Templ<T>::getAnotherNum() const
{
return 5;
}
#if 0
template<>
int Templ<int>::getNum() const
{
return 42;
}
#endif
template class MYLIB_EXPORT Templ<int>;
这个消费者:
#include "mylib.h"
#include <iostream>
int main()
{
Templ<int> ti;
std::cout << ti.getNum() << " -- " << ti.getAnotherNum() << std::endl;
return 0;
}
和以下 CMakeLists.txt:
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(cpptest)
if (NOT WIN32)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined")
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined")
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
endif()
add_compile_options(-Werror)
add_library(mylib SHARED mylib.cpp)
add_executable(myexe main.cpp)
target_link_libraries(myexe PRIVATE mylib)
如果我使用 MSVC 或 GCC 构建和运行,我会得到预期的输出:
7 -- 5
但是,如果我在 mylib.cpp 中启用模板专业化,那么我会使用 GCC 构建失败:
$ cmake --build .
[1/3] Building CXX object CMakeFiles/mylib.dir/mylib.cpp.o
FAILED: CMakeFiles/mylib.dir/mylib.cpp.o
/usr/lib/ccache/c++ -Dmylib_EXPORTS -fPIC -fvisibility=hidden -fvisibility-inlines-hidden
-Werror -MD -MT CMakeFiles/mylib.dir/mylib.cpp.o -MF CMakeFiles/mylib.dir/mylib.cpp.o.d -o
CMakeFiles/mylib.dir/mylib.cpp.o -c ../mylib.cpp
../mylib.cpp:24:29: error: type attributes ignored after type is already defined [-Werror=attributes]
template class MYLIB_EXPORT Templ<int>;
^~~~~~~~~~
cc1plus: all warnings being treated as errors
ninja: build stopped: subcommand failed.
并使用 MSVC:
LINK Pass 1: command "C:\PROGRA~2\MICROS~3.0\VC\bin\amd64\link.exe /nologo CMakeFiles\myexe.dir
\main.cpp.obj /out:myexe.exe /implib:myexe.lib /pdb:myexe.pdb /version:0.0 /machine:x64 /debug
/INCREMENTAL /subsystem:console mylib.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib
ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST
/MANIFESTFILE:CMakeFiles\myexe.dir/intermediate.manifest CMakeFiles\myexe.dir/manifest.res" failed
(exit code 1120) with the following output:
main.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: int __cdecl
Templ<int>::getNum(void)const " (__imp_?getNum@?$Templ@H@@QEBAHXZ) referenced in function main
myexe.exe : fatal error LNK1120: 1 unresolved externals
ninja: build stopped: subcommand failed.
和铿锵声:
: && /usr/lib/ccache/clang++ CMakeFiles/myexe.dir/main.cpp.o -o myexe -Wl,-rpath,/home/stephen
/dev/src/playground/cpp/build libmylib.so && :
CMakeFiles/myexe.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x14): undefined reference to `Templ<int>::getNum() const'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
从共享库中 dllexport 模板实例化(可能包括模板部分的模板特化)的正确且可移植的方法是什么?
解决方案
你只需要MYLIB_EXPORT
在这一行前面:
int Templ<int>::getNum() const
推荐阅读
- python - 如何在 Python-Django 框架中解决未定义的变量模型错误
- css - 如何在小型设备上呈现 Bootstrap 4 表?
- flutter - Flutter auth ui facebook sdk问题
- python - scipy插值的问题
- android - 为 Google Play 多人游戏创建不同的房间
- google-cloud-platform - 子文件夹的 GCS 对象更改通知
- python - 是否有可能获得 Spacy 命名实体识别的置信度分数
- angular - 我应该使用 null 作为数字的值吗 - Angular
- node.js - 如何在nodejs中promise类型的函数中完成.map函数后返回对象
- php - 调用Factory时Laravel记录被删除