Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Source / cmSystemTools.h
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt 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 "cmsys/Process.h"
22 #include "cmsys/Status.hxx"      // IWYU pragma: export
23 #include "cmsys/SystemTools.hxx" // IWYU pragma: export
24
25 #include "cmCryptoHash.h"
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   /**
44    * Look for and replace registry values in a string
45    */
46   static void ExpandRegistryValues(std::string& source,
47                                    KeyWOW64 view = KeyWOW64_Default);
48
49   /** Map help document name to file name.  */
50   static std::string HelpFileName(cm::string_view);
51
52   using MessageCallback =
53     std::function<void(const std::string&, const cmMessageMetadata&)>;
54   /**
55    *  Set the function used by GUIs to display error messages
56    *  Function gets passed: message as a const char*,
57    *  title as a const char*.
58    */
59   static void SetMessageCallback(MessageCallback f);
60
61   /**
62    * Display an error message.
63    */
64   static void Error(const std::string& m);
65
66   /**
67    * Display a message.
68    */
69   static void Message(const std::string& m, const char* title = nullptr);
70   static void Message(const std::string& m, const cmMessageMetadata& md);
71
72   using OutputCallback = std::function<void(std::string const&)>;
73
74   //! Send a string to stdout
75   static void Stdout(const std::string& s);
76   static void SetStdoutCallback(OutputCallback f);
77
78   //! Send a string to stderr
79   static void Stderr(const std::string& s);
80   static void SetStderrCallback(OutputCallback f);
81
82   using InterruptCallback = std::function<bool()>;
83   static void SetInterruptCallback(InterruptCallback f);
84   static bool GetInterruptFlag();
85
86   //! Return true if there was an error at any point.
87   static bool GetErrorOccurredFlag()
88   {
89     return cmSystemTools::s_ErrorOccurred ||
90       cmSystemTools::s_FatalErrorOccurred || GetInterruptFlag();
91   }
92   //! If this is set to true, cmake stops processing commands.
93   static void SetFatalErrorOccurred()
94   {
95     cmSystemTools::s_FatalErrorOccurred = true;
96   }
97   static void SetErrorOccurred() { cmSystemTools::s_ErrorOccurred = true; }
98   //! Return true if there was an error at any point.
99   static bool GetFatalErrorOccurred()
100   {
101     return cmSystemTools::s_FatalErrorOccurred || GetInterruptFlag();
102   }
103
104   //! Set the error occurred flag and fatal error back to false
105   static void ResetErrorOccurredFlag()
106   {
107     cmSystemTools::s_FatalErrorOccurred = false;
108     cmSystemTools::s_ErrorOccurred = false;
109   }
110
111   //! Return true if the path is a framework
112   static bool IsPathToFramework(const std::string& path);
113
114   //! Return true if the path is a macOS non-framework shared library (aka
115   //! .dylib)
116   static bool IsPathToMacOSSharedLibrary(const std::string& path);
117
118   static bool DoesFileExistWithExtensions(
119     const std::string& name, const std::vector<std::string>& sourceExts);
120
121   /**
122    * Check if the given file exists in one of the parent directory of the
123    * given file or directory and if it does, return the name of the file.
124    * Toplevel specifies the top-most directory to where it will look.
125    */
126   static std::string FileExistsInParentDirectories(
127     const std::string& fname, const std::string& directory,
128     const std::string& toplevel);
129
130   static void Glob(const std::string& directory, const std::string& regexp,
131                    std::vector<std::string>& files);
132   static void GlobDirs(const std::string& fullPath,
133                        std::vector<std::string>& files);
134
135   /**
136    * Try to find a list of files that match the "simple" globbing
137    * expression. At this point in time the globbing expressions have
138    * to be in form: /directory/partial_file_name*. The * character has
139    * to be at the end of the string and it does not support ?
140    * []... The optional argument type specifies what kind of files you
141    * want to find. 0 means all files, -1 means directories, 1 means
142    * files only. This method returns true if search was successful.
143    */
144   static bool SimpleGlob(const std::string& glob,
145                          std::vector<std::string>& files, int type = 0);
146
147   enum class CopyWhen
148   {
149     Always,
150     OnlyIfDifferent,
151   };
152   enum class CopyResult
153   {
154     Success,
155     Failure,
156   };
157
158 #if defined(_MSC_VER)
159   /** Visual C++ does not define mode_t. */
160   using mode_t = unsigned short;
161 #endif
162
163   /**
164    * Make a new temporary directory.  The path must end in "XXXXXX", and will
165    * be modified to reflect the name of the directory created.  This function
166    * is similar to POSIX mkdtemp (and is implemented using the same where that
167    * function is available).
168    *
169    * This function can make a full path even if none of the directories existed
170    * prior to calling this function.
171    *
172    * Note that this function may modify \p path even if it does not succeed.
173    */
174   static cmsys::Status MakeTempDirectory(char* path,
175                                          const mode_t* mode = nullptr);
176   static cmsys::Status MakeTempDirectory(std::string& path,
177                                          const mode_t* mode = nullptr);
178
179   /** Copy a file. */
180   static bool CopySingleFile(const std::string& oldname,
181                              const std::string& newname);
182   static CopyResult CopySingleFile(std::string const& oldname,
183                                    std::string const& newname, CopyWhen when,
184                                    std::string* err = nullptr);
185
186   enum class Replace
187   {
188     Yes,
189     No,
190   };
191   enum class RenameResult
192   {
193     Success,
194     NoReplace,
195     Failure,
196   };
197
198   /** Rename a file or directory within a single disk volume (atomic
199       if possible).  */
200   static bool RenameFile(const std::string& oldname,
201                          const std::string& newname);
202   static RenameResult RenameFile(std::string const& oldname,
203                                  std::string const& newname, Replace replace,
204                                  std::string* err = nullptr);
205
206   //! Rename a file if contents are different, delete the source otherwise
207   static void MoveFileIfDifferent(const std::string& source,
208                                   const std::string& destination);
209
210 #ifndef CMAKE_BOOTSTRAP
211   //! Compute the hash of a file
212   static std::string ComputeFileHash(const std::string& source,
213                                      cmCryptoHash::Algo algo);
214
215   /** Compute the md5sum of a string.  */
216   static std::string ComputeStringMD5(const std::string& input);
217
218 #  ifdef _WIN32
219   //! Get the SHA thumbprint for a certificate file
220   static std::string ComputeCertificateThumbprint(const std::string& source);
221 #  endif
222 #endif
223
224   /**
225    * Run a single executable command
226    *
227    * Output is controlled with outputflag. If outputflag is OUTPUT_NONE, no
228    * user-viewable output from the program being run will be generated.
229    * OUTPUT_MERGE is the legacy behavior where stdout and stderr are merged
230    * into stdout.  OUTPUT_FORWARD copies the output to stdout/stderr as
231    * it was received.  OUTPUT_PASSTHROUGH passes through the original handles.
232    *
233    * If timeout is specified, the command will be terminated after
234    * timeout expires. Timeout is specified in seconds.
235    *
236    * Argument retVal should be a pointer to the location where the
237    * exit code will be stored. If the retVal is not specified and
238    * the program exits with a code other than 0, then the this
239    * function will return false.
240    *
241    * If the command has spaces in the path the caller MUST call
242    * cmSystemTools::ConvertToRunCommandPath on the command before passing
243    * it into this function or it will not work.  The command must be correctly
244    * escaped for this to with spaces.
245    */
246   enum OutputOption
247   {
248     OUTPUT_NONE = 0,
249     OUTPUT_MERGE,
250     OUTPUT_FORWARD,
251     OUTPUT_PASSTHROUGH
252   };
253   static bool RunSingleCommand(const std::string& command,
254                                std::string* captureStdOut = nullptr,
255                                std::string* captureStdErr = nullptr,
256                                int* retVal = nullptr,
257                                const char* dir = nullptr,
258                                OutputOption outputflag = OUTPUT_MERGE,
259                                cmDuration timeout = cmDuration::zero());
260   /**
261    * In this version of RunSingleCommand, command[0] should be
262    * the command to run, and each argument to the command should
263    * be in command[1]...command[command.size()]
264    */
265   static bool RunSingleCommand(std::vector<std::string> const& command,
266                                std::string* captureStdOut = nullptr,
267                                std::string* captureStdErr = nullptr,
268                                int* retVal = nullptr,
269                                const char* dir = nullptr,
270                                OutputOption outputflag = OUTPUT_MERGE,
271                                cmDuration timeout = cmDuration::zero(),
272                                Encoding encoding = cmProcessOutput::Auto);
273
274   static std::string PrintSingleCommand(std::vector<std::string> const&);
275
276   /**
277    * Parse arguments out of a single string command
278    */
279   static std::vector<std::string> ParseArguments(const std::string& command);
280
281   /** Parse arguments out of a windows command line string.  */
282   static void ParseWindowsCommandLine(const char* command,
283                                       std::vector<std::string>& args);
284
285   /** Parse arguments out of a unix command line string.  */
286   static void ParseUnixCommandLine(const char* command,
287                                    std::vector<std::string>& args);
288
289   /** Split a command-line string into the parsed command and the unparsed
290       arguments.  Returns false on unfinished quoting or escaping.  */
291   static bool SplitProgramFromArgs(std::string const& command,
292                                    std::string& program, std::string& args);
293
294   /**
295    * Handle response file in an argument list and return a new argument list
296    * **/
297   static std::vector<std::string> HandleResponseFile(
298     std::vector<std::string>::const_iterator argBeg,
299     std::vector<std::string>::const_iterator argEnd);
300
301   static size_t CalculateCommandLineLengthLimit();
302
303   static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
304   static void EnableRunCommandOutput() { s_DisableRunCommandOutput = false; }
305   static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; }
306
307   enum CompareOp
308   {
309     OP_EQUAL = 1,
310     OP_LESS = 2,
311     OP_GREATER = 4,
312     OP_LESS_EQUAL = OP_LESS | OP_EQUAL,
313     OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL
314   };
315
316   /**
317    * Compare versions
318    */
319   static bool VersionCompare(CompareOp op, const std::string& lhs,
320                              const std::string& rhs);
321   static bool VersionCompare(CompareOp op, const std::string& lhs,
322                              const char rhs[]);
323   static bool VersionCompareEqual(std::string const& lhs,
324                                   std::string const& rhs);
325   static bool VersionCompareGreater(std::string const& lhs,
326                                     std::string const& rhs);
327   static bool VersionCompareGreaterEq(std::string const& lhs,
328                                       std::string const& rhs);
329
330   /**
331    * Compare two ASCII strings using natural versioning order.
332    * Non-numerical characters are compared directly.
333    * Numerical characters are first globbed such that, e.g.
334    * `test000 < test01 < test0 < test1 < test10`.
335    * Return a value less than, equal to, or greater than zero if lhs
336    * precedes, equals, or succeeds rhs in the defined ordering.
337    */
338   static int strverscmp(std::string const& lhs, std::string const& rhs);
339
340   /** Windows if this is true, the CreateProcess in RunCommand will
341    *  not show new console windows when running programs.
342    */
343   static void SetRunCommandHideConsole(bool v) { s_RunCommandHideConsole = v; }
344   static bool GetRunCommandHideConsole() { return s_RunCommandHideConsole; }
345   /** Call cmSystemTools::Error with the message m, plus the
346    * result of strerror(errno)
347    */
348   static void ReportLastSystemError(const char* m);
349
350   /** a general output handler for cmsysProcess  */
351   static int WaitForLine(cmsysProcess* process, std::string& line,
352                          cmDuration timeout, std::vector<char>& out,
353                          std::vector<char>& err);
354
355   static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
356   static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
357
358   // ConvertToOutputPath use s_ForceUnixPaths
359   static std::string ConvertToOutputPath(std::string const& path);
360   static void ConvertToOutputSlashes(std::string& path);
361
362   // ConvertToRunCommandPath does not use s_ForceUnixPaths and should
363   // be used when RunCommand is called from cmake, because the
364   // running cmake needs paths to be in its format
365   static std::string ConvertToRunCommandPath(const std::string& path);
366
367   /**
368    * For windows computes the long path for the given path,
369    * For Unix, it is a noop
370    */
371   static void ConvertToLongPath(std::string& path);
372
373   /** compute the relative path from local to remote.  local must
374       be a directory.  remote can be a file or a directory.
375       Both remote and local must be full paths.  Basically, if
376       you are in directory local and you want to access the file in remote
377       what is the relative path to do that.  For example:
378       /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
379       from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
380   */
381   static std::string RelativePath(std::string const& local,
382                                   std::string const& remote);
383
384   /**
385    * Convert the given remote path to a relative path with respect to
386    * the given local path.  Both paths must use forward slashes and not
387    * already be escaped or quoted.
388    */
389   static std::string ForceToRelativePath(std::string const& local_path,
390                                          std::string const& remote_path);
391
392   /**
393    * Express the 'in' path relative to 'top' if it does not start in '../'.
394    */
395   static std::string RelativeIfUnder(std::string const& top,
396                                      std::string const& in);
397
398 #ifndef CMAKE_BOOTSTRAP
399   /** Remove an environment variable */
400   static bool UnsetEnv(const char* value);
401
402   /** Get the list of all environment variables */
403   static std::vector<std::string> GetEnvironmentVariables();
404
405   /** Append multiple variables to the current environment. */
406   static void AppendEnv(std::vector<std::string> const& env);
407
408   /**
409    * Helper class to represent an environment diff directly. This is to avoid
410    * repeated in-place environment modification (i.e. via setenv/putenv), which
411    * could be slow.
412    */
413   class EnvDiff
414   {
415   public:
416     /** Append multiple variables to the current environment diff */
417     void AppendEnv(std::vector<std::string> const& env);
418
419     /**
420      * Add a single variable (or remove if no = sign) to the current
421      * environment diff.
422      */
423     void PutEnv(const std::string& env);
424
425     /** Remove a single variable from the current environment diff. */
426     void UnPutEnv(const std::string& env);
427
428     /**
429      * Apply an ENVIRONMENT_MODIFICATION operation to this diff. Returns
430      * false and issues an error on parse failure.
431      */
432     bool ParseOperation(const std::string& envmod);
433
434     /**
435      * Apply this diff to the actual environment, optionally writing out the
436      * modifications to a CTest-compatible measurement stream.
437      */
438     void ApplyToCurrentEnv(std::ostringstream* measurement = nullptr);
439
440   private:
441     std::map<std::string, cm::optional<std::string>> diff;
442   };
443
444   /** Helper class to save and restore the environment.
445       Instantiate this class as an automatic variable on
446       the stack. Its constructor saves a copy of the current
447       environment and then its destructor restores the
448       original environment. */
449   class SaveRestoreEnvironment
450   {
451   public:
452     SaveRestoreEnvironment();
453     ~SaveRestoreEnvironment();
454
455     SaveRestoreEnvironment(SaveRestoreEnvironment const&) = delete;
456     SaveRestoreEnvironment& operator=(SaveRestoreEnvironment const&) = delete;
457
458   private:
459     std::vector<std::string> Env;
460   };
461 #endif
462
463   /** Setup the environment to enable VS 8 IDE output.  */
464   static void EnableVSConsoleOutput();
465
466   enum cmTarAction
467   {
468     TarActionCreate,
469     TarActionList,
470     TarActionExtract,
471     TarActionNone
472   };
473
474   /** Create tar */
475   enum cmTarCompression
476   {
477     TarCompressGZip,
478     TarCompressBZip2,
479     TarCompressXZ,
480     TarCompressZstd,
481     TarCompressNone
482   };
483
484   enum class cmTarExtractTimestamps
485   {
486     Yes,
487     No
488   };
489
490   static bool ListTar(const std::string& outFileName,
491                       const std::vector<std::string>& files, bool verbose);
492   static bool CreateTar(const std::string& outFileName,
493                         const std::vector<std::string>& files,
494                         cmTarCompression compressType, bool verbose,
495                         std::string const& mtime = std::string(),
496                         std::string const& format = std::string(),
497                         int compressionLevel = 0);
498   static bool ExtractTar(const std::string& inFileName,
499                          const std::vector<std::string>& files,
500                          cmTarExtractTimestamps extractTimestamps,
501                          bool verbose);
502   // This should be called first thing in main
503   // it will keep child processes from inheriting the
504   // stdin and stdout of this process.  This is important
505   // if you want to be able to kill child processes and
506   // not get stuck waiting for all the output on the pipes.
507   static void DoNotInheritStdPipes();
508
509   static void EnsureStdPipes();
510
511   /** Random seed generation.  */
512   static unsigned int RandomSeed();
513
514   /** Find the directory containing CMake executables.  */
515   static void FindCMakeResources(const char* argv0);
516
517   /** Get the CMake resource paths, after FindCMakeResources.  */
518   static std::string const& GetCTestCommand();
519   static std::string const& GetCPackCommand();
520   static std::string const& GetCMakeCommand();
521   static std::string const& GetCMakeGUICommand();
522   static std::string const& GetCMakeCursesCommand();
523   static std::string const& GetCMClDepsCommand();
524   static std::string const& GetCMakeRoot();
525   static std::string const& GetHTMLDoc();
526
527   /** Get the CWD mapped through the KWSys translation map.  */
528   static std::string GetCurrentWorkingDirectory();
529
530   /** Echo a message in color using KWSys's Terminal cprintf.  */
531   static void MakefileColorEcho(int color, const char* message, bool newLine,
532                                 bool enabled);
533
534   /** Try to guess the soname of a shared library.  */
535   static bool GuessLibrarySOName(std::string const& fullPath,
536                                  std::string& soname);
537
538   /** Try to guess the install name of a shared library.  */
539   static bool GuessLibraryInstallName(std::string const& fullPath,
540                                       std::string& soname);
541
542   /** Try to change the RPATH in an ELF binary.  */
543   static bool ChangeRPath(std::string const& file, std::string const& oldRPath,
544                           std::string const& newRPath,
545                           bool removeEnvironmentRPath,
546                           std::string* emsg = nullptr,
547                           bool* changed = nullptr);
548
549   /** Try to set the RPATH in an ELF binary.  */
550   static bool SetRPath(std::string const& file, std::string const& newRPath,
551                        std::string* emsg = nullptr, bool* changed = nullptr);
552
553   /** Try to remove the RPATH from an ELF binary.  */
554   static bool RemoveRPath(std::string const& file, std::string* emsg = nullptr,
555                           bool* removed = nullptr);
556
557   /** Check whether the RPATH in an ELF binary contains the path
558       given.  */
559   static bool CheckRPath(std::string const& file, std::string const& newRPath);
560
561   /** Remove a directory; repeat a few times in case of locked files.  */
562   static bool RepeatedRemoveDirectory(const std::string& dir);
563
564   /** Encode a string as a URL.  */
565   static std::string EncodeURL(std::string const& in,
566                                bool escapeSlashes = true);
567
568 #ifdef _WIN32
569   struct WindowsFileRetry
570   {
571     unsigned int Count;
572     unsigned int Delay;
573   };
574   static WindowsFileRetry GetWindowsFileRetry();
575   static WindowsFileRetry GetWindowsDirectoryRetry();
576
577   struct WindowsVersion
578   {
579     unsigned int dwMajorVersion;
580     unsigned int dwMinorVersion;
581     unsigned int dwBuildNumber;
582   };
583   static WindowsVersion GetWindowsVersion();
584 #endif
585
586   /** Get the real path for a given path, removing all symlinks.
587       This variant of GetRealPath also works on Windows but will
588       resolve subst drives too.  */
589   static std::string GetRealPathResolvingWindowsSubst(
590     const std::string& path, std::string* errorMessage = nullptr);
591
592   /** Perform one-time initialization of libuv.  */
593   static void InitializeLibUV();
594
595   /** Create a symbolic link if the platform supports it.  Returns whether
596       creation succeeded. */
597   static cmsys::Status CreateSymlink(std::string const& origName,
598                                      std::string const& newName);
599   static cmsys::Status CreateSymlinkQuietly(std::string const& origName,
600                                             std::string const& newName);
601
602   /** Create a hard link if the platform supports it.  Returns whether
603       creation succeeded. */
604   static cmsys::Status CreateLink(std::string const& origName,
605                                   std::string const& newName);
606   static cmsys::Status CreateLinkQuietly(std::string const& origName,
607                                          std::string const& newName);
608
609   /** Get the system name. */
610   static cm::string_view GetSystemName();
611
612   /** Get the system path separator character */
613   static char GetSystemPathlistSeparator();
614
615 private:
616   static bool s_ForceUnixPaths;
617   static bool s_RunCommandHideConsole;
618   static bool s_ErrorOccurred;
619   static bool s_FatalErrorOccurred;
620   static bool s_DisableRunCommandOutput;
621 };