• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #856

28 Dec 2022 02:00AM UTC coverage: 86.602% (+0.05%) from 86.55%
#856

push

StellarBot
Merge #6119

6119: Update CMakeLists.txt r=hkaiser a=khuck

updating the default APEX version


Co-authored-by: Kevin Huck <khuck@cs.uoregon.edu>

174566 of 201573 relevant lines covered (86.6%)

1876093.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.97
/libs/full/command_line_handling/src/parse_command_line.cpp
1
//  Copyright (c) 2007-2022 Hartmut Kaiser
2
//
3
//  SPDX-License-Identifier: BSL-1.0
4
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6

7
#include <hpx/command_line_handling/parse_command_line.hpp>
8
#include <hpx/command_line_handling_local/parse_command_line_local.hpp>
9
#include <hpx/datastructures/any.hpp>
10
#include <hpx/ini/ini.hpp>
11
#include <hpx/modules/errors.hpp>
12
#include <hpx/modules/filesystem.hpp>
13
#include <hpx/util/from_string.hpp>
14

15
#include <cctype>
16
#include <cstddef>
17
#include <fstream>
18
#include <iostream>
19
#include <stdexcept>
20
#include <string>
21
#include <utility>
22
#include <vector>
23

24
///////////////////////////////////////////////////////////////////////////////
25
namespace hpx { namespace util {
26
    namespace detail {
27

28
        ///////////////////////////////////////////////////////////////////////
29
        // All command line options which are normally formatted as --hpx:foo
30
        // should be usable as --hpx:N:foo, where N is the node number this
31
        // option should be exclusively used for.
32
        bool handle_node_specific_option(std::string const& s, std::size_t node,
×
33
            std::pair<std::string, std::string>& opt)
34
        {
35
            // any option not starting with --hpx: will be handled elsewhere
36
            constexpr char const hpx_prefix[] = "--hpx:";
×
37
            constexpr std::string::size_type const hpx_prefix_len =
×
38
                sizeof(hpx_prefix) - 1;
39

40
            if (s.size() < hpx_prefix_len ||
×
41
                s.compare(0, hpx_prefix_len, hpx_prefix) != 0 ||
×
42
                !std::isdigit(s[hpx_prefix_len]))    // -V557
×
43
            {
44
                return false;
×
45
            }
46

47
            // any --hpx: option without a second ':' is handled elsewhere as
48
            // well
49
            std::string::size_type p = s.find_first_of(':', hpx_prefix_len);
×
50
            if (p == std::string::npos)
×
51
                return false;
×
52

53
            if (hpx::util::from_string<std::size_t>(
×
54
                    s.substr(hpx_prefix_len, p - hpx_prefix_len),
×
55
                    std::size_t(-1)) == node)
×
56
            {
57
                using hpx::local::detail::trim_whitespace;
58

59
                // this option is for the current locality only
60
                std::string::size_type p1 = s.find_first_of('=', p);
×
61
                if (p1 != std::string::npos)
×
62
                {
63
                    // the option has a value
64
                    std::string o(
65
                        "hpx:" + trim_whitespace(s.substr(p + 1, p1 - p - 1)));
×
66
                    std::string v(trim_whitespace(s.substr(p1 + 1)));
×
67
                    opt = std::make_pair(o, v);
×
68
                }
×
69
                else
70
                {
71
                    // no value
72
                    std::string o("hpx:" + trim_whitespace(s.substr(p + 1)));
×
73
                    opt = std::make_pair(o, std::string());
×
74
                }
×
75
                return true;
×
76
            }
77

78
            // This option is specifically not for us, so we return an option
79
            // which will be silently ignored.
80
            opt = std::make_pair(std::string("hpx:ignore"), std::string());
×
81
            return true;
×
82
        }
×
83

84
        ///////////////////////////////////////////////////////////////////////
85
        // Additional command line parser which interprets '@something' as an
86
        // option "options-file" with the value "something". Additionally we
87
        // resolve defined command line option aliases.
88
        struct option_parser : hpx::local::detail::option_parser
89
        {
90
            using base_type = hpx::local::detail::option_parser;
91

92
            option_parser(
×
93
                util::section const& ini, std::size_t node, bool ignore_aliases)
94
              : base_type(ini, ignore_aliases)
×
95
              , node_(node)
×
96
            {
×
97
            }
×
98

99
            std::pair<std::string, std::string> operator()(
×
100
                std::string const& s) const
101
            {
102
                // handle node specific options
103
                std::pair<std::string, std::string> opt;
×
104
                if (handle_node_specific_option(s, node_, opt))
×
105
                    return opt;
×
106

107
                // handle aliasing, if enabled
108
                return static_cast<base_type const&>(*this)(s);
×
109
            }
×
110

111
            std::size_t node_;
112
        };
113

114
        ///////////////////////////////////////////////////////////////////////
115
        // Handle all options from a given config file, parse and add them to
116
        // the given variables_map
117
        bool handle_config_file_options(std::vector<std::string> const& options,
11,305✔
118
            hpx::program_options::options_description const& desc,
119
            hpx::program_options::variables_map& vm, util::section const& rtcfg,
120
            std::size_t node, util::commandline_error_mode error_mode)
121
        {
122
            // add options to parsed settings
123
            if (!options.empty())
11,305✔
124
            {
125
                using hpx::program_options::command_line_parser;
126
                using hpx::program_options::store;
127
                using hpx::program_options::command_line_style::unix_style;
128

129
                util::commandline_error_mode mode =
×
130
                    error_mode & util::commandline_error_mode::ignore_aliases;
×
131
                util::commandline_error_mode notmode =
×
132
                    error_mode & ~util::commandline_error_mode::ignore_aliases;
×
133

134
                store(hpx::local::detail::get_commandline_parser(
×
135
                          command_line_parser(options)
×
136
                              .options(desc)
×
137
                              .style(unix_style)
×
138
                              .extra_parser(hpx::util::detail::option_parser(
×
139
                                  rtcfg, node, as_bool(mode))),
×
140
                          notmode)
×
141
                          .run(),
×
142
                    vm);
×
143
                notify(vm);
×
144
                return true;
×
145
            }
146
            return false;
11,305✔
147
        }
11,305✔
148

149
        // try to find a config file somewhere up the filesystem hierarchy
150
        // starting with the input file path. This allows to use a general
151
        // <app_name>.cfg file for all executables in a certain project.
152
        void handle_generic_config_options(std::string appname,
1,792✔
153
            hpx::program_options::variables_map& vm,
154
            hpx::program_options::options_description const& desc_cfgfile,
155
            util::section const& ini, std::size_t node,
156
            util::commandline_error_mode error_mode)
157
        {
158
            if (appname.empty())
1,792✔
159
                return;
×
160

161
            filesystem::path dir(filesystem::initial_path());
1,792✔
162
            filesystem::path app(appname);
1,792✔
163
            appname = filesystem::basename(app.filename());
1,792✔
164

165
            // walk up the hierarchy, trying to find a file <appname>.cfg
166
            while (!dir.empty())
11,305✔
167
            {
168
                filesystem::path filename = dir / (appname + ".cfg");
11,305✔
169
                util::commandline_error_mode mode = error_mode &
22,610✔
170
                    ~util::commandline_error_mode::report_missing_config_file;
11,305✔
171
                std::vector<std::string> options =
172
                    hpx::local::detail::read_config_file_options(
11,305✔
173
                        filename.string(), mode);
11,305✔
174

175
                bool result = handle_config_file_options(
11,305✔
176
                    options, desc_cfgfile, vm, ini, node, mode);
11,305✔
177
                if (result)
11,305✔
178
                {
179
                    break;    // break on the first options file found
×
180
                }
181

182
                // Boost filesystem and C++17 filesystem behave differently
183
                // here. Boost filesystem returns an empty path for
184
                // "/".parent_path() whereas C++17 filesystem will keep
185
                // returning "/".
186
#if !defined(HPX_FILESYSTEM_HAVE_BOOST_FILESYSTEM_COMPATIBILITY)
187
                auto dir_prev = dir;
11,305✔
188
                dir = dir.parent_path();    // chop off last directory part
11,305✔
189
                if (dir_prev == dir)
11,305✔
190
                    break;
1,792✔
191
#else
192
                dir = dir.parent_path();    // chop off last directory part
193
#endif
194
            }
11,305✔
195
        }
1,792✔
196

197
        // handle all --options-config found on the command line
198
        void handle_config_options(hpx::program_options::variables_map& vm,
1,792✔
199
            hpx::program_options::options_description const& desc_cfgfile,
200
            util::section const& ini, std::size_t node,
201
            util::commandline_error_mode error_mode)
202
        {
203
            using hpx::program_options::options_description;
204
            if (vm.count("hpx:options-file"))
1,792✔
205
            {
206
                std::vector<std::string> const& cfg_files =
×
207
                    vm["hpx:options-file"].as<std::vector<std::string>>();
×
208

209
                for (std::string const& cfg_file : cfg_files)
×
210
                {
211
                    // parse a single config file and store the results
212
                    std::vector<std::string> options =
213
                        hpx::local::detail::read_config_file_options(
×
214
                            cfg_file, error_mode);
×
215

216
                    handle_config_file_options(
×
217
                        options, desc_cfgfile, vm, ini, node, error_mode);
×
218
                }
×
219
            }
×
220
        }
1,792✔
221

222
        hpx::local::detail::options_map compose_all_options(
1,792✔
223
            hpx::runtime_mode mode)
224
        {
225
            using hpx::local::detail::options_type;
226
            using hpx::program_options::value;
227

228
            hpx::local::detail::options_map all_options =
1,792✔
229
                hpx::local::detail::compose_local_options();
1,792✔
230

231
            switch (mode)
1,792✔
232
            {
233
            case runtime_mode::default_:
234
#if defined(HPX_HAVE_NETWORKING)
235
                // clang-format off
236
                all_options[options_type::hpx_options].add_options()
592✔
237
                    ("hpx:worker", "run this instance in worker mode")
238
                    ("hpx:console", "run this instance in console mode")
239
                    ("hpx:connect", "run this instance in worker mode, "
240
                         "but connecting late")
241
                ;
242
#else
243
                all_options[options_type::hpx_options].add_options()
244
                    ("hpx:console", "run this instance in console mode")
245
                ;
246
                // clang-format on
247
#endif
248
                break;
592✔
249

250
#if defined(HPX_HAVE_NETWORKING)
251
            case runtime_mode::worker:
252
            case runtime_mode::console:
253
            case runtime_mode::connect:
254
                // If the runtime for this application is always run in worker
255
                // mode, silently ignore the worker option for hpx_pbs
256
                // compatibility.
257

258
                // clang-format off
259
                all_options[options_type::hidden_options].add_options()
1,192✔
260
                    ("hpx:worker", "run this instance in worker mode")
261
                    ("hpx:console", "run this instance in console mode")
262
                    ("hpx:connect", "run this instance in worker mode, "
263
                        "but connecting late")
264
                ;
265
                // clang-format on
266
                break;
1,192✔
267
#else
268
            case runtime_mode::console:
269
                // clang-format off
270
                all_options[options_type::hidden_options].add_options()
271
                    ("hpx:console", "run this instance in console mode")
272
                ;
273
                // clang-format on
274
                break;
275
#endif
276
            case runtime_mode::local:
277
                break;
8✔
278

279
            case runtime_mode::invalid:
280
            default:
281
                throw hpx::detail::command_line_error(
×
282
                    "Invalid runtime mode specified");
283
            }
284

285
            // Always add the option to start the local runtime
286
            // clang-format off
287
            all_options[options_type::hpx_options].add_options()
1,792✔
288
                ("hpx:local",
289
                  "run this instance in local mode (experimental; certain "
290
                  "functionalities are not available at runtime)")
291
            ;
292
            // clang-format on
293

294
            // general options definitions
295
            // clang-format off
296
            all_options[options_type::hpx_options].add_options()
17,920✔
297
                ("hpx:run-hpx-main",
298
                  "run the hpx_main function, regardless of locality mode")
299
#if defined(HPX_HAVE_NETWORKING)
300
                ("hpx:agas", value<std::string>(),
1,792✔
301
                  "the IP address the AGAS root server is running on, "
302
                  "expected format: `address:port' (default: "
303
                  "127.0.0.1:7910)")
304
                ("hpx:hpx", value<std::string>(),
1,792✔
305
                  "the IP address the HPX parcelport is listening on, "
306
                  "expected format: `address:port' (default: "
307
                  "127.0.0.1:7910)")
308
                ("hpx:nodefile", value<std::string>(),
1,792✔
309
                  "the file name of a node file to use (list of nodes, one "
310
                  "node name per line and core)")
311
                ("hpx:nodes", value<std::vector<std::string> >()->multitoken(),
1,792✔
312
                  "the (space separated) list of the nodes to use (usually "
313
                  "this is extracted from a node file)")
314
                ("hpx:endnodes", "this can be used to end the list of nodes "
315
                  "specified using the option --hpx:nodes")
316
                ("hpx:ifsuffix", value<std::string>(),
1,792✔
317
                  "suffix to append to host names in order to resolve them "
318
                  "to the proper network interconnect")
319
                ("hpx:ifprefix", value<std::string>(),
1,792✔
320
                  "prefix to prepend to host names in order to resolve them "
321
                  "to the proper network interconnect")
322
                ("hpx:iftransform", value<std::string>(),
1,792✔
323
                  "sed-style search and replace (s/search/replace/) used to "
324
                  "transform host names to the proper network interconnect")
325
                ("hpx:force_ipv4", "Force ipv4 for resolving network hostnames")
326
#endif
327
#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
328
                ("hpx:localities", value<std::size_t>(),
1,792✔
329
                  "the number of localities to wait for at application "
330
                  "startup (default: 1)")
331
#endif
332
#if defined(HPX_HAVE_NETWORKING)
333
                ("hpx:node", value<std::size_t>(),
1,792✔
334
                  "number of the node this locality is run on "
335
                  "(must be unique, alternatively: -0, -1, ..., -9)")
336
                ("hpx:ignore-batch-env", "ignore batch environment variables "
337
                 "(implied by --hpx:use-process-mask)")
338
                ("hpx:expect-connecting-localities",
339
                  "this locality expects other localities to dynamically connect "
340
                  "(default: false if the number of localities is equal to one, "
341
                  "true if the number of initial localities is larger than 1)")
342
#endif
343
            ;
344

345
            all_options[options_type::debugging_options].add_options()
5,376✔
346
                ("hpx:debug-agas-log", value<std::string>()->implicit_value("cout"),
1,792✔
347
                  "enable all messages on the AGAS log channel and send all "
348
                  "AGAS logs to the target destination")
349
                ("hpx:debug-parcel-log", value<std::string>()->implicit_value("cout"),
1,792✔
350
                  "enable all messages on the parcel transport log channel and send all "
351
                  "parcel transport logs to the target destination")
352
#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
353
                ("hpx:list-symbolic-names", "list all registered symbolic "
354
                  "names after startup")
355
                ("hpx:list-component-types", "list all dynamic component types "
356
                  "after startup")
357
#endif
358
#if defined(HPX_HAVE_NETWORKING)
359
                ("hpx:list-parcel-ports", "list all available parcel-ports")
360
#endif
361
            ;
362

363
#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
364
            all_options[options_type::counter_options].add_options()
14,336✔
365
                ("hpx:print-counter", value<std::vector<std::string> >()->composing(),
1,792✔
366
                  "print the specified performance counter either repeatedly "
367
                  "and/or at the times specified by --hpx:print-counter-at "
368
                    "(see also option --hpx:print-counter-interval)")
369
                ("hpx:print-counter-reset",
370
                        value<std::vector<std::string> >()->composing(),
1,792✔
371
                  "print the specified performance counter either repeatedly "
372
                  "and/or at the times specified by --hpx:print-counter-at, "
373
                    "reset the counter after the "
374
                    "value is queried (see also option --hpx:print-counter-interval)")
375
                ("hpx:print-counter-interval", value<std::size_t>(),
1,792✔
376
                  "print the performance counter(s) specified with --hpx:print-counter "
377
                  "repeatedly after the time interval (specified in milliseconds) "
378
                  "(default: 0, which means print once at shutdown)")
379
                ("hpx:print-counter-destination", value<std::string>(),
1,792✔
380
                  "print the performance counter(s) specified with --hpx:print-counter "
381
                  "to the given file (default: console (cout), "
382
                  "possible values: 'cout' (console), 'none' (no output), or "
383
                  "any file name")
384
                ("hpx:list-counters", value<std::string>()->implicit_value("minimal"),
1,792✔
385
                  "list the names of all registered performance counters, "
386
                  "possible values:\n"
387
                  "   'minimal' (prints counter name skeletons)\n"
388
                  "   'full' (prints all available counter names)")
389
                ("hpx:list-counter-infos",
390
                    value<std::string>()->implicit_value("minimal"),
1,792✔
391
                  "list the description of all registered performance counters, "
392
                  "possible values:\n"
393
                  "   'minimal' (prints infos for counter name skeletons)\n"
394
                  "   'full' (prints all available counter infos)")
395
                ("hpx:print-counter-format", value<std::string>(),
1,792✔
396
                  "print the performance counter(s) specified with --hpx:print-counter "
397
                  "in a given format (default: normal)")
398
                ("hpx:csv-header",
399
                  "print the performance counter(s) specified with --hpx:print-counter "
400
                  "with header when format specified with --hpx:print-counter-format"
401
                  "is csv or csv-short")
402
                ("hpx:no-csv-header",
403
                  "print the performance counter(s) specified with --hpx:print-counter "
404
                  "without header when format specified with --hpx:print-counter-format"
405
                  "is csv or csv-short")
406
                ("hpx:print-counter-at",
407
                    value<std::vector<std::string> >()->composing(),
1,792✔
408
                  "print the performance counter(s) specified with "
409
                  "--hpx:print-counter (or --hpx:print-counter-reset) at the given "
410
                  "point in time, possible "
411
                  "argument values: 'startup', 'shutdown' (default), 'noshutdown'")
412
                ("hpx:reset-counters",
413
                  "reset all performance counter(s) specified with --hpx:print-counter "
414
                  "after they have been evaluated")
415
                ("hpx:print-counters-locally",
416
                  "each locality prints only its own local counters")
417
                ("hpx:print-counter-types",
418
                  "append counter type description to generated output")
419
            ;
420
#endif
421
            // clang-format on
422

423
            return all_options;
1,792✔
424
        }
1,792✔
425
    }    // namespace detail
426

427
    ///////////////////////////////////////////////////////////////////////////
428
    // parse the command line
429
    bool parse_commandline(util::section const& rtcfg,
1,792✔
430
        hpx::program_options::options_description const& app_options,
431
        std::string const& arg0, std::vector<std::string> const& args,
432
        hpx::program_options::variables_map& vm, std::size_t node,
433
        util::commandline_error_mode error_mode, hpx::runtime_mode mode,
434
        hpx::program_options::options_description* visible,
435
        std::vector<std::string>* unregistered_options)
436
    {
437
        using hpx::local::detail::options_type;
438

439
        try
440
        {
441
            // construct the overall options description and parse the
442
            // command line
443
            hpx::local::detail::options_map all_options =
444
                detail::compose_all_options(mode);
1,792✔
445

446
            hpx::local::detail::compose_all_options(app_options, all_options);
1,792✔
447

448
#if defined(HPX_HAVE_DISTRIBUTED_RUNTIME)
449
            all_options[options_type::desc_cmdline].add(
3,584✔
450
                all_options[options_type::counter_options]);
1,792✔
451
            all_options[options_type::desc_cfgfile].add(
3,584✔
452
                all_options[options_type::counter_options]);
1,792✔
453
#endif
454
            bool result = hpx::local::detail::parse_commandline(rtcfg,
3,584✔
455
                all_options, app_options, args, vm, error_mode, visible,
1,792✔
456
                unregistered_options);
1,792✔
457

458
            if (result && visible != nullptr)
1,792✔
459
            {
460
                (*visible).add(all_options[options_type::counter_options]);
598✔
461
            }
598✔
462

463
            detail::handle_generic_config_options(arg0, vm,
1,792✔
464
                all_options[options_type::desc_cfgfile], rtcfg, node,
1,792✔
465
                error_mode);
1,792✔
466
            detail::handle_config_options(vm,
1,792✔
467
                all_options[options_type::desc_cfgfile], rtcfg, node,
1,792✔
468
                error_mode);
1,792✔
469

470
            return result;
1,792✔
471
        }
1,792✔
472
        catch (std::exception const& e)
473
        {
474
            if (as_bool(error_mode &
×
475
                    util::commandline_error_mode::rethrow_on_error))
476
            {
477
                throw;
×
478
            }
479

480
            std::cerr << "hpx::init: exception caught: " << e.what()
×
481
                      << std::endl;
×
482
        }
×
483
        return false;
×
484
    }
1,792✔
485

486
    ///////////////////////////////////////////////////////////////////////////
487
    namespace detail {
488
        std::string extract_arg0(std::string const& cmdline)
596✔
489
        {
490
            std::string::size_type p = cmdline.find_first_of(" \t");
596✔
491
            if (p != std::string::npos)
596✔
492
            {
493
                return cmdline.substr(0, p);
596✔
494
            }
495
            return cmdline;
×
496
        }
596✔
497
    }    // namespace detail
498

499
    bool parse_commandline(util::section const& rtcfg,
596✔
500
        hpx::program_options::options_description const& app_options,
501
        std::string const& cmdline, hpx::program_options::variables_map& vm,
502
        std::size_t node, util::commandline_error_mode error_mode,
503
        hpx::runtime_mode mode,
504
        hpx::program_options::options_description* visible,
505
        std::vector<std::string>* unregistered_options)
506
    {
507
        using namespace hpx::program_options;
508
#if defined(HPX_WINDOWS)
509
        std::vector<std::string> args = split_winmain(cmdline);
510
#else
511
        std::vector<std::string> args = split_unix(cmdline);
596✔
512
#endif
513
        return parse_commandline(rtcfg, app_options,
596✔
514
            detail::extract_arg0(cmdline), args, vm, node, error_mode, mode,
596✔
515
            visible, unregistered_options);
596✔
516
    }
596✔
517
}}    // namespace hpx::util
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc