Repository: bitcoin/bitcoin
File: src/bitcoin.cpp (C++)

Code before:

#ifdef WIN32
#include <process.h>
#include <windows.h>
#define execvp _execvp
#else
#include <unistd.h>
#endif

extern const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;

static constexpr auto HELP_USAGE = R"(Usage: %1$s [OPTIONS] COMMAND...

Commands (run help command for more information):
  {gui,daemon,rpc,wallet,test,help}

Options:
  -m, --multiprocess     Run multiprocess binaries bitcoin-node, bitcoin-gui.\n"
  -M, --monolothic       Run monolithic binaries bitcoind, bitcoin-qt. (Default behavior)\n"
  -v, --version          Show version information
  -h, --help             Show this help message
)";

static constexpr auto HELP_COMMANDS = R"(Command overview:

%1$s gui [ARGS]     Start GUI, equivalent to running 'bitcoin-qt [ARGS]' or 'bitcoin-gui [ARGS]'.
%1$s daemon [ARGS]  Start daemon, equivalent to running 'bitcoind [ARGS]' or 'bitcoin-node [ARGS]'.
%1$s rpc [ARGS]     Call RPC method, equivalent to running 'bitcoin-cli -named [ARGS]'.
%1$s wallet [ARGS]  Call wallet command, equivalent to running 'bitcoin-wallet [ARGS]'.
%1$s tx [ARGS]      Manipulate hex-encoded transactions, equivalent to running 'bitcoin-tx [ARGS]'.
%1$s test [ARGS]    Run unit tests, equivalent to running 'test_bitcoin [ARGS]'.
%1$s help           Show this help message.
)";

struct CommandLine {
    bool use_multiprocess{false};
    bool show_version{false};
    bool show_help{false};
    std::string_view command;
    std::vector<std::string_view> args;
};

CommandLine ParseCommandLine(int argc, char* argv[]);
void ExecCommand(const std::vector<std::string>& args, std::string_view argv0);

int main(int argc, char* argv[])
{
    try {
        CommandLine cmd{ParseCommandLine(argc, argv)};
        if (cmd.show_version) {
            tfm::format(std::cout, "%s version %s\n%s", CLIENT_NAME, FormatFullVersion(), FormatParagraph(LicenseInfo()));

Review comment (suggestion):
So, the user must have a knowledge whether his Bitcoin Core was compiled with or without multiprocess and start either `bitcoin -M gui` or `bitcoin -m gui`. Could we spare them this? The `bitcoin` executable has that knowledge.

Then the user can run just `bitcoin gui` and under the hood either `bitcoin-qt` or `bitcoin-gui` will be executed, depending on how it was compiled? Or maybe we can probe at run time whether the executables `bitcoin-qt` and `bitcoin-gui` exist and run whichever is present.

Code after:
#include <vector>

const TranslateFn G_TRANSLATION_FUN{nullptr};

static constexpr auto HELP_USAGE = R"(Usage: %s [OPTIONS] COMMAND...

Options:
  -m, --multiprocess     Run multiprocess binaries bitcoin-node, bitcoin-gui.
  -M, --monolithic       Run monolithic binaries bitcoind, bitcoin-qt. (Default behavior)
  -v, --version          Show version information
  -h, --help             Show this help message

Commands:
  gui [ARGS]     Start GUI, equivalent to running 'bitcoin-qt [ARGS]' or 'bitcoin-gui [ARGS]'.
  node [ARGS]    Start node, equivalent to running 'bitcoind [ARGS]' or 'bitcoin-node [ARGS]'.
  rpc [ARGS]     Call RPC method, equivalent to running 'bitcoin-cli -named [ARGS]'.
  wallet [ARGS]  Call wallet command, equivalent to running 'bitcoin-wallet [ARGS]'.
  tx [ARGS]      Manipulate hex-encoded transactions, equivalent to running 'bitcoin-tx [ARGS]'.
  help [-a]      Show this help message. Include -a or --all to show additional commands.
)";

static constexpr auto HELP_EXTRA = R"(
Additional less commonly used commands:
  bench [ARGS]      Run bench command, equivalent to running 'bench_bitcoin [ARGS]'.
  chainstate [ARGS] Run bitcoin kernel chainstate util, equivalent to running 'bitcoin-chainstate [ARGS]'.
  test [ARGS]       Run unit tests, equivalent to running 'test_bitcoin [ARGS]'.
  test-gui [ARGS]   Run GUI unit tests, equivalent to running 'test_bitcoin-qt [ARGS]'.
)";

struct CommandLine {
    bool use_multiprocess{false};
    bool show_version{false};
    bool show_help{false};
    bool show_help_all{false};
    std::string_view command;
    std::vector<const char*> args;
};

CommandLine ParseCommandLine(int argc, char* argv[]);
static void ExecCommand(const std::vector<const char*>& args, std::string_view argv0);

int main(int argc, char* argv[])
{
    try {
        CommandLine cmd{ParseCommandLine(argc, argv)};
        if (cmd.show_version) {
            tfm::format(std::cout, "%s version %s\n%s", CLIENT_NAME, FormatFullVersion(), FormatParagraph(LicenseInfo()));
            return EXIT_SUCCESS;
        }

        std::vector<const char*> args;