how to recompile a C++ file at runtime? - c++

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.

Related

Override System class in Java and more precisely currentTimeMillis [duplicate]

Aside from recompiling rt.jar is there any way I can replace the currentTimeMillis() call with one of my own?
1# The right way to do it is use a Clock object and abstract time.
I know it but we'll be running code developed by an endless number of developers that have not implemented Clock or have made an implementation of their own.
2# Use a mock tool like JMockit to mock that class.
Even though that only works with Hotspot disabled -Xint and we have success using the code bellow it does not "persist" on external libraries. Meaning that you'd have to Mock it everywhere which, as the code is out of our control, is not feasible. All code under main() does return 0 milis (as from the example) but a new DateTime() will return the actual system millis.
#MockClass(realClass = System.class)
public class SystemMock extends MockUp<System> {
// returns 1970-01-01
#Mock public static long currentTimeMillis() { return 0; }
}
3# Re-declare System on start up by using -Xbootclasspath/p (edited)
While possible, and though you can create/alter methods, the one in question is declared as public static native long currentTimeMillis();. You cannot change it's declaration without digging into Sun's proprietary and native code which would make this an exercise of reverse engineering and hardly a stable approach.
All recent SUN JVM crash with the following error:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000, pid=4668, tid=5736
4# Use a custom ClassLoader (new test as suggested on the comments)
While trivial to replace the system CL using -Djava.system.class.loader JVM actually loads up the custom classLoader resorting to the default classLoader and System is not even pushed trough the custom CL.
public class SimpleClassLoader extends ClassLoader {
public SimpleClassLoader(ClassLoader classLoader) {
super(classLoader);
}
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}
}
We can see that java.lang.System is loaded from rt.jar using java -verbose:class
Line 15: [Loaded java.lang.System from C:\jdk1.7.0_25\jre\lib\rt.jar]
I'm running out of options.
Is there some approach I'm missing?
You could use an AspectJ compiler/weaver to compile/weave the problematic user code, replacing the calls to java.lang.System.currentTimeMillis() with your own code. The following aspect will just do that:
public aspect CurrentTimeInMillisMethodCallChanger {
long around():
call(public static native long java.lang.System.currentTimeMillis())
&& within(user.code.base.pckg.*) {
return 0; //provide your own implementation returning a long
}
}
I'm not 100% sure if I oversee something here, but you can create your own System class like this:
public static class System {
static PrintStream err = System.err;
static InputStream in = System.in;
static PrintStream out = System.out;
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
System.arraycopy(src, srcPos, dest, destPos, length);
}
// ... and so on with all methods (currently 26) except `currentTimeMillis()`
static long currentTimeMillis() {
return 4711L; // Your application specific clock value
}
}
than import your own System class in every java file. Reorganize imports in Eclipse should do the trick.
And than all java files should use your applicatikon specific System class.
As I said, not a nice solution because you will need to maintain your System class whenever Java changes the original one. Also you must make sure, that always your class is used.
As discussed in the comments, it is possible that option #3 in the original question has actually worked, successfully replacing the default System class.
If that is true, then application code which calls currentTimeMillis() will be calling the replacement, as expected.
Perhaps unexpectedly, core classes like java.util.Timer would also get the replacement!
If all of the above are true, then the root cause of the crash could be the successful replacement of the System class.
To test, you could instead replace System with a copy that is functionally identical to the original to see if the crashes disappear.
Unfortunately, if this answer turns out to be correct, it would seem that we have a new question. :) It might go like this:
"How do you provide an altered System.currentTimeMillis() to application classes, but leave the default implementation in place for core classes?"
i've tried using javassist to remove the native currentTimeMills, add a pure java one and load it using bootclasspath/p, but i got the same exception access violation as you did. i believe that's probably because of the native method registerNatives that's called in the static block but it's really too much to disassemble the native library.
so, instead of changing the System.currentTimeMills, how about changing the user code? if the user code already compiled (you don't have source code), we can use tools like findbugs to identify the use of currentTimeMillis and reject the code (maybe we can even replace the call to currentTimeMills with your own implementation).

Implicit use of symbol from a static library

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.

How to add code in runtime

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.

Compiling issue with SFML library in C++

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!

unable to successfully call function in dynamically loaded plugin in c++

I've successfully loaded a C++ plugin using a custom plugin loader class. Each plugin has an extern "C" create_instance function that returns a new instance using "new".
A plugin is an abstract class with a few non-virtual functions and several protected variables(std::vector refList being one of them).
The plugin_loader class successfully loads and even calls a virtual method on the loaded class (namely "std::string plugin::getName()".
The main function creates an instance of "host" which contains a vector of reference counted smart pointers, refptr, to the class "plugin". Then, main creates an instance of plugin_loader which actually does the dlopen/dlsym, and creates an instance of refptr passing create_instance() to it. Finally, it passes the created refptr back to host's addPlugin function. host::addPlugin successfully calls several functions on the passed plugin instance and finally adds it to a vector<refptr<plugin> >.
The main function then subscribes to several Apple events and calls RunApplicationEventLoop(). The event callback decodes the result and then calls a function in host, host::sendToPlugin, that identifies the plugin the event is intended for and then calls the handler in the plugin. It's at this point that things stop working.
host::sendToPlugin reads the result and determines the plugin to send the event off to.
I'm using an extremely basic plugin created as a debugging plugin that returns static values for every non-void function.
Any call on any virtual function in plugin in the vector causes a bad access exception. I've tried replacing the refptrs with regular pointers and also boost::shared_ptrs and I keep getting the same exception. I know that the plugin instance is valid as I can examine the instance in Xcode's debugger and even view the items in the plugin's refList.
I think it might be a threading problem because the plugins were created in the main thread while the callback is operating in a seperate thread. I think things are still running in the main thread judging by the backtrace when the program hits the error but I don't know Apple's implementation of RunApplicationEventLoop so I can't be sure.
Any ideas as to why this is happening?
class plugin
{
public:
virtual std::string getName();
protected:
std::vector<std::string> refList;
};
and the pluginLoader class:
template<typename T> class pluginLoader
{
public: pluginLoader(std::string path);
// initializes private mPath string with path to dylib
bool open();
// opens the dylib and looks up the createInstance function. Returns true if successful, false otherwise
T * create_instance();
// Returns a new instance of T, NULL if unsuccessful
};
class host
{
public:
addPlugin(int id, plugin * plug);
sendToPlugin(); // this is the problem method
static host * me;
private:
std::vector<plugin *> plugins; // or vector<shared_ptr<plugin> > or vector<refptr<plugin> >
};
apple event code from host.cpp;
host * host::me;
pascal OSErr HandleSpeechDoneAppleEvent(const AppleEvent *theAEevt, AppleEvent *reply, SRefCon refcon) {
// this is all boilerplate taken straight from an apple sample except for the host::me->ae_callback line
OSErr status = 0;
Result result = 0;
// get the result
if (!status) {
host::me->ae_callback(result);
}
return status;
}
void host::ae_callback(Result result) {
OSErr err;
// again, boilerplate apple code
// grab information from result
if (!err)
sendToPlugin();
}
void host::sendToPlugin() {
// calling *any* method in plugin results in failure regardless of what I do
}
EDIT: This is being run on OSX 10.5.8 and I'm using GCC 4.0 with Xcode. This is not designed to be a cross platform app.
EDIT: To be clear, the plugin works up until the Apple-supplied event loop calls my callback function. When the callback function calls back into host is when things stop working. This is the problem I'm having, everything else up to that point works.
Without seeing all of your code it isn't going to be easy to work out exactly what is going wrong. Some things to look at:
Make sure that the linker isn't throwing anything away. On gcc try the compile options -Wl -E -- we use this on Linux, but don't seem to have found a need for it on the Macs.
Make sure that you're not accidentally unloading the dynamic library before you've finished with it. RAII doesn't work for unloading dynamic libraries unless you also stop exceptions at the dynamic library border.
You may want to examine our plug in library which works on Linux, Macs and Windows. The dynamic loading code (along with a load of other library stuff) is available at http://svn.felspar.com/public/fost-base/trunk/
We don't use the dlsym mechanism -- it's kind of hard to use properly (and portably). Instead we create a library of plugins by name and put what are basically factories in there. You can examine how this works by looking at the way that .so's with test suites can be dynamically loaded. An example loader is at http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-ftest/ftest.cpp and the test suite registration is in http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-test/testsuite.cpp The threadsafe_store holds the factories by name and the suite constructor registers the factory.
I completely missed the fact that I was calling dlclose in my plugin_loader's dtor and for some reason the plugins were getting destructed between the RunApplicatoinEventLoop call and the call to sendToPlugin. I removed dlclose and things work now.