mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 02:08:27 +08:00
StdIo: Factor out helper to initialize stdin, stdout, and stderr
Move logic from commitc85524a94a
(Ensure stdin, stdout, and stderr pipes are always open, 2019-05-02, v3.15.0-rc1~171^2) and commit96010cc968
(Ensure stdin, stdout, stderr FILE streams are open on Windows, 2024-01-24, v3.29.0-rc1~65^2) to a dedicated source. Expose it through an `Init` class constructor to make it optionally available during static initialization. Issue: #26924
This commit is contained in:
@@ -468,6 +468,8 @@ add_library(
|
||||
cmStateSnapshot.cxx
|
||||
cmStateSnapshot.h
|
||||
cmStateTypes.h
|
||||
cmStdIoInit.h
|
||||
cmStdIoInit.cxx
|
||||
cmStringAlgorithms.cxx
|
||||
cmStringAlgorithms.h
|
||||
cmSyntheticTargetCache.h
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include "cmMakefile.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStateSnapshot.h"
|
||||
#include "cmStdIoInit.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmValue.h"
|
||||
@@ -89,7 +90,7 @@ std::vector<cmDocumentationEntry> makeGeneratorDocs(
|
||||
// this is CPack.
|
||||
int main(int argc, char const* const* argv)
|
||||
{
|
||||
cmSystemTools::EnsureStdPipes();
|
||||
cm::StdIo::Init();
|
||||
|
||||
// Replace streambuf so we can output Unicode to console
|
||||
cmConsoleBuf consoleBuf;
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "cmDocumentationEntry.h"
|
||||
#include "cmMessageMetadata.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStdIoInit.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmake.h"
|
||||
@@ -62,7 +63,8 @@ cmCursesForm* cmCursesForm::CurrentForm = nullptr;
|
||||
|
||||
int main(int argc, char const* const* argv)
|
||||
{
|
||||
cmSystemTools::EnsureStdPipes();
|
||||
cm::StdIo::Init();
|
||||
|
||||
cmsys::Encoding::CommandLineArguments encoding_args =
|
||||
cmsys::Encoding::CommandLineArguments::Main(argc, argv);
|
||||
argc = encoding_args.argc();
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmDocumentation.h"
|
||||
#include "cmDocumentationEntry.h"
|
||||
#include "cmStdIoInit.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h" // IWYU pragma: keep
|
||||
#include "cmake.h"
|
||||
@@ -66,7 +67,8 @@ void OpenReferenceManual(QString const& filename);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
cmSystemTools::EnsureStdPipes();
|
||||
cm::StdIo::Init();
|
||||
|
||||
cmsys::Encoding::CommandLineArguments encoding_args =
|
||||
cmsys::Encoding::CommandLineArguments::Main(argc, argv);
|
||||
int argc2 = encoding_args.argc();
|
||||
|
102
Source/cmStdIoInit.cxx
Normal file
102
Source/cmStdIoInit.cxx
Normal file
@@ -0,0 +1,102 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#include "cmStdIoInit.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
|
||||
# include <io.h> // for _close, _dup2, _get_osfhandle
|
||||
|
||||
# include "cm_fileno.hxx"
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace cm {
|
||||
namespace StdIo {
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef _WIN32
|
||||
void InitStdPipe(int stdFd, DWORD nStdHandle, FILE* stream,
|
||||
wchar_t const* mode)
|
||||
{
|
||||
if (cm_fileno(stream) >= 0) {
|
||||
return;
|
||||
}
|
||||
_close(stdFd);
|
||||
_wfreopen(L"NUL", mode, stream);
|
||||
int fd = cm_fileno(stream);
|
||||
if (fd < 0) {
|
||||
perror("failed to open NUL for missing stdio pipe");
|
||||
abort();
|
||||
}
|
||||
if (fd != stdFd) {
|
||||
_dup2(fd, stdFd);
|
||||
}
|
||||
SetStdHandle(nStdHandle, reinterpret_cast<HANDLE>(_get_osfhandle(fd)));
|
||||
}
|
||||
#else
|
||||
void InitStdPipe(int fd)
|
||||
{
|
||||
if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
|
||||
return;
|
||||
}
|
||||
|
||||
int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
|
||||
if (f == -1) {
|
||||
perror("failed to open /dev/null for missing stdio pipe");
|
||||
abort();
|
||||
}
|
||||
if (f != fd) {
|
||||
dup2(f, fd);
|
||||
close(f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct InitStdPipes
|
||||
{
|
||||
InitStdPipes()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
InitStdPipe(0, STD_INPUT_HANDLE, stdin, L"rb");
|
||||
InitStdPipe(1, STD_OUTPUT_HANDLE, stdout, L"wb");
|
||||
InitStdPipe(2, STD_ERROR_HANDLE, stderr, L"wb");
|
||||
#else
|
||||
InitStdPipe(STDIN_FILENO);
|
||||
InitStdPipe(STDOUT_FILENO);
|
||||
InitStdPipe(STDERR_FILENO);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class Globals
|
||||
{
|
||||
public:
|
||||
InitStdPipes InitPipes;
|
||||
|
||||
static Globals& Get();
|
||||
};
|
||||
|
||||
Globals& Globals::Get()
|
||||
{
|
||||
static Globals globals;
|
||||
return globals;
|
||||
}
|
||||
|
||||
Init::Init()
|
||||
{
|
||||
Globals::Get();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
27
Source/cmStdIoInit.h
Normal file
27
Source/cmStdIoInit.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
namespace cm {
|
||||
namespace StdIo {
|
||||
|
||||
/**
|
||||
* Initialize process-wide `stdin`, `stdout`, and `stderr` streams.
|
||||
* After construction, standard in/out/err descriptors/handles are open,
|
||||
* and standard `FILE*` streams from `<cstdio>` are associated with them.
|
||||
*/
|
||||
class Init
|
||||
{
|
||||
public:
|
||||
Init();
|
||||
~Init() = default;
|
||||
Init(Init&&) noexcept = default;
|
||||
Init(Init const&) = delete;
|
||||
Init& operator=(Init&&) noexcept = default;
|
||||
Init& operator=(Init const&) = delete;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
@@ -2866,58 +2866,6 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static void EnsureStdPipe(int stdFd, DWORD nStdHandle, FILE* stream,
|
||||
wchar_t const* mode)
|
||||
{
|
||||
if (fileno(stream) >= 0) {
|
||||
return;
|
||||
}
|
||||
_close(stdFd);
|
||||
_wfreopen(L"NUL", mode, stream);
|
||||
int fd = fileno(stream);
|
||||
if (fd < 0) {
|
||||
perror("failed to open NUL for missing stdio pipe");
|
||||
abort();
|
||||
}
|
||||
if (fd != stdFd) {
|
||||
_dup2(fd, stdFd);
|
||||
}
|
||||
SetStdHandle(nStdHandle, reinterpret_cast<HANDLE>(_get_osfhandle(fd)));
|
||||
}
|
||||
|
||||
void cmSystemTools::EnsureStdPipes()
|
||||
{
|
||||
EnsureStdPipe(0, STD_INPUT_HANDLE, stdin, L"rb");
|
||||
EnsureStdPipe(1, STD_OUTPUT_HANDLE, stdout, L"wb");
|
||||
EnsureStdPipe(2, STD_ERROR_HANDLE, stderr, L"wb");
|
||||
}
|
||||
#else
|
||||
static void EnsureStdPipe(int fd)
|
||||
{
|
||||
if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
|
||||
return;
|
||||
}
|
||||
|
||||
int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
|
||||
if (f == -1) {
|
||||
perror("failed to open /dev/null for missing stdio pipe");
|
||||
abort();
|
||||
}
|
||||
if (f != fd) {
|
||||
dup2(f, fd);
|
||||
close(f);
|
||||
}
|
||||
}
|
||||
|
||||
void cmSystemTools::EnsureStdPipes()
|
||||
{
|
||||
EnsureStdPipe(STDIN_FILENO);
|
||||
EnsureStdPipe(STDOUT_FILENO);
|
||||
EnsureStdPipe(STDERR_FILENO);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef CRYPT_SILENT
|
||||
# define CRYPT_SILENT 0x40 /* Not defined by VS 6 version of header. */
|
||||
|
@@ -554,8 +554,6 @@ public:
|
||||
cmTarExtractTimestamps extractTimestamps,
|
||||
bool verbose);
|
||||
|
||||
static void EnsureStdPipes();
|
||||
|
||||
/** Random number generation. */
|
||||
static unsigned int RandomSeed();
|
||||
static unsigned int RandomNumber();
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "cmMessageMetadata.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmStdIoInit.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmValue.h"
|
||||
@@ -1142,7 +1143,7 @@ int do_open(int ac, char const* const* av)
|
||||
|
||||
int main(int ac, char const* const* av)
|
||||
{
|
||||
cmSystemTools::EnsureStdPipes();
|
||||
cm::StdIo::Init();
|
||||
|
||||
// Replace streambuf so we can output Unicode to console
|
||||
auto consoleBuf = cm::make_unique<cmConsoleBuf>();
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "cmDocumentationEntry.h"
|
||||
#include "cmInstrumentation.h"
|
||||
#include "cmInstrumentationQuery.h"
|
||||
#include "cmStdIoInit.h"
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
#include "CTest/cmCTestLaunch.h"
|
||||
@@ -166,7 +167,7 @@ cmDocumentationEntry const cmDocumentationOptions[] = {
|
||||
// this is a test driver program for cmCTest.
|
||||
int main(int argc, char const* const* argv)
|
||||
{
|
||||
cmSystemTools::EnsureStdPipes();
|
||||
cm::StdIo::Init();
|
||||
|
||||
// Replace streambuf so we can output Unicode to console
|
||||
cmConsoleBuf consoleBuf;
|
||||
|
@@ -24,6 +24,7 @@ set(CMakeLib_TESTS
|
||||
testRange.cxx
|
||||
testOptional.cxx
|
||||
testPathResolver.cxx
|
||||
testStdIo.cxx
|
||||
testString.cxx
|
||||
testStringAlgorithms.cxx
|
||||
testSystemTools.cxx
|
||||
|
15
Tests/CMakeLib/testStdIo.cxx
Normal file
15
Tests/CMakeLib/testStdIo.cxx
Normal file
@@ -0,0 +1,15 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmStdIoInit.h"
|
||||
|
||||
#include "testCommon.h"
|
||||
|
||||
namespace {
|
||||
}
|
||||
|
||||
int testStdIo(int /*unused*/, char* /*unused*/[])
|
||||
{
|
||||
cm::StdIo::Init();
|
||||
return runTests({});
|
||||
}
|
Reference in New Issue
Block a user