mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-22 10:05:37 -04:00
297 lines
11 KiB
C++
297 lines
11 KiB
C++
/*
|
|
* GDevelop Core
|
|
* Copyright 2008-2014 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
|
|
* This project is released under the MIT License.
|
|
*/
|
|
|
|
#include <boost/version.hpp>
|
|
#include "GDCore/PlatformDefinition/PlatformExtension.h"
|
|
#include "GDCore/PlatformDefinition/Platform.h"
|
|
#include "GDCore/IDE/ExtensionsLoader.h"
|
|
#include "GDCore/Tools/Version.h"
|
|
#include "GDCore/Tools/DynamicLibrariesTools.h"
|
|
#include "GDCore/CommonTools.h"
|
|
#include "GDCore/Tools/Log.h"
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
#include <wx/msgdlg.h>
|
|
#include <wx/filename.h>
|
|
#include "GDCore/Tools/Locale/LocaleManager.h"
|
|
#endif
|
|
|
|
//Compiler specific include, for listing files of directory ( see below )
|
|
#if defined(__GNUC__)
|
|
#include <dirent.h>
|
|
#elif defined(_MSC_VER)
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
typedef gd::PlatformExtension* (*createExtension)();
|
|
|
|
using namespace std;
|
|
|
|
namespace gd
|
|
{
|
|
|
|
void ExtensionsLoader::LoadAllExtensions(const std::string & directory, gd::Platform & platform, bool forgiving)
|
|
{
|
|
std::cout << "Loading extensions for " << platform.GetName() << "... ";
|
|
string suffix = "";
|
|
|
|
#if defined(WINDOWS)
|
|
suffix += "w";
|
|
#elif defined(LINUX)
|
|
suffix += "l";
|
|
#elif defined(MAC)
|
|
suffix += "m";
|
|
#else
|
|
#warning No target system defined.
|
|
#endif
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
suffix += "e";
|
|
#endif
|
|
|
|
#if defined(__GNUC__) //For compilers with posix support
|
|
struct dirent *lecture;
|
|
DIR *rep;
|
|
rep = opendir( directory.c_str() );
|
|
int l = 0;
|
|
|
|
if ( rep == NULL )
|
|
{
|
|
cout << "Unable to open Extensions ("<< directory <<") directory." << endl;
|
|
return;
|
|
}
|
|
|
|
std::vector<std::string> librariesLoaded;
|
|
while ( (lecture = readdir( rep )) )
|
|
{
|
|
string lec = lecture->d_name;
|
|
if ( lec != "." && lec != ".." && lec.find(".xgd"+suffix, lec.length()-4-suffix.length()) != string::npos)
|
|
{
|
|
//Use a log file, in IDE only
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
{
|
|
wxFile errorDetectFile(wxFileName::GetTempDir()+"/ExtensionBeingLoaded.log", wxFile::write);
|
|
errorDetectFile.Write(directory+"/"+lec);
|
|
}
|
|
#endif
|
|
|
|
LoadExtension(directory+"/"+lec, platform, forgiving);
|
|
|
|
//Everything is ok : Delete the log file
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
wxRemoveFile(wxFileName::GetTempDir()+"/ExtensionBeingLoaded.log");
|
|
#endif
|
|
|
|
librariesLoaded.push_back(directory+"/"+lec);
|
|
|
|
l++;
|
|
}
|
|
}
|
|
|
|
closedir( rep );
|
|
|
|
#elif defined(_MSC_VER)
|
|
WIN32_FIND_DATA f;
|
|
string dirPart = "/*.xgd";
|
|
string dirComplete = directory + dirPart + suffix;
|
|
HANDLE h = FindFirstFile(dirComplete.c_str(), &f);
|
|
if(h != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
//Use a log file, in IDE only
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
{
|
|
wxFile errorDetectFile(wxFileName::GetTempDir()+"/ExtensionBeingLoaded.log", wxFile::write);
|
|
errorDetectFile.Write(f.cFileName);
|
|
}
|
|
#endif
|
|
|
|
LoadExtension(f.cFileName, platform, forgiving);
|
|
|
|
//Everything is ok : Delete the log file
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
wxRemoveFile(wxFileName::GetTempDir()+"/ExtensionBeingLoaded.log");
|
|
#endif
|
|
|
|
} while(FindNextFile(h, &f));
|
|
}
|
|
#else
|
|
#warning Compiler not supported (but might support one style of directory listing, update defines if necessary) for dynamic libraries loading
|
|
#endif
|
|
std::cout << " done. " << std::endl;
|
|
}
|
|
|
|
void ExtensionsLoader::ExtensionsLoadingDone(const std::string & directory)
|
|
{
|
|
string suffix = "";
|
|
|
|
#if defined(WINDOWS)
|
|
suffix += "w";
|
|
#elif defined(LINUX)
|
|
suffix += "l";
|
|
#elif defined(MAC)
|
|
suffix += "m";
|
|
#else
|
|
#warning No target system defined.
|
|
#endif
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
suffix += "e";
|
|
#endif
|
|
|
|
#if defined(LINUX) || defined (MAC)
|
|
|
|
//List all extensions loaded
|
|
struct dirent *lecture;
|
|
DIR *rep;
|
|
rep = opendir( directory.c_str() );
|
|
int l = 0;
|
|
|
|
if ( rep == NULL )
|
|
{
|
|
cout << "Unable to open Extensions ("<< directory <<") directory." << endl;
|
|
return;
|
|
}
|
|
|
|
std::vector<std::string> librariesLoaded;
|
|
while ( (lecture = readdir( rep )) )
|
|
{
|
|
string lec = lecture->d_name;
|
|
if ( lec != "." && lec != ".." && lec.find(".xgd"+suffix, lec.length()-4-suffix.length()) != string::npos)
|
|
{
|
|
librariesLoaded.push_back(directory+"/"+lec);
|
|
l++;
|
|
}
|
|
}
|
|
|
|
closedir( rep );
|
|
|
|
//Libraries are loaded using dlopen(.., RTLD_LAZY|RTLD_LOCAL) meaning that their symbols are not available for other libraries
|
|
//nor for LLVM/Clang. We then reload set them as global to make their symbols available for LLVM/Clang. We couldn't mark them
|
|
//as global when loading them as every extension use the same "CreateGDExtension" symbol.
|
|
//SetLibraryGlobal is also setting RTLD_NOW to ensure that all symbols are resolved: Otherwise, we can get weird
|
|
//"symbol lookup error" even if the symbols exist in the extensions!
|
|
for (unsigned int i = 0;i<librariesLoaded.size();++i)
|
|
SetLibraryGlobal(librariesLoaded[i].c_str());
|
|
#else
|
|
//Nothing to do on Windows.
|
|
#endif
|
|
}
|
|
|
|
void ExtensionsLoader::LoadExtension(const std::string & fullpath, gd::Platform & platform, bool forgiving)
|
|
{
|
|
if ( platform.GetExtensionCreateFunctionName().empty() )
|
|
{
|
|
cout << "Unable to load extension " << fullpath << ":" << endl;
|
|
cout << "The plaftorm does not support extensions creation." << endl;
|
|
return;
|
|
}
|
|
|
|
Handle extensionHdl = OpenLibrary(fullpath.c_str());
|
|
if (extensionHdl == NULL)
|
|
{
|
|
std::string error = DynamicLibraryLastError();
|
|
|
|
cout << "Unable to load extension " << fullpath << "." << endl;
|
|
cout << "Error returned : \"" << error << "\"" << endl;
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
wxString userMsg = string(_("Extension "))+ fullpath + string(_(" could not be loaded.\nContact the developer for more informations.\n\nDetailed log:\n") + error);
|
|
wxMessageBox(userMsg, _("Extension not compatible"), wxOK | wxICON_EXCLAMATION);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
createExtension create_extension = (createExtension)GetSymbol(extensionHdl, platform.GetExtensionCreateFunctionName().c_str());
|
|
|
|
if (create_extension == NULL)
|
|
{
|
|
if (!forgiving)
|
|
{
|
|
cout << "Unable to load extension " << fullpath << " (Creation function symbol not found)." << endl;
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
wxString userMsg = string(_("Extension "))+ fullpath + string(_(" could not be loaded.\nContact the developer for more informations." ));
|
|
wxMessageBox(userMsg, _("Extension not compatible"), wxOK | wxICON_EXCLAMATION);
|
|
#endif
|
|
}
|
|
|
|
CloseLibrary(extensionHdl);
|
|
return;
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
gd::LocaleManager::Get()->AddCatalog(ToString(wxFileName(fullpath).GetName())); //In editor, load catalog associated with extension, if any.
|
|
#endif
|
|
|
|
gd::PlatformExtension * extensionPtr = create_extension();
|
|
string error;
|
|
|
|
//Perform safety check about the compilation
|
|
if ( !extensionPtr->compilationInfo.informationCompleted )
|
|
error += "Compilation information not filled.\n";
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
else if ( extensionPtr->compilationInfo.runtimeOnly )
|
|
error += "Extension compiled for runtime only.\n";
|
|
|
|
#if !defined(GD_NO_WX_GUI)
|
|
else if ( extensionPtr->compilationInfo.wxWidgetsMajorVersion != wxMAJOR_VERSION ||
|
|
extensionPtr->compilationInfo.wxWidgetsMinorVersion != wxMINOR_VERSION ||
|
|
extensionPtr->compilationInfo.wxWidgetsReleaseNumber != wxRELEASE_NUMBER ||
|
|
extensionPtr->compilationInfo.wxWidgetsSubReleaseNumber != wxSUBRELEASE_NUMBER )
|
|
error += "Not the same wxWidgets version.\n";
|
|
#endif
|
|
#endif
|
|
#if defined(__GNUC__)
|
|
else if ( extensionPtr->compilationInfo.gccMajorVersion != __GNUC__ ||
|
|
extensionPtr->compilationInfo.gccMinorVersion != __GNUC_MINOR__ )
|
|
error += "Not the same GNU Compiler version.\n";
|
|
|
|
#endif
|
|
else if ( extensionPtr->compilationInfo.sfmlMajorVersion != 2 ||
|
|
extensionPtr->compilationInfo.sfmlMinorVersion != 0 )
|
|
error += "Not the same SFML version.\n";
|
|
|
|
else if ( extensionPtr->compilationInfo.boostVersion != BOOST_VERSION )
|
|
error += "Not the same Boost version.\n(Extension is using "+ToString(extensionPtr->compilationInfo.boostVersion)+", GDevelop is using "+ToString(BOOST_VERSION)+")\n";
|
|
|
|
else if ( extensionPtr->compilationInfo.gdCoreVersion != GDCore_RC_FILEVERSION_STRING)
|
|
error += "Not the same GDevelop Core version.\n(Extension is using "+extensionPtr->compilationInfo.gdCoreVersion+", GDevelop is using "+GDCore_RC_FILEVERSION_STRING+")\n";
|
|
|
|
else if ( extensionPtr->compilationInfo.sizeOfpInt != sizeof(int*))
|
|
error += "Not the same architecture.\n(Extension sizeof(int*) is "+ToString(extensionPtr->compilationInfo.sizeOfpInt)+", GDevelop sizeof(int*) is "+ToString(sizeof(int*))+")\n";
|
|
|
|
if ( !error.empty() )
|
|
{
|
|
char beep = 7;
|
|
cout << "-- WARNING ! --" << beep << endl;
|
|
cout << "Bad extension " + fullpath + " loaded :\n" + error;
|
|
cout << "---------------" << endl;
|
|
|
|
#if defined(RELEASE)//Load extension despite errors in non release build
|
|
|
|
//Destroy the extension class THEN unload the library from memory
|
|
delete extensionPtr;
|
|
CloseLibrary(extensionHdl);
|
|
#endif
|
|
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI) && defined(RELEASE) //Show errors in IDE only
|
|
wxString userMsg = string(_("Extension "))+ fullpath + string(_(" has errors :\n")) + error + string(_("\nThe extension was not loaded. Contact the developer to get more information." ));
|
|
wxMessageBox(userMsg, _("Extension not compatible"), wxOK | wxICON_EXCLAMATION);
|
|
#endif
|
|
|
|
#if defined(RELEASE)//Load extension despite errors in non release build
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
boost::shared_ptr<gd::PlatformExtension> extension(extensionPtr);
|
|
platform.AddExtension(extension);
|
|
return;
|
|
}
|
|
|
|
}
|