summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c774
1 files changed, 774 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..385e43d
--- /dev/null
+++ b/main.c
@@ -0,0 +1,774 @@
+/*
+ * Copyright (C) 2001, 2002 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pkg.h"
+#include "parse.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#ifdef G_OS_WIN32
+#define STRICT
+#include <windows.h>
+#undef STRICT
+#endif
+
+static int want_debug_spew = 0;
+static int want_verbose_errors = 0;
+static int want_stdout_errors = 0;
+char *pcsysrootdir = NULL;
+char *pkg_config_pc_path = NULL;
+
+void
+debug_spew (const char *format, ...)
+{
+ va_list args;
+ gchar *str;
+ FILE* stream;
+
+ g_return_if_fail (format != NULL);
+
+ if (!want_debug_spew)
+ return;
+
+ va_start (args, format);
+ str = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ if (want_stdout_errors)
+ stream = stdout;
+ else
+ stream = stderr;
+
+ fputs (str, stream);
+ fflush (stream);
+
+ g_free (str);
+}
+
+void
+verbose_error (const char *format, ...)
+{
+ va_list args;
+ gchar *str;
+ FILE* stream;
+
+ g_return_if_fail (format != NULL);
+
+ if (!want_verbose_errors)
+ return;
+
+ va_start (args, format);
+ str = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ if (want_stdout_errors)
+ stream = stdout;
+ else
+ stream = stderr;
+
+ fputs (str, stream);
+ fflush (stream);
+
+ g_free (str);
+}
+
+static gboolean
+define_variable_cb (const char *opt, const char *arg, gpointer data,
+ GError **error)
+{
+ char *varname;
+ char *varval;
+ char *tmp;
+
+ tmp = g_strdup (arg);
+
+ varname = tmp;
+ while (*varname && isspace ((guchar)*varname))
+ ++varname;
+
+ varval = varname;
+ while (*varval && *varval != '=' && *varval != ' ')
+ ++varval;
+
+ while (*varval && (*varval == '=' || *varval == ' '))
+ {
+ *varval = '\0';
+ ++varval;
+ }
+
+ if (*varval == '\0')
+ {
+ fprintf (stderr, "--define-variable argument does not have a value "
+ "for the variable\n");
+ exit (1);
+ }
+
+ define_global_variable (varname, varval);
+
+ g_free (tmp);
+ return TRUE;
+}
+
+static gboolean
+pkg_uninstalled (Package *pkg)
+{
+ /* See if > 0 pkgs were uninstalled */
+ GSList *tmp;
+
+ if (pkg->uninstalled)
+ return TRUE;
+
+ tmp = pkg->requires;
+ while (tmp != NULL)
+ {
+ Package *pkg = tmp->data;
+
+ if (pkg_uninstalled (pkg))
+ return TRUE;
+
+ tmp = g_slist_next (tmp);
+ }
+
+ return FALSE;
+}
+
+void
+print_hashtable_key (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ printf("%s\n", (gchar*)key);
+}
+
+static void
+init_pc_path (void)
+{
+#ifdef G_OS_WIN32
+ char *instdir, *lpath, *shpath;
+
+ instdir = g_win32_get_package_installation_directory_of_module (NULL);
+ if (instdir == NULL)
+ {
+ /* This only happens when GetModuleFilename() fails. If it does, that
+ * failure should be investigated and fixed.
+ */
+ debug_spew ("g_win32_get_package_installation_directory_of_module failed\n");
+ return;
+ }
+
+ lpath = g_build_filename (instdir, "lib", "pkgconfig", NULL);
+ shpath = g_build_filename (instdir, "share", "pkgconfig", NULL);
+ pkg_config_pc_path = g_strconcat (lpath, G_SEARCHPATH_SEPARATOR_S, shpath,
+ NULL);
+ g_free (instdir);
+ g_free (lpath);
+ g_free (shpath);
+#else
+ pkg_config_pc_path = PKG_CONFIG_PC_PATH;
+#endif
+}
+
+int
+main (int argc, char **argv)
+{
+ static int want_my_version = 0;
+ static int want_version = 0;
+ static int want_libs = 0;
+ static int want_cflags = 0;
+ static int want_l_libs = 0;
+ static int want_L_libs = 0;
+ static int want_other_libs = 0;
+ static int want_I_cflags = 0;
+ static int want_other_cflags = 0;
+ static int want_list = 0;
+ static int want_static_lib_list = ENABLE_INDIRECT_DEPS;
+ static int want_short_errors = 0;
+ static int want_uninstalled = 0;
+ static char *variable_name = NULL;
+ static int want_exists = 0;
+ static int want_provides = 0;
+ static int want_requires = 0;
+ static int want_requires_private = 0;
+ static char *required_atleast_version = NULL;
+ static char *required_exact_version = NULL;
+ static char *required_max_version = NULL;
+ static char *required_pkgconfig_version = NULL;
+ static int want_silence_errors = 0;
+ static int want_variable_list = 0;
+ GString *str;
+ GSList *packages = NULL;
+ char *search_path;
+ char *pcbuilddir;
+ gboolean need_newline;
+ FILE *log = NULL;
+ GError *error = NULL;
+ GOptionContext *opt_context;
+
+ GOptionEntry options_table[] = {
+ { "version", 0, 0, G_OPTION_ARG_NONE, &want_my_version,
+ "output version of pkg-config", NULL },
+ { "modversion", 0, 0, G_OPTION_ARG_NONE, &want_version,
+ "output version for package", NULL },
+ { "atleast-pkgconfig-version", 0, 0, G_OPTION_ARG_STRING,
+ &required_pkgconfig_version,
+ "require given version of pkg-config", "VERSION" },
+ { "libs", 0, 0, G_OPTION_ARG_NONE, &want_libs,
+ "output all linker flags", NULL },
+ { "static", 0, 0, G_OPTION_ARG_NONE, &want_static_lib_list,
+ "output linker flags for static linking", NULL },
+ { "short-errors", 0, 0, G_OPTION_ARG_NONE, &want_short_errors,
+ "print short errors", NULL },
+ { "libs-only-l", 0, 0, G_OPTION_ARG_NONE, &want_l_libs,
+ "output -l flags", NULL },
+ { "libs-only-other", 0, 0, G_OPTION_ARG_NONE, &want_other_libs,
+ "output other libs (e.g. -pthread)", NULL },
+ { "libs-only-L", 0, 0, G_OPTION_ARG_NONE, &want_L_libs,
+ "output -L flags", NULL },
+ { "cflags", 0, 0, G_OPTION_ARG_NONE, &want_cflags,
+ "output all pre-processor and compiler flags", NULL },
+ { "cflags-only-I", 0, 0, G_OPTION_ARG_NONE, &want_I_cflags,
+ "output -I flags", NULL },
+ { "cflags-only-other", 0, 0, G_OPTION_ARG_NONE, &want_other_cflags,
+ "output cflags not covered by the cflags-only-I option", NULL },
+ { "variable", 0, 0, G_OPTION_ARG_STRING, &variable_name,
+ "get the value of variable named NAME", "NAME" },
+ { "define-variable", 0, 0, G_OPTION_ARG_CALLBACK, &define_variable_cb,
+ "set variable NAME to VALUE", "NAME=VALUE" },
+ { "exists", 0, 0, G_OPTION_ARG_NONE, &want_exists,
+ "return 0 if the module(s) exist", NULL },
+ { "print-variables", 0, 0, G_OPTION_ARG_NONE, &want_variable_list,
+ "output list of variables defined by the module", NULL },
+ { "uninstalled", 0, 0, G_OPTION_ARG_NONE, &want_uninstalled,
+ "return 0 if the uninstalled version of one or more module(s) "
+ "or their dependencies will be used", NULL },
+ { "atleast-version", 0, 0, G_OPTION_ARG_STRING, &required_atleast_version,
+ "return 0 if the module is at least version VERSION", "VERSION" },
+ { "exact-version", 0, 0, G_OPTION_ARG_STRING, &required_exact_version,
+ "return 0 if the module is at exactly version VERSION", "VERSION" },
+ { "max-version", 0, 0, G_OPTION_ARG_STRING, &required_max_version,
+ "return 0 if the module is at no newer than version VERSION", "VERSION" },
+ { "list-all", 0, 0, G_OPTION_ARG_NONE, &want_list,
+ "list all known packages", NULL },
+ { "debug", 0, 0, G_OPTION_ARG_NONE, &want_debug_spew,
+ "show verbose debug information", NULL },
+ { "print-errors", 0, 0, G_OPTION_ARG_NONE, &want_verbose_errors,
+ "show verbose information about missing or conflicting packages,"
+ "default if --cflags or --libs given on the command line", NULL },
+ { "silence-errors", 0, 0, G_OPTION_ARG_NONE, &want_silence_errors,
+ "be silent about errors (default unless --cflags or --libs"
+ "given on the command line)", NULL },
+ { "errors-to-stdout", 0, 0, G_OPTION_ARG_NONE, &want_stdout_errors,
+ "print errors from --print-errors to stdout not stderr", NULL },
+ { "print-provides", 0, 0, G_OPTION_ARG_NONE, &want_provides,
+ "print which packages the package provides", NULL },
+ { "print-requires", 0, 0, G_OPTION_ARG_NONE, &want_requires,
+ "print which packages the package requires", NULL },
+ { "print-requires-private", 0, 0, G_OPTION_ARG_NONE, &want_requires_private,
+ "print which packages the package requires for static linking", NULL },
+#ifdef G_OS_WIN32
+ { "dont-define-prefix", 0, 0, G_OPTION_ARG_NONE, &dont_define_prefix,
+ "don't try to override the value of prefix for each .pc file found with "
+ "a guesstimated value based on the location of the .pc file", NULL },
+ { "prefix-variable", 0, 0, G_OPTION_ARG_STRING, &prefix_variable,
+ "set the name of the variable that pkg-config automatically sets",
+ "PREFIX" },
+ { "msvc-syntax", 0, 0, G_OPTION_ARG_NONE, &msvc_syntax,
+ "output -l and -L flags for the Microsoft compiler (cl)", NULL },
+#endif
+ { NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
+ /* This is here so that we get debug spew from the start,
+ * during arg parsing
+ */
+ if (getenv ("PKG_CONFIG_DEBUG_SPEW"))
+ {
+ want_debug_spew = TRUE;
+ want_verbose_errors = TRUE;
+ want_silence_errors = FALSE;
+ debug_spew ("PKG_CONFIG_DEBUG_SPEW variable enabling debug spew\n");
+ }
+
+
+ /* Get the built-in search path */
+ init_pc_path ();
+ if (pkg_config_pc_path == NULL)
+ {
+ /* Even when we override the built-in search path, we still use it later
+ * to add pc_path to the virtual pkg-config package.
+ */
+ verbose_error ("Failed to get default search path\n");
+ exit (1);
+ }
+
+ search_path = getenv ("PKG_CONFIG_PATH");
+ if (search_path)
+ {
+ add_search_dirs(search_path, G_SEARCHPATH_SEPARATOR_S);
+ }
+ if (getenv("PKG_CONFIG_LIBDIR") != NULL)
+ {
+ add_search_dirs(getenv("PKG_CONFIG_LIBDIR"), G_SEARCHPATH_SEPARATOR_S);
+ }
+ else
+ {
+ add_search_dirs(pkg_config_pc_path, G_SEARCHPATH_SEPARATOR_S);
+ }
+
+ pcsysrootdir = getenv ("PKG_CONFIG_SYSROOT_DIR");
+ if (pcsysrootdir)
+ {
+ define_global_variable ("pc_sysrootdir", pcsysrootdir);
+ }
+ else
+ {
+ define_global_variable ("pc_sysrootdir", "/");
+ }
+
+ pcbuilddir = getenv ("PKG_CONFIG_TOP_BUILD_DIR");
+ if (pcbuilddir)
+ {
+ define_global_variable ("pc_top_builddir", pcbuilddir);
+ }
+ else
+ {
+ /* Default appropriate for automake */
+ define_global_variable ("pc_top_builddir", "$(top_builddir)");
+ }
+
+ if (getenv ("PKG_CONFIG_DISABLE_UNINSTALLED"))
+ {
+ debug_spew ("disabling auto-preference for uninstalled packages\n");
+ disable_uninstalled = TRUE;
+ }
+
+ /* Parse options */
+ opt_context = g_option_context_new (NULL);
+ g_option_context_add_main_entries (opt_context, options_table, NULL);
+ if (!g_option_context_parse(opt_context, &argc, &argv, &error))
+ {
+ fprintf (stderr, "%s\n", error->message);
+ return 1;
+ }
+
+
+ /* Error printing is determined as follows:
+ * - for --cflags, --libs, etc. it's on by default
+ * and --silence-errors can turn it off
+ * - for --exists, --max-version, etc. and no options
+ * at all, it's off by default and --print-errors
+ * will turn it on
+ */
+
+ if (want_my_version ||
+ want_version ||
+ want_libs ||
+ want_cflags ||
+ want_l_libs ||
+ want_L_libs ||
+ want_other_libs ||
+ want_I_cflags ||
+ want_other_cflags ||
+ want_list ||
+ want_variable_list)
+ {
+ debug_spew ("Error printing enabled by default due to use of --version, --libs, --cflags, --libs-only-l, --libs-only-L, --libs-only-other, --cflags-only-I, --cflags-only-other or --list. Value of --silence-errors: %d\n", want_silence_errors);
+
+ if (want_silence_errors && getenv ("PKG_CONFIG_DEBUG_SPEW") == NULL)
+ want_verbose_errors = FALSE;
+ else
+ want_verbose_errors = TRUE;
+ }
+ else
+ {
+ debug_spew ("Error printing disabled by default, value of --print-errors: %d\n",
+ want_verbose_errors);
+
+ /* Leave want_verbose_errors unchanged, reflecting --print-errors */
+ }
+
+ if (want_verbose_errors)
+ debug_spew ("Error printing enabled\n");
+ else
+ debug_spew ("Error printing disabled\n");
+
+ if (want_static_lib_list)
+ enable_private_libs();
+ else
+ disable_private_libs();
+
+ /* honor Requires.private if any Cflags are requested or any static
+ * libs are requested */
+
+ if (want_I_cflags || want_other_cflags || want_cflags ||
+ want_requires_private || want_exists ||
+ (want_static_lib_list && (want_libs || want_l_libs || want_L_libs)))
+ enable_requires_private();
+
+ /* ignore Requires if no Cflags or Libs are requested */
+
+ if (!want_I_cflags && !want_other_cflags && !want_cflags &&
+ !want_libs && !want_l_libs && !want_L_libs && !want_requires &&
+ !want_exists)
+ disable_requires();
+
+ if (want_my_version)
+ {
+ printf ("%s\n", VERSION);
+ return 0;
+ }
+
+ if (required_pkgconfig_version)
+ {
+ if (compare_versions (VERSION, required_pkgconfig_version) >= 0)
+ return 0;
+ else
+ return 1;
+ }
+
+ package_init ();
+
+ if (want_list)
+ {
+ print_package_list ();
+ return 0;
+ }
+
+ /* Collect packages from remaining args */
+ str = g_string_new ("");
+ while (argc > 1)
+ {
+ argc--;
+ argv++;
+
+ g_string_append (str, *argv);
+ g_string_append (str, " ");
+ }
+
+ g_option_context_free (opt_context);
+
+ g_strstrip (str->str);
+
+ if (getenv("PKG_CONFIG_LOG") != NULL)
+ {
+ log = fopen (getenv ("PKG_CONFIG_LOG"), "a");
+ if (log == NULL)
+ {
+ fprintf (stderr, "Cannot open log file: %s\n",
+ getenv ("PKG_CONFIG_LOG"));
+ exit (1);
+ }
+ }
+
+ {
+ gboolean failed = FALSE;
+ GSList *reqs;
+ GSList *iter;
+
+ reqs = parse_module_list (NULL, str->str,
+ "(command line arguments)");
+
+ iter = reqs;
+
+ while (iter != NULL)
+ {
+ Package *req;
+ RequiredVersion *ver = iter->data;
+
+ /* override requested versions with cmdline options */
+ if (required_exact_version)
+ {
+ g_free (ver->version);
+ ver->comparison = EQUAL;
+ ver->version = g_strdup (required_exact_version);
+ }
+ else if (required_atleast_version)
+ {
+ g_free (ver->version);
+ ver->comparison = GREATER_THAN_EQUAL;
+ ver->version = g_strdup (required_atleast_version);
+ }
+ else if (required_max_version)
+ {
+ g_free (ver->version);
+ ver->comparison = LESS_THAN_EQUAL;
+ ver->version = g_strdup (required_max_version);
+ }
+
+ if (want_short_errors)
+ req = get_package_quiet (ver->name);
+ else
+ req = get_package (ver->name);
+
+ if (log != NULL)
+ {
+ if (req == NULL)
+ fprintf (log, "%s NOT-FOUND", ver->name);
+ else
+ fprintf (log, "%s %s %s", ver->name,
+ comparison_to_str (ver->comparison),
+ (ver->version == NULL) ? "(null)" : ver->version);
+ fprintf (log, "\n");
+ }
+
+ if (req == NULL)
+ {
+ failed = TRUE;
+ verbose_error ("No package '%s' found\n", ver->name);
+ goto nextiter;
+ }
+
+ if (!version_test (ver->comparison, req->version, ver->version))
+ {
+ failed = TRUE;
+ verbose_error ("Requested '%s %s %s' but version of %s is %s\n",
+ ver->name,
+ comparison_to_str (ver->comparison),
+ ver->version,
+ req->name,
+ req->version);
+
+ if (req->url)
+ verbose_error ("You may find new versions of %s at %s\n",
+ req->name, req->url);
+
+ goto nextiter;
+ }
+
+ packages = g_slist_prepend (packages, req);
+
+ nextiter:
+ iter = g_slist_next (iter);
+ }
+
+ if (log != NULL)
+ {
+ fclose (log);
+ }
+
+ if (failed) {
+ return 1;
+ }
+
+ if (want_variable_list)
+ {
+ GSList *tmp;
+ tmp = packages;
+ while (tmp != NULL)
+ {
+ Package *pkg = tmp->data;
+ g_hash_table_foreach(pkg->vars,
+ &print_hashtable_key,
+ NULL);
+ tmp = g_slist_next (tmp);
+ if (tmp) printf ("\n");
+ }
+ need_newline = FALSE;
+ }
+
+ }
+
+ g_string_free (str, TRUE);
+
+ packages = g_slist_reverse (packages);
+
+ if (packages == NULL)
+ {
+ fprintf (stderr, "Must specify package names on the command line\n");
+
+ exit (1);
+ }
+
+ if (want_exists)
+ return 0; /* if we got here, all the packages existed. */
+
+ if (want_uninstalled)
+ {
+ /* See if > 0 pkgs (including dependencies recursively) were uninstalled */
+ GSList *tmp;
+ tmp = packages;
+ while (tmp != NULL)
+ {
+ Package *pkg = tmp->data;
+
+ if (pkg_uninstalled (pkg))
+ return 0;
+
+ tmp = g_slist_next (tmp);
+ }
+
+ return 1;
+ }
+
+ if (want_version)
+ {
+ GSList *tmp;
+ tmp = packages;
+ while (tmp != NULL)
+ {
+ Package *pkg = tmp->data;
+
+ printf ("%s\n", pkg->version);
+
+ tmp = g_slist_next (tmp);
+ }
+ }
+
+ if (want_provides)
+ {
+ GSList *tmp;
+ tmp = packages;
+ while (tmp != NULL)
+ {
+ Package *pkg = tmp->data;
+ char *key;
+ key = pkg->key;
+ while (*key == '/')
+ key++;
+ if (strlen(key) > 0)
+ printf ("%s = %s\n", key, pkg->version);
+ tmp = g_slist_next (tmp);
+ }
+ }
+
+ if (want_requires)
+ {
+ GSList *pkgtmp;
+ for (pkgtmp = packages; pkgtmp != NULL; pkgtmp = g_slist_next (pkgtmp))
+ {
+ Package *pkg = pkgtmp->data;
+ GSList *reqtmp;
+
+ /* process Requires: */
+ for (reqtmp = pkg->requires; reqtmp != NULL; reqtmp = g_slist_next (reqtmp))
+ {
+ Package *deppkg = reqtmp->data;
+ RequiredVersion *req;
+ req = g_hash_table_lookup(pkg->required_versions, deppkg->key);
+ if ((req == NULL) || (req->comparison == ALWAYS_MATCH))
+ printf ("%s\n", deppkg->key);
+ else
+ printf ("%s %s %s\n", deppkg->key,
+ comparison_to_str(req->comparison),
+ req->version);
+ }
+ }
+ }
+ if (want_requires_private)
+ {
+ GSList *pkgtmp;
+ for (pkgtmp = packages; pkgtmp != NULL; pkgtmp = g_slist_next (pkgtmp))
+ {
+ Package *pkg = pkgtmp->data;
+ GSList *reqtmp;
+ /* process Requires.private: */
+ for (reqtmp = pkg->requires_private; reqtmp != NULL; reqtmp = g_slist_next (reqtmp))
+ {
+
+ Package *deppkg = reqtmp->data;
+ RequiredVersion *req;
+
+ if (g_slist_find (pkg->requires, reqtmp->data))
+ continue;
+
+ req = g_hash_table_lookup(pkg->required_versions, deppkg->key);
+ if ((req == NULL) || (req->comparison == ALWAYS_MATCH))
+ printf ("%s\n", deppkg->key);
+ else
+ printf ("%s %s %s\n", deppkg->key,
+ comparison_to_str(req->comparison),
+ req->version);
+ }
+ }
+ }
+
+ /* Print all flags; then print a newline at the end. */
+ need_newline = FALSE;
+
+ if (variable_name)
+ {
+ char *str = packages_get_var (packages, variable_name);
+ printf ("%s", str);
+ g_free (str);
+ need_newline = TRUE;
+ }
+
+ if (want_I_cflags)
+ {
+ char *str = packages_get_I_cflags (packages);
+ printf ("%s ", str);
+ g_free (str);
+ need_newline = TRUE;
+ }
+ else if (want_other_cflags)
+ {
+ char *str = packages_get_other_cflags (packages);
+ printf ("%s ", str);
+ g_free (str);
+ need_newline = TRUE;
+ }
+ else if (want_cflags)
+ {
+ char *str = packages_get_all_cflags (packages);
+ printf ("%s ", str);
+ g_free (str);
+ need_newline = TRUE;
+ }
+
+ if (want_l_libs)
+ {
+ char *str = packages_get_l_libs (packages);
+ printf ("%s ", str);
+ g_free (str);
+ need_newline = TRUE;
+ }
+ else if (want_L_libs)
+ {
+ char *str = packages_get_L_libs (packages);
+ printf ("%s ", str);
+ g_free (str);
+ need_newline = TRUE;
+ }
+ else if (want_other_libs)
+ {
+ char *str = packages_get_other_libs (packages);
+ printf ("%s ", str);
+ g_free (str);
+ need_newline = TRUE;
+ }
+ else if (want_libs)
+ {
+ char *str = packages_get_all_libs (packages);
+ printf ("%s ", str);
+ g_free (str);
+ need_newline = TRUE;
+ }
+
+ if (need_newline)
+ printf ("\n");
+
+ return 0;
+}