Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmSystemTools.h
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#pragma once
4
5
#include "cmConfigure.h" // IWYU pragma: keep
6
7
#if !defined(_WIN32)
8
#  include <sys/types.h>
9
#endif
10
11
#include <cstddef>
12
#include <functional>
13
#include <map>
14
#include <sstream>
15
#include <string>
16
#include <vector>
17
18
#include <cm/optional>
19
#include <cm/string_view>
20
21
#include <cm3p/uv.h>
22
23
#include "cmsys/Status.hxx"      // IWYU pragma: export
24
#include "cmsys/SystemTools.hxx" // IWYU pragma: export
25
26
#include "cmDuration.h"
27
#include "cmProcessOutput.h"
28
29
struct cmMessageMetadata;
30
31
/** \class cmSystemTools
32
 * \brief A collection of useful functions for CMake.
33
 *
34
 * cmSystemTools is a class that provides helper functions
35
 * for the CMake build system.
36
 */
37
class cmSystemTools : public cmsys::SystemTools
38
{
39
public:
40
  using Superclass = cmsys::SystemTools;
41
  using Encoding = cmProcessOutput::Encoding;
42
43
  /** Return a lower-case string.  */
44
  static std::string LowerCase(cm::string_view s)
45
0
  {
46
0
    return cmsys::SystemTools::LowerCase(std::string(s));
47
0
  }
48
  static std::string LowerCase(char const* s)
49
0
  {
50
0
    return LowerCase(cm::string_view{ s });
51
0
  }
52
  using cmsys::SystemTools::LowerCase;
53
54
  /** Return an upper-case string.  */
55
  static std::string UpperCase(cm::string_view s)
56
0
  {
57
0
    return cmsys::SystemTools::UpperCase(std::string(s));
58
0
  }
59
  static std::string UpperCase(char const* s)
60
0
  {
61
0
    return UpperCase(cm::string_view{ s });
62
0
  }
63
  using cmsys::SystemTools::UpperCase;
64
65
  /**
66
   * Look for and replace registry values in a string
67
   */
68
  static void ExpandRegistryValues(std::string& source,
69
                                   KeyWOW64 view = KeyWOW64_Default);
70
71
  /** Map help document name to file name.  */
72
  static std::string HelpFileName(cm::string_view);
73
74
  using MessageCallback =
75
    std::function<void(std::string const&, cmMessageMetadata const&)>;
76
  /**
77
   *  Set the function used by GUIs to display error messages
78
   *  Function gets passed: message as a const char*,
79
   *  title as a const char*.
80
   */
81
  static void SetMessageCallback(MessageCallback f);
82
83
  /**
84
   * Display an error message.
85
   */
86
  static void Error(std::string const& m);
87
88
  /**
89
   * Display a message.
90
   */
91
  static void Message(std::string const& m, char const* title = nullptr);
92
  static void Message(std::string const& m, cmMessageMetadata const& md);
93
94
  using OutputCallback = std::function<void(std::string const&)>;
95
96
  //! Send a string to stdout
97
  static void Stdout(std::string const& s);
98
  static void SetStdoutCallback(OutputCallback f);
99
100
  //! Send a string to stderr
101
  static void Stderr(std::string const& s);
102
  static void SetStderrCallback(OutputCallback f);
103
104
  using InterruptCallback = std::function<bool()>;
105
  static void SetInterruptCallback(InterruptCallback f);
106
  static bool GetInterruptFlag();
107
108
  //! Return true if there was an error at any point.
109
  static bool GetErrorOccurredFlag()
110
36
  {
111
36
    return cmSystemTools::s_ErrorOccurred ||
112
1
      cmSystemTools::s_FatalErrorOccurred || GetInterruptFlag();
113
36
  }
114
  //! If this is set to true, cmake stops processing commands.
115
  static void SetFatalErrorOccurred()
116
1
  {
117
1
    cmSystemTools::s_FatalErrorOccurred = true;
118
1
  }
119
1
  static void SetErrorOccurred() { cmSystemTools::s_ErrorOccurred = true; }
120
  //! Return true if there was an error at any point.
121
  static bool GetFatalErrorOccurred()
122
0
  {
123
0
    return cmSystemTools::s_FatalErrorOccurred || GetInterruptFlag();
124
0
  }
125
126
  //! Set the error occurred flag and fatal error back to false
127
  static void ResetErrorOccurredFlag()
128
0
  {
129
0
    cmSystemTools::s_FatalErrorOccurred = false;
130
0
    cmSystemTools::s_ErrorOccurred = false;
131
0
  }
132
133
  //! Return true if the path is a framework
134
  static bool IsPathToFramework(std::string const& path);
135
136
  //! Return true if the path is a xcframework
137
  static bool IsPathToXcFramework(std::string const& path);
138
139
  //! Return true if the path is a macOS non-framework shared library (aka
140
  //! .dylib)
141
  static bool IsPathToMacOSSharedLibrary(std::string const& path);
142
143
  static bool DoesFileExistWithExtensions(
144
    std::string const& name, std::vector<std::string> const& sourceExts);
145
146
  /**
147
   * Check if the given file exists in one of the parent directory of the
148
   * given file or directory and if it does, return the name of the file.
149
   * Toplevel specifies the top-most directory to where it will look.
150
   */
151
  static std::string FileExistsInParentDirectories(
152
    std::string const& fname, std::string const& directory,
153
    std::string const& toplevel);
154
155
  static void Glob(std::string const& directory, std::string const& regexp,
156
                   std::vector<std::string>& files);
157
  static void GlobDirs(std::string const& fullPath,
158
                       std::vector<std::string>& files);
159
160
  /**
161
   * Try to find a list of files that match the "simple" globbing
162
   * expression. At this point in time the globbing expressions have
163
   * to be in form: /directory/partial_file_name*. The * character has
164
   * to be at the end of the string and it does not support ?
165
   * []... The optional argument type specifies what kind of files you
166
   * want to find. 0 means all files, -1 means directories, 1 means
167
   * files only. This method returns true if search was successful.
168
   */
169
  static bool SimpleGlob(std::string const& glob,
170
                         std::vector<std::string>& files, int type = 0);
171
172
  enum class CopyInputRecent
173
  {
174
    No,
175
    Yes,
176
  };
177
  enum class CopyResult
178
  {
179
    Success,
180
    Failure,
181
  };
182
183
#if defined(_MSC_VER)
184
  /** Visual C++ does not define mode_t. */
185
  using mode_t = unsigned short;
186
#endif
187
188
  /**
189
   * Make a new temporary directory.  The path must end in "XXXXXX", and will
190
   * be modified to reflect the name of the directory created.  This function
191
   * is similar to POSIX mkdtemp (and is implemented using the same where that
192
   * function is available).
193
   *
194
   * This function can make a full path even if none of the directories existed
195
   * prior to calling this function.
196
   *
197
   * Note that this function may modify \p path even if it does not succeed.
198
   */
199
  static cmsys::Status MakeTempDirectory(char* path,
200
                                         mode_t const* mode = nullptr);
201
  static cmsys::Status MakeTempDirectory(std::string& path,
202
                                         mode_t const* mode = nullptr);
203
204
  /** Copy a file. */
205
  static CopyResult CopySingleFile(std::string const& oldname,
206
                                   std::string const& newname, CopyWhen when,
207
                                   CopyInputRecent inputRecent,
208
                                   std::string* err = nullptr);
209
210
  enum class Replace
211
  {
212
    Yes,
213
    No,
214
  };
215
  enum class RenameResult
216
  {
217
    Success,
218
    NoReplace,
219
    Failure,
220
  };
221
222
  /** Rename a file or directory within a single disk volume (atomic
223
      if possible).  */
224
  static bool RenameFile(std::string const& oldname,
225
                         std::string const& newname);
226
  static RenameResult RenameFile(std::string const& oldname,
227
                                 std::string const& newname, Replace replace,
228
                                 std::string* err = nullptr);
229
230
  //! Rename a file if contents are different, delete the source otherwise
231
  static cmsys::Status MoveFileIfDifferent(std::string const& source,
232
                                           std::string const& destination);
233
234
  /**
235
   * According to the CreateProcessW documentation:
236
   *
237
   *   To run a batch file, you must start the command interpreter; set
238
   *   lpApplicationName to cmd.exe and set lpCommandLine to the following
239
   *   arguments: /c plus the name of the batch file.
240
   *
241
   * Additionally, "cmd /c" does not always parse batch file names correctly
242
   * if they contain spaces, but using "cmd /c call" seems to work.
243
   *
244
   *  The function is noop on platforms different from the pure WIN32 one.
245
   */
246
  static void MaybePrependCmdExe(std::vector<std::string>& cmdLine);
247
248
  /**
249
   * Run a single executable command
250
   *
251
   * Output is controlled with outputflag. If outputflag is OUTPUT_NONE, no
252
   * user-viewable output from the program being run will be generated.
253
   * OUTPUT_MERGE is the legacy behavior where stdout and stderr are merged
254
   * into stdout.  OUTPUT_FORWARD copies the output to stdout/stderr as
255
   * it was received.  OUTPUT_PASSTHROUGH passes through the original handles.
256
   *
257
   * If timeout is specified, the command will be terminated after
258
   * timeout expires. Timeout is specified in seconds.
259
   *
260
   * Argument retVal should be a pointer to the location where the
261
   * exit code will be stored. If the retVal is not specified and
262
   * the program exits with a code other than 0, then the this
263
   * function will return false.
264
   *
265
   * If the command has spaces in the path the caller MUST call
266
   * cmSystemTools::ConvertToRunCommandPath on the command before passing
267
   * it into this function or it will not work.  The command must be correctly
268
   * escaped for this to with spaces.
269
   */
270
  enum OutputOption
271
  {
272
    OUTPUT_NONE = 0,
273
    OUTPUT_MERGE,
274
    OUTPUT_FORWARD,
275
    OUTPUT_PASSTHROUGH
276
  };
277
  static bool RunSingleCommand(std::string const& command,
278
                               std::string* captureStdOut = nullptr,
279
                               std::string* captureStdErr = nullptr,
280
                               int* retVal = nullptr,
281
                               char const* dir = nullptr,
282
                               OutputOption outputflag = OUTPUT_MERGE,
283
                               cmDuration timeout = cmDuration::zero());
284
  /**
285
   * In this version of RunSingleCommand, command[0] should be
286
   * the command to run, and each argument to the command should
287
   * be in command[1]...command[command.size()]
288
   */
289
  static bool RunSingleCommand(std::vector<std::string> const& command,
290
                               std::string* captureStdOut = nullptr,
291
                               std::string* captureStdErr = nullptr,
292
                               int* retVal = nullptr,
293
                               char const* dir = nullptr,
294
                               OutputOption outputflag = OUTPUT_MERGE,
295
                               cmDuration timeout = cmDuration::zero(),
296
                               Encoding encoding = cmProcessOutput::Auto);
297
298
  static std::string PrintSingleCommand(std::vector<std::string> const&);
299
300
  /**
301
   * Parse arguments out of a single string command
302
   */
303
  static std::vector<std::string> ParseArguments(std::string const& command);
304
305
  /** Parse arguments out of a windows command line string.  */
306
  static void ParseWindowsCommandLine(char const* command,
307
                                      std::vector<std::string>& args);
308
309
  /** Parse arguments out of a unix command line string.  */
310
  static void ParseUnixCommandLine(char const* command,
311
                                   std::vector<std::string>& args);
312
313
  /** Split a command-line string into the parsed command and the unparsed
314
      arguments.  Returns false on unfinished quoting or escaping.  */
315
  static bool SplitProgramFromArgs(std::string const& command,
316
                                   std::string& program, std::string& args);
317
318
  /**
319
   * Handle response file in an argument list and return a new argument list
320
   * **/
321
  static std::vector<std::string> HandleResponseFile(
322
    std::vector<std::string>::const_iterator argBeg,
323
    std::vector<std::string>::const_iterator argEnd);
324
325
  static std::size_t CalculateCommandLineLengthLimit();
326
327
0
  static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
328
0
  static void EnableRunCommandOutput() { s_DisableRunCommandOutput = false; }
329
0
  static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; }
330
331
  enum CompareOp
332
  {
333
    OP_EQUAL = 1,
334
    OP_LESS = 2,
335
    OP_GREATER = 4,
336
    OP_LESS_EQUAL = OP_LESS | OP_EQUAL,
337
    OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL
338
  };
339
340
  /**
341
   * Compare versions
342
   */
343
  static bool VersionCompare(CompareOp op, std::string const& lhs,
344
                             std::string const& rhs);
345
  static bool VersionCompare(CompareOp op, std::string const& lhs,
346
                             char const rhs[]);
347
  static bool VersionCompareEqual(std::string const& lhs,
348
                                  std::string const& rhs);
349
  static bool VersionCompareGreater(std::string const& lhs,
350
                                    std::string const& rhs);
351
  static bool VersionCompareGreaterEq(std::string const& lhs,
352
                                      std::string const& rhs);
353
354
  /**
355
   * Compare two ASCII strings using natural versioning order.
356
   * Non-numerical characters are compared directly.
357
   * Numerical characters are first globbed such that, e.g.
358
   * `test000 < test01 < test0 < test1 < test10`.
359
   * Return a value less than, equal to, or greater than zero if lhs
360
   * precedes, equals, or succeeds rhs in the defined ordering.
361
   */
362
  static int strverscmp(std::string const& lhs, std::string const& rhs);
363
364
  /** Windows if this is true, the CreateProcess in RunCommand will
365
   *  not show new console windows when running programs.
366
   */
367
0
  static void SetRunCommandHideConsole(bool v) { s_RunCommandHideConsole = v; }
368
0
  static bool GetRunCommandHideConsole() { return s_RunCommandHideConsole; }
369
  /** Call cmSystemTools::Error with the message m, plus the
370
   * result of strerror(errno)
371
   */
372
  static void ReportLastSystemError(char const* m);
373
374
  enum class WaitForLineResult
375
  {
376
    None,
377
    STDOUT,
378
    STDERR,
379
  };
380
381
  /** a general output handler for libuv  */
382
  static WaitForLineResult WaitForLine(uv_loop_t* loop, uv_stream_t* outPipe,
383
                                       uv_stream_t* errPipe, std::string& line,
384
                                       std::vector<char>& out,
385
                                       std::vector<char>& err);
386
387
0
  static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
388
0
  static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
389
390
  // ConvertToOutputPath use s_ForceUnixPaths
391
  static std::string ConvertToOutputPath(std::string const& path);
392
  static void ConvertToOutputSlashes(std::string& path);
393
394
  // ConvertToRunCommandPath does not use s_ForceUnixPaths and should
395
  // be used when RunCommand is called from cmake, because the
396
  // running cmake needs paths to be in its format
397
  static std::string ConvertToRunCommandPath(std::string const& path);
398
399
  /**
400
   * For windows computes the long path for the given path,
401
   * For Unix, it is a noop
402
   */
403
  static void ConvertToLongPath(std::string& path);
404
405
  /** compute the relative path from local to remote.  local must
406
      be a directory.  remote can be a file or a directory.
407
      Both remote and local must be full paths.  Basically, if
408
      you are in directory local and you want to access the file in remote
409
      what is the relative path to do that.  For example:
410
      /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
411
      from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
412
  */
413
  static std::string RelativePath(std::string const& local,
414
                                  std::string const& remote);
415
416
  /**
417
   * Convert the given remote path to a relative path with respect to
418
   * the given local path.  Both paths must use forward slashes and not
419
   * already be escaped or quoted.
420
   */
421
  static std::string ForceToRelativePath(std::string const& local_path,
422
                                         std::string const& remote_path);
423
424
  /**
425
   * Express the 'in' path relative to 'top' if it does not start in '../'.
426
   */
427
  static std::string RelativeIfUnder(std::string const& top,
428
                                     std::string const& in);
429
430
  static cm::optional<std::string> GetEnvVar(std::string const& var);
431
  static std::vector<std::string> GetEnvPathNormalized(std::string const& var);
432
433
  static std::vector<std::string> SplitEnvPath(cm::string_view in);
434
  static std::vector<std::string> SplitEnvPathNormalized(cm::string_view in);
435
436
  /** Convert an input path to an absolute path with no '/..' components.
437
      Backslashes in the input path are converted to forward slashes.
438
      Relative paths are interpreted w.r.t. GetLogicalWorkingDirectory.
439
      This is similar to 'realpath', but preserves symlinks that are
440
      not erased by '../' components.
441
442
      On Windows and macOS, the on-disk capitalization is loaded for
443
      existing paths.  */
444
  static std::string ToNormalizedPathOnDisk(std::string p);
445
446
#ifndef CMAKE_BOOTSTRAP
447
  /** Remove an environment variable */
448
  static bool UnsetEnv(char const* value);
449
450
  /** Get the list of all environment variables */
451
  static std::vector<std::string> GetEnvironmentVariables();
452
453
  /** Append multiple variables to the current environment. */
454
  static void AppendEnv(std::vector<std::string> const& env);
455
456
  /**
457
   * Helper class to represent an environment diff directly. This is to avoid
458
   * repeated in-place environment modification (i.e. via setenv/putenv), which
459
   * could be slow.
460
   */
461
  class EnvDiff
462
  {
463
  public:
464
    /** Append multiple variables to the current environment diff */
465
    void AppendEnv(std::vector<std::string> const& env);
466
467
    /**
468
     * Add a single variable (or remove if no = sign) to the current
469
     * environment diff.
470
     */
471
    void PutEnv(std::string const& env);
472
473
    /** Remove a single variable from the current environment diff. */
474
    void UnPutEnv(std::string const& env);
475
476
    /**
477
     * Apply an ENVIRONMENT_MODIFICATION operation to this diff. Returns
478
     * false and issues an error on parse failure.
479
     */
480
    bool ParseOperation(std::string const& envmod);
481
482
    /**
483
     * Apply this diff to the actual environment, optionally writing out the
484
     * modifications to a CTest-compatible measurement stream.
485
     */
486
    void ApplyToCurrentEnv(std::ostringstream* measurement = nullptr);
487
488
  private:
489
    std::map<std::string, cm::optional<std::string>> diff;
490
  };
491
492
  /** Helper class to save and restore the environment.
493
      Instantiate this class as an automatic variable on
494
      the stack. Its constructor saves a copy of the current
495
      environment and then its destructor restores the
496
      original environment. */
497
  class SaveRestoreEnvironment
498
  {
499
  public:
500
    SaveRestoreEnvironment();
501
    ~SaveRestoreEnvironment();
502
503
    SaveRestoreEnvironment(SaveRestoreEnvironment const&) = delete;
504
    SaveRestoreEnvironment& operator=(SaveRestoreEnvironment const&) = delete;
505
506
  private:
507
    std::vector<std::string> Env;
508
  };
509
#endif
510
511
  /** \class ScopedEnv
512
   * \brief An RAII class to temporarily set/unset an environment variable.
513
   *
514
   * The value passed to the constructor is put into the environment. This
515
   * variable is of the form "var=value" and the original value of the "var"
516
   * environment variable is saved. When the object is destroyed, the original
517
   * value for the environment variable is restored. If the variable didn't
518
   * exist, it will be unset.
519
   */
520
  class ScopedEnv
521
  {
522
  public:
523
    ScopedEnv(cm::string_view val);
524
    ~ScopedEnv();
525
526
    ScopedEnv(ScopedEnv const&) = delete;
527
    ScopedEnv& operator=(ScopedEnv const&) = delete;
528
529
  private:
530
    std::string Key;
531
    cm::optional<std::string> Original;
532
  };
533
534
  /** Setup the environment to enable VS 8 IDE output.  */
535
  static void EnableVSConsoleOutput();
536
537
  enum cmTarAction
538
  {
539
    TarActionCreate,
540
    TarActionList,
541
    TarActionExtract,
542
    TarActionNone
543
  };
544
545
  /** Create tar */
546
  enum cmTarCompression
547
  {
548
    TarCompressGZip,
549
    TarCompressBZip2,
550
    TarCompressLZMA,
551
    TarCompressXZ,
552
    TarCompressZstd,
553
    TarCompressPPMd,
554
    TarCompressAuto,
555
    TarCompressNone
556
  };
557
558
  enum class cmTarExtractTimestamps
559
  {
560
    Yes,
561
    No
562
  };
563
564
  static bool ListTar(std::string const& arFileName,
565
                      std::vector<std::string> const& files, bool verbose);
566
  static bool CreateTar(std::string const& arFileName,
567
                        std::vector<std::string> const& files,
568
                        std::string const& workingDirectory,
569
                        cmTarCompression compressType, bool verbose,
570
                        std::string const& mtime = std::string(),
571
                        std::string const& format = std::string(),
572
                        int compressionLevel = 0, int numThreads = 1);
573
  static bool ExtractTar(std::string const& arFileName,
574
                         std::vector<std::string> const& files,
575
                         cmTarExtractTimestamps extractTimestamps,
576
                         bool verbose);
577
578
  /** Random number generation.  */
579
  static unsigned int RandomSeed();
580
  static unsigned int RandomNumber();
581
582
  /**
583
   * Find an executable in the system PATH, with optional extra paths.
584
   * This wraps KWSys's FindProgram to add ToNormalizedPathOnDisk.
585
   */
586
  static std::string FindProgram(
587
    std::string const& name,
588
    std::vector<std::string> const& path = std::vector<std::string>());
589
590
  /** Find the directory containing CMake executables.  */
591
  static void FindCMakeResources(char const* argv0);
592
593
  /** Get the CMake resource paths, after FindCMakeResources.  */
594
  static std::string const& GetCTestCommand();
595
  static std::string const& GetCPackCommand();
596
  static std::string const& GetCMakeCommand();
597
  static std::string const& GetCMakeGUICommand();
598
  static std::string const& GetCMakeCursesCommand();
599
  static std::string const& GetCMClDepsCommand();
600
  static std::string const& GetCMakeRoot();
601
  static std::string const& GetHTMLDoc();
602
603
  /** Get the CMake config directory **/
604
  static cm::optional<std::string> GetSystemConfigDirectory();
605
  static cm::optional<std::string> GetCMakeConfigDirectory();
606
607
  static std::string const& GetLogicalWorkingDirectory();
608
609
  /** The logical working directory may contain symlinks but must not
610
      contain any '../' path components.  */
611
  static cmsys::Status SetLogicalWorkingDirectory(std::string const& lwd);
612
613
  /** Try to guess the soname of a shared library.  */
614
  static bool GuessLibrarySOName(std::string const& fullPath,
615
                                 std::string& soname);
616
617
  /** Try to guess the install name of a shared library.  */
618
  static bool GuessLibraryInstallName(std::string const& fullPath,
619
                                      std::string& soname);
620
621
  /** Try to change the RPATH in an ELF binary.  */
622
  static bool ChangeRPath(std::string const& file, std::string const& oldRPath,
623
                          std::string const& newRPath,
624
                          bool removeEnvironmentRPath,
625
                          std::string* emsg = nullptr,
626
                          bool* changed = nullptr);
627
628
  /** Try to set the RPATH in an ELF binary.  */
629
  static bool SetRPath(std::string const& file, std::string const& newRPath,
630
                       std::string* emsg = nullptr, bool* changed = nullptr);
631
632
  /** Try to remove the RPATH from an ELF binary.  */
633
  static bool RemoveRPath(std::string const& file, std::string* emsg = nullptr,
634
                          bool* removed = nullptr);
635
636
  /** Check whether the RPATH in an ELF binary contains the path
637
      given.  */
638
  static bool CheckRPath(std::string const& file, std::string const& newRPath);
639
640
  /** Remove a directory; repeat a few times in case of locked files.  */
641
  static cmsys::Status RepeatedRemoveDirectory(std::string const& dir);
642
643
  /** Encode a string as a URL.  */
644
  static std::string EncodeURL(std::string const& in,
645
                               bool escapeSlashes = true);
646
647
  enum class DirCase
648
  {
649
    Sensitive,
650
    Insensitive,
651
  };
652
653
  /** Returns nullopt when `dir` is not a valid directory */
654
  static cm::optional<DirCase> GetDirCase(std::string const& dir);
655
656
#ifdef _WIN32
657
  struct WindowsFileRetry
658
  {
659
    unsigned int Count;
660
    unsigned int Delay;
661
  };
662
  static WindowsFileRetry GetWindowsFileRetry();
663
  static WindowsFileRetry GetWindowsDirectoryRetry();
664
665
  struct WindowsVersion
666
  {
667
    unsigned int dwMajorVersion;
668
    unsigned int dwMinorVersion;
669
    unsigned int dwBuildNumber;
670
  };
671
  static WindowsVersion GetWindowsVersion();
672
673
  /** Attempt to get full path to COMSPEC, default "cmd.exe" */
674
  static std::string GetComspec();
675
#endif
676
677
  /** Get the real path for a given path, removing all symlinks.
678
      This variant of GetRealPath also works on Windows but will
679
      resolve subst drives too.  */
680
  static std::string GetRealPathResolvingWindowsSubst(
681
    std::string const& path, std::string* errorMessage = nullptr);
682
683
  /** Get the real path for a given path, removing all symlinks.  */
684
  static std::string GetRealPath(std::string const& path,
685
                                 std::string* errorMessage = nullptr);
686
687
  /** Perform one-time initialization of libuv.  */
688
  static void InitializeLibUV();
689
690
  /** Create a symbolic link if the platform supports it.  Returns whether
691
      creation succeeded. */
692
  static cmsys::Status CreateSymlink(std::string const& origName,
693
                                     std::string const& newName);
694
  static cmsys::Status CreateSymlinkQuietly(std::string const& origName,
695
                                            std::string const& newName);
696
697
  /** Create a hard link if the platform supports it.  Returns whether
698
      creation succeeded. */
699
  static cmsys::Status CreateLink(std::string const& origName,
700
                                  std::string const& newName);
701
  static cmsys::Status CreateLinkQuietly(std::string const& origName,
702
                                         std::string const& newName);
703
704
  /** Get the system name. */
705
  static cm::string_view GetSystemName();
706
707
  /** Get the system path separator character */
708
  static char GetSystemPathlistSeparator();
709
710
  /** Return subview of the full filename (i.e. file name without path) */
711
  static cm::string_view GetFilenameNameView(cm::string_view filename);
712
713
  /**
714
   * Return subview of file extension of a full filename (dot included).
715
   * Warning: this is the shortest extension (for example: .gz of .tar.gz)
716
   */
717
  static cm::string_view GetFilenameLastExtensionView(
718
    cm::string_view filename);
719
720
private:
721
  static bool s_ForceUnixPaths;
722
  static bool s_RunCommandHideConsole;
723
  static bool s_ErrorOccurred;
724
  static bool s_FatalErrorOccurred;
725
  static bool s_DisableRunCommandOutput;
726
};