Skip to content

Commit 4e25396

Browse files
authored
Merge pull request #424 from apple/revert-422-AUnitaryOperation
Revert "Fixed the Unit Tests on Windows" to unblock Swift-CI rdar://problem/47741242
2 parents b76a01f + a9064fb commit 4e25396

File tree

11 files changed

+111
-276
lines changed

11 files changed

+111
-276
lines changed

docs/buildsystem.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ Symlink Tool
437437
This tool is used to create a symbolic link at a particular location, with
438438
appropriate dependency tracking. Due to the nature of symbolic links it is
439439
important to use this tool when creating links during a build, as opposed to the
440-
usual `shell` tool. The reason why is that the build system will, by default,
440+
usuall `shell` tool. The reason why is that the build system will, by default,
441441
use `stat(2)` to examine the contents of output files for the purposes of
442442
evaluating the build state. In the case of a symbolic link this is incorrect, as
443443
it will retrieve the status information of the target, not the link itself. This

include/llbuild/Basic/PlatformUtility.h

-3
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@ char *strsep(char **stringp, const char *delim);
4747
// it's path.
4848
std::string makeTmpDir();
4949

50-
// Return a string containing all valid path separators on the current platform
51-
std::string getPathSeparators();
52-
5350
/// Sets the max open file limit to min(max(soft_limit, limit), hard_limit),
5451
/// where soft_limit and hard_limit are gathered from the system.
5552
///

lib/Basic/FileSystem.cpp

-7
Original file line numberDiff line numberDiff line change
@@ -171,17 +171,10 @@ class LocalFileSystem : public FileSystem {
171171
return true;
172172
}
173173

174-
#if defined(_WIN32)
175-
// Windows sets EACCES if the file is a directory
176-
if (errno != EACCES) {
177-
return false;
178-
}
179-
#else
180174
// Error can't be that `path` is actually a directory (on Linux `EISDIR` will be returned since 2.1.132).
181175
if (errno != EPERM && errno != EISDIR) {
182176
return false;
183177
}
184-
#endif
185178

186179
// Check if `path` is a directory.
187180
llbuild::basic::sys::StatStruct statbuf;

lib/Basic/PlatformUtility.cpp

+24-110
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@
1111
#include "llbuild/Basic/Stat.h"
1212
#include "llvm/ADT/SmallVector.h"
1313
#include "llvm/Support/ConvertUTF.h"
14-
#include "llvm/Support/Path.h"
1514

1615
#if defined(_WIN32)
1716
#include "LeanWindows.h"
1817
#include <Shlwapi.h>
1918
#include <direct.h>
2019
#include <io.h>
21-
#include <time.h>
2220
#else
2321
#include <fnmatch.h>
2422
#include <unistd.h>
@@ -30,9 +28,7 @@ using namespace llbuild::basic;
3028

3129
bool sys::chdir(const char *fileName) {
3230
#if defined(_WIN32)
33-
llvm::SmallVector<UTF16, 20> wFileName;
34-
llvm::convertUTF8ToUTF16String(fileName, wFileName);
35-
return SetCurrentDirectoryW((LPCWSTR)wFileName.data());
31+
return SetCurrentDirectoryA(fileName);
3632
#else
3733
return ::chdir(fileName) == 0;
3834
#endif
@@ -46,68 +42,11 @@ int sys::close(int fileHandle) {
4642
#endif
4743
}
4844

49-
#if defined(_WIN32)
50-
time_t filetimeToTime_t(FILETIME ft) {
51-
long long ltime = ft.dwLowDateTime | ((long long)ft.dwHighDateTime << 32);
52-
return (time_t)((ltime - 116444736000000000) / 10000000);
53-
}
54-
#endif
55-
5645
int sys::lstat(const char *fileName, sys::StatStruct *buf) {
5746
#if defined(_WIN32)
58-
llvm::SmallVector<UTF16, 20> wfilename;
59-
llvm::convertUTF8ToUTF16String(fileName, wfilename);
60-
HANDLE h = CreateFileW(
61-
/*lpFileName=*/(LPCWSTR)wfilename.data(),
62-
/*dwDesiredAccess=*/0,
63-
/*dwShareMode=*/FILE_SHARE_READ,
64-
/*lpSecurityAttributes=*/NULL,
65-
/*dwCreationDisposition=*/OPEN_EXISTING,
66-
/*dwFlagsAndAttributes=*/FILE_FLAG_OPEN_REPARSE_POINT |
67-
FILE_FLAG_BACKUP_SEMANTICS,
68-
/*hTemplateFile=*/NULL);
69-
if (h == INVALID_HANDLE_VALUE) {
70-
int err = GetLastError();
71-
if (err == ERROR_FILE_NOT_FOUND) {
72-
errno = ENOENT;
73-
}
74-
return -1;
75-
}
76-
BY_HANDLE_FILE_INFORMATION info;
77-
GetFileInformationByHandle(h, &info);
78-
// Group id is always 0 on Windows
79-
buf->st_gid = 0;
80-
buf->st_atime = filetimeToTime_t(info.ftLastAccessTime);
81-
buf->st_ctime = filetimeToTime_t(info.ftCreationTime);
82-
buf->st_dev = info.dwVolumeSerialNumber;
83-
// inodes have meaning on FAT/HPFS/NTFS
84-
buf->st_ino = 0;
85-
buf->st_rdev = info.dwVolumeSerialNumber;
86-
buf->st_mode =
87-
// On a symlink to a directory, Windows sets both the REPARSE_POINT and
88-
// DIRECTORY attributes. Since Windows doesn't provide S_IFLNK and we
89-
// want unix style "symlinks to directories are not directories
90-
// themselves, we say symlinks are regular files
91-
(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
92-
? _S_IFREG
93-
: (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR
94-
: _S_IFREG;
95-
buf->st_mode |= (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
96-
? _S_IREAD
97-
: _S_IREAD | _S_IWRITE;
98-
llvm::StringRef extension =
99-
llvm::sys::path::extension(llvm::StringRef(fileName));
100-
if (extension == ".exe" || extension == ".cmd" || extension == ".bat" ||
101-
extension == ".com") {
102-
buf->st_mode |= _S_IEXEC;
103-
}
104-
buf->st_mtime = filetimeToTime_t(info.ftLastWriteTime);
105-
buf->st_nlink = info.nNumberOfLinks;
106-
buf->st_size = ((long long)info.nFileSizeHigh << 32) | info.nFileSizeLow;
107-
// Uid is always 0 on Windows systems
108-
buf->st_uid = 0;
109-
CloseHandle(h);
110-
return 0;
47+
// We deliberately ignore lstat on Windows, and delegate
48+
// to stat.
49+
return ::_stat(fileName, buf);
11150
#else
11251
return ::lstat(fileName, buf);
11352
#endif
@@ -170,25 +109,17 @@ int sys::stat(const char *fileName, StatStruct *buf) {
170109
#endif
171110
}
172111

173-
// Create a symlink named linkPath which contains the string pointsTo
174-
int sys::symlink(const char *pointsTo, const char *linkPath) {
112+
int sys::symlink(const char *source, const char *target) {
175113
#if defined(_WIN32)
176-
llvm::SmallVector<UTF16, 20> wPointsTo;
177-
llvm::convertUTF8ToUTF16String(pointsTo, wPointsTo);
178-
llvm::SmallVector<UTF16, 20> wLinkPath;
179-
llvm::convertUTF8ToUTF16String(linkPath, wLinkPath);
180-
DWORD attributes = GetFileAttributesW((LPCWSTR)wPointsTo.data());
181-
DWORD directoryFlag = (attributes != INVALID_FILE_ATTRIBUTES &&
182-
attributes & FILE_ATTRIBUTE_DIRECTORY)
183-
? SYMBOLIC_LINK_FLAG_DIRECTORY
184-
: 0;
185-
// Note that CreateSymbolicLinkW takes its arguments in reverse order
186-
// compared to symlink/_symlink
187-
return !::CreateSymbolicLinkW(
188-
(LPCWSTR)wLinkPath.data(), (LPCWSTR)wPointsTo.data(),
189-
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE | directoryFlag);
114+
DWORD attributes = GetFileAttributesA(source);
115+
if (attributes != INVALID_FILE_ATTRIBUTES &&
116+
(attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
117+
return ::CreateSymbolicLinkA(source, target, SYMBOLIC_LINK_FLAG_DIRECTORY);
118+
}
119+
120+
return ::CreateSymbolicLinkA(source, target, 0);
190121
#else
191-
return ::symlink(pointsTo, linkPath);
122+
return ::symlink(source, target);
192123
#endif
193124
}
194125

@@ -286,29 +217,23 @@ std::string sys::strerror(int error) {
286217

287218
char *sys::strsep(char **stringp, const char *delim) {
288219
#if defined(_WIN32)
289-
// If *stringp is NULL, the strsep() function returns NULL and does nothing
290-
// else.
220+
char *begin, *end = *stringp;
291221
if (*stringp == NULL) {
292222
return NULL;
293223
}
294-
char *begin = *stringp;
295-
char *end = *stringp;
296-
do {
297-
// Otherwise, this function finds the first token in the string *stringp,
298-
// that is delimited by one of the bytes in the string delim.
299-
for (int i = 0; delim[i] != '\0'; i++) {
224+
int delimLen = strlen(delim);
225+
bool found = false;
226+
while (*end) {
227+
for (int i = 0; i < delimLen; i++) {
300228
if (*end == delim[i]) {
301-
// This token is terminated by overwriting the delimiter with a null
302-
// byte ('\0'), and *stringp is updated to point past the token.
303-
*end = '\0';
304-
*stringp = end + 1;
305-
return begin;
229+
found = true;
306230
}
307231
}
308-
} while (*(++end));
309-
// In case no delimiter was found, the token is taken to be the entire string
310-
// *stringp, and *stringp is made NULL.
311-
*stringp = NULL;
232+
if (found) {
233+
*stringp = end + 1;
234+
}
235+
}
236+
*end = '\0';
312237
return begin;
313238
#else
314239
return ::strsep(stringp, delim);
@@ -319,20 +244,9 @@ std::string sys::makeTmpDir() {
319244
#if defined(_WIN32)
320245
char path[MAX_PATH];
321246
tmpnam_s(path, MAX_PATH);
322-
llvm::SmallVector<UTF16, 20> wPath;
323-
llvm::convertUTF8ToUTF16String(path, wPath);
324-
CreateDirectoryW((LPCWSTR)wPath.data(), NULL);
325247
return std::string(path);
326248
#else
327249
char tmpDirPathBuf[] = "/tmp/fileXXXXXX";
328250
return std::string(mkdtemp(tmpDirPathBuf));
329251
#endif
330252
}
331-
332-
std::string sys::getPathSeparators() {
333-
#if defined(_WIN32)
334-
return "/\\";
335-
#else
336-
return "/";
337-
#endif
338-
}

lib/Basic/Subprocess.cpp

+28-27
Original file line numberDiff line numberDiff line change
@@ -285,10 +285,11 @@ static void cleanUpExecutedProcess(ProcessDelegate& delegate,
285285
FILETIME stimeTicks;
286286
int waitResult = WaitForSingleObject(pid, INFINITE);
287287
int err = GetLastError();
288-
DWORD exitCode = 0;
288+
DWORD exitCode;
289289
GetExitCodeProcess(pid, &exitCode);
290290

291-
if (waitResult == WAIT_FAILED || waitResult == WAIT_ABANDONED) {
291+
if (exitCode != 0 || waitResult == WAIT_FAILED ||
292+
waitResult == WAIT_ABANDONED) {
292293
auto result = ProcessResult::makeFailed(exitCode);
293294
delegate.processHadError(ctx, handle,
294295
Twine("unable to wait for process (") +
@@ -297,25 +298,6 @@ static void cleanUpExecutedProcess(ProcessDelegate& delegate,
297298
completionFn(result);
298299
return;
299300
}
300-
#else
301-
// Wait for the command to complete.
302-
struct rusage usage;
303-
int exitCode, result = wait4(pid, &exitCode, 0, &usage);
304-
while (result == -1 && errno == EINTR)
305-
result = wait4(pid, &exitCode, 0, &usage);
306-
#endif
307-
// Close the release pipe
308-
//
309-
// Note: We purposely hold this open until after the process has finished as
310-
// it simplifies client implentation. If we close it early, clients need to be
311-
// aware of and potentially handle a SIGPIPE.
312-
if (releaseFd >= 0) {
313-
sys::FileDescriptorTraits<>::Close(releaseFd);
314-
}
315-
316-
// Update the set of spawned processes.
317-
pgrp.remove(pid);
318-
#if defined(_WIN32)
319301
PROCESS_MEMORY_COUNTERS counters;
320302
bool res =
321303
GetProcessTimes(pid, &creationTime, &exitTime, &stimeTicks, &utimeTicks);
@@ -335,6 +317,9 @@ static void cleanUpExecutedProcess(ProcessDelegate& delegate,
335317
((uint64_t)stimeTicks.dwHighDateTime << 32 | stimeTicks.dwLowDateTime) /
336318
10;
337319
GetProcessMemoryInfo(pid, &counters, sizeof(counters));
320+
sys::FileDescriptorTraits<>::Close(releaseFd);
321+
322+
pgrp.remove(pid);
338323

339324
// We report additional info in the tracing interval
340325
// - user time, in µs
@@ -345,16 +330,32 @@ static void cleanUpExecutedProcess(ProcessDelegate& delegate,
345330
// subprocess (probably as a new point sample).
346331

347332
// Notify of the process completion.
348-
ProcessStatus processStatus =
349-
(exitCode == 0) ? ProcessStatus::Succeeded : ProcessStatus::Failed;
333+
ProcessStatus processStatus = ProcessStatus::Succeeded;
350334
ProcessResult processResult(processStatus, exitCode, pid, utime, stime,
351335
counters.PeakWorkingSetSize);
352336
#else // !defined(_WIN32)
337+
// Wait for the command to complete.
338+
struct rusage usage;
339+
int exitCode, result = wait4(pid, &exitCode, 0, &usage);
340+
while (result == -1 && errno == EINTR)
341+
result = wait4(pid, &exitCode, 0, &usage);
342+
343+
// Close the release pipe
344+
//
345+
// Note: We purposely hold this open until after the process has finished as
346+
// it simplifies client implentation. If we close it early, clients need to be
347+
// aware of and potentially handle a SIGPIPE.
348+
if (releaseFd >= 0) {
349+
sys::FileDescriptorTraits<>::Close(releaseFd);
350+
}
351+
352+
// Update the set of spawned processes.
353+
pgrp.remove(pid);
354+
353355
if (result == -1) {
354356
auto result = ProcessResult::makeFailed(exitCode);
355357
delegate.processHadError(ctx, handle,
356-
Twine("unable to wait for process (") +
357-
strerror(errno) + ")");
358+
Twine("unable to wait for process (") + strerror(errno) + ")");
358359
delegate.processFinished(ctx, handle, result);
359360
completionFn(result);
360361
return;
@@ -438,8 +439,8 @@ void llbuild::basic::spawnProcess(
438439
startupInfo.dwFlags = STARTF_USESTDHANDLES;
439440
// Set NUL as stdin
440441
HANDLE nul =
441-
CreateFileW(L"NUL", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
442-
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
442+
CreateFileA("NUL", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
443+
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
443444
startupInfo.hStdInput = nul;
444445
#else
445446
// Initialize the spawn attributes.

lib/BuildSystem/BuildSystem.cpp

+9-14
Original file line numberDiff line numberDiff line change
@@ -3453,11 +3453,11 @@ class SymlinkCommand : public Command {
34533453
// FIXME: Need to use the filesystem interfaces.
34543454
bsci.getDelegate().commandStarted(this);
34553455
auto success = true;
3456-
if (basic::sys::symlink(contents.c_str(), outputPath.str().c_str())) {
3456+
if (llvm::sys::fs::create_link(contents, outputPath)) {
34573457
// On failure, we attempt to unlink the file and retry.
34583458
basic::sys::unlink(outputPath.str().c_str());
3459-
3460-
if (basic::sys::symlink(contents.c_str(), outputPath.str().c_str())) {
3459+
3460+
if (llvm::sys::fs::create_link(contents, outputPath)) {
34613461
getBuildSystem(bsci.getBuildEngine()).getDelegate().commandHadError(this,
34623462
"unable to create symlink at '" + outputPath.str() + "'");
34633463
success = false;
@@ -3650,7 +3650,7 @@ class StaleFileRemovalCommand : public Command {
36503650
BuildValue priorValue;
36513651
bool hasPriorResult = false;
36523652

3653-
std::string pathSeparators = llbuild::basic::sys::getPathSeparators();
3653+
char path_separator = llvm::sys::path::get_separator()[0];
36543654

36553655
virtual void configureDescription(const ConfigureContext&, StringRef value) override {
36563656
description = value;
@@ -3790,8 +3790,7 @@ class StaleFileRemovalCommand : public Command {
37903790
bool isLocatedUnderRootPath = roots.size() == 0 ? true : false;
37913791

37923792
// If root paths are defined, stale file paths should be absolute.
3793-
if (roots.size() > 0 &&
3794-
pathSeparators.find(fileToDelete[0]) == std::string::npos) {
3793+
if (roots.size() > 0 && fileToDelete[0] != path_separator) {
37953794
bsci.getDelegate().commandHadWarning(this, "Stale file '" + fileToDelete + "' has a relative path. This is invalid in combination with the root path attribute.\n");
37963795
continue;
37973796
}
@@ -4013,14 +4012,10 @@ void BuildSystem::resetForBuild() {
40134012

40144013
// This function checks if the given path is prefixed by another path.
40154014
bool llbuild::buildsystem::pathIsPrefixedByPath(std::string path, std::string prefixPath) {
4016-
std::string pathSeparators = llbuild::basic::sys::getPathSeparators();
4017-
auto res = std::mismatch(prefixPath.begin(), prefixPath.end(), path.begin(),
4018-
path.end());
4015+
static char path_separator = llvm::sys::path::get_separator()[0];
4016+
auto res = std::mismatch(prefixPath.begin(), prefixPath.end(), path.begin());
40194017
// Check if `prefixPath` has been exhausted or just a separator remains.
4020-
bool isPrefix = res.first == prefixPath.end() ||
4021-
(pathSeparators.find(*(res.first++)) != std::string::npos);
4018+
bool isPrefix = res.first == prefixPath.end() || (*(res.first++) == path_separator);
40224019
// Check if `path` has been exhausted or just a separator remains.
4023-
return isPrefix &&
4024-
(res.second == path.end() ||
4025-
(pathSeparators.find(*(res.second++)) != std::string::npos));
4020+
return isPrefix && (res.second == path.end() || (*(res.second++) == path_separator));
40264021
}

0 commit comments

Comments
 (0)