I come to submit a problem I have while trying to import symbols from static library implicitly.
Let me set up the problem with a peace of simplified code:
I have 3 projects:
- a static plugin handler project that defines a registry class, it is linked in the other two projects
- a static plugin project
- a final project that has a plugin handler and "load statically" the plugin.
first, the static plugin handler project:
struct PluginType
{
virtual void doMyStuff() = 0 ;
};
typedef PluginType* (*PluginCreator)();
struct Registry
{
std::map<std::string, PluginCreator> _item_list;
static Registry& instance()
{
static Registry singleton;
return singleton;
}
static PluginType* create(std::string const& name)
{
// call the creator function that returns an PluginType*
return instance()[name]();
}
};
struct RecordInRegistry
{
RecordInRegistry(std::string const& key, PluginCreator new_item_creator)
{
Registry::instance()._item_list[key] = new_item_creator;
}
};
Now, a static plugin project
struct ADerivedItem : public PluginType
{
virtual void doMyStuff() override
{
//some really interesting stuffs
}
static PluginType* create() { return new ADerivedItem() ; }
}
export "C" const RecordInRegistry i_record_derived_item_class("derived_item", &ADerivedItem::create);
Then, the final project where i use the plugin. This project links the two other porjects !
int main()
{
PluginType* my_instance = Registry::create("derived_item");
return 0;
}
What I hope is that I will be able to register my static plugin just by linking the static library plugin
to the project.
It almost worked ! The only problem I got is that the symbol "i_record_derived_item_class" from the static
plugin is not explicitly used in the final project, thus this symbol is not imported from the static plugin lib !
I work on visual studio, i found a simple fix that consists in forcing the symbol import, something like
/INCLUDE:i_record_derived_item_class, and everything works fine.
I want to know if you see a work around to this, what I would like is to be able to add this kind of static
plung just by linking it, without having to add anything more than /LINK:myStaticPlugin.lib
Any idea ?
Moreover it would be really nice to avoid MSVC-specific solution.
Thanks in advance !
The problem is that symbols in library are used only when required. Draft n4659 says at 5.2 Phases of translation [lex.phases]:
All external entity references are resolved. Library components are linked to satisfy external references
to entities not defined in the current translation.
As your current source has no external references to i_record_derived_item_class, nor to the class ADerivedItem, nothing will be loaded by default from the plugin project. Worse, even the plugin handler module has no reference either, so you need to declare an undefined reference to the build system itself, be it MSVC or anything else.
Alternatively, you could link a minimal translation unit (means a .cpp or .o file) containing an external reference to i_record_derived_item_class, to force the resolution from a library.
Related
Update: I ended up getting this work by using DLLs and loading and unloading them. https://www.youtube.com/watch?v=mFSv0tf6Vwc
I know its possible because I've seen posts about this but i don't really understand them.
So i have class(DetailsLayout) that calls a method in another class(Components). At runtime i change the contents of Components to add another component that the user created to that method. I want to recompile the DetailsLayout.cpp and the Components.h but i'm confused as to how to go about this.
right now i'm trying this because of this post : Using G++ to compile multiple .cpp and .h files
system(("g++ -c ProjectComponents.hpp").c_str());
system(("g++ -c DetailsLayout.cpp").c_str());
DetailsLayout::CreateMenu();
I get an error that says g++ is not recognized as an internal or external command.
as per Jesper's suggestion ill mention what id like my end goal to be. So right now in my Game Engine i allow users to add components (that i made) to objects in the scene dynamically. When i tried to make it so that the "user" can make a component and add it dynamically i couldn't do it unless i compiled the .h and .cpp file i made for them. If i manually include the file into my project and run the method for adding the class it works but i want that to happen when i click a button for compiling.
My Components all inherit from this class.
class Component
{
public:
Component();
~Component();
virtual bool Initialize() { return true; }
virtual bool Update(float dt) { dt; return true; }
virtual bool Draw() { return true; }
template <class T> T* GetSiblingComponent()
{
return m_owner->GetComponentByType<T>();
}
protected:
Entity* m_owner;
char m_name[Imgn::MAX_NAME_LEN];
bool m_enabled;
};
I get an error that says g++ is not recognized as an internal or external command.
Well, it's not guaranteed that GCC is installed at your target machine. You have to ensure that in first place if you want to compile and run your code at arbitrary host machines.
Also you seem to miss the linking stage, and calling the resulting executable as well.
I was searching through stackoverflow questions but none of them answered my question. I have a game engine and I want to load player AI (written in c++) in runtime.
Click on button, file dialog appears
Choose file with AI (.dll or something?)
Click on 'start' button, game starts using AI's that I add.
AI could be a method or whole class, it doesn't matter. I think I should generate .dll but I not sure how to do that. This class should look like this:
class PlayerAI
{
void computeSomething(list of argument, Object& output)
{
// some logic
}
}
Assuming pure Windows platform since none specified -
If you want to inject DLL, first obtain a handle to it using LoadLibrary-function like so:
HINSTANCE handleLib;
handleLib = LoadLibrary(TEXT("YourDLL.dll"));
You may then obtain a function pointer to a specific function in the lib. Like this:
FUNC_PTR func;
func = (FUNC_PTR) GetProcAddress(handleLib, "yourFunc");
Then you can call the function like so:
(func) (L"TESTSTRING HERE");
When done, call FreeLibrary(libhandle)
How to declare a function as exported is in VS for instance like this (this is needed to mark your function in your DLL that you precompile:
__declspec(dllexport) int __cdecl yourFunc(LPWSTR someString)
{
//Code here...
}
Since you mention already compiled DLLs, you want to look at LoadLibrary and GetProcAddress. That's how you do runtime loads of DLLs and extract specific functions from them.
Examples can be found under Using Run-Time Dynamic Linking.
I have been going through links on StackOverflow on how to resolve the Method name mangling but did not find any solution with a real time example.
Scenario-A C++ Ex.dll file is provided by client. I need to access the Ex.dll and call the methods in the same through Java.
Restrictions- Cannot modify the Ex.dll, i can only access the same.
Issue Faced- Getting the below exception when i access the Ex.dll through JNA
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'getCPUSpeed': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:134)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:336)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:316)
at com.sun.jna.Library$Handler.invoke(Library.java:203)
at $Proxy0.getCPUSpeed(Unknown Source)
at cpp.java.JnaTest.main(JnaTest.java:16)
Googled a lot and found that its due to method name Mangling, but again could not find any good sample code with the solution.
This is code i used-
import com.sun.jna.Native;
class JnaTest
{
public static void main(String args[])
{
try
{
JnaInterface jInterface = (JnaInterface) Native.loadLibrary("Ex", JnaInterface.class);
System.out.println("Calling C++ DLL method");
System.out.println("========================");
System.out.println("getCPUSpeed() -- "+jInterface.getCPUSpeed());
} catch (Exception e) {
e.printStackTrace();
}
}
}
package cpp.java;
import com.sun.jna.Library;
public interface JnaInterface extends Library{
public int getCPUSpeed();
}
Update 1: **************************************
Below mentioned is the actual functions i get when i browse the DBMM.dll through dependency walker-
DBMM DLL functions-
??0cDbmmInterfaceCache##QAE#ABV0##Z
??0cDbmmInterfaceCache##QAE#XZ
??0cDbmmInterfaceControl##QAE#ABV0##Z
??0cDbmmInterfaceControl##QAE#XZ
??0cDbmmInterfaceEcon##QAE#ABV0##Z
??0cDbmmInterfaceEcon##QAE#XZ
??0cDbmmInterfaceKnob##QAE#XZ
??0cDbmmInterfaceOutput##QAE#ABV0##Z
??0cDbmmInterfaceOutput##QAE#H#Z
??0cDbmmInterfacePoolLoan##QAE#ABV0##Z
??0cDbmmInterfacePoolLoan##QAE#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z
??0cDbmmMacroEcon##QAE#ABV0##Z
??0cDbmmMacroEcon##QAE#ABVcDbmmInterfaceEcon##_N#Z
??0cDbmmMtgBasisConstSpreadModel##IAE#XZ
??0cDbmmMtgBasisConstSpreadModel##QAE#ABV0##Z
??0cDbmmMtgBasisConstSpreadModel##QAE#PBD#Z
??0cDbmmMtgBasisModel##QAE#ABV0##Z
??0cDbmmMtgBasisModel##QAE#XZ
??0cScaleFieldsSubSum##QAE#NN#Z
??1cDbmmInterfaceCache##QAE#XZ
??1cDbmmInterfaceControl##QAE#XZ
??1cDbmmInterfaceEcon##QAE#XZ
??1cDbmmInterfaceKnob##QAE#XZ
??1cDbmmInterfaceOutput##QAE#XZ
??1cDbmmInterfacePoolLoan##QAE#XZ
??1cDbmmMacroEcon##QAE#XZ
??1cDbmmMtgBasisConstSpreadModel##UAE#XZ
??1cDbmmMtgBasisModel##UAE#XZ
??1cScaleFieldsSubSum##QAE#XZ
??4cDbmmInterface##QAEAAV0#ABV0##Z
??4cDbmmInterfaceCache##QAEAAV0#ABV0##Z
??4cDbmmInterfaceControl##QAEAAV0#ABV0##Z
??4cDbmmInterfaceEcon##QAEAAV0#ABV0##Z
??4cDbmmInterfaceKnob##QAEAAV0#ABV0##Z
??4cDbmmInterfaceOutput##QAEAAV0#ABV0##Z
??4cDbmmInterfacePoolLoan##QAEAAV0#ABV0##Z
??4cDbmmMacroEcon##QAEAAV0#ABV0##Z
??4cDbmmMtgBasisConstSpreadModel##QAEAAV0#ABV0##Z
??4cDbmmMtgBasisModel##QAEAAV0#ABV0##Z
??4cScaleFieldsSubSum##QAEAAV0#ABV0##Z
??_7cDbmmMtgBasisConstSpreadModel##6B#
??_7cDbmmMtgBasisModel##6B#
??_FcDbmmInterfaceOutput##QAEXXZ
??_FcDbmmInterfacePoolLoan##QAEXXZ
??_FcScaleFieldsSubSum##QAEXXZ
?Add#cScaleFieldsSubSum##QAEXNN#Z
?InitSubsum#cScaleFieldsSubSum##QAEXNN#Z
?ReInit#cDbmmMacroEcon##QAEX_N#Z
Not sure how can i call these functions through Java.
Appreciate if somebody could provide me a solution from Java end, with a sample code please :)
Your function is decorated with JNI and stdcall conventions; it is not C++-mangled.
It looks like the library is a JNI library, given the Java_sysInfo_ prefix. If that is the case, you need only declare the equivalent Java-side, e.g.
// default package
public class sysInfo {
static { System.loadLibrary("Ex"); }
public static native int getCPUSpeed();
}
I think you'll probably find that this mapping is the correct one and that you don't need JNA.
EDIT
Given a C++ class with an arbitrary ctor input argument and method getCount():
extern "C" int getCountForName(const char* name) {
MyCPPClass mycpp(name);
return mycpp.getCount();
}
Compile that into a shared library, and load via JNA.
If your building the DLL through Visual studio, you should be able to build it as a release instead of debug to fix the function names if you are not already doing this.
I am making some project using SFML. I have downloaded library from their official site, using cmake I made VS10 project, compiled it and got all the libs and files I need. However, in my project I keep getting nonsense errors like
class "sf::SoundBuffer" has no member "LoadFromFile"
class "sf::Sound" has no member "SetBuffer"
even though I have checked in SoundBuffer header there is a function named LoadFromFile and in Sound there is a function called SetBuffer.
SoundM::SoundM(void)
{
buffer.LoadFromFile("ress/soundA.wav");
collision.SetBuffer(buffer);
}
#ifndef SOUND_H
#define SOUND_H
enum Sounds {
PaddleCollision,
Losing
};
class SoundM {
public:
SoundM(void);
void play(Sounds Sound);
private:
sf::SoundBuffer buffer;
sf::Sound collision;
};
#endif
What am I missing here?
I assume that you are using the SFML version 2.0 RC. There was a name convention change and now, all function names start with a lowercase letter (camel case).
So you should try that.
buffer.loadFromFile("ress/soundA.wav");
collision.setBuffer(buffer);
Instead of that.
buffer.LoadFromFile("ress/soundA.wav");
collision.SetBuffer(buffer);
I hope that helps you!
I have created a simple RAII class in one of my DLLs (let's call it the exporting DLL) which monitors for configuration restore in my application:
Header file
class __declspec(dllexport) CEmuConfigurationRestoreMonitor
{
public:
CEmuConfigurationRestoreMonitor()
{
m_restoreInProgress = true;
}
~CEmuConfigurationRestoreMonitor()
{
m_restoreInProgress = false;
}
static bool IsRestoreInProgress()
{
return m_restoreInProgress;
}
private:
static bool m_restoreInProgress;
};
Source file
bool CEmuConfigurationRestoreMonitor::m_restoreInProgress = false;
The idea is that the restore code in the exporting DLL will instantiate a CEmuConfigurationRestoreMonitor on the stack and when it goes out of scope at the end of the method, the flag will be switched off.
The problem is that I want to query the flag, using IsRestoreInProgress(), from another DLL (let's say the importing DLL). This is why I put __declspec(dllexport) in the class declaration in the exporting DLL.
When I link the importing DLL, I got an unresolved symbol for m_restoreInProgress. So I added the following line to a .cpp file in the importing DLL and it fixes that issue:
bool CEmuConfigurationRestoreMonitor::m_restoreInProgress = false;
What I am finding now is that even if m_restoreInProgress is set to true, when I query it from the importing DLL, it's always returning false.
Is the static initialization in the importing DLL somehow overriding the real (current) value in the exporting DLL?
You've given each DLL its own copy of m_restoreInProgress.
You could fix this by:
Not using an inline function.
Using a file-scoped variable for m_resotreInProgress, in a source file included in only the exporting DLL.