1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
5 #include "cmConfigure.h" // IWYU pragma: keep
8 # include <sys/types.h>
18 #include <cm/optional>
19 #include <cm/string_view>
21 #include "cmsys/Process.h"
22 #include "cmsys/Status.hxx" // IWYU pragma: export
23 #include "cmsys/SystemTools.hxx" // IWYU pragma: export
25 #include "cmCryptoHash.h"
26 #include "cmDuration.h"
27 #include "cmProcessOutput.h"
29 struct cmMessageMetadata;
31 /** \class cmSystemTools
32 * \brief A collection of useful functions for CMake.
34 * cmSystemTools is a class that provides helper functions
35 * for the CMake build system.
37 class cmSystemTools : public cmsys::SystemTools
40 using Superclass = cmsys::SystemTools;
41 using Encoding = cmProcessOutput::Encoding;
44 * Look for and replace registry values in a string
46 static void ExpandRegistryValues(std::string& source,
47 KeyWOW64 view = KeyWOW64_Default);
49 /** Map help document name to file name. */
50 static std::string HelpFileName(cm::string_view);
52 using MessageCallback =
53 std::function<void(const std::string&, const cmMessageMetadata&)>;
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*.
59 static void SetMessageCallback(MessageCallback f);
62 * Display an error message.
64 static void Error(const std::string& m);
69 static void Message(const std::string& m, const char* title = nullptr);
70 static void Message(const std::string& m, const cmMessageMetadata& md);
72 using OutputCallback = std::function<void(std::string const&)>;
74 //! Send a string to stdout
75 static void Stdout(const std::string& s);
76 static void SetStdoutCallback(OutputCallback f);
78 //! Send a string to stderr
79 static void Stderr(const std::string& s);
80 static void SetStderrCallback(OutputCallback f);
82 using InterruptCallback = std::function<bool()>;
83 static void SetInterruptCallback(InterruptCallback f);
84 static bool GetInterruptFlag();
86 //! Return true if there was an error at any point.
87 static bool GetErrorOccurredFlag()
89 return cmSystemTools::s_ErrorOccurred ||
90 cmSystemTools::s_FatalErrorOccurred || GetInterruptFlag();
92 //! If this is set to true, cmake stops processing commands.
93 static void SetFatalErrorOccurred()
95 cmSystemTools::s_FatalErrorOccurred = true;
97 static void SetErrorOccurred() { cmSystemTools::s_ErrorOccurred = true; }
98 //! Return true if there was an error at any point.
99 static bool GetFatalErrorOccurred()
101 return cmSystemTools::s_FatalErrorOccurred || GetInterruptFlag();
104 //! Set the error occurred flag and fatal error back to false
105 static void ResetErrorOccurredFlag()
107 cmSystemTools::s_FatalErrorOccurred = false;
108 cmSystemTools::s_ErrorOccurred = false;
111 //! Return true if the path is a framework
112 static bool IsPathToFramework(const std::string& path);
114 //! Return true if the path is a macOS non-framework shared library (aka
116 static bool IsPathToMacOSSharedLibrary(const std::string& path);
118 static bool DoesFileExistWithExtensions(
119 const std::string& name, const std::vector<std::string>& sourceExts);
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.
126 static std::string FileExistsInParentDirectories(
127 const std::string& fname, const std::string& directory,
128 const std::string& toplevel);
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);
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.
144 static bool SimpleGlob(const std::string& glob,
145 std::vector<std::string>& files, int type = 0);
152 enum class CopyResult
158 #if defined(_MSC_VER)
159 /** Visual C++ does not define mode_t. */
160 using mode_t = unsigned short;
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).
169 * This function can make a full path even if none of the directories existed
170 * prior to calling this function.
172 * Note that this function may modify \p path even if it does not succeed.
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);
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);
191 enum class RenameResult
198 /** Rename a file or directory within a single disk volume (atomic
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);
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);
210 #ifndef CMAKE_BOOTSTRAP
211 //! Compute the hash of a file
212 static std::string ComputeFileHash(const std::string& source,
213 cmCryptoHash::Algo algo);
215 /** Compute the md5sum of a string. */
216 static std::string ComputeStringMD5(const std::string& input);
219 //! Get the SHA thumbprint for a certificate file
220 static std::string ComputeCertificateThumbprint(const std::string& source);
225 * Run a single executable command
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.
233 * If timeout is specified, the command will be terminated after
234 * timeout expires. Timeout is specified in seconds.
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.
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.
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());
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()]
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);
274 static std::string PrintSingleCommand(std::vector<std::string> const&);
277 * Parse arguments out of a single string command
279 static std::vector<std::string> ParseArguments(const std::string& command);
281 /** Parse arguments out of a windows command line string. */
282 static void ParseWindowsCommandLine(const char* command,
283 std::vector<std::string>& args);
285 /** Parse arguments out of a unix command line string. */
286 static void ParseUnixCommandLine(const char* command,
287 std::vector<std::string>& args);
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);
295 * Handle response file in an argument list and return a new argument list
297 static std::vector<std::string> HandleResponseFile(
298 std::vector<std::string>::const_iterator argBeg,
299 std::vector<std::string>::const_iterator argEnd);
301 static size_t CalculateCommandLineLengthLimit();
303 static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
304 static void EnableRunCommandOutput() { s_DisableRunCommandOutput = false; }
305 static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; }
312 OP_LESS_EQUAL = OP_LESS | OP_EQUAL,
313 OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL
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,
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);
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.
338 static int strverscmp(std::string const& lhs, std::string const& rhs);
340 /** Windows if this is true, the CreateProcess in RunCommand will
341 * not show new console windows when running programs.
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)
348 static void ReportLastSystemError(const char* m);
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);
355 static void SetForceUnixPaths(bool v) { s_ForceUnixPaths = v; }
356 static bool GetForceUnixPaths() { return s_ForceUnixPaths; }
358 // ConvertToOutputPath use s_ForceUnixPaths
359 static std::string ConvertToOutputPath(std::string const& path);
360 static void ConvertToOutputSlashes(std::string& path);
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);
368 * For windows computes the long path for the given path,
369 * For Unix, it is a noop
371 static void ConvertToLongPath(std::string& path);
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
381 static std::string RelativePath(std::string const& local,
382 std::string const& remote);
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.
389 static std::string ForceToRelativePath(std::string const& local_path,
390 std::string const& remote_path);
393 * Express the 'in' path relative to 'top' if it does not start in '../'.
395 static std::string RelativeIfUnder(std::string const& top,
396 std::string const& in);
398 #ifndef CMAKE_BOOTSTRAP
399 /** Remove an environment variable */
400 static bool UnsetEnv(const char* value);
402 /** Get the list of all environment variables */
403 static std::vector<std::string> GetEnvironmentVariables();
405 /** Append multiple variables to the current environment. */
406 static void AppendEnv(std::vector<std::string> const& env);
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
416 /** Append multiple variables to the current environment diff */
417 void AppendEnv(std::vector<std::string> const& env);
420 * Add a single variable (or remove if no = sign) to the current
423 void PutEnv(const std::string& env);
425 /** Remove a single variable from the current environment diff. */
426 void UnPutEnv(const std::string& env);
429 * Apply an ENVIRONMENT_MODIFICATION operation to this diff. Returns
430 * false and issues an error on parse failure.
432 bool ParseOperation(const std::string& envmod);
435 * Apply this diff to the actual environment, optionally writing out the
436 * modifications to a CTest-compatible measurement stream.
438 void ApplyToCurrentEnv(std::ostringstream* measurement = nullptr);
441 std::map<std::string, cm::optional<std::string>> diff;
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
452 SaveRestoreEnvironment();
453 ~SaveRestoreEnvironment();
455 SaveRestoreEnvironment(SaveRestoreEnvironment const&) = delete;
456 SaveRestoreEnvironment& operator=(SaveRestoreEnvironment const&) = delete;
459 std::vector<std::string> Env;
463 /** Setup the environment to enable VS 8 IDE output. */
464 static void EnableVSConsoleOutput();
475 enum cmTarCompression
484 enum class cmTarExtractTimestamps
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,
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();
509 static void EnsureStdPipes();
511 /** Random seed generation. */
512 static unsigned int RandomSeed();
514 /** Find the directory containing CMake executables. */
515 static void FindCMakeResources(const char* argv0);
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();
527 /** Get the CWD mapped through the KWSys translation map. */
528 static std::string GetCurrentWorkingDirectory();
530 /** Echo a message in color using KWSys's Terminal cprintf. */
531 static void MakefileColorEcho(int color, const char* message, bool newLine,
534 /** Try to guess the soname of a shared library. */
535 static bool GuessLibrarySOName(std::string const& fullPath,
536 std::string& soname);
538 /** Try to guess the install name of a shared library. */
539 static bool GuessLibraryInstallName(std::string const& fullPath,
540 std::string& soname);
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);
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);
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);
557 /** Check whether the RPATH in an ELF binary contains the path
559 static bool CheckRPath(std::string const& file, std::string const& newRPath);
561 /** Remove a directory; repeat a few times in case of locked files. */
562 static bool RepeatedRemoveDirectory(const std::string& dir);
564 /** Encode a string as a URL. */
565 static std::string EncodeURL(std::string const& in,
566 bool escapeSlashes = true);
569 struct WindowsFileRetry
574 static WindowsFileRetry GetWindowsFileRetry();
575 static WindowsFileRetry GetWindowsDirectoryRetry();
577 struct WindowsVersion
579 unsigned int dwMajorVersion;
580 unsigned int dwMinorVersion;
581 unsigned int dwBuildNumber;
583 static WindowsVersion GetWindowsVersion();
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);
592 /** Perform one-time initialization of libuv. */
593 static void InitializeLibUV();
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);
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);
609 /** Get the system name. */
610 static cm::string_view GetSystemName();
612 /** Get the system path separator character */
613 static char GetSystemPathlistSeparator();
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;