* gcc-plugin.h (enum plugin_event): Add PLUGIN_ALL_IPA_PASSES_START,
[official-gcc.git] / gcc / plugin.c
blob19e103a3f4a1c6dd91d15c4b92cef8e502dabca9
1 /* Support for GCC plugin mechanism.
2 Copyright (C) 2009 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 /* This file contains the support for GCC plugin mechanism based on the
21 APIs described in doc/plugin.texi. */
23 #include "config.h"
24 #include "system.h"
26 /* If plugin support is not enabled, do not try to execute any code
27 that may reference libdl. The generic code is still compiled in to
28 avoid including too many conditional compilation paths in the rest
29 of the compiler. */
30 #ifdef ENABLE_PLUGIN
31 #include <dlfcn.h>
32 #endif
34 #include "coretypes.h"
35 #include "toplev.h"
36 #include "tree.h"
37 #include "tree-pass.h"
38 #include "intl.h"
39 #include "plugin.h"
40 #include "timevar.h"
41 #include "ggc.h"
43 #ifdef ENABLE_PLUGIN
44 #include "plugin-version.h"
45 #endif
47 #include "highlev-plugin-internal.h"
49 /* Event names as strings. Keep in sync with enum plugin_event. */
50 static const char *plugin_event_name_init[] =
52 "PLUGIN_PASS_MANAGER_SETUP",
53 "PLUGIN_FINISH_TYPE",
54 "PLUGIN_FINISH_UNIT",
55 "PLUGIN_CXX_CP_PRE_GENERICIZE",
56 "PLUGIN_FINISH",
57 "PLUGIN_INFO",
58 "PLUGIN_GGC_START",
59 "PLUGIN_GGC_MARKING",
60 "PLUGIN_GGC_END",
61 "PLUGIN_REGISTER_GGC_ROOTS",
62 "PLUGIN_REGISTER_GGC_CACHES",
63 "PLUGIN_ATTRIBUTES",
64 "PLUGIN_START_UNIT",
65 "PLUGIN_PRAGMAS",
66 "unroll_parameter_handler",
67 "all_passes_start",
68 "all_passes_execution",
69 "all_passes_end",
70 "all_ipa_passes_start",
71 "all_ipa_passes_execution",
72 "all_ipa_passes_end",
73 "avoid_gate",
74 "pass_execution",
75 "early_gimple_passes_start",
76 "early_gimple_passes_end",
77 "PLUGIN_EVENT_LAST",
80 const char **plugin_event_name = plugin_event_name_init;
82 /* A hash table to map event names the the position of the names in the
83 plugin_event_name. */
84 static htab_t event_tab;
86 /* Keep track of the limit of allocated events and space ready for
87 allocating events. */
88 int event_last = PLUGIN_EVENT_LAST;
89 static int event_horizon = PLUGIN_EVENT_LAST;
91 /* Hash table for the plugin_name_args objects created during command-line
92 parsing. */
93 static htab_t plugin_name_args_tab = NULL;
95 /* List node for keeping track of plugin-registered callback. */
96 struct callback_info
98 const char *plugin_name; /* Name of plugin that registers the callback. */
99 plugin_callback_func func; /* Callback to be called. */
100 void *user_data; /* plugin-specified data. */
101 struct callback_info *next;
104 /* An array of lists of 'callback_info' objects indexed by the event id. */
105 static struct callback_info *plugin_callbacks_init[PLUGIN_EVENT_LAST];
106 static struct callback_info **plugin_callbacks = plugin_callbacks_init;
109 #ifdef ENABLE_PLUGIN
110 /* Each plugin should define an initialization function with exactly
111 this name. */
112 static const char *str_plugin_init_func_name = "plugin_init";
114 /* Each plugin should define this symbol to assert that it is
115 distributed under a GPL-compatible license. */
116 static const char *str_license = "plugin_is_GPL_compatible";
117 #endif
119 /* Helper function for the hash table that compares the base_name of the
120 existing entry (S1) with the given string (S2). */
122 static int
123 htab_str_eq (const void *s1, const void *s2)
125 const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
126 return !strcmp (plugin->base_name, (const char *) s2);
130 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
131 return NAME. */
133 static char *
134 get_plugin_base_name (const char *full_name)
136 /* First get the base name part of the full-path name, i.e. NAME.so. */
137 char *base_name = xstrdup (lbasename (full_name));
139 /* Then get rid of '.so' part of the name. */
140 strip_off_ending (base_name, strlen (base_name));
142 return base_name;
146 /* Create a plugin_name_args object for the give plugin and insert it to
147 the hash table. This function is called when -fplugin=/path/to/NAME.so
148 option is processed. */
150 void
151 add_new_plugin (const char* plugin_name)
153 struct plugin_name_args *plugin;
154 void **slot;
155 char *base_name = get_plugin_base_name (plugin_name);
157 /* If this is the first -fplugin= option we encounter, create
158 'plugin_name_args_tab' hash table. */
159 if (!plugin_name_args_tab)
160 plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq,
161 NULL);
163 slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
165 /* If the same plugin (name) has been specified earlier, either emit an
166 error or a warning message depending on if they have identical full
167 (path) names. */
168 if (*slot)
170 plugin = (struct plugin_name_args *) *slot;
171 if (strcmp (plugin->full_name, plugin_name))
172 error ("Plugin %s was specified with different paths:\n%s\n%s",
173 plugin->base_name, plugin->full_name, plugin_name);
174 return;
177 plugin = XCNEW (struct plugin_name_args);
178 plugin->base_name = base_name;
179 plugin->full_name = plugin_name;
181 *slot = plugin;
185 /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
186 'plugin_argument' object for the parsed key-value pair. ARG is
187 the <name>-<key>[=<value>] part of the option. */
189 void
190 parse_plugin_arg_opt (const char *arg)
192 size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
193 const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
194 char *name, *key, *value;
195 void **slot;
196 bool name_parsed = false, key_parsed = false;
198 /* Iterate over the ARG string and identify the starting character position
199 of 'name', 'key', and 'value' and their lengths. */
200 for (ptr = arg; *ptr; ++ptr)
202 /* Only the first '-' encountered is considered a separator between
203 'name' and 'key'. All the subsequent '-'s are considered part of
204 'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
205 the plugin name is 'foo' and the key is 'bar-primary-key'. */
206 if (*ptr == '-' && !name_parsed)
208 name_len = len;
209 len = 0;
210 key_start = ptr + 1;
211 name_parsed = true;
212 continue;
214 else if (*ptr == '=')
216 if (key_parsed)
218 error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
219 arg);
220 return;
222 key_len = len;
223 len = 0;
224 value_start = ptr + 1;
225 key_parsed = true;
226 continue;
228 else
229 ++len;
232 if (!key_start)
234 error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
235 arg);
236 return;
239 /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
240 Otherwise, it is the VALUE_LEN. */
241 if (!value_start)
242 key_len = len;
243 else
244 value_len = len;
246 name = XNEWVEC (char, name_len + 1);
247 strncpy (name, name_start, name_len);
248 name[name_len] = '\0';
250 /* Check if the named plugin has already been specified earlier in the
251 command-line. */
252 if (plugin_name_args_tab
253 && ((slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT))
254 != NULL))
256 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
258 key = XNEWVEC (char, key_len + 1);
259 strncpy (key, key_start, key_len);
260 key[key_len] = '\0';
261 if (value_start)
263 value = XNEWVEC (char, value_len + 1);
264 strncpy (value, value_start, value_len);
265 value[value_len] = '\0';
267 else
268 value = NULL;
270 /* Create a plugin_argument object for the parsed key-value pair.
271 If there are already arguments for this plugin, we will need to
272 adjust the argument array size by creating a new array and deleting
273 the old one. If the performance ever becomes an issue, we can
274 change the code by pre-allocating a larger array first. */
275 if (plugin->argc > 0)
277 struct plugin_argument *args = XNEWVEC (struct plugin_argument,
278 plugin->argc + 1);
279 memcpy (args, plugin->argv,
280 sizeof (struct plugin_argument) * plugin->argc);
281 XDELETEVEC (plugin->argv);
282 plugin->argv = args;
283 ++plugin->argc;
285 else
287 gcc_assert (plugin->argv == NULL);
288 plugin->argv = XNEWVEC (struct plugin_argument, 1);
289 plugin->argc = 1;
292 plugin->argv[plugin->argc - 1].key = key;
293 plugin->argv[plugin->argc - 1].value = value;
295 else
296 error ("Plugin %s should be specified before -fplugin-arg-%s "
297 "in the command line", name, arg);
299 /* We don't need the plugin's name anymore. Just release it. */
300 XDELETEVEC (name);
303 /* Register additional plugin information. NAME is the name passed to
304 plugin_init. INFO is the information that should be registered. */
306 static void
307 register_plugin_info (const char* name, struct plugin_info *info)
309 void **slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT);
310 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
311 plugin->version = info->version;
312 plugin->help = info->help;
315 /* Helper function for the event hash table that compares the name of an
316 existing entry (E1) with the given string (S2). */
318 static int
319 htab_event_eq (const void *e1, const void *s2)
321 const char *s1= *(const char * const *) e1;
322 return !strcmp (s1, (const char *) s2);
325 /* Look up the event id for NAME. If the name is not found, return -1
326 if INSERT is NO_INSERT. */
328 get_named_event_id (const char *name, enum insert_option insert)
330 void **slot;
332 if (!event_tab)
334 int i;
336 event_tab = htab_create (150, htab_hash_string, htab_event_eq, NULL);
337 for (i = 0; i < PLUGIN_EVENT_LAST; i++)
339 slot = htab_find_slot (event_tab, plugin_event_name[i], INSERT);
340 gcc_assert (*slot == HTAB_EMPTY_ENTRY);
341 *slot = &plugin_event_name[i];
344 slot = htab_find_slot (event_tab, name, insert);
345 if (slot == NULL)
346 return -1;
347 if (*slot != HTAB_EMPTY_ENTRY)
348 return (const char **) *slot - &plugin_event_name[0];
350 if (event_last >= event_horizon)
352 event_horizon = event_last * 2;
353 if (plugin_event_name == plugin_event_name_init)
355 plugin_event_name = XNEWVEC (const char *, event_horizon);
356 memcpy (plugin_event_name, plugin_event_name_init,
357 sizeof plugin_event_name_init);
358 plugin_callbacks = XNEWVEC (struct callback_info *, event_horizon);
359 memcpy (plugin_callbacks, plugin_callbacks_init,
360 sizeof plugin_callbacks_init);
362 else
364 plugin_event_name
365 = XRESIZEVEC (const char *, plugin_event_name, event_horizon);
366 plugin_callbacks = XRESIZEVEC (struct callback_info *,
367 plugin_callbacks, event_horizon);
369 /* All the pointers in the hash table will need to be updated. */
370 htab_delete (event_tab);
371 event_tab = NULL;
373 else
374 *slot = &plugin_event_name[event_last];
375 plugin_event_name[event_last] = name;
376 return event_last++;
379 /* Called from the plugin's initialization code. Register a single callback.
380 This function can be called multiple times.
382 PLUGIN_NAME - display name for this plugin
383 EVENT - which event the callback is for
384 CALLBACK - the callback to be called at the event
385 USER_DATA - plugin-provided data */
387 void
388 register_callback (const char *plugin_name,
389 int event,
390 plugin_callback_func callback,
391 void *user_data)
393 switch (event)
395 case PLUGIN_PASS_MANAGER_SETUP:
396 gcc_assert (!callback);
397 register_pass ((struct register_pass_info *) user_data);
398 break;
399 case PLUGIN_INFO:
400 gcc_assert (!callback);
401 register_plugin_info (plugin_name, (struct plugin_info *) user_data);
402 break;
403 case PLUGIN_REGISTER_GGC_ROOTS:
404 gcc_assert (!callback);
405 ggc_register_root_tab ((const struct ggc_root_tab*) user_data);
406 break;
407 case PLUGIN_REGISTER_GGC_CACHES:
408 gcc_assert (!callback);
409 ggc_register_cache_tab ((const struct ggc_cache_tab*) user_data);
410 break;
411 case PLUGIN_EVENT_LAST:
412 default:
413 if (event < PLUGIN_FIRST_EXPERIMENTAL || event >= event_last)
415 error ("Unknown callback event registered by plugin %s",
416 plugin_name);
417 return;
419 /* Fall through. */
420 case PLUGIN_FINISH_TYPE:
421 case PLUGIN_START_UNIT:
422 case PLUGIN_FINISH_UNIT:
423 case PLUGIN_CXX_CP_PRE_GENERICIZE:
424 case PLUGIN_GGC_START:
425 case PLUGIN_GGC_MARKING:
426 case PLUGIN_GGC_END:
427 case PLUGIN_ATTRIBUTES:
428 case PLUGIN_PRAGMAS:
429 case PLUGIN_FINISH:
431 struct callback_info *new_callback;
432 if (!callback)
434 error ("Plugin %s registered a null callback function "
435 "for event %s", plugin_name, plugin_event_name[event]);
436 return;
438 new_callback = XNEW (struct callback_info);
439 new_callback->plugin_name = plugin_name;
440 new_callback->func = callback;
441 new_callback->user_data = user_data;
442 new_callback->next = plugin_callbacks[event];
443 plugin_callbacks[event] = new_callback;
445 break;
450 unregister_callback (const char *plugin_name, int event)
452 struct callback_info *callback, **cbp;
454 if (event >= event_last)
455 return PLUGEVT_NO_SUCH_EVENT;
457 for (cbp = &plugin_callbacks[event]; callback = *cbp; cbp = &callback->next)
458 if (strcmp (callback->plugin_name, plugin_name) == 0)
460 *cbp = callback->next;
461 return PLUGEVT_SUCCESS;
463 return PLUGEVT_NO_CALLBACK;
466 /* Called from inside GCC. Invoke all plug-in callbacks registered with
467 the specified event.
469 EVENT - the event identifier
470 GCC_DATA - event-specific data provided by the compiler */
473 invoke_plugin_callbacks (int event, void *gcc_data)
475 int retval = PLUGEVT_SUCCESS;
477 timevar_push (TV_PLUGIN_RUN);
479 switch (event)
481 case PLUGIN_EVENT_LAST:
482 default:
483 gcc_assert (event >= PLUGIN_FIRST_EXPERIMENTAL);
484 gcc_assert (event < event_last);
485 /* Fall through. */
486 case PLUGIN_FINISH_TYPE:
487 case PLUGIN_START_UNIT:
488 case PLUGIN_FINISH_UNIT:
489 case PLUGIN_CXX_CP_PRE_GENERICIZE:
490 case PLUGIN_ATTRIBUTES:
491 case PLUGIN_PRAGMAS:
492 case PLUGIN_FINISH:
493 case PLUGIN_GGC_START:
494 case PLUGIN_GGC_MARKING:
495 case PLUGIN_GGC_END:
497 /* Iterate over every callback registered with this event and
498 call it. */
499 struct callback_info *callback = plugin_callbacks[event];
501 if (!callback)
502 retval = PLUGEVT_NO_CALLBACK;
503 for ( ; callback; callback = callback->next)
504 (*callback->func) (gcc_data, callback->user_data);
506 break;
508 case PLUGIN_PASS_MANAGER_SETUP:
509 case PLUGIN_REGISTER_GGC_ROOTS:
510 case PLUGIN_REGISTER_GGC_CACHES:
511 gcc_assert (false);
514 timevar_pop (TV_PLUGIN_RUN);
515 return retval;
519 invoke_plugin_va_callbacks (int event, ...)
521 va_list va;
522 int retval;
524 va_start (va, event);
525 retval = invoke_plugin_callbacks (event, &va);
526 va_end (va);
527 return retval;
530 #ifdef ENABLE_PLUGIN
531 /* We need a union to cast dlsym return value to a function pointer
532 as ISO C forbids assignment between function pointer and 'void *'.
533 Use explicit union instead of __extension__(<union_cast>) for
534 portability. */
535 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
536 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
537 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
539 /* Try to initialize PLUGIN. Return true if successful. */
541 static bool
542 try_init_one_plugin (struct plugin_name_args *plugin)
544 void *dl_handle;
545 plugin_init_func plugin_init;
546 const char *err;
547 PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
549 /* We use RTLD_NOW to accelerate binding and detect any mismatch
550 between the API expected by the plugin and the GCC API; we use
551 RTLD_GLOBAL which is useful to plugins which themselves call
552 dlopen. */
553 dl_handle = dlopen (plugin->full_name, RTLD_NOW | RTLD_GLOBAL);
554 if (!dl_handle)
556 error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
557 return false;
560 /* Clear any existing error. */
561 dlerror ();
563 /* Check the plugin license. */
564 if (dlsym (dl_handle, str_license) == NULL)
565 fatal_error ("plugin %s is not licensed under a GPL-compatible license\n"
566 "%s", plugin->full_name, dlerror ());
568 PTR_UNION_AS_VOID_PTR (plugin_init_union) =
569 dlsym (dl_handle, str_plugin_init_func_name);
570 plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
572 if ((err = dlerror ()) != NULL)
574 error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
575 plugin->full_name, err);
576 return false;
579 /* Call the plugin-provided initialization routine with the arguments. */
580 if ((*plugin_init) (plugin, &gcc_version))
582 error ("Fail to initialize plugin %s", plugin->full_name);
583 return false;
586 return true;
590 /* Routine to dlopen and initialize one plugin. This function is passed to
591 (and called by) the hash table traverse routine. Return 1 for the
592 htab_traverse to continue scan, 0 to stop.
594 SLOT - slot of the hash table element
595 INFO - auxiliary pointer handed to hash table traverse routine
596 (unused in this function) */
598 static int
599 init_one_plugin (void **slot, void * ARG_UNUSED (info))
601 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
602 bool ok = try_init_one_plugin (plugin);
603 if (!ok)
605 htab_remove_elt (plugin_name_args_tab, plugin->base_name);
606 XDELETE (plugin);
608 return 1;
611 #endif /* ENABLE_PLUGIN */
613 /* Main plugin initialization function. Called from compile_file() in
614 toplev.c. */
616 void
617 initialize_plugins (void)
619 /* Loads ICI plugin */
620 load_ici_plugin ();
622 /* If no plugin was specified in the command-line, simply return. */
623 if (!plugin_name_args_tab)
624 return;
626 timevar_push (TV_PLUGIN_INIT);
628 #ifdef ENABLE_PLUGIN
629 /* Traverse and initialize each plugin specified in the command-line. */
630 htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
631 #endif
633 timevar_pop (TV_PLUGIN_INIT);
636 /* Release memory used by one plugin. */
638 static int
639 finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
641 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
642 XDELETE (plugin);
643 return 1;
646 /* Free memory allocated by the plugin system. */
648 void
649 finalize_plugins (void)
651 if (!plugin_name_args_tab)
652 return;
654 /* We can now delete the plugin_name_args object as it will no longer
655 be used. Note that base_name and argv fields (both of which were also
656 dynamically allocated) are not freed as they could still be used by
657 the plugin code. */
659 htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
661 /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it. */
662 htab_delete (plugin_name_args_tab);
663 plugin_name_args_tab = NULL;
666 /* Used to pass options to htab_traverse callbacks. */
668 struct print_options
670 FILE *file;
671 const char *indent;
674 /* Print the version of one plugin. */
676 static int
677 print_version_one_plugin (void **slot, void *data)
679 struct print_options *opt = (struct print_options *) data;
680 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
681 const char *version = plugin->version ? plugin->version : "Unknown version.";
683 fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
684 return 1;
687 /* Print the version of each plugin. */
689 void
690 print_plugins_versions (FILE *file, const char *indent)
692 struct print_options opt;
693 opt.file = file;
694 opt.indent = indent;
695 if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
696 return;
698 fprintf (file, "%sVersions of loaded plugins:\n", indent);
699 htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
702 /* Print help for one plugin. SLOT is the hash table slot. DATA is the
703 argument to htab_traverse_noresize. */
705 static int
706 print_help_one_plugin (void **slot, void *data)
708 struct print_options *opt = (struct print_options *) data;
709 struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
710 const char *help = plugin->help ? plugin->help : "No help available .";
712 char *dup = xstrdup (help);
713 char *p, *nl;
714 fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
716 for (p = nl = dup; nl; p = nl)
718 nl = strchr (nl, '\n');
719 if (nl)
721 *nl = '\0';
722 nl++;
724 fprintf (opt->file, " %s %s\n", opt->indent, p);
727 free (dup);
728 return 1;
731 /* Print help for each plugin. The output goes to FILE and every line starts
732 with INDENT. */
734 void
735 print_plugins_help (FILE *file, const char *indent)
737 struct print_options opt;
738 opt.file = file;
739 opt.indent = indent;
740 if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
741 return;
743 fprintf (file, "%sHelp for the loaded plugins:\n", indent);
744 htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
748 /* Return true if plugins have been loaded. */
750 bool
751 plugins_active_p (void)
753 int event;
755 for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
756 if (plugin_callbacks[event])
757 return true;
759 return false;
763 /* Dump to FILE the names and associated events for all the active
764 plugins. */
766 void
767 dump_active_plugins (FILE *file)
769 int event;
771 if (!plugins_active_p ())
772 return;
774 fprintf (stderr, "Event\t\t\tPlugins\n");
775 for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
776 if (plugin_callbacks[event])
778 struct callback_info *ci;
780 fprintf (file, "%s\t", plugin_event_name[event]);
782 for (ci = plugin_callbacks[event]; ci; ci = ci->next)
783 fprintf (file, "%s ", ci->plugin_name);
785 fprintf (file, "\n");
790 /* Dump active plugins to stderr. */
792 void
793 debug_active_plugins (void)
795 dump_active_plugins (stderr);
798 /* The default version check. Compares every field in VERSION. */
800 bool
801 plugin_default_version_check (struct plugin_gcc_version *gcc_version,
802 struct plugin_gcc_version *plugin_version)
804 if (!gcc_version || !plugin_version)
805 return false;
807 if (strcmp (gcc_version->basever, plugin_version->basever))
808 return false;
809 if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
810 return false;
811 if (strcmp (gcc_version->devphase, plugin_version->devphase))
812 return false;
813 if (strcmp (gcc_version->revision, plugin_version->revision))
814 return false;
815 if (strcmp (gcc_version->configuration_arguments,
816 plugin_version->configuration_arguments))
817 return false;
818 return true;