CMake Nightly Date Stamp
[kiteware-cmake.git] / Source / cmSystemTools.h
blobd12ab070d59b64be943f70e002c817a415fa8c39
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
5 #include "cmConfigure.h" // IWYU pragma: keep
7 #if !defined(_WIN32)
8 # include <sys/types.h>
9 #endif
11 #include <cstddef>
12 #include <functional>
13 #include <map>
14 #include <sstream>
15 #include <string>
16 #include <vector>
18 #include <cm/optional>
19 #include <cm/string_view>
21 #include <cm3p/uv.h>
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
39 public:
40 using Superclass = cmsys::SystemTools;
41 using Encoding = cmProcessOutput::Encoding;
43 /**
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&)>;
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*.
59 static void SetMessageCallback(MessageCallback f);
61 /**
62 * Display an error message.
64 static void Error(const std::string& m);
66 /**
67 * Display a message.
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
118 //! .dylib)
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);
150 enum class CopyWhen
152 Always,
153 OnlyIfDifferent,
155 enum class CopyInputRecent
158 Yes,
160 enum class CopyResult
162 Success,
163 Failure,
166 #if defined(_MSC_VER)
167 /** Visual C++ does not define mode_t. */
168 using mode_t = unsigned short;
169 #endif
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);
187 /** Copy a file. */
188 static CopyResult CopySingleFile(std::string const& oldname,
189 std::string const& newname, CopyWhen when,
190 CopyInputRecent inputRecent,
191 std::string* err = nullptr);
193 enum class Replace
195 Yes,
198 enum class RenameResult
200 Success,
201 NoReplace,
202 Failure,
205 /** Rename a file or directory within a single disk volume (atomic
206 if possible). */
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.
239 enum OutputOption
241 OUTPUT_NONE = 0,
242 OUTPUT_MERGE,
243 OUTPUT_FORWARD,
244 OUTPUT_PASSTHROUGH
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
289 * **/
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; }
300 enum CompareOp
302 OP_EQUAL = 1,
303 OP_LESS = 2,
304 OP_GREATER = 4,
305 OP_LESS_EQUAL = OP_LESS | OP_EQUAL,
306 OP_GREATER_EQUAL = OP_GREATER | OP_EQUAL
310 * Compare versions
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,
315 const char rhs[]);
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
345 None,
346 STDOUT,
347 STDERR,
348 Timeout,
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,
354 cmDuration timeout,
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
417 * could be slow.
419 class EnvDiff
421 public:
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
427 * environment diff.
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);
446 private:
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
457 public:
458 SaveRestoreEnvironment();
459 ~SaveRestoreEnvironment();
461 SaveRestoreEnvironment(SaveRestoreEnvironment const&) = delete;
462 SaveRestoreEnvironment& operator=(SaveRestoreEnvironment const&) = delete;
464 private:
465 std::vector<std::string> Env;
467 #endif
469 /** Setup the environment to enable VS 8 IDE output. */
470 static void EnableVSConsoleOutput();
472 enum cmTarAction
474 TarActionCreate,
475 TarActionList,
476 TarActionExtract,
477 TarActionNone
480 /** Create tar */
481 enum cmTarCompression
483 TarCompressGZip,
484 TarCompressBZip2,
485 TarCompressXZ,
486 TarCompressZstd,
487 TarCompressNone
490 enum class cmTarExtractTimestamps
492 Yes,
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,
507 bool verbose);
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,
532 bool enabled);
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
558 given. */
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);
568 #ifdef _WIN32
569 struct WindowsFileRetry
571 unsigned int Count;
572 unsigned int Delay;
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();
584 #endif
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();
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;