I have the following three projects:
Host
: An executable that exports a global variable (declared extern)Plugin
: A runtime library that is loaded by Host
and references the global variableTool
: An executable that links against the Plugin
and uses some functionality of it. It doesn't reference the global variable in any way.Now if I build this on windows everything is fine. The Tool
will only link to the export library of the Plugin
and will not try to resolve the global variable.
On linux I'm facing a problem. The Tool
tries to link against the Plugin
.so library (because there is no export library) and will find the reference to the global variable in Host
which it can't resolve.
How to solve this problem?
Edit:
The following is a compilable example of the problem using CMake.
CMakeLists.txt
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/bin")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/bin")
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
ADD_SUBDIRECTORY(Host)
ADD_SUBDIRECTORY(Plugin)
ADD_SUBDIRECTORY(Tool)
Host/Host.h
#ifndef HOST_H
#define HOST_H
#ifdef _MSC_VER
#ifdef COMPILE_HOST
#define HOST_EXPORT __declspec(dllexport)
#else
#define HOST_EXPORT __declspec(dllimport)
#endif
#else
#define HOST_EXPORT
#endif
class HOST_EXPORT Host
{
public:
int getAnswer();
};
extern HOST_EXPORT Host g_host;
#endif
Host/Host.cpp
#include "Host.h"
#include "../Plugin/Plugin.h"
#include <iostream>
Host g_host;
int Host::getAnswer()
{
return 42;
}
int main()
{
std::cout << g_host.getAnswer() << std::endl;
// load plugin and use it
}
Host/CMakeLists.txt
PROJECT(Host)
ADD_EXECUTABLE(Host Host.cpp Host.h)
ADD_DEFINITIONS(-DCOMPILE_HOST)
SET_TARGET_PROPERTIES(Host PROPERTIES ENABLE_EXPORTS ON)
Plugin/Plugin.h
#ifndef PLUGIN_H
#define PLUGIN_H
class Plugin
{
public:
Plugin();
};
#endif
Plugin/Plugin.cpp
#include "Plugin.h"
#include "../Host/Host.h"
#include <iostream>
Plugin::Plugin()
{
std::cout << g_host.getAnswer() << std::endl;
}
Plugin/PluginFunc.h
#ifndef PLUGINFUNC_H
#define PLUGINFUNC_H
#ifdef _MSC_VER
#define PLUGIN_EXPORT __declspec(dllexport)
#else
#define PLUGIN_EXPORT
#endif
namespace plug
{
int PLUGIN_EXPORT getRandomNumber();
}
#endif
Plugin/PluginFunc.cpp
#include "PluginFunc.h"
int plug::getRandomNumber()
{
return 4;
}
Plugin/CMakeLists.txt
PROJECT(Plugin)
ADD_LIBRARY(Plugin SHARED Plugin.cpp Plugin.h PluginFunc.cpp PluginFunc.h)
TARGET_LINK_LIBRARIES(Plugin Host)
Tool/Tool.cpp
#include "../Plugin/PluginFunc.h"
#include <iostream>
int main()
{
std::cout << plug::getRandomNumber() << std::endl;
}
Tool/CMakeLists.txt
PROJECT(Tool)
ADD_EXECUTABLE(Tool Tool.cpp)
TARGET_LINK_LIBRARIES(Tool Plugin)
On Windows it builds and runs. Host.exe displays "42" and Tool.exe displays "4".
On Linux I get the following linking error:
usr@debian64:~/vbox/testlink/build$ make
Scanning dependencies of target Host
[ 25%] Building CXX object Host/CMakeFiles/Host.dir/Host.o
Linking CXX executable Host
[ 25%] Built target Host
Scanning dependencies of target Plugin
[ 50%] Building CXX object Plugin/CMakeFiles/Plugin.dir/Plugin.o
[ 75%] Building CXX object Plugin/CMakeFiles/Plugin.dir/PluginFunc.o
Linking CXX shared library libPlugin.so
[ 75%] Built target Plugin
Scanning dependencies of target Tool
[100%] Building CXX object Tool/CMakeFiles/Tool.dir/Tool.o
Linking CXX executable Tool
../Plugin/libPlugin.so: undefined reference to `Host::getAnswer()'
../Plugin/libPlugin.so: undefined reference to `g_host'
collect2: error: ld returned 1 exit status
make[2]: *** [Tool/Tool] Error 1
make[1]: *** [Tool/CMakeFiles/Tool.dir/all] Error 2
make: *** [all] Error 2
Two other approaches are:
gcc -Wl,--defsym=GlobalSymbol=0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With