Commit 99dbc6c1 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Make plugins cache relocatable

The plugins cache now contains plugins file path relative to the base
plugins directory (the directory that contains plugins.dat). The cache
can hence be generated from a different absolute directory than the one
it is later installed to.

For native or emulated native builds, this enables build-time cache
generation.

Note however that the relative paths are different in the build tree
(modules/*/.libs/lib*_plugin.*) and in standard installation
(plugins/*/lib*_plugin.*). The cache cannot be copied from the build
tree to the installation directory.
parent 9ef30ee8
...@@ -60,16 +60,7 @@ static struct ...@@ -60,16 +60,7 @@ static struct
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
#ifdef HAVE_DYNAMIC_PLUGINS #ifdef HAVE_DYNAMIC_PLUGINS
typedef enum { CACHE_USE, CACHE_RESET, CACHE_IGNORE } cache_mode_t;
typedef struct module_bank module_bank_t;
static void AllocateAllPlugins (vlc_object_t *); static void AllocateAllPlugins (vlc_object_t *);
static void AllocatePluginPath (vlc_object_t *, const char *, cache_mode_t);
static void AllocatePluginDir( vlc_object_t *, module_bank_t *, const char *,
unsigned, cache_mode_t );
static int AllocatePluginFile( vlc_object_t *, module_bank_t *, const char *,
const struct stat *, cache_mode_t );
static module_t *module_InitDynamic (vlc_object_t *, const char *, bool);
#endif #endif
static module_t *module_InitStatic (vlc_plugin_cb); static module_t *module_InitStatic (vlc_plugin_cb);
...@@ -229,10 +220,18 @@ module_t **module_list_get (size_t *n) ...@@ -229,10 +220,18 @@ module_t **module_list_get (size_t *n)
char *psz_vlcpath = NULL; char *psz_vlcpath = NULL;
#ifdef HAVE_DYNAMIC_PLUGINS #ifdef HAVE_DYNAMIC_PLUGINS
typedef enum { CACHE_USE, CACHE_RESET, CACHE_IGNORE } cache_mode_t;
/***************************************************************************** static void AllocatePluginPath (vlc_object_t *, const char *, cache_mode_t);
* AllocateAllPlugins: load all plugin modules we can find.
*****************************************************************************/ /**
* Enumerates all dynamic plug-ins that can be found.
*
* This function will recursively browse the default plug-ins directory and any
* directory listed in the VLC_PLUGIN_PATH environment variable.
* For performance reasons, a cache is normally used so that plug-in shared
* objects do not need to loaded and linked into the process.
*/
static void AllocateAllPlugins (vlc_object_t *p_this) static void AllocateAllPlugins (vlc_object_t *p_this)
{ {
const char *vlcpath = psz_vlcpath; const char *vlcpath = psz_vlcpath;
...@@ -273,16 +272,26 @@ static void AllocateAllPlugins (vlc_object_t *p_this) ...@@ -273,16 +272,26 @@ static void AllocateAllPlugins (vlc_object_t *p_this)
free( paths ); free( paths );
} }
struct module_bank typedef struct module_bank
{ {
/* Plugins cache */ vlc_object_t *obj;
const char *base;
cache_mode_t mode;
size_t i_cache; size_t i_cache;
module_cache_t *cache; module_cache_t *cache;
int i_loaded_cache; int i_loaded_cache;
module_cache_t *loaded_cache; module_cache_t *loaded_cache;
}; } module_bank_t;
static void AllocatePluginDir (module_bank_t *, unsigned,
const char *, const char *);
/**
* Scans for plug-ins within a file system hierarchy.
* \param path base directory to browse
*/
static void AllocatePluginPath (vlc_object_t *p_this, const char *path, static void AllocatePluginPath (vlc_object_t *p_this, const char *path,
cache_mode_t mode) cache_mode_t mode)
{ {
...@@ -304,13 +313,16 @@ static void AllocatePluginPath (vlc_object_t *p_this, const char *path, ...@@ -304,13 +313,16 @@ static void AllocatePluginPath (vlc_object_t *p_this, const char *path,
msg_Dbg( p_this, "recursively browsing `%s'", path ); msg_Dbg( p_this, "recursively browsing `%s'", path );
bank.obj = p_this;
bank.base = path;
bank.mode = mode;
bank.cache = NULL; bank.cache = NULL;
bank.i_cache = 0; bank.i_cache = 0;
bank.loaded_cache = cache; bank.loaded_cache = cache;
bank.i_loaded_cache = count; bank.i_loaded_cache = count;
/* Don't go deeper than 5 subdirectories */ /* Don't go deeper than 5 subdirectories */
AllocatePluginDir (p_this, &bank, path, 5, mode); AllocatePluginDir (&bank, 5, path, NULL);
switch( mode ) switch( mode )
{ {
...@@ -330,109 +342,135 @@ static void AllocatePluginPath (vlc_object_t *p_this, const char *path, ...@@ -330,109 +342,135 @@ static void AllocatePluginPath (vlc_object_t *p_this, const char *path,
} }
} }
/***************************************************************************** static int AllocatePluginFile (module_bank_t *, const char *,
* AllocatePluginDir: recursively parse a directory to look for plugins const char *, const struct stat *);
*****************************************************************************/
static void AllocatePluginDir( vlc_object_t *p_this, module_bank_t *p_bank, /**
const char *psz_dir, unsigned i_maxdepth, * Recursively browses a directory to look for plug-ins.
cache_mode_t mode ) */
static void AllocatePluginDir (module_bank_t *bank, unsigned maxdepth,
const char *absdir, const char *reldir)
{ {
if( i_maxdepth == 0 ) if (maxdepth == 0)
return; return;
maxdepth--;
DIR *dh = vlc_opendir (psz_dir); DIR *dh = vlc_opendir (absdir);
if (dh == NULL) if (dh == NULL)
return; return;
/* Parse the directory and try to load all files it contains. */ /* Parse the directory and try to load all files it contains. */
for (;;) for (;;)
{ {
char *file = vlc_readdir (dh), *path; char *file = vlc_readdir (dh), *relpath = NULL, *abspath = NULL;
struct stat st;
if (file == NULL) if (file == NULL)
break; break;
/* Skip ".", ".." */ /* Skip ".", ".." */
if (!strcmp (file, ".") || !strcmp (file, "..")) if (!strcmp (file, ".") || !strcmp (file, ".."))
goto skip;
/* Compute path relative to plug-in base directory */
if (reldir != NULL)
{ {
free (file); if (asprintf (&relpath, "%s"DIR_SEP"%s", reldir, file) == -1)
continue; relpath = NULL;
} }
else
relpath = strdup (file);
if (unlikely(relpath == NULL))
goto skip;
const int pathlen = asprintf (&path, "%s"DIR_SEP"%s", psz_dir, file); /* Compute absolute path */
free (file); if (asprintf (&abspath, "%s"DIR_SEP"%s", bank->base, relpath) == -1)
if (pathlen == -1 || vlc_stat (path, &st)) {
continue; abspath = NULL;
goto skip;
}
struct stat st;
if (vlc_stat (abspath, &st) == -1)
goto skip;
if (S_ISDIR (st.st_mode)) if (S_ISREG (st.st_mode))
{
static const char prefix[] = "lib";
static const char suffix[] = "_plugin"LIBEXT;
size_t len = strlen (file);
/* Check that file matches the "lib*_plugin"LIBEXT pattern */
if (len > strlen (suffix)
&& !strncmp (file, prefix, strlen (prefix))
&& !strcmp (file + len - strlen (suffix), suffix))
AllocatePluginFile (bank, abspath, relpath, &st);
}
else if (S_ISDIR (st.st_mode))
/* Recurse into another directory */ /* Recurse into another directory */
AllocatePluginDir (p_this, p_bank, path, i_maxdepth - 1, mode); AllocatePluginDir (bank, maxdepth, abspath, relpath);
else skip:
if (S_ISREG (st.st_mode) free (relpath);
&& strncmp (path, "lib", 3) free (abspath);
&& ((size_t)pathlen >= sizeof ("_plugin"LIBEXT)) free (file);
&& !strncasecmp (path + pathlen - strlen ("_plugin"LIBEXT),
"_plugin"LIBEXT, strlen ("_plugni"LIBEXT)))
/* ^^ We only load files matching "lib*_plugin"LIBEXT */
AllocatePluginFile (p_this, p_bank, path, &st, mode);
free (path);
} }
closedir (dh); closedir (dh);
} }
/***************************************************************************** static module_t *module_InitDynamic (vlc_object_t *, const char *, bool);
* AllocatePluginFile: load a module into memory and initialize it.
***************************************************************************** /**
* This function loads a dynamically loadable module and allocates a structure * Scans a plug-in from a file.
* for its information data. The module can then be handled by module_need */
* and module_unneed. static int AllocatePluginFile (module_bank_t *bank, const char *abspath,
*****************************************************************************/ const char *relpath, const struct stat *st)
static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank,
const char *path, const struct stat *st,
cache_mode_t mode )
{ {
module_t * p_module = NULL; module_t *module = NULL;
/* Check our plugins cache first then load plugin if needed */ /* Check our plugins cache first then load plugin if needed */
if( mode == CACHE_USE ) if (bank->mode == CACHE_USE)
p_module = CacheFind (p_bank->loaded_cache, p_bank->i_loaded_cache, {
path, st); module = CacheFind (bank->loaded_cache, bank->i_loaded_cache,
if( p_module == NULL ) relpath, st);
p_module = module_InitDynamic (p_this, path, true); if (module != NULL)
if( p_module == NULL ) {
module->psz_filename = strdup (abspath);
if (unlikely(module->psz_filename == NULL))
{
vlc_module_destroy (module);
module = NULL;
}
}
}
if (module == NULL)
module = module_InitDynamic (bank->obj, abspath, true);
if (module == NULL)
return -1; return -1;
/* We have not already scanned and inserted this module */ /* We have not already scanned and inserted this module */
assert( p_module->next == NULL ); assert (module->next == NULL);
/* Unload plugin until we really need it */ /* Unload plugin until we really need it */
if( p_module->b_loaded && p_module->b_unloadable ) if (module->b_loaded && module->b_unloadable)
{ {
module_Unload( p_module->handle ); module_Unload (module->handle);
p_module->b_loaded = false; module->b_loaded = false;
} }
/* For now we force loading if the module's config contains /* For now we force loading if the module's config contains
* callbacks or actions. * callbacks or actions.
* Could be optimized by adding an API call.*/ * Could be optimized by adding an API call.*/
for( size_t n = p_module->confsize, i = 0; i < n; i++ ) for (size_t n = module->confsize, i = 0; i < n; i++)
if( p_module->p_config[i].i_action ) if (module->p_config[i].i_action)
{ {
/* !unloadable not allowed for plugins with callbacks */ /* !unloadable not allowed for plugins with callbacks */
vlc_module_destroy (p_module); vlc_module_destroy (module);
p_module = module_InitDynamic (p_this, path, false); module = module_InitDynamic (bank->obj, abspath, false);
break; break;
} }
module_StoreBank (p_module); module_StoreBank (module);
if( mode == CACHE_IGNORE )
return 0;
/* Add entry to cache */ if (bank->mode != CACHE_IGNORE) /* Add entry to cache */
CacheAdd (&p_bank->cache, &p_bank->i_cache, path, st, p_module); CacheAdd (&bank->cache, &bank->i_cache, relpath, st, module);
/* TODO: deal with errors */ /* TODO: deal with errors */
return 0; return 0;
} }
...@@ -446,8 +484,8 @@ static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank, ...@@ -446,8 +484,8 @@ static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank,
* \param fast whether to optimize loading for speed or safety * \param fast whether to optimize loading for speed or safety
* (fast is used when the plug-in is registered but not used) * (fast is used when the plug-in is registered but not used)
*/ */
static module_t *module_InitDynamic (vlc_object_t *obj, static module_t *module_InitDynamic (vlc_object_t *obj, const char *path,
const char *path, bool fast) bool fast)
{ {
module_handle_t handle; module_handle_t handle;
......
...@@ -59,7 +59,7 @@ static int CacheLoadConfig ( module_t *, FILE * ); ...@@ -59,7 +59,7 @@ static int CacheLoadConfig ( module_t *, FILE * );
/* Sub-version number /* Sub-version number
* (only used to avoid breakage in dev version when cache structure changes) */ * (only used to avoid breakage in dev version when cache structure changes) */
#define CACHE_SUBVERSION_NUM 16 #define CACHE_SUBVERSION_NUM 17
/* Cache filename */ /* Cache filename */
#define CACHE_NAME "plugins.dat" #define CACHE_NAME "plugins.dat"
...@@ -638,9 +638,6 @@ module_t *CacheFind (module_cache_t *cache, size_t count, ...@@ -638,9 +638,6 @@ module_t *CacheFind (module_cache_t *cache, size_t count,
{ {
module_t *module = cache->p_module; module_t *module = cache->p_module;
cache->p_module = NULL; cache->p_module = NULL;
module->psz_filename = cache->path;
cache->path = NULL;
return module; return module;
} }
cache++; cache++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment