cmSystemTools.h 20.8 KB
Newer Older
1
2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
3
4
#ifndef cmSystemTools_h
#define cmSystemTools_h
5

6
#include "cmConfigure.h" // IWYU pragma: keep
7

8
#include "cmCryptoHash.h"
9
#include "cmDuration.h"
10
11
#include "cmProcessOutput.h"
#include "cmsys/Process.h"
Daniel Pfeifer's avatar
Daniel Pfeifer committed
12
#include "cmsys/SystemTools.hxx" // IWYU pragma: export
wahikihiki's avatar
wahikihiki committed
13
#include <functional>
14
15
16
#include <stddef.h>
#include <string>
#include <vector>
17

18
class cmSystemToolsFileTime;
Brad King's avatar
Brad King committed
19

20
21
22
23
24
25
/** \class cmSystemTools
 * \brief A collection of useful functions for CMake.
 *
 * cmSystemTools is a class that provides helper functions
 * for the CMake build system.
 */
26
class cmSystemTools : public cmsys::SystemTools
27
28
{
public:
29
  typedef cmsys::SystemTools Superclass;
30
  typedef cmProcessOutput::Encoding Encoding;
31

32
33
  /** Expand out any arguments in the vector that have ; separated
   *  strings into multiple arguments.  A new vector is created
34
35
   *  containing the expanded versions of all arguments in argsIn.
   */
36
37
38
  static void ExpandList(std::vector<std::string> const& argsIn,
                         std::vector<std::string>& argsOut);
  static void ExpandListArgument(const std::string& arg,
39
                                 std::vector<std::string>& argsOut,
40
                                 bool emptyArgs = false);
41

42
43
44
  /**
   * Look for and replace registry values in a string
   */
45
46
  static void ExpandRegistryValues(std::string& source,
                                   KeyWOW64 view = KeyWOW64_Default);
47

48
  ///! Escape quotes in a string.
49
  static std::string EscapeQuotes(const std::string& str);
50

51
52
53
  /** Map help document name to file name.  */
  static std::string HelpFileName(std::string);

54
55
56
57
58
  /**
   * Returns a string that has whitespace removed from the start and the end.
   */
  static std::string TrimWhitespace(const std::string& s);

59
  using MessageCallback = std::function<void(const char*, const char*)>;
60
  /**
61
   *  Set the function used by GUIs to display error messages
62
   *  Function gets passed: message as a const char*,
63
   *  title as a const char*.
64
   */
wahikihiki's avatar
wahikihiki committed
65
  static void SetMessageCallback(MessageCallback f);
66

67
68
69
  /**
   * Display an error message.
   */
Daniel Pfeifer's avatar
Daniel Pfeifer committed
70
71
  static void Error(const char* m, const char* m2 = nullptr,
                    const char* m3 = nullptr, const char* m4 = nullptr);
72
  static void Error(const std::string& m);
Bill Hoffman's avatar
Bill Hoffman committed
73

Ken Martin's avatar
Ken Martin committed
74
75
76
  /**
   * Display a message.
   */
Daniel Pfeifer's avatar
Daniel Pfeifer committed
77
  static void Message(const char* m, const char* title = nullptr);
78
79
80
81
  static void Message(const std::string& m, const char* title = nullptr)
  {
    Message(m.c_str(), title);
  }
Ken Martin's avatar
Ken Martin committed
82

83
  using OutputCallback = std::function<void(std::string const&)>;
84

85
  ///! Send a string to stdout
86
  static void Stdout(const std::string& s);
wahikihiki's avatar
wahikihiki committed
87
  static void SetStdoutCallback(OutputCallback f);
88

89
  ///! Send a string to stderr
90
  static void Stderr(const std::string& s);
wahikihiki's avatar
wahikihiki committed
91
  static void SetStderrCallback(OutputCallback f);
92

wahikihiki's avatar
wahikihiki committed
93
94
  using InterruptCallback = std::function<bool()>;
  static void SetInterruptCallback(InterruptCallback f);
95
96
  static bool GetInterruptFlag();

Bill Hoffman's avatar
Bill Hoffman committed
97
  ///! Return true if there was an error at any point.
98
  static bool GetErrorOccuredFlag()
99
100
101
102
  {
    return cmSystemTools::s_ErrorOccured ||
      cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
  }
103
104
  ///! If this is set to true, cmake stops processing commands.
  static void SetFatalErrorOccured()
105
106
107
108
109
  {
    cmSystemTools::s_FatalErrorOccured = true;
  }
  static void SetErrorOccured() { cmSystemTools::s_ErrorOccured = true; }
  ///! Return true if there was an error at any point.
110
  static bool GetFatalErrorOccured()
111
112
113
  {
    return cmSystemTools::s_FatalErrorOccured || GetInterruptFlag();
  }
114

115
  ///! Set the error occurred flag and fatal error back to false
116
  static void ResetErrorOccuredFlag()
117
118
119
120
  {
    cmSystemTools::s_FatalErrorOccured = false;
    cmSystemTools::s_ErrorOccured = false;
  }
121

122
123
124
125
126
127
  /**
   * Does a string indicates that CMake/CPack/CTest internally
   * forced this value. This is not the same as On, but this
   * may be considered as "internally switched on".
   */
  static bool IsInternallyOn(const char* val);
128
  /**
Ken Martin's avatar
Ken Martin committed
129
   * does a string indicate a true or on value ? This is not the same
130
131
   * as ifdef.
   */
Ken Martin's avatar
Ken Martin committed
132
  static bool IsOn(const char* val);
133
  static bool IsOn(const std::string& val);
134
135

  /**
Ken Martin's avatar
Ken Martin committed
136
137
138
139
   * does a string indicate a false or off value ? Note that this is
   * not the same as !IsOn(...) because there are a number of
   * ambiguous values such as "/usr/local/bin" a path will result in
   * IsON and IsOff both returning false. Note that the special path
140
   * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
Ken Martin's avatar
Ken Martin committed
141
   */
142
  static bool IsOff(const char* val);
143
  static bool IsOff(const std::string& val);
Ken Martin's avatar
Ken Martin committed
144

Bill Hoffman's avatar
Bill Hoffman committed
145
146
  ///! Return true if value is NOTFOUND or ends in -NOTFOUND.
  static bool IsNOTFOUND(const char* value);
147
148
  ///! Return true if the path is a framework
  static bool IsPathToFramework(const char* value);
149

Ken Martin's avatar
Ken Martin committed
150
  static bool DoesFileExistWithExtensions(
151
    const char* name, const std::vector<std::string>& sourceExts);
Ken Martin's avatar
Ken Martin committed
152

153
154
155
156
157
158
  /**
   * Check if the given file exists in one of the parent directory of the
   * given file or directory and if it does, return the name of the file.
   * Toplevel specifies the top-most directory to where it will look.
   */
  static std::string FileExistsInParentDirectories(const char* fname,
159
160
                                                   const char* directory,
                                                   const char* toplevel);
161

162
  static void Glob(const std::string& directory, const std::string& regexp,
Ken Martin's avatar
Ken Martin committed
163
                   std::vector<std::string>& files);
164
165
  static void GlobDirs(const std::string& fullPath,
                       std::vector<std::string>& files);
166
167
168
169
170
171
172
173

  /**
   * Try to find a list of files that match the "simple" globbing
   * expression. At this point in time the globbing expressions have
   * to be in form: /directory/partial_file_name*. The * character has
   * to be at the end of the string and it does not support ?
   * []... The optional argument type specifies what kind of files you
   * want to find. 0 means all files, -1 means directories, 1 means
Luz Paz's avatar
Luz Paz committed
174
   * files only. This method returns true if search was successful.
175
   */
176
  static bool SimpleGlob(const std::string& glob,
177
                         std::vector<std::string>& files, int type = 0);
178

Brad King's avatar
Brad King committed
179
  ///! Copy a file.
180
181
  static bool cmCopyFile(const std::string& source,
                         const std::string& destination);
Bill Hoffman's avatar
Bill Hoffman committed
182

183
184
  /** Rename a file or directory within a single disk volume (atomic
      if possible).  */
185
186
  static bool RenameFile(const std::string& oldname,
                         const std::string& newname);
187

188
189
190
  ///! Compute the hash of a file
  static std::string ComputeFileHash(const std::string& source,
                                     cmCryptoHash::Algo algo);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
191

192
  /** Compute the md5sum of a string.  */
193
  static std::string ComputeStringMD5(const std::string& input);
194

195
196
197
  ///! Get the SHA thumbprint for a certificate file
  static std::string ComputeCertificateThumbprint(const std::string& source);

198
  /**
199
   * Run a single executable command
200
   *
201
202
203
   * Output is controlled with outputflag. If outputflag is OUTPUT_NONE, no
   * user-viewable output from the program being run will be generated.
   * OUTPUT_MERGE is the legacy behaviour where stdout and stderr are merged
204
   * into stdout.  OUTPUT_FORWARD copies the output to stdout/stderr as
205
   * it was received.  OUTPUT_PASSTHROUGH passes through the original handles.
206
207
208
209
210
   *
   * If timeout is specified, the command will be terminated after
   * timeout expires. Timeout is specified in seconds.
   *
   * Argument retVal should be a pointer to the location where the
211
212
   * exit code will be stored. If the retVal is not specified and
   * the program exits with a code other than 0, then the this
213
   * function will return false.
214
215
216
217
   *
   * If the command has spaces in the path the caller MUST call
   * cmSystemTools::ConvertToRunCommandPath on the command before passing
   * it into this function or it will not work.  The command must be correctly
218
   * escaped for this to with spaces.
219
   */
220
221
222
223
224
225
226
  enum OutputOption
  {
    OUTPUT_NONE = 0,
    OUTPUT_MERGE,
    OUTPUT_FORWARD,
    OUTPUT_PASSTHROUGH
  };
227
  static bool RunSingleCommand(const char* command,
Daniel Pfeifer's avatar
Daniel Pfeifer committed
228
229
230
231
                               std::string* captureStdOut = nullptr,
                               std::string* captureStdErr = nullptr,
                               int* retVal = nullptr,
                               const char* dir = nullptr,
232
                               OutputOption outputflag = OUTPUT_MERGE,
233
                               cmDuration timeout = cmDuration::zero());
234
  /**
235
236
   * In this version of RunSingleCommand, command[0] should be
   * the command to run, and each argument to the command should
Luz Paz's avatar
Luz Paz committed
237
   * be in command[1]...command[command.size()]
238
   */
239
  static bool RunSingleCommand(std::vector<std::string> const& command,
Daniel Pfeifer's avatar
Daniel Pfeifer committed
240
241
242
243
                               std::string* captureStdOut = nullptr,
                               std::string* captureStdErr = nullptr,
                               int* retVal = nullptr,
                               const char* dir = nullptr,
244
                               OutputOption outputflag = OUTPUT_MERGE,
245
                               cmDuration timeout = cmDuration::zero(),
246
                               Encoding encoding = cmProcessOutput::Auto);
247

248
249
  static std::string PrintSingleCommand(std::vector<std::string> const&);

250
251
252
  /**
   * Parse arguments out of a single string command
   */
253
  static std::vector<std::string> ParseArguments(const char* command);
254
255
256
257
258

  /** Parse arguments out of a windows command line string.  */
  static void ParseWindowsCommandLine(const char* command,
                                      std::vector<std::string>& args);

259
260
261
262
  /** Parse arguments out of a unix command line string.  */
  static void ParseUnixCommandLine(const char* command,
                                   std::vector<std::string>& args);

263
264
265
266
267
  /** Split a command-line string into the parsed command and the unparsed
      arguments.  Returns false on unfinished quoting or escaping.  */
  static bool SplitProgramFromArgs(std::string const& command,
                                   std::string& program, std::string& args);

268
269
270
271
272
273
274
  /**
   * Handle response file in an argument list and return a new argument list
   * **/
  static std::vector<std::string> HandleResponseFile(
    std::vector<std::string>::const_iterator argBeg,
    std::vector<std::string>::const_iterator argEnd);

275
276
  static size_t CalculateCommandLineLengthLimit();

277
278
  static void EnableMessages() { s_DisableMessages = false; }
  static void DisableMessages() { s_DisableMessages = true; }
279
280
  static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
  static void EnableRunCommandOutput() { s_DisableRunCommandOutput = false; }
281
  static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; }
282
283

  /**
284
   * Some constants for different file formats.
285
   */
286
287
  enum FileFormat
  {
288
289
290
    NO_FILE_FORMAT = 0,
    C_FILE_FORMAT,
    CXX_FILE_FORMAT,
Bill Hoffman's avatar
Bill Hoffman committed
291
    FORTRAN_FILE_FORMAT,
292
    JAVA_FILE_FORMAT,
293
    CUDA_FILE_FORMAT,
294
295
296
297
298
299
300
301
302
303
    HEADER_FILE_FORMAT,
    RESOURCE_FILE_FORMAT,
    DEFINITION_FILE_FORMAT,
    STATIC_LIBRARY_FILE_FORMAT,
    SHARED_LIBRARY_FILE_FORMAT,
    MODULE_FILE_FORMAT,
    OBJECT_FILE_FORMAT,
    UNKNOWN_FILE_FORMAT
  };

304
305
  enum CompareOp
  {
306
307
308
309
310
    OP_EQUAL = 1,
    OP_LESS = 2,
    OP_GREATER = 4,
    OP_LESS_EQUAL = OP_LESS | OP_EQUAL,
    OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL
311
312
313
314
315
316
  };

  /**
   * Compare versions
   */
  static bool VersionCompare(CompareOp op, const char* lhs, const char* rhs);
317
318
  static bool VersionCompareEqual(std::string const& lhs,
                                  std::string const& rhs);
319
320
  static bool VersionCompareGreater(std::string const& lhs,
                                    std::string const& rhs);
321
322
  static bool VersionCompareGreaterEq(std::string const& lhs,
                                      std::string const& rhs);
323

Brad King's avatar
Brad King committed
324
325
326
327
328
329
330
331
332
333
  /**
   * Compare two ASCII strings using natural versioning order.
   * Non-numerical characters are compared directly.
   * Numerical characters are first globbed such that, e.g.
   * `test000 < test01 < test0 < test1 < test10`.
   * Return a value less than, equal to, or greater than zero if lhs
   * precedes, equals, or succeeds rhs in the defined ordering.
   */
  static int strverscmp(std::string const& lhs, std::string const& rhs);

334
335
336
  /**
   * Determine the file type based on the extension
   */
337
  static FileFormat GetFileFormat(std::string const& ext);
338

339
  /** Windows if this is true, the CreateProcess in RunCommand will
luz.paz's avatar
luz.paz committed
340
   *  not show new console windows when running programs.
341
   */
342
343
  static void SetRunCommandHideConsole(bool v) { s_RunCommandHideConsole = v; }
  static bool GetRunCommandHideConsole() { return s_RunCommandHideConsole; }
344
345
346
347
  /** Call cmSystemTools::Error with the message m, plus the
   * result of strerror(errno)
   */
  static void ReportLastSystemError(const char* m);
348

349
350
  /** a general output handler for cmsysProcess  */
  static int WaitForLine(cmsysProcess* process, std::string& line,
351
                         cmDuration timeout, std::vector<char>& out,
352
                         std::vector<char>& err);
353

Brad King's avatar
Brad King committed
354
355
  /** Split a string on its newlines into multiple lines.  Returns
      false only if the last line stored had no newline.  */
356
  static bool Split(const char* s, std::vector<std::string>& l);
357
358
  static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
  static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
359

360
  // ConvertToOutputPath use s_ForceUnixPaths
361
  static std::string ConvertToOutputPath(std::string const& path);
362
363
  static void ConvertToOutputSlashes(std::string& path);

364
  // ConvertToRunCommandPath does not use s_ForceUnixPaths and should
365
  // be used when RunCommand is called from cmake, because the
366
367
  // running cmake needs paths to be in its format
  static std::string ConvertToRunCommandPath(const char* path);
368
369
370

  /** compute the relative path from local to remote.  local must
      be a directory.  remote can be a file or a directory.
371
372
373
374
375
376
      Both remote and local must be full paths.  Basically, if
      you are in directory local and you want to access the file in remote
      what is the relative path to do that.  For example:
      /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
      from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
  */
377
378
  static std::string RelativePath(std::string const& local,
                                  std::string const& remote);
379

380
381
382
383
384
385
386
387
  /**
   * Convert the given remote path to a relative path with respect to
   * the given local path.  Both paths must use forward slashes and not
   * already be escaped or quoted.
   */
  static std::string ForceToRelativePath(std::string const& local_path,
                                         std::string const& remote_path);

388
389
390
391
392
393
  /** Joins two paths while collapsing x/../ parts
   * For example CollapseCombinedPath("a/b/c", "../../d") results in "a/d"
   */
  static std::string CollapseCombinedPath(std::string const& dir,
                                          std::string const& file);

394
#ifdef CMAKE_BUILD_WITH_CMAKE
395
396
397
398
  /** Remove an environment variable */
  static bool UnsetEnv(const char* value);

  /** Get the list of all environment variables */
399
  static std::vector<std::string> GetEnvironmentVariables();
400

401
402
  /** Append multiple variables to the current environment. */
  static void AppendEnv(std::vector<std::string> const& env);
403
404
405
406
407
408
409
410
411
412

  /** Helper class to save and restore the environment.
      Instantiate this class as an automatic variable on
      the stack. Its constructor saves a copy of the current
      environment and then its destructor restores the
      original environment. */
  class SaveRestoreEnvironment
  {
  public:
    SaveRestoreEnvironment();
413
    ~SaveRestoreEnvironment();
414

wahikihiki's avatar
wahikihiki committed
415
416
417
    SaveRestoreEnvironment(SaveRestoreEnvironment const&) = delete;
    SaveRestoreEnvironment& operator=(SaveRestoreEnvironment const&) = delete;

418
419
420
  private:
    std::vector<std::string> Env;
  };
421
#endif
422

423
424
425
  /** Setup the environment to enable VS 8 IDE output.  */
  static void EnableVSConsoleOutput();

Andy Cedilnik's avatar
Andy Cedilnik committed
426
  /** Create tar */
427
428
429
430
431
432
433
  enum cmTarCompression
  {
    TarCompressGZip,
    TarCompressBZip2,
    TarCompressXZ,
    TarCompressNone
  };
434
  static bool ListTar(const char* outFileName, bool verbose);
435
  static bool CreateTar(const char* outFileName,
436
                        const std::vector<std::string>& files,
437
                        cmTarCompression compressType, bool verbose,
438
439
                        std::string const& mtime = std::string(),
                        std::string const& format = std::string());
440
  static bool ExtractTar(const char* inFileName, bool verbose);
441
442
443
444
445
446
  // This should be called first thing in main
  // it will keep child processes from inheriting the
  // stdin and stdout of this process.  This is important
  // if you want to be able to kill child processes and
  // not get stuck waiting for all the output on the pipes.
  static void DoNotInheritStdPipes();
447
448
449
450
451

  /** Copy the file create/access/modify times from the file named by
      the first argument to that named by the second.  */
  static bool CopyFileTime(const char* fromFile, const char* toFile);

452
453
454
455
456
457
  /** Save and restore file times.  */
  static cmSystemToolsFileTime* FileTimeNew();
  static void FileTimeDelete(cmSystemToolsFileTime*);
  static bool FileTimeGet(const char* fname, cmSystemToolsFileTime* t);
  static bool FileTimeSet(const char* fname, cmSystemToolsFileTime* t);

458
459
460
  /** Random seed generation.  */
  static unsigned int RandomSeed();

461
462
463
464
465
466
467
468
469
  /** Find the directory containing CMake executables.  */
  static void FindCMakeResources(const char* argv0);

  /** Get the CMake resource paths, after FindCMakeResources.  */
  static std::string const& GetCTestCommand();
  static std::string const& GetCPackCommand();
  static std::string const& GetCMakeCommand();
  static std::string const& GetCMakeGUICommand();
  static std::string const& GetCMakeCursesCommand();
470
  static std::string const& GetCMClDepsCommand();
471
  static std::string const& GetCMakeRoot();
472

473
  /** Echo a message in color using KWSys's Terminal cprintf.  */
474
475
  static void MakefileColorEcho(int color, const char* message, bool newLine,
                                bool enabled);
476

477
478
479
480
  /** Try to guess the soname of a shared library.  */
  static bool GuessLibrarySOName(std::string const& fullPath,
                                 std::string& soname);

481
482
  /** Try to guess the install name of a shared library.  */
  static bool GuessLibraryInstallName(std::string const& fullPath,
483
                                      std::string& soname);
484

485
  /** Try to set the RPATH in an ELF binary.  */
486
  static bool ChangeRPath(std::string const& file, std::string const& oldRPath,
Daniel Pfeifer's avatar
Daniel Pfeifer committed
487
                          std::string const& newRPath,
Daniel Pfeifer's avatar
Daniel Pfeifer committed
488
489
                          std::string* emsg = nullptr,
                          bool* changed = nullptr);
490

491
  /** Try to remove the RPATH from an ELF binary.  */
Daniel Pfeifer's avatar
Daniel Pfeifer committed
492
493
  static bool RemoveRPath(std::string const& file, std::string* emsg = nullptr,
                          bool* removed = nullptr);
494
495
496

  /** Check whether the RPATH in an ELF binary contains the path
      given.  */
497
  static bool CheckRPath(std::string const& file, std::string const& newRPath);
498

499
500
501
  /** Remove a directory; repeat a few times in case of locked files.  */
  static bool RepeatedRemoveDirectory(const char* dir);

502
503
504
  /** Tokenize a string */
  static std::vector<std::string> tokenize(const std::string& str,
                                           const std::string& sep);
505

506
507
  /** Convert string to long. Expected that the whole string is an integer */
  static bool StringToLong(const char* str, long* value);
508
  static bool StringToULong(const char* str, unsigned long* value);
509

510
511
512
513
  /** Encode a string as a URL.  */
  static std::string EncodeURL(std::string const& in,
                               bool escapeSlashes = true);

514
515
516
517
518
519
520
521
#ifdef _WIN32
  struct WindowsFileRetry
  {
    unsigned int Count;
    unsigned int Delay;
  };
  static WindowsFileRetry GetWindowsFileRetry();
#endif
522

523
524
525
526
527
528
  /** Get the real path for a given path, removing all symlinks.
      This variant of GetRealPath also works on Windows but will
      resolve subst drives too.  */
  static std::string GetRealPathResolvingWindowsSubst(
    const std::string& path, std::string* errorMessage = nullptr);

529
530
531
  /** Perform one-time initialization of libuv.  */
  static void InitializeLibUV();

532
533
534
  /** Create a symbolic link if the platform supports it.  Returns whether
      creation succeeded. */
  static bool CreateSymlink(const std::string& origName,
535
536
                            const std::string& newName,
                            std::string* errorMessage = nullptr);
537

538
539
540
  /** Create a hard link if the platform supports it.  Returns whether
      creation succeeded. */
  static bool CreateLink(const std::string& origName,
541
542
                         const std::string& newName,
                         std::string* errorMessage = nullptr);
543

Bill Hoffman's avatar
Bill Hoffman committed
544
private:
545
  static bool s_ForceUnixPaths;
546
  static bool s_RunCommandHideConsole;
Bill Hoffman's avatar
Bill Hoffman committed
547
  static bool s_ErrorOccured;
548
  static bool s_FatalErrorOccured;
549
  static bool s_DisableMessages;
550
  static bool s_DisableRunCommandOutput;
551
552
553
};

#endif