1147 lines
28 KiB
C
1147 lines
28 KiB
C
/* pikatool in C
|
|
* Copyright (C) 2001-2007 Tor Lillqvist
|
|
*
|
|
* 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 3 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, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* Pikatool rewritten in C, originally for Win32, where end-users who
|
|
* might want to build and install a plug-in from source don't
|
|
* necessarily have any Bourne-compatible shell to run the pikatool
|
|
* script in. Later fixed up to replace the pikatool script on all
|
|
* platforms.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <gio/gio.h>
|
|
|
|
#include "libpikabase/pikabase.h"
|
|
|
|
#ifdef G_OS_WIN32
|
|
#include "libpikabase/pikawin32-io.h"
|
|
#endif
|
|
|
|
|
|
static gboolean silent = FALSE;
|
|
static gboolean dry_run = FALSE;
|
|
static const gchar *cli_prefix;
|
|
static const gchar *cli_exec_prefix;
|
|
|
|
static gboolean msvc_syntax = FALSE;
|
|
static const gchar *env_cc;
|
|
static const gchar *env_cflags;
|
|
static const gchar *env_ldflags;
|
|
static const gchar *env_libs;
|
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
#define EXEEXT ".exe"
|
|
#else
|
|
#define EXEEXT ""
|
|
#endif
|
|
|
|
#ifdef G_OS_WIN32
|
|
#define COPY win32_command ("copy")
|
|
#define REMOVE win32_command ("del")
|
|
#define REMOVE_DIR win32_command ("rd /s /q")
|
|
#else
|
|
#define COPY "cp"
|
|
#define REMOVE "rm -f"
|
|
#define REMOVE_DIR "rm -Rf"
|
|
#endif
|
|
|
|
static struct {
|
|
const gchar *option;
|
|
const gchar *value;
|
|
} dirs[] = {
|
|
{ "prefix", PREFIX },
|
|
{ "exec-prefix", EXEC_PREFIX },
|
|
{ "bindir", BINDIR },
|
|
{ "sbindir", SBINDIR },
|
|
{ "libexecdir", LIBEXECDIR },
|
|
{ "datadir", DATADIR },
|
|
{ "datarootdir", DATAROOTDIR },
|
|
{ "sysconfdir", SYSCONFDIR },
|
|
{ "sharedstatedir", SHAREDSTATEDIR },
|
|
{ "localstatedir", LOCALSTATEDIR },
|
|
{ "libdir", LIBDIR },
|
|
{ "infodir", INFODIR },
|
|
{ "mandir", MANDIR },
|
|
#if 0
|
|
/* For --includedir we want the includedir of the developer package,
|
|
* not an includedir under the runtime installation prefix.
|
|
*/
|
|
{ "includedir", INCLUDEDIR },
|
|
#endif
|
|
{ "pikaplugindir", PIKAPLUGINDIR },
|
|
{ "pikadatadir", PIKADATADIR }
|
|
};
|
|
|
|
|
|
static void usage (int exit_status) G_GNUC_NORETURN;
|
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
static const gchar *
|
|
win32_command (const gchar *command)
|
|
{
|
|
static gchar *cmd = NULL;
|
|
const gchar *comspec = getenv ("COMSPEC");
|
|
|
|
if (comspec == NULL)
|
|
comspec = "cmd.exe";
|
|
|
|
g_free (cmd);
|
|
cmd = g_strdup_printf ("%s /c %s", comspec, command);
|
|
|
|
return (const gchar *) cmd;
|
|
}
|
|
|
|
#endif
|
|
|
|
static gboolean
|
|
starts_with_dir (const gchar *string,
|
|
const gchar *dir)
|
|
{
|
|
gchar *dirslash = g_strconcat (dir, "/", NULL);
|
|
gboolean retval;
|
|
|
|
retval = (g_str_has_prefix (string, dirslash) ||
|
|
g_strcmp0 (string, dir) == 0);
|
|
g_free (dirslash);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static gchar *
|
|
one_line_output (const gchar *program,
|
|
const gchar *args)
|
|
{
|
|
gchar *command = g_strconcat (program, " ", args, NULL);
|
|
FILE *pipe = popen (command, "r");
|
|
gchar line[4096];
|
|
|
|
if (pipe == NULL)
|
|
{
|
|
g_printerr ("Cannot run '%s'\n", command);
|
|
g_free (command);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
if (fgets (line, sizeof (line), pipe) == NULL)
|
|
line[0] = '\0';
|
|
|
|
if (strlen (line) > 0 && line [strlen (line) - 1] == '\n')
|
|
line [strlen (line) - 1] = '\0';
|
|
if (strlen (line) > 0 && line [strlen (line) - 1] == '\r')
|
|
line [strlen (line) - 1] = '\0';
|
|
|
|
pclose (pipe);
|
|
|
|
if (strlen (line) == 0)
|
|
{
|
|
g_printerr ("No output from '%s'\n", command);
|
|
g_free (command);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
g_free (command);
|
|
|
|
return g_strdup (line);
|
|
}
|
|
|
|
static gchar *
|
|
pkg_config (const gchar *args)
|
|
{
|
|
#ifdef G_OS_WIN32
|
|
if (msvc_syntax)
|
|
return one_line_output ("pkg-config --msvc-syntax", args);
|
|
#endif
|
|
|
|
return one_line_output ("pkg-config", args);
|
|
}
|
|
|
|
static gchar *
|
|
get_runtime_prefix (gchar slash)
|
|
{
|
|
#ifdef G_OS_WIN32
|
|
|
|
/* Don't use the developer package prefix, but deduce the
|
|
* installation-time prefix from where pika-x.y.exe can be found.
|
|
*/
|
|
|
|
gchar *path;
|
|
gchar *p, *r;
|
|
|
|
path = g_find_program_in_path ("pika-" PIKA_APP_VERSION ".exe");
|
|
|
|
if (path == NULL)
|
|
path = g_find_program_in_path ("pika.exe");
|
|
|
|
if (path != NULL)
|
|
{
|
|
r = strrchr (path, G_DIR_SEPARATOR);
|
|
if (r != NULL)
|
|
{
|
|
*r = '\0';
|
|
if (strlen (path) >= 4 &&
|
|
g_ascii_strcasecmp (r - 4, G_DIR_SEPARATOR_S "bin") == 0)
|
|
{
|
|
r[-4] = '\0';
|
|
if (slash == '/')
|
|
{
|
|
/* Use forward slashes, less quoting trouble in Makefiles */
|
|
while ((p = strchr (path, '\\')) != NULL)
|
|
*p = '/';
|
|
}
|
|
return path;
|
|
}
|
|
}
|
|
}
|
|
|
|
g_printerr ("Cannot determine PIKA " PIKA_APP_VERSION " installation location\n");
|
|
|
|
exit (EXIT_FAILURE);
|
|
#else
|
|
/* On Unix assume the executable package is in the same prefix as the developer stuff */
|
|
return pkg_config ("--variable=prefix pika-" PIKA_PKGCONFIG_VERSION);
|
|
#endif
|
|
}
|
|
|
|
static gchar *
|
|
get_exec_prefix (gchar slash)
|
|
{
|
|
#ifdef G_OS_WIN32
|
|
if (cli_exec_prefix != NULL)
|
|
return g_strdup (cli_exec_prefix);
|
|
|
|
/* On Win32, exec_prefix is always same as prefix. Or is it? Maybe not,
|
|
* but at least in tml's prebuilt stuff it is. If somebody else does
|
|
* it another way, feel free to hack this.
|
|
*/
|
|
return get_runtime_prefix (slash);
|
|
#else
|
|
return g_strdup (EXEC_PREFIX);
|
|
#endif
|
|
}
|
|
|
|
static gchar *
|
|
expand_and_munge (const gchar *value)
|
|
{
|
|
gchar *retval;
|
|
|
|
if (starts_with_dir (value, "${prefix}"))
|
|
retval = g_strconcat (PREFIX, value + strlen ("${prefix}"), NULL);
|
|
else if (starts_with_dir (value, "${exec_prefix}"))
|
|
retval = g_strconcat (EXEC_PREFIX, value + strlen ("${exec_prefix}"), NULL);
|
|
else
|
|
retval = g_strdup (value);
|
|
|
|
if (starts_with_dir (retval, EXEC_PREFIX))
|
|
{
|
|
gchar *exec_prefix = get_exec_prefix ('/');
|
|
|
|
retval = g_strconcat (exec_prefix, retval + strlen (EXEC_PREFIX), NULL);
|
|
g_free (exec_prefix);
|
|
}
|
|
|
|
if (starts_with_dir (retval, PREFIX))
|
|
{
|
|
gchar *runtime_prefix = get_runtime_prefix ('/');
|
|
|
|
retval = g_strconcat (runtime_prefix, retval + strlen (PREFIX), NULL);
|
|
g_free (runtime_prefix);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void
|
|
find_out_env_flags (void)
|
|
{
|
|
gchar *p;
|
|
|
|
if ((p = getenv ("CC")) != NULL && *p != '\0')
|
|
env_cc = p;
|
|
else if (msvc_syntax)
|
|
env_cc = "cl -MD";
|
|
else
|
|
env_cc = CC;
|
|
|
|
if (g_ascii_strncasecmp (env_cc, "cl", 2) == 0 &&
|
|
g_ascii_strncasecmp (env_cc, "clang", 5) != 0)
|
|
msvc_syntax = TRUE;
|
|
|
|
if ((p = getenv ("CFLAGS")) != NULL)
|
|
env_cflags = p;
|
|
else
|
|
env_cflags = "";
|
|
|
|
if ((p = getenv ("LDFLAGS")) != NULL)
|
|
env_ldflags = p;
|
|
else
|
|
env_ldflags = "";
|
|
|
|
if ((p = getenv ("LIBS")) != NULL && *p != '\0')
|
|
env_libs = p;
|
|
else
|
|
env_libs = "";
|
|
}
|
|
|
|
static void
|
|
usage (int exit_status)
|
|
{
|
|
g_print ("\
|
|
Usage: pikatool-" PIKA_TOOL_VERSION " [OPTION]...\n\
|
|
\n\
|
|
General options:\n\
|
|
--help print this message\n\
|
|
--quiet, --silent don't echo build commands\n\
|
|
--version print the version of PIKA associated with this script\n\
|
|
-n, --just-print, --dry-run, --recon\n\
|
|
don't actually run any commands; just print them\n\
|
|
Developer options:\n\
|
|
--cflags print the compiler flags that are necessary to\n\
|
|
compile a plug-in\n\
|
|
--libs print the linker flags that are necessary to link a\n\
|
|
plug-in\n\
|
|
--prefix=PREFIX use PREFIX instead of the installation prefix that\n\
|
|
PIKA was built when computing the output for --cflags\n\
|
|
and --libs\n\
|
|
--exec-prefix=PREFIX use PREFIX instead of the installation exec prefix\n\
|
|
that PIKA was built when computing the output for\n\
|
|
--cflags and --libs\n\
|
|
--msvc-syntax print flags in MSVC syntax\n\
|
|
\n\
|
|
Installation directory options:\n\
|
|
--prefix --exec-prefix --bindir --sbindir --libexecdir --datadir --sysconfdir\n\
|
|
--sharedstatedir --localstatedir --libdir --infodir --mandir --includedir\n\
|
|
--pikaplugindir --pikadatadir\n\
|
|
\n\
|
|
The --cflags and --libs options can be appended with -noui to get appropriate\n\
|
|
settings for plug-ins which do not use GTK+.\n\
|
|
\n\
|
|
User options:\n\
|
|
--build plug-in.c build a plug-in from a source file\n\
|
|
--install plug-in.c same as --build, but installs the built\n\
|
|
plug-in as well\n\
|
|
--install-bin plug-in install a compiled plug-in\n\
|
|
--install-script script.scm install a script-fu script\n\
|
|
\n\
|
|
--uninstall-bin plug-in remove a plug-in again\n\
|
|
--uninstall-script plug-in remove a script-fu script\n\
|
|
\n\
|
|
The --install and --uninstall options have \"admin\" counterparts (with\n\
|
|
prefix --install-admin instead of --install) that can be used instead to\n\
|
|
install/uninstall a plug-in or script in the machine directory instead of a\n\
|
|
user directory.\n\
|
|
\n\
|
|
For plug-ins which do not use GTK+, the --build and --install options can be\n\
|
|
appended with -noui for appropriate settings. For plug-ins that use GTK+ but\n\
|
|
not libpikaui, append -nopikaui.\n");
|
|
exit (exit_status);
|
|
}
|
|
|
|
static gchar *
|
|
get_includedir (void)
|
|
{
|
|
return pkg_config ("--variable=includedir pika-" PIKA_PKGCONFIG_VERSION);
|
|
}
|
|
|
|
static void
|
|
do_includedir (void)
|
|
{
|
|
gchar *includedir = get_includedir ();
|
|
|
|
g_print ("%s\n", includedir);
|
|
g_free (includedir);
|
|
}
|
|
|
|
static gchar *
|
|
get_cflags (void)
|
|
{
|
|
return pkg_config ("--cflags pikaui-" PIKA_PKGCONFIG_VERSION);
|
|
}
|
|
|
|
static void
|
|
do_cflags (void)
|
|
{
|
|
gchar *cflags = get_cflags ();
|
|
|
|
g_print ("%s\n", cflags);
|
|
g_free (cflags);
|
|
}
|
|
|
|
static gchar *
|
|
get_cflags_noui (void)
|
|
{
|
|
return pkg_config ("--cflags pika-" PIKA_PKGCONFIG_VERSION);
|
|
}
|
|
|
|
static void
|
|
do_cflags_noui (void)
|
|
{
|
|
gchar *cflags = get_cflags_noui ();
|
|
|
|
g_print ("%s\n", cflags);
|
|
g_free (cflags);
|
|
}
|
|
|
|
static gchar *
|
|
get_cflags_nopikaui (void)
|
|
{
|
|
return pkg_config ("--cflags pika-" PIKA_PKGCONFIG_VERSION " gtk+-3.0");
|
|
}
|
|
|
|
static void
|
|
do_cflags_nopikaui (void)
|
|
{
|
|
gchar *cflags = get_cflags_nopikaui ();
|
|
|
|
g_print ("%s\n", cflags);
|
|
g_free (cflags);
|
|
}
|
|
|
|
static gchar *
|
|
get_libs (void)
|
|
{
|
|
return pkg_config ("--libs pikaui-" PIKA_PKGCONFIG_VERSION);
|
|
}
|
|
|
|
static void
|
|
do_libs (void)
|
|
{
|
|
gchar *libs = get_libs ();
|
|
|
|
g_print ("%s\n", libs);
|
|
g_free (libs);
|
|
}
|
|
|
|
static gchar *
|
|
get_libs_noui (void)
|
|
{
|
|
return pkg_config ("--libs pika-" PIKA_PKGCONFIG_VERSION);
|
|
}
|
|
|
|
static void
|
|
do_libs_noui (void)
|
|
{
|
|
gchar *libs = get_libs_noui ();
|
|
|
|
g_print ("%s\n", libs);
|
|
g_free (libs);
|
|
}
|
|
|
|
static gchar *
|
|
get_libs_nopikaui (void)
|
|
{
|
|
return pkg_config ("--libs pika-" PIKA_PKGCONFIG_VERSION " gtk+-3.0");
|
|
}
|
|
|
|
static void
|
|
do_libs_nopikaui (void)
|
|
{
|
|
gchar *libs = get_libs_nopikaui ();
|
|
|
|
g_print ("%s\n", libs);
|
|
g_free (libs);
|
|
}
|
|
|
|
static void
|
|
maybe_run (gchar *cmd)
|
|
{
|
|
if (!silent)
|
|
g_print ("%s\n", cmd);
|
|
|
|
/* system() declared with attribute warn_unused_result.
|
|
* Trick to get rid of the compilation warning without using the result.
|
|
*/
|
|
if (dry_run || system (cmd))
|
|
;
|
|
}
|
|
|
|
static void
|
|
do_build_2 (const gchar *cflags,
|
|
const gchar *libs,
|
|
const gchar *install_dir,
|
|
const gchar *what)
|
|
{
|
|
const gchar *lang_flag = "";
|
|
const gchar *output_flag;
|
|
const gchar *here_comes_linker_flags = "";
|
|
const gchar *windows_subsystem_flag = "";
|
|
gchar *cmd;
|
|
gchar *dest_dir;
|
|
gchar *dest_exe;
|
|
gchar *source = g_shell_quote (what);
|
|
|
|
gchar *tmp;
|
|
gchar *p, *q;
|
|
|
|
if (install_dir != NULL)
|
|
dest_dir = g_strconcat (install_dir, "/", NULL);
|
|
else
|
|
dest_dir = g_strdup ("");
|
|
|
|
dest_exe = g_strdup (what);
|
|
|
|
p = strrchr (dest_exe, '.');
|
|
if (p == NULL ||
|
|
!(strcmp (p, ".c") == 0 ||
|
|
strcmp (p, ".cc") == 0 ||
|
|
strcmp (p, ".cpp") == 0))
|
|
{
|
|
/* If the file doesn't have a "standard" C/C++ suffix and:
|
|
* 1) if the compiler is known as a C++ compiler, then treat the file as a
|
|
* C++ file if possible.
|
|
* It's known that G++ and Clang++ treat a file as a C file if they are
|
|
* run with the "-x c++" option.
|
|
* 2) if the compiler is known as a C compiler or a multiple-language
|
|
* compiler, then treat the file as a C file if possible.
|
|
* It's known that GCC and Clang treat a file as a C file if they are
|
|
* run with the "-x c" option.
|
|
* TODO We may want to further support compilation with a source file
|
|
* without a standard suffix in more compilers as far as possible.
|
|
*/
|
|
if (strcmp (env_cc, "g++") == 0 ||
|
|
strncmp (env_cc, "g++-", sizeof ("g++-") - 1) == 0 ||
|
|
strcmp (env_cc, "clang++") == 0 ||
|
|
strncmp (env_cc, "clang++-", sizeof ("clang++-") - 1) == 0)
|
|
lang_flag = "-x c++ ";
|
|
else if (strcmp (env_cc, "gcc") == 0 ||
|
|
strncmp (env_cc, "gcc-", sizeof ("gcc-") - 1) == 0)
|
|
{
|
|
/* It's known GCC recognizes .CPP and .cxx, so bypass these suffixes */
|
|
if (p != NULL && strcmp (p, ".CPP") != 0 && strcmp (p, ".cxx") != 0)
|
|
lang_flag = "-x c ";
|
|
}
|
|
else if (strcmp (env_cc, "clang") == 0 ||
|
|
strncmp (env_cc, "clang-", sizeof ("clang-") - 1) == 0)
|
|
{
|
|
/* It's known Clang recognizes .CC, .CPP, .cxx and .CXX,
|
|
* so bypass these suffixes
|
|
*/
|
|
if (p != NULL && strcmp (p, ".CC") != 0 && strcmp (p, ".CPP") != 0 &&
|
|
strcmp (p, ".cxx") != 0 && strcmp (p, ".CXX") != 0)
|
|
lang_flag = "-x c ";
|
|
}
|
|
else
|
|
{
|
|
g_printerr ("The source file (%s) doesn't have a \"standard\" C or C++ suffix, "
|
|
"and the tool failed to confirm the language of the file.\n"
|
|
"Please be explicit about the language of the file "
|
|
"by renaming it with one of the suffixes: .c .cc .cpp\n",
|
|
what);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
if (p)
|
|
*p = '\0';
|
|
q = strrchr (dest_exe, G_DIR_SEPARATOR);
|
|
#ifdef G_OS_WIN32
|
|
{
|
|
gchar *r = strrchr (dest_exe, '/');
|
|
if (r != NULL && (q == NULL || r > q))
|
|
q = r;
|
|
}
|
|
#endif
|
|
if (q == NULL)
|
|
q = dest_exe;
|
|
else
|
|
q++;
|
|
|
|
if (install_dir)
|
|
{
|
|
tmp = dest_dir;
|
|
dest_dir = g_strconcat (dest_dir, q, G_DIR_SEPARATOR_S, NULL);
|
|
g_free (tmp);
|
|
|
|
g_mkdir_with_parents (dest_dir,
|
|
S_IRUSR | S_IXUSR | S_IWUSR |
|
|
S_IRGRP | S_IXGRP |
|
|
S_IROTH | S_IXOTH);
|
|
}
|
|
|
|
tmp = g_strconcat (dest_dir, q, NULL);
|
|
g_free (dest_dir);
|
|
|
|
dest_exe = g_shell_quote (tmp);
|
|
g_free (tmp);
|
|
|
|
if (msvc_syntax)
|
|
{
|
|
output_flag = "-Fe";
|
|
here_comes_linker_flags = " -link";
|
|
windows_subsystem_flag = " -subsystem:windows";
|
|
}
|
|
else
|
|
{
|
|
output_flag = "-o ";
|
|
#ifdef G_OS_WIN32
|
|
windows_subsystem_flag = " -mwindows";
|
|
#endif
|
|
}
|
|
|
|
cmd = g_strdup_printf ("%s %s%s %s %s%s %s%s %s%s %s %s",
|
|
env_cc,
|
|
lang_flag,
|
|
env_cflags,
|
|
cflags,
|
|
output_flag,
|
|
dest_exe,
|
|
source,
|
|
here_comes_linker_flags,
|
|
env_ldflags,
|
|
windows_subsystem_flag,
|
|
libs,
|
|
env_libs);
|
|
|
|
maybe_run (cmd);
|
|
|
|
g_free (dest_exe);
|
|
g_free (source);
|
|
}
|
|
|
|
static void
|
|
do_build (const gchar *what)
|
|
{
|
|
gchar *cflags = get_cflags ();
|
|
gchar *libs = get_libs ();
|
|
|
|
do_build_2 (cflags, libs, NULL, what);
|
|
|
|
g_free (cflags);
|
|
g_free (libs);
|
|
}
|
|
|
|
static void
|
|
do_build_noui (const gchar *what)
|
|
{
|
|
gchar *cflags = get_cflags_noui ();
|
|
gchar *libs = get_libs_noui ();
|
|
|
|
do_build_2 (cflags, libs, NULL, what);
|
|
|
|
g_free (cflags);
|
|
g_free (libs);
|
|
}
|
|
|
|
static void
|
|
do_build_nopikaui (const gchar *what)
|
|
{
|
|
do_build (what);
|
|
}
|
|
|
|
static gchar *
|
|
get_user_plugin_dir (void)
|
|
{
|
|
return g_build_filename (pika_directory (),
|
|
"plug-ins",
|
|
NULL);
|
|
}
|
|
|
|
static gchar *
|
|
get_plugin_dir (const gchar *base_dir,
|
|
const gchar *what)
|
|
{
|
|
gchar *separator, *dot, *plugin_name, *plugin_dir;
|
|
gchar *tmp = g_strdup (what);
|
|
|
|
separator = strrchr (tmp, G_DIR_SEPARATOR);
|
|
#ifdef G_OS_WIN32
|
|
{
|
|
gchar *alt_separator = strrchr (tmp, '/');
|
|
|
|
if (alt_separator != NULL &&
|
|
(separator == NULL || alt_separator > separator))
|
|
{
|
|
separator = alt_separator;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
dot = strrchr (tmp, '.');
|
|
|
|
if (separator)
|
|
plugin_name = separator + 1;
|
|
else
|
|
plugin_name = tmp;
|
|
|
|
if (dot)
|
|
*dot = '\0';
|
|
|
|
plugin_dir = g_strconcat (base_dir,
|
|
G_DIR_SEPARATOR_S,
|
|
plugin_name,
|
|
NULL);
|
|
|
|
g_free (tmp);
|
|
|
|
return plugin_dir;
|
|
}
|
|
|
|
static void
|
|
do_install (const gchar *what)
|
|
{
|
|
gchar *cflags = get_cflags ();
|
|
gchar *libs = get_libs ();
|
|
gchar *dir = get_user_plugin_dir ();
|
|
|
|
do_build_2 (cflags, libs, dir, what);
|
|
|
|
g_free (cflags);
|
|
g_free (libs);
|
|
g_free (dir);
|
|
}
|
|
|
|
static void
|
|
do_install_noui (const gchar *what)
|
|
{
|
|
gchar *cflags = get_cflags_noui ();
|
|
gchar *libs = get_libs_noui ();
|
|
gchar *dir = get_user_plugin_dir ();
|
|
|
|
do_build_2 (cflags, libs, dir, what);
|
|
|
|
g_free (cflags);
|
|
g_free (libs);
|
|
g_free (dir);
|
|
}
|
|
|
|
static void
|
|
do_install_nopikaui (const gchar *what)
|
|
{
|
|
do_install (what);
|
|
}
|
|
|
|
static gchar *
|
|
get_sys_plugin_dir (gboolean forward_slashes)
|
|
{
|
|
gchar *dir;
|
|
|
|
#ifdef G_OS_WIN32
|
|
gchar *rprefix;
|
|
|
|
rprefix = get_runtime_prefix (forward_slashes ? '/' : G_DIR_SEPARATOR);
|
|
|
|
dir = g_build_path (forward_slashes ? "/" : G_DIR_SEPARATOR_S,
|
|
rprefix,
|
|
"lib", "pika",
|
|
PIKA_PLUGIN_VERSION,
|
|
"plug-ins",
|
|
NULL);
|
|
g_free (rprefix);
|
|
#else
|
|
dir = g_build_path (forward_slashes ? "/" : G_DIR_SEPARATOR_S,
|
|
LIBDIR,
|
|
"pika",
|
|
PIKA_PLUGIN_VERSION,
|
|
"plug-ins",
|
|
NULL);
|
|
#endif
|
|
|
|
return dir;
|
|
}
|
|
|
|
static void
|
|
do_install_admin (const gchar *what)
|
|
{
|
|
gchar *cflags = get_cflags ();
|
|
gchar *libs = get_libs ();
|
|
gchar *dir = get_sys_plugin_dir (TRUE);
|
|
|
|
do_build_2 (cflags, libs, dir, what);
|
|
|
|
g_free (cflags);
|
|
g_free (libs);
|
|
g_free (dir);
|
|
}
|
|
|
|
static void
|
|
do_install_admin_noui (const gchar *what)
|
|
{
|
|
gchar *cflags = get_cflags_noui ();
|
|
gchar *libs = get_libs_noui ();
|
|
gchar *dir = get_sys_plugin_dir (TRUE);
|
|
|
|
do_build_2 (cflags, libs, dir, what);
|
|
|
|
g_free (cflags);
|
|
g_free (libs);
|
|
g_free (dir);
|
|
}
|
|
|
|
static void
|
|
do_install_admin_nopikaui (const gchar *what)
|
|
{
|
|
gchar *cflags = get_cflags ();
|
|
gchar *libs = get_libs ();
|
|
gchar *dir = get_sys_plugin_dir (TRUE);
|
|
|
|
do_build_2 (cflags, libs, dir, what);
|
|
|
|
g_free (cflags);
|
|
g_free (libs);
|
|
g_free (dir);
|
|
}
|
|
|
|
static void
|
|
do_install_bin_2 (const gchar *dir,
|
|
const gchar *what)
|
|
{
|
|
gchar *cmd;
|
|
gchar *quoted_src;
|
|
gchar *quoted_dir;
|
|
|
|
gchar *dest_dir = g_strconcat (dir, G_DIR_SEPARATOR_S, NULL);
|
|
|
|
g_mkdir_with_parents (dest_dir,
|
|
S_IRUSR | S_IXUSR | S_IWUSR |
|
|
S_IRGRP | S_IXGRP |
|
|
S_IROTH | S_IXOTH);
|
|
|
|
quoted_src = g_shell_quote (what);
|
|
quoted_dir = g_shell_quote (dest_dir);
|
|
cmd = g_strconcat (COPY, " ", quoted_src, " ", quoted_dir, NULL);
|
|
maybe_run (cmd);
|
|
|
|
g_free (dest_dir);
|
|
g_free (cmd);
|
|
g_free (quoted_src);
|
|
g_free (quoted_dir);
|
|
}
|
|
|
|
static void
|
|
do_install_bin (const gchar *what)
|
|
{
|
|
gchar *dir = get_user_plugin_dir ();
|
|
gchar *plugin_dir = get_plugin_dir (dir, what);
|
|
|
|
do_install_bin_2 (plugin_dir, what);
|
|
|
|
g_free (plugin_dir);
|
|
g_free (dir);
|
|
}
|
|
|
|
static void
|
|
do_install_admin_bin (const gchar *what)
|
|
{
|
|
gchar *dir = get_sys_plugin_dir (FALSE);
|
|
gchar *plugin_dir = get_plugin_dir (dir, what);
|
|
|
|
do_install_bin_2 (dir, what);
|
|
|
|
g_free (plugin_dir);
|
|
g_free (dir);
|
|
}
|
|
|
|
static void
|
|
do_uninstall (const gchar *dir)
|
|
{
|
|
gchar *cmd;
|
|
gchar *quoted_src;
|
|
|
|
quoted_src = g_shell_quote (dir);
|
|
|
|
cmd = g_strconcat (REMOVE_DIR, " ", quoted_src, NULL);
|
|
maybe_run (cmd);
|
|
|
|
g_free (cmd);
|
|
g_free (quoted_src);
|
|
}
|
|
|
|
static void
|
|
do_uninstall_script_2 (const gchar *dir,
|
|
const gchar *what)
|
|
{
|
|
gchar *cmd;
|
|
gchar *quoted_src;
|
|
gchar *src;
|
|
|
|
src = g_strconcat (dir, G_DIR_SEPARATOR_S, what, NULL);
|
|
quoted_src = g_shell_quote (src);
|
|
|
|
cmd = g_strconcat (REMOVE, " ", quoted_src, NULL);
|
|
maybe_run (cmd);
|
|
|
|
g_free (cmd);
|
|
g_free (quoted_src);
|
|
g_free (src);
|
|
}
|
|
|
|
static gchar *
|
|
maybe_append_exe (const gchar *what)
|
|
{
|
|
#ifdef G_OS_WIN32
|
|
gchar *p = strrchr (what, '.');
|
|
|
|
if (p == NULL || g_ascii_strcasecmp (p, ".exe") != 0)
|
|
return g_strconcat (what, ".exe", NULL);
|
|
#endif
|
|
|
|
return g_strdup (what);
|
|
}
|
|
|
|
static void
|
|
do_uninstall_bin (const gchar *what)
|
|
{
|
|
gchar *dir = get_user_plugin_dir ();
|
|
gchar *exe = maybe_append_exe (what);
|
|
gchar *plugin_dir = get_plugin_dir (dir, what);
|
|
|
|
do_uninstall (plugin_dir);
|
|
|
|
g_free (plugin_dir);
|
|
g_free (dir);
|
|
g_free (exe);
|
|
}
|
|
|
|
static void
|
|
do_uninstall_admin_bin (const gchar *what)
|
|
{
|
|
gchar *dir = get_sys_plugin_dir (FALSE);
|
|
gchar *exe = maybe_append_exe (what);
|
|
gchar *plugin_dir = get_plugin_dir (dir, what);
|
|
|
|
do_uninstall (plugin_dir);
|
|
|
|
g_free (plugin_dir);
|
|
g_free (dir);
|
|
g_free (exe);
|
|
}
|
|
|
|
static gchar *
|
|
get_user_script_dir (void)
|
|
{
|
|
return g_build_filename (pika_directory (),
|
|
"scripts",
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
do_install_script (const gchar *what)
|
|
{
|
|
gchar *dir = get_user_script_dir ();
|
|
|
|
do_install_bin_2 (dir, what);
|
|
g_free (dir);
|
|
}
|
|
|
|
static gchar *
|
|
get_sys_script_dir (void)
|
|
{
|
|
gchar *dir;
|
|
gchar *prefix = get_runtime_prefix (G_DIR_SEPARATOR);
|
|
|
|
dir = g_build_filename (prefix, "share", "pika",
|
|
PIKA_PLUGIN_VERSION, "scripts",
|
|
NULL);
|
|
g_free (prefix);
|
|
|
|
return dir;
|
|
}
|
|
|
|
static void
|
|
do_install_admin_script (const gchar *what)
|
|
{
|
|
gchar *dir = get_sys_script_dir ();
|
|
|
|
do_install_bin_2 (dir, what);
|
|
g_free (dir);
|
|
}
|
|
|
|
static void
|
|
do_uninstall_script (const gchar *what)
|
|
{
|
|
gchar *dir = get_user_script_dir ();
|
|
|
|
do_uninstall_script_2 (dir, what);
|
|
g_free (dir);
|
|
}
|
|
|
|
static void
|
|
do_uninstall_admin_script (const gchar *what)
|
|
{
|
|
gchar *dir = get_sys_script_dir ();
|
|
|
|
do_uninstall_script_2 (dir, what);
|
|
g_free (dir);
|
|
}
|
|
|
|
int
|
|
main (int argc,
|
|
char **argv)
|
|
{
|
|
gint argi;
|
|
gint i;
|
|
|
|
if (argc == 1)
|
|
usage (EXIT_SUCCESS);
|
|
|
|
/* First scan for flags that affect our behavior globally, but
|
|
* are still allowed late on the command line.
|
|
*/
|
|
argi = 0;
|
|
while (++argi < argc)
|
|
{
|
|
if (strcmp (argv[argi], "-n") == 0 ||
|
|
strcmp (argv[argi], "--just-print") == 0 ||
|
|
strcmp (argv[argi], "--dry-run") == 0 ||
|
|
strcmp (argv[argi], "--recon") == 0)
|
|
{
|
|
dry_run = TRUE;
|
|
}
|
|
else if (strcmp (argv[argi], "--help") == 0)
|
|
{
|
|
usage (EXIT_SUCCESS);
|
|
}
|
|
else if (g_str_has_prefix (argv[argi], "--prefix="))
|
|
{
|
|
cli_prefix = argv[argi] + strlen ("--prefix=");
|
|
}
|
|
else if (g_str_has_prefix (argv[argi], "--exec-prefix="))
|
|
{
|
|
cli_exec_prefix = argv[argi] + strlen ("--exec_prefix=");
|
|
}
|
|
else if (strcmp (argv[argi], "--msvc-syntax") == 0)
|
|
{
|
|
#ifdef G_OS_WIN32
|
|
msvc_syntax = TRUE;
|
|
#else
|
|
g_printerr ("Ignoring --msvc-syntax\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
find_out_env_flags ();
|
|
|
|
/* Second pass, actually do something. */
|
|
argi = 0;
|
|
while (++argi < argc)
|
|
{
|
|
for (i = 0; i < G_N_ELEMENTS (dirs); i++)
|
|
{
|
|
gchar *test = g_strconcat ("--", dirs[i].option, NULL);
|
|
|
|
if (strcmp (argv[argi], test) == 0)
|
|
{
|
|
g_free (test);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
g_free (test);
|
|
}
|
|
}
|
|
|
|
if (i < G_N_ELEMENTS (dirs))
|
|
{
|
|
gchar *expanded = expand_and_munge (dirs[i].value);
|
|
|
|
g_print ("%s\n", expanded);
|
|
g_free (expanded);
|
|
}
|
|
else if (strcmp (argv[argi], "--quiet") == 0 ||
|
|
strcmp (argv[argi], "--silent") == 0)
|
|
{
|
|
silent = TRUE;
|
|
}
|
|
else if (strcmp (argv[argi], "--version") == 0)
|
|
{
|
|
g_print ("%d.%d.%d\n",
|
|
PIKA_MAJOR_VERSION, PIKA_MINOR_VERSION, PIKA_MICRO_VERSION);
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
else if (strcmp (argv[argi], "-n") == 0 ||
|
|
strcmp (argv[argi], "--just-print") == 0 ||
|
|
strcmp (argv[argi], "--dry-run") == 0 ||
|
|
strcmp (argv[argi], "--recon") == 0)
|
|
; /* Already handled */
|
|
else if (strcmp (argv[argi], "--includedir") == 0)
|
|
do_includedir ();
|
|
else if (strcmp (argv[argi], "--cflags") == 0)
|
|
do_cflags ();
|
|
else if (strcmp (argv[argi], "--cflags-noui") == 0)
|
|
do_cflags_noui ();
|
|
else if (strcmp (argv[argi], "--cflags-nopikaui") == 0)
|
|
do_cflags_nopikaui ();
|
|
else if (strcmp (argv[argi], "--libs") == 0)
|
|
do_libs ();
|
|
else if (strcmp (argv[argi], "--libs-noui") == 0)
|
|
do_libs_noui ();
|
|
else if (strcmp (argv[argi], "--libs-nopikaui") == 0)
|
|
do_libs_nopikaui ();
|
|
else if (g_str_has_prefix (argv[argi], "--prefix="))
|
|
;
|
|
else if (g_str_has_prefix (argv[argi], "--exec-prefix="))
|
|
;
|
|
else if (strcmp (argv[argi], "--msvc-syntax") == 0)
|
|
;
|
|
else if (strcmp (argv[argi], "--build") == 0)
|
|
do_build (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--build-noui") == 0)
|
|
do_build_noui (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--build-nopikaui") == 0)
|
|
do_build_nopikaui (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install") == 0)
|
|
do_install (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install-noui") == 0)
|
|
do_install_noui (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install-nopikaui") == 0)
|
|
do_install_nopikaui (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install-admin") == 0)
|
|
do_install_admin (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install-admin-noui") == 0)
|
|
do_install_admin_noui (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install-admin-nopikaui") == 0)
|
|
do_install_admin_nopikaui (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install-bin") == 0)
|
|
do_install_bin (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install-admin-bin") == 0)
|
|
do_install_admin_bin (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--uninstall-bin") == 0)
|
|
do_uninstall_bin (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--uninstall-admin-bin") == 0)
|
|
do_uninstall_admin_bin (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install-script") == 0)
|
|
do_install_script (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--install-admin-script") == 0)
|
|
do_install_admin_script (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--uninstall-script") == 0)
|
|
do_uninstall_script (argv[++argi]);
|
|
else if (strcmp (argv[argi], "--uninstall-admin-script") == 0)
|
|
do_uninstall_admin_script (argv[++argi]);
|
|
else
|
|
{
|
|
g_printerr ("Unrecognized switch %s\n", argv[argi]);
|
|
usage (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
/*
|
|
* Local Variables:
|
|
* mode: c
|
|
* End:
|
|
*/
|