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>
23 #include "cmsys/Status.hxx" // IWYU pragma: export
24 #include "cmsys/SystemTools.hxx" // IWYU pragma: export
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 xcframework
115 static bool IsPathToXcFramework(const std::string
& path
);
117 //! Return true if the path is a macOS non-framework shared library (aka
119 static bool IsPathToMacOSSharedLibrary(const std::string
& path
);
121 static bool DoesFileExistWithExtensions(
122 const std::string
& name
, const std::vector
<std::string
>& sourceExts
);
125 * Check if the given file exists in one of the parent directory of the
126 * given file or directory and if it does, return the name of the file.
127 * Toplevel specifies the top-most directory to where it will look.
129 static std::string
FileExistsInParentDirectories(
130 const std::string
& fname
, const std::string
& directory
,
131 const std::string
& toplevel
);
133 static void Glob(const std::string
& directory
, const std::string
& regexp
,
134 std::vector
<std::string
>& files
);
135 static void GlobDirs(const std::string
& fullPath
,
136 std::vector
<std::string
>& files
);
139 * Try to find a list of files that match the "simple" globbing
140 * expression. At this point in time the globbing expressions have
141 * to be in form: /directory/partial_file_name*. The * character has
142 * to be at the end of the string and it does not support ?
143 * []... The optional argument type specifies what kind of files you
144 * want to find. 0 means all files, -1 means directories, 1 means
145 * files only. This method returns true if search was successful.
147 static bool SimpleGlob(const std::string
& glob
,
148 std::vector
<std::string
>& files
, int type
= 0);
155 enum class CopyInputRecent
160 enum class CopyResult
166 #if defined(_MSC_VER)
167 /** Visual C++ does not define mode_t. */
168 using mode_t
= unsigned short;
172 * Make a new temporary directory. The path must end in "XXXXXX", and will
173 * be modified to reflect the name of the directory created. This function
174 * is similar to POSIX mkdtemp (and is implemented using the same where that
175 * function is available).
177 * This function can make a full path even if none of the directories existed
178 * prior to calling this function.
180 * Note that this function may modify \p path even if it does not succeed.
182 static cmsys::Status
MakeTempDirectory(char* path
,
183 const mode_t
* mode
= nullptr);
184 static cmsys::Status
MakeTempDirectory(std::string
& path
,
185 const mode_t
* mode
= nullptr);
188 static CopyResult
CopySingleFile(std::string
const& oldname
,
189 std::string
const& newname
, CopyWhen when
,
190 CopyInputRecent inputRecent
,
191 std::string
* err
= nullptr);
198 enum class RenameResult
205 /** Rename a file or directory within a single disk volume (atomic
207 static bool RenameFile(const std::string
& oldname
,
208 const std::string
& newname
);
209 static RenameResult
RenameFile(std::string
const& oldname
,
210 std::string
const& newname
, Replace replace
,
211 std::string
* err
= nullptr);
213 //! Rename a file if contents are different, delete the source otherwise
214 static void MoveFileIfDifferent(const std::string
& source
,
215 const std::string
& destination
);
218 * Run a single executable command
220 * Output is controlled with outputflag. If outputflag is OUTPUT_NONE, no
221 * user-viewable output from the program being run will be generated.
222 * OUTPUT_MERGE is the legacy behavior where stdout and stderr are merged
223 * into stdout. OUTPUT_FORWARD copies the output to stdout/stderr as
224 * it was received. OUTPUT_PASSTHROUGH passes through the original handles.
226 * If timeout is specified, the command will be terminated after
227 * timeout expires. Timeout is specified in seconds.
229 * Argument retVal should be a pointer to the location where the
230 * exit code will be stored. If the retVal is not specified and
231 * the program exits with a code other than 0, then the this
232 * function will return false.
234 * If the command has spaces in the path the caller MUST call
235 * cmSystemTools::ConvertToRunCommandPath on the command before passing
236 * it into this function or it will not work. The command must be correctly
237 * escaped for this to with spaces.
246 static bool RunSingleCommand(const std::string
& command
,
247 std::string
* captureStdOut
= nullptr,
248 std::string
* captureStdErr
= nullptr,
249 int* retVal
= nullptr,
250 const char* dir
= nullptr,
251 OutputOption outputflag
= OUTPUT_MERGE
,
252 cmDuration timeout
= cmDuration::zero());
254 * In this version of RunSingleCommand, command[0] should be
255 * the command to run, and each argument to the command should
256 * be in command[1]...command[command.size()]
258 static bool RunSingleCommand(std::vector
<std::string
> const& command
,
259 std::string
* captureStdOut
= nullptr,
260 std::string
* captureStdErr
= nullptr,
261 int* retVal
= nullptr,
262 const char* dir
= nullptr,
263 OutputOption outputflag
= OUTPUT_MERGE
,
264 cmDuration timeout
= cmDuration::zero(),
265 Encoding encoding
= cmProcessOutput::Auto
);
267 static std::string
PrintSingleCommand(std::vector
<std::string
> const&);
270 * Parse arguments out of a single string command
272 static std::vector
<std::string
> ParseArguments(const std::string
& command
);
274 /** Parse arguments out of a windows command line string. */
275 static void ParseWindowsCommandLine(const char* command
,
276 std::vector
<std::string
>& args
);
278 /** Parse arguments out of a unix command line string. */
279 static void ParseUnixCommandLine(const char* command
,
280 std::vector
<std::string
>& args
);
282 /** Split a command-line string into the parsed command and the unparsed
283 arguments. Returns false on unfinished quoting or escaping. */
284 static bool SplitProgramFromArgs(std::string
const& command
,
285 std::string
& program
, std::string
& args
);
288 * Handle response file in an argument list and return a new argument list
290 static std::vector
<std::string
> HandleResponseFile(
291 std::vector
<std::string
>::const_iterator argBeg
,
292 std::vector
<std::string
>::const_iterator argEnd
);
294 static std::size_t CalculateCommandLineLengthLimit();
296 static void DisableRunCommandOutput() { s_DisableRunCommandOutput
= true; }
297 static void EnableRunCommandOutput() { s_DisableRunCommandOutput
= false; }
298 static bool GetRunCommandOutput() { return s_DisableRunCommandOutput
; }
305 OP_LESS_EQUAL
= OP_LESS
| OP_EQUAL
,
306 OP_GREATER_EQUAL
= OP_GREATER
| OP_EQUAL
312 static bool VersionCompare(CompareOp op
, const std::string
& lhs
,
313 const std::string
& rhs
);
314 static bool VersionCompare(CompareOp op
, const std::string
& lhs
,
316 static bool VersionCompareEqual(std::string
const& lhs
,
317 std::string
const& rhs
);
318 static bool VersionCompareGreater(std::string
const& lhs
,
319 std::string
const& rhs
);
320 static bool VersionCompareGreaterEq(std::string
const& lhs
,
321 std::string
const& rhs
);
324 * Compare two ASCII strings using natural versioning order.
325 * Non-numerical characters are compared directly.
326 * Numerical characters are first globbed such that, e.g.
327 * `test000 < test01 < test0 < test1 < test10`.
328 * Return a value less than, equal to, or greater than zero if lhs
329 * precedes, equals, or succeeds rhs in the defined ordering.
331 static int strverscmp(std::string
const& lhs
, std::string
const& rhs
);
333 /** Windows if this is true, the CreateProcess in RunCommand will
334 * not show new console windows when running programs.
336 static void SetRunCommandHideConsole(bool v
) { s_RunCommandHideConsole
= v
; }
337 static bool GetRunCommandHideConsole() { return s_RunCommandHideConsole
; }
338 /** Call cmSystemTools::Error with the message m, plus the
339 * result of strerror(errno)
341 static void ReportLastSystemError(const char* m
);
343 enum class WaitForLineResult
351 /** a general output handler for libuv */
352 static WaitForLineResult
WaitForLine(uv_loop_t
* loop
, uv_stream_t
* outPipe
,
353 uv_stream_t
* errPipe
, std::string
& line
,
355 std::vector
<char>& out
,
356 std::vector
<char>& err
);
358 static void SetForceUnixPaths(bool v
) { s_ForceUnixPaths
= v
; }
359 static bool GetForceUnixPaths() { return s_ForceUnixPaths
; }
361 // ConvertToOutputPath use s_ForceUnixPaths
362 static std::string
ConvertToOutputPath(std::string
const& path
);
363 static void ConvertToOutputSlashes(std::string
& path
);
365 // ConvertToRunCommandPath does not use s_ForceUnixPaths and should
366 // be used when RunCommand is called from cmake, because the
367 // running cmake needs paths to be in its format
368 static std::string
ConvertToRunCommandPath(const std::string
& path
);
371 * For windows computes the long path for the given path,
372 * For Unix, it is a noop
374 static void ConvertToLongPath(std::string
& path
);
376 /** compute the relative path from local to remote. local must
377 be a directory. remote can be a file or a directory.
378 Both remote and local must be full paths. Basically, if
379 you are in directory local and you want to access the file in remote
380 what is the relative path to do that. For example:
381 /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1
382 from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp
384 static std::string
RelativePath(std::string
const& local
,
385 std::string
const& remote
);
388 * Convert the given remote path to a relative path with respect to
389 * the given local path. Both paths must use forward slashes and not
390 * already be escaped or quoted.
392 static std::string
ForceToRelativePath(std::string
const& local_path
,
393 std::string
const& remote_path
);
396 * Express the 'in' path relative to 'top' if it does not start in '../'.
398 static std::string
RelativeIfUnder(std::string
const& top
,
399 std::string
const& in
);
401 static cm::optional
<std::string
> GetEnvVar(std::string
const& var
);
402 static std::vector
<std::string
> SplitEnvPath(std::string
const& value
);
404 #ifndef CMAKE_BOOTSTRAP
405 /** Remove an environment variable */
406 static bool UnsetEnv(const char* value
);
408 /** Get the list of all environment variables */
409 static std::vector
<std::string
> GetEnvironmentVariables();
411 /** Append multiple variables to the current environment. */
412 static void AppendEnv(std::vector
<std::string
> const& env
);
415 * Helper class to represent an environment diff directly. This is to avoid
416 * repeated in-place environment modification (i.e. via setenv/putenv), which
422 /** Append multiple variables to the current environment diff */
423 void AppendEnv(std::vector
<std::string
> const& env
);
426 * Add a single variable (or remove if no = sign) to the current
429 void PutEnv(const std::string
& env
);
431 /** Remove a single variable from the current environment diff. */
432 void UnPutEnv(const std::string
& env
);
435 * Apply an ENVIRONMENT_MODIFICATION operation to this diff. Returns
436 * false and issues an error on parse failure.
438 bool ParseOperation(const std::string
& envmod
);
441 * Apply this diff to the actual environment, optionally writing out the
442 * modifications to a CTest-compatible measurement stream.
444 void ApplyToCurrentEnv(std::ostringstream
* measurement
= nullptr);
447 std::map
<std::string
, cm::optional
<std::string
>> diff
;
450 /** Helper class to save and restore the environment.
451 Instantiate this class as an automatic variable on
452 the stack. Its constructor saves a copy of the current
453 environment and then its destructor restores the
454 original environment. */
455 class SaveRestoreEnvironment
458 SaveRestoreEnvironment();
459 ~SaveRestoreEnvironment();
461 SaveRestoreEnvironment(SaveRestoreEnvironment
const&) = delete;
462 SaveRestoreEnvironment
& operator=(SaveRestoreEnvironment
const&) = delete;
465 std::vector
<std::string
> Env
;
469 /** Setup the environment to enable VS 8 IDE output. */
470 static void EnableVSConsoleOutput();
481 enum cmTarCompression
490 enum class cmTarExtractTimestamps
496 static bool ListTar(const std::string
& outFileName
,
497 const std::vector
<std::string
>& files
, bool verbose
);
498 static bool CreateTar(const std::string
& outFileName
,
499 const std::vector
<std::string
>& files
,
500 cmTarCompression compressType
, bool verbose
,
501 std::string
const& mtime
= std::string(),
502 std::string
const& format
= std::string(),
503 int compressionLevel
= 0);
504 static bool ExtractTar(const std::string
& inFileName
,
505 const std::vector
<std::string
>& files
,
506 cmTarExtractTimestamps extractTimestamps
,
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
;