Coverage Report

Created: 2026-10-28 06:38

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