Uniform and less verbose startup for all binaries.
authorTeemu Murtola <teemu.murtola@gmail.com>
Sat, 29 Jun 2013 12:24:39 +0000 (15:24 +0300)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Fri, 19 Jul 2013 15:25:43 +0000 (17:25 +0200)
Now all binaries call gmx::ProgramInfo::init() as more or less the first
thing.  Removed set_program_name() as unnecessary, since the above call
does all that.  Make CommandLineModuleManager responsible of also
printing any common startup header, and add a method to suppress this
stderr output in unit tests.

Replace CopyRight() with a less verbose method and move the
responsibility of calling it to parse_common_args().
Added a PCA_STANDALONE flag for parse_common_args() to know when to do
this (can be removed once all programs are part of the wrapper binary).

Left the CopyRight() function still there, in case we want to add a
-license command-line option or similar to print that information.
Currently, it is not called from anywhere.  Removed GMX_NO_CREDITS and
some other unnecessary code from CopyRight().

Most stuff in contrib is broken by this.  There may be more changes
coming to the initialization sequence, and it will be simple to adapt
those programs that people want to get working again, but it is not
worth doing it more than once.

Part of #1209.

Change-Id: I5403dd259ab5f314cce3283aac275a6c26d4818d

14 files changed:
src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/commandline/cmdlinemodulemanager.h
src/gromacs/commandline/tests/cmdlinemodulemanager.cpp
src/gromacs/gmxana/gmx_pme_error.cpp
src/gromacs/gmxlib/copyrite.cpp
src/gromacs/gmxlib/statutil.cpp
src/gromacs/legacyheaders/copyrite.h
src/gromacs/legacyheaders/statutil.h
src/gromacs/trajectoryanalysis/cmdlinerunner.cpp
src/gromacs/utility/programinfo.cpp
src/ngmx/g_xrama.cpp
src/ngmx/ngmx.cpp
src/programs/gmx/gmx.cpp
src/programs/mdrun/mdrun.cpp

index 3bb6f69681c6ae3375aa5dec611b84955dbaa484..642e3588cd2700e9aaece0b0156b5130657d5a6f 100644 (file)
@@ -382,10 +382,12 @@ class CommandLineModuleManager::Impl
          * The pointed module is owned by the \a modules_ container.
          */
         CommandLineHelpModule  *helpModule_;
+        //! Whether all stderr output should be suppressed.
+        bool                    bQuiet_;
 };
 
 CommandLineModuleManager::Impl::Impl(const ProgramInfo &programInfo)
-    : programInfo_(programInfo), helpModule_(NULL)
+    : programInfo_(programInfo), helpModule_(NULL), bQuiet_(false)
 {
 }
 
@@ -427,6 +429,11 @@ CommandLineModuleManager::~CommandLineModuleManager()
 {
 }
 
+void CommandLineModuleManager::setQuiet(bool bQuiet)
+{
+    impl_->bQuiet_ = bQuiet;
+}
+
 void CommandLineModuleManager::addModule(CommandLineModulePointer module)
 {
     GMX_ASSERT(impl_->modules_.find(module->name()) == impl_->modules_.end(),
@@ -447,12 +454,19 @@ int CommandLineModuleManager::run(int argc, char *argv[])
     int argOffset = 0;
     CommandLineModuleMap::const_iterator module
         = impl_->findModuleFromBinaryName(impl_->programInfo_);
+    if (!impl_->bQuiet_)
+    {
+        printBinaryInformation(stderr, impl_->programInfo_);
+    }
     if (module == impl_->modules_.end())
     {
         if (argc < 2)
         {
             impl_->helpModule_->printUsage();
-            gmx_thanx(stderr);
+            if (!impl_->bQuiet_)
+            {
+                gmx_thanx(stderr);
+            }
             return 2;
         }
         module    = impl_->findModuleByName(argv[1]);
@@ -462,11 +476,17 @@ int CommandLineModuleManager::run(int argc, char *argv[])
     {
         fprintf(stderr, "Unknown command: '%s'\n\n", argv[1]);
         impl_->helpModule_->printUsage();
-        gmx_thanx(stderr);
+        if (!impl_->bQuiet_)
+        {
+            gmx_thanx(stderr);
+        }
         return 2;
     }
     int rc = module->second->run(argc - argOffset, argv + argOffset);
-    gmx_thanx(stderr);
+    if (!impl_->bQuiet_)
+    {
+        gmx_thanx(stderr);
+    }
     return rc;
 }
 
index d2fc744a1e7ff6dbfaa495ffef971c3cc55a12b6..11198b8dd416bac8cdec3e5683d8ce7fc80bdb4b 100644 (file)
@@ -67,7 +67,6 @@ typedef gmx_unique_ptr<CommandLineModuleInterface>::type
    {
        const gmx::ProgramInfo &programInfo =
            gmx::ProgramInfo::init("gmx", argc, argv);
-       CopyRight(stderr, argv[0]);
        try
        {
            gmx::CommandLineModuleManager manager(programInfo);
@@ -100,6 +99,18 @@ class CommandLineModuleManager
         explicit CommandLineModuleManager(const ProgramInfo &programInfo);
         ~CommandLineModuleManager();
 
+        /*! \brief
+         * Sets the module manager to quiet mode: don't print anything.
+         *
+         * \param[in] bQuiet  Whether the module manager should remain silent.
+         *
+         * Normally, the module manager prints out some information to stderr
+         * before it starts the module and after it finishes.  This removes
+         * that output, which is useful in particular for unit tests so that
+         * they don't spam stderr.
+         */
+        void setQuiet(bool bQuiet);
+
         /*! \brief
          * Adds a given module to this manager.
          *
index 594910425198cbc2a04046c43e1738ccdfa0b0a0..a32e1cdb02ad74267c3d47f51d41ad5b2637350b 100644 (file)
@@ -116,6 +116,7 @@ void CommandLineModuleManagerTest::initManager(const CommandLine &args)
     manager_.reset();
     programInfo_.reset(new gmx::ProgramInfo("g_test", args.argc(), args.argv()));
     manager_.reset(new gmx::CommandLineModuleManager(*programInfo_));
+    manager_->setQuiet(true);
 }
 
 MockModule &
index ed92c87dbb20868244934dbbb1992d5cc4c8340d..88b9d261638930ff4b6b8f8a87cbf784e4efbb13 100644 (file)
@@ -52,6 +52,8 @@
 #include "main.h"
 #include "macros.h"
 
+#include "gromacs/utility/programinfo.h"
+
 /* We use the same defines as in mvdata.c here */
 #define  block_bc(cr,   d) gmx_bcast(     sizeof(d),     &(d), (cr))
 #define nblock_bc(cr, nr, d) gmx_bcast((nr)*sizeof((d)[0]), (d), (cr))
@@ -1122,17 +1124,13 @@ int gmx_pme_error(int argc, char *argv[])
 #define NFILE asize(fnm)
 
     cr = init_par(&argc, &argv);
+    gmx::ProgramInfo::init(argc, argv);
 
 #ifdef GMX_LIB_MPI
     MPI_Barrier(MPI_COMM_WORLD);
 #endif
 
-    if (MASTER(cr))
-    {
-        CopyRight(stderr, argv[0]);
-    }
-
-    PCA_Flags  = PCA_NOEXIT_ON_ARGS;
+    PCA_Flags  = PCA_NOEXIT_ON_ARGS | PCA_STANDALONE;
     PCA_Flags |= (MASTER(cr) ? 0 : PCA_QUIET);
 
     parse_common_args(&argc, argv, PCA_Flags,
index 36ca65246613159d130628fe06e22d91eed24690..fdb7de8da9cd95ad801a718a062a5f3b8d5eedbc 100644 (file)
@@ -59,6 +59,7 @@
 #include "gromacs/legacyheaders/vec.h"
 
 #include "gromacs/fft/fft.h"
+#include "gromacs/utility/programinfo.h"
 
 #include "buildinfo.h"
 
@@ -177,9 +178,9 @@ void cool_quote(char *retstring, int retsize, int *cqnum)
     sfree(tmpstr);
 }
 
-void CopyRight(FILE *out, const char *szProgram)
+void CopyRight(FILE *out)
 {
-    static const char * CopyrightText[] = {
+    static const char * const CopyrightText[] = {
         "Written by Emile Apol, Rossen Apostolov, Herman J.C. Berendsen,",
         "Aldert van Buuren, Pär Bjelkmar, Rudi van Drunen, Anton Feenstra, ",
         "Gerrit Groenhof, Peter Kasson, Per Larsson, Pieter Meulenhoff, ",
@@ -187,22 +188,18 @@ void CopyRight(FILE *out, const char *szProgram)
         "Michael Shirts, Alfons Sijbers, Peter Tieleman,\n",
         "Berk Hess, David van der Spoel, and Erik Lindahl.\n",
         "Copyright (c) 1991-2000, University of Groningen, The Netherlands.",
-        "Copyright (c) 2001-2010, The GROMACS development team at",
+        "Copyright (c) 2001-2013, The GROMACS development team at",
         "Uppsala University & The Royal Institute of Technology, Sweden.",
         "check out http://www.gromacs.org for more information.\n"
     };
 
-    static const char * LicenseText[] = {
+    static const char * const LicenseText[] = {
         "This program is free software; you can redistribute it and/or",
         "modify it under the terms of the GNU Lesser General Public License",
         "as published by the Free Software Foundation; either version 2.1",
         "of the License, or (at your option) any later version."
     };
 
-    /* Dont change szProgram arbitrarily - it must be argv[0], i.e. the
-     * name of a file. Otherwise, we won't be able to find the library dir.
-     */
-
 #define NCR (int)asize(CopyrightText)
 /* TODO: Is this exception still needed? */
 #ifdef GMX_FAHCORE
@@ -211,15 +208,9 @@ void CopyRight(FILE *out, const char *szProgram)
 #define NLICENSE (int)asize(LicenseText)
 #endif
 
-    char buf[256], tmpstr[1024];
+    char tmpstr[1024];
     int  i;
 
-#ifdef GMX_FAHCORE
-    set_program_name("Gromacs");
-#else
-    set_program_name(szProgram);
-#endif
-
     ster_print(out, "G  R  O  M  A  C  S");
     fprintf(out, "\n");
 
@@ -227,20 +218,6 @@ void CopyRight(FILE *out, const char *szProgram)
     sp_print(out, tmpstr);
     fprintf(out, "\n");
 
-    ster_print(out, GromacsVersion());
-    fprintf(out, "\n");
-
-    if (getenv("GMX_NO_CREDITS"))
-    {
-        return;
-    }
-
-    /* fprintf(out,"\n");*/
-
-    /* sp_print(out,"PLEASE NOTE: THIS IS A BETA VERSION\n");
-
-       fprintf(out,"\n"); */
-
     for (i = 0; (i < NCR); i++)
     {
         sp_print(out, CopyrightText[i]);
@@ -249,15 +226,6 @@ void CopyRight(FILE *out, const char *szProgram)
     {
         sp_print(out, LicenseText[i]);
     }
-
-    fprintf(out, "\n");
-
-    snprintf(buf, 256, "%s", Program());
-#ifdef GMX_DOUBLE
-    strcat(buf, " (double precision)");
-#endif
-    ster_print(out, buf);
-    fprintf(out, "\n");
 }
 
 
@@ -710,5 +678,23 @@ void gmx_print_version_info(FILE *fp)
 #ifdef GMX_GPU
     gmx_print_version_info_gpu(fp);
 #endif
+}
+
+namespace gmx
+{
 
+void printBinaryInformation(FILE *fp, const ProgramInfo &programInfo)
+{
+    const char *precisionString = "";
+#ifdef GMX_DOUBLE
+    precisionString = " (double precision)";
+#endif
+    const std::string &name = programInfo.programName();
+    fprintf(fp, "GROMACS:    %s, %s%s\n", name.c_str(),
+            GromacsVersion(), precisionString);
+    fprintf(fp, "Executable: %s\n", programInfo.programNameWithPath().c_str());
+    fprintf(fp, "Command line:\n  %s\n", programInfo.commandLine().c_str());
+    fprintf(fp, "\n");
 }
+
+} // namespace gmx
index 15453727731fc029f4b7fa5895deac217fb556dc..281f969e958aa5a1ccddde0080c41e532db86c0e 100644 (file)
@@ -114,13 +114,6 @@ const char *command_line(void)
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 }
 
-void set_program_name(const char *argvzero)
-{
-    // The negative argc is a hack to make the ProgramInfo overridable in
-    // parse_common_args(), where the full command-line is known.
-    gmx::ProgramInfo::init(-1, &argvzero);
-}
-
 /* utility functions */
 
 gmx_bool bRmod_fd(double a, double b, double c, gmx_bool bDouble)
@@ -580,11 +573,20 @@ void parse_common_args(int *argc, char *argv[], unsigned long Flags,
     };
 #define NPCA_PA asize(pca_pa)
     FILE    *fp;
-    gmx_bool bPrint, bExit, bXvgr;
+    gmx_bool bExit, bXvgr;
     int      i, j, k, npall, max_pa;
 
+    // Handle the flags argument, which is a bit field
+    // The FF macro returns whether or not the bit is set
 #define FF(arg) ((Flags & arg) == arg)
 
+    // Ensure that the program info is initialized; if already done, returns
+    // the already initialized object.
+    const gmx::ProgramInfo &programInfo = gmx::ProgramInfo::init(*argc, argv);
+    if (FF(PCA_STANDALONE))
+    {
+        gmx::printBinaryInformation(stderr, programInfo);
+    }
     /* Check for double arguments */
     for (i = 1; (i < *argc); i++)
     {
@@ -610,12 +612,6 @@ void parse_common_args(int *argc, char *argv[], unsigned long Flags,
         }
     }
     debug_gmx();
-    gmx::ProgramInfo::init(*argc, argv);
-
-    /* Handle the flags argument, which is a bit field
-     * The FF macro returns whether or not the bit is set
-     */
-    bPrint        = !FF(PCA_SILENT);
 
     /* Check ALL the flags ... */
     max_pa = NPCA_PA + EXTRA_PA + npargs+1;
@@ -797,7 +793,7 @@ void parse_common_args(int *argc, char *argv[], unsigned long Flags,
             write_man(stderr, "help", output_env_get_program_name(*oenv),
                       ndesc, desc, nfile, fnm, npall, all_pa, nbugs, bugs, bHidden);
         }
-        else if (bPrint)
+        else
         {
             pr_fns(stderr, nfile, fnm);
             print_pargs(stderr, npall, all_pa, FALSE);
index 28ab375239f01ec347cb4527e8ab946af55e58d7..e3830bb8af877acd4160558136cc85936438d561 100644 (file)
@@ -47,10 +47,6 @@ const char *GromacsVersion(void);
 void
 gmx_print_version_info(FILE *fp);
 
-void
-CopyRight(FILE *out, const char *szProgram);
-
-
 /* For both bromacs() and cool_quote() you have to provide a pointer to
  * a string of reasonable length (say 256) and the string length. This
  * is necessary to make the routines threadsafe and avoid allocating
@@ -74,6 +70,22 @@ please_cite(FILE *fp, const char *key);
 
 #ifdef __cplusplus
 }
+
+namespace gmx
+{
+
+class ProgramInfo;
+
+/*! \brief
+ * Print basic information about the executable.
+ *
+ * \param     fp           Where to print the information to.
+ * \param[in] programInfo  Program information object to use.
+ */
+void printBinaryInformation(FILE *fp, const ProgramInfo &programInfo);
+
+} // namespace gmx;
+
 #endif
 
 #endif  /* _copyright_h */
index d20669c43ff76c00592141a1cb8fdd9c74ea4437..1cb66a27909f1b69d5eb6004bf8f66d00f7b302e 100644 (file)
@@ -89,7 +89,6 @@ const char *command_line(void);
  * directory from its location!
  */
 const char *Program(void);
-void set_program_name(const char *argvzero);
 /* Id. without leading directory */
 const char *ShortProgram(void);
 
@@ -256,8 +255,8 @@ t_topology *read_top(const char *fn, int *ePBC);
 /* set time unit for output */
 #define PCA_KEEP_ARGS      (1<<8)
 /* keep parsed args in argv (doesn't make sense without NOEXIT_ON_ARGS) */
-#define PCA_SILENT         (1<<9)
-/* don't print options by default */
+#define PCA_STANDALONE     (1<<9)
+/* add options for standalone programs and print a header */
 #define PCA_CAN_SET_DEFFNM (1<<10)
 /* does something for non-master mdrun nodes */
 #define PCA_NOEXIT_ON_ARGS (1<<11)
index 9c1c737d3407385fe2b8d3610cfb8be3be188f48..2e7c1f27b6b7c19595e44e6bfdafaecbca4cf8c6 100644 (file)
@@ -63,6 +63,7 @@
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/file.h"
 #include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/programinfo.h"
 
 namespace gmx
 {
@@ -215,7 +216,7 @@ TrajectoryAnalysisCommandLineRunner::run(int argc, char *argv[])
 
     if (impl_->bStandalone_)
     {
-        CopyRight(stderr, argv[0]);
+        printBinaryInformation(stderr, ProgramInfo::getInstance());
     }
 
     SelectionCollection  selections;
index b00d6a9c47b097f8d9d6f59b9d573d2b45af0205..0e42df125091d03ba0abd47cd4c0794ec4e198b3 100644 (file)
@@ -68,8 +68,6 @@ namespace
 {
 //! Mutex for updates to the global program info objects.
 tMPI::mutex                    g_programInfoMutex;
-//! Partially filled program info, needed to support set_program_name().
-boost::scoped_ptr<ProgramInfo> g_partialProgramInfo;
 //! Global program info; stores the object initialized with ProgramInfo::init().
 boost::scoped_ptr<ProgramInfo> g_programInfo;
 }   // namespace
@@ -154,10 +152,6 @@ const ProgramInfo &ProgramInfo::getInstance()
     tMPI::lock_guard<tMPI::mutex> lock(g_programInfoMutex);
     if (g_programInfo.get() == NULL)
     {
-        if (g_partialProgramInfo.get() != NULL)
-        {
-            return *g_partialProgramInfo;
-        }
         static ProgramInfo fallbackInfo;
         return fallbackInfo;
     }
@@ -179,17 +173,6 @@ const ProgramInfo &ProgramInfo::init(const char *realBinaryName,
         tMPI::lock_guard<tMPI::mutex> lock(g_programInfoMutex);
         if (g_programInfo.get() == NULL)
         {
-            // TODO: Remove this hack with negative argc once there is no need for
-            // set_program_name().
-            if (argc < 0)
-            {
-                if (g_partialProgramInfo.get() == NULL)
-                {
-                    g_partialProgramInfo.reset(
-                            new ProgramInfo(realBinaryName, -argc, argv));
-                }
-                return *g_partialProgramInfo;
-            }
             g_programInfo.reset(new ProgramInfo(realBinaryName, argc, argv));
         }
         return *g_programInfo;
index ecc0c6a83780b04fa27ad338fc4fee92cdefc2e6..c7bba8ac1c0ba7691ffa0bff5359ed4207d2a4dc 100644 (file)
@@ -50,6 +50,8 @@
 #include "rama.bm"
 #include "nrama.h"
 
+#include "gromacs/utility/programinfo.h"
+
 #define MAXDEG 360
 
 enum {
@@ -358,9 +360,9 @@ int main(int argc, char *argv[])
     };
 #define NFILE asize(fnm)
 
-    CopyRight(stderr, argv[0]);
-    parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm, 0, NULL,
-                      asize(desc), desc, 0, NULL, &oenv);
+    gmx::ProgramInfo::init(argc, argv);
+    parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_STANDALONE, NFILE, fnm,
+                      0, NULL, asize(desc), desc, 0, NULL, &oenv);
 
 
     if ((x11 = GetX11(&argc, argv)) == NULL)
index b428c0b0df650e07332547e886b7a6f6fd417577..112f19d230a464a07be361ed816fe715ad0500a3 100644 (file)
@@ -305,8 +305,8 @@ int main(int argc, char *argv[])
     };
 #define NFILE asize(fnm)
 
-    CopyRight(stderr, argv[0]);
-    parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm,
+    gmx::ProgramInfo::init(argc, argv);
+    parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_STANDALONE, NFILE, fnm,
                       0, NULL, asize(desc), desc, asize(bugs), bugs, &oenv);
 
     if ((x11 = GetX11(&argc, argv)) == NULL)
index 160748853b231f1f481d2b233c8d77e7b5f0459d..c4d21abe5efa63abdc6bfc023448db80451013f7 100644 (file)
@@ -37,8 +37,6 @@
  *
  * \author Teemu Murtola <teemu.murtola@gmail.com>
  */
-#include "gromacs/legacyheaders/copyrite.h"
-
 #include "gromacs/commandline/cmdlinemodulemanager.h"
 #include "gromacs/selection/selectioncollection.h"
 #include "gromacs/trajectoryanalysis/modules.h"
@@ -52,9 +50,6 @@ main(int argc, char *argv[])
 {
     const gmx::ProgramInfo &info =
         gmx::ProgramInfo::init("gmx", argc, argv);
-    // TODO: With the addition of ProgramInfo above, this no longer needs to
-    // be here, so think where it would best go.
-    CopyRight(stderr, argv[0]);
     try
     {
         gmx::CommandLineModuleManager manager(info);
index 9c6fff96b38e166cb54d21b69aa980d9a66c4cc1..ead14cf8ea3bec1b9b79bb750d0c30f6e98b2676 100644 (file)
@@ -51,6 +51,8 @@
 #include "gromacs/legacyheaders/statutil.h"
 #include "gromacs/legacyheaders/typedefs.h"
 
+#include "gromacs/utility/programinfo.h"
+
 int main(int argc, char *argv[])
 {
     const char   *desc[] = {
@@ -550,13 +552,9 @@ int main(int argc, char *argv[])
 
 
     cr = init_par(&argc, &argv);
+    gmx::ProgramInfo::init(argc, argv);
 
-    if (MASTER(cr))
-    {
-        CopyRight(stderr, argv[0]);
-    }
-
-    PCA_Flags = (PCA_CAN_SET_DEFFNM | (MASTER(cr) ? 0 : PCA_QUIET));
+    PCA_Flags = (PCA_CAN_SET_DEFFNM | PCA_STANDALONE | (MASTER(cr) ? 0 : PCA_QUIET));
 
     /* Comment this in to do fexist calls only on master
      * works not with rerun or tables at the moment
@@ -704,7 +702,6 @@ int main(int argc, char *argv[])
     {
         gmx_log_open(ftp2fn(efLOG, NFILE, fnm), cr,
                      !bSepPot, Flags & MD_APPENDFILES, &fplog);
-        CopyRight(fplog, argv[0]);
         please_cite(fplog, "Hess2008b");
         please_cite(fplog, "Spoel2005a");
         please_cite(fplog, "Lindahl2001a");