Skip to content

Commit 17221fe

Browse files
authored
Merge pull request #490 from dmbryson/swift-5.1-branch
Merge 'master' into 'swift-5.1-branch'
2 parents 2df8acd + c093b1b commit 17221fe

27 files changed

+306
-54
lines changed

CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ else()
1212
set(cmake_3_2_USES_TERMINAL USES_TERMINAL)
1313
endif()
1414

15+
option(BUILD_SHARED_LIBS "Build Shared Libraries" ON)
16+
1517
# Configure the default set of bindings to build.
1618
if(NOT DEFINED LLBUILD_SUPPORT_BINDINGS)
1719
set(LLBUILD_SUPPORT_BINDINGS "")

Xcode/Configs/Version.xcconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
SWIFT_VERSION = 4.2
13+
SWIFT_VERSION = 5.0

include/llbuild/Basic/PlatformUtility.h

+34
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include <cstdint>
2323
#include <cstdio>
2424
#include <string>
25+
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
26+
#include <unistd.h>
27+
#endif
2528
#if !defined(_WIN32)
2629
#include <sys/resource.h>
2730
#endif
@@ -87,6 +90,37 @@ template <> struct FileDescriptorTraits<int> {
8790
return read(hFile, destinationBuffer, maxCharCount);
8891
}
8992
};
93+
94+
enum class OSStyle {
95+
Windows,
96+
POSIX,
97+
98+
#if defined(_WIN32)
99+
Default = Windows,
100+
#elif defined(_POSIX_VERSION)
101+
Default = POSIX,
102+
#endif
103+
};
104+
105+
template <OSStyle = OSStyle::Default>
106+
struct ModuleTraits;
107+
108+
#if defined(_WIN32)
109+
template <>
110+
struct ModuleTraits<OSStyle::Windows> {
111+
using Handle = HMODULE;
112+
};
113+
#endif
114+
115+
template <>
116+
struct ModuleTraits<OSStyle::POSIX> {
117+
using Handle = void *;
118+
};
119+
120+
ModuleTraits<>::Handle OpenLibrary(const char *);
121+
void *GetSymbolByname(ModuleTraits<>::Handle, const char *);
122+
void CloseLibrary(ModuleTraits<>::Handle);
123+
90124
}
91125
}
92126
}

include/llbuild/Basic/ShellUtility.h

+13-5
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,35 @@
1515

1616
#include "llvm/ADT/StringRef.h"
1717
#include "llvm/Support/raw_ostream.h"
18-
19-
using namespace llvm;
18+
#include <vector>
2019

2120
namespace llbuild {
2221
namespace basic {
2322

23+
#if defined(_WIN32)
24+
/// Formats a command line using the Windows command line escaping rules a la a
25+
/// reverse CommandLineToArgVW
26+
///
27+
/// \param args The arugments to escape
28+
///
29+
std::string formatWindowsCommandString(std::vector<std::string> args);
30+
#endif
31+
2432
/// Appends a shell escaped string to an output stream.
2533
/// For e.g. hello -> hello, hello$world -> 'hello$world', input A -> 'input A'
2634
///
2735
/// \param os Reference of the output stream to append to.
2836
///
2937
/// \param string The string to be escaped and appended.
30-
///
31-
void appendShellEscapedString(llvm::raw_ostream& os, StringRef string);
38+
///
39+
void appendShellEscapedString(llvm::raw_ostream& os, llvm::StringRef string);
3240

3341
/// Creates and returns a shell escaped string of the input.
3442
///
3543
/// \param string The string to be escaped.
3644
///
3745
/// \returns escaped string.
38-
std::string shellEscaped(StringRef string);
46+
std::string shellEscaped(llvm::StringRef string);
3947

4048
}
4149
}

include/llbuild/Core/BuildDB.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ class BuildDBDelegate {
4242
/// implementations may (and do) cache these values for future use.
4343
///
4444
/// \param key [out] The key whose unique ID is being returned.
45-
virtual KeyID getKeyID(const KeyType& key) = 0;
45+
virtual const KeyID getKeyID(const KeyType& key) = 0;
4646

4747
/// Get the key corresponding to a key ID.
4848
///
4949
/// This method must be thread safe, and must not fail.
50-
virtual KeyType getKeyForID(KeyID key) = 0;
50+
virtual KeyType getKeyForID(const KeyID key) = 0;
5151
};
5252

5353

lib/Basic/CMakeLists.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
add_llbuild_library(llbuildBasic
1+
add_llbuild_library(llbuildBasic STATIC
22
ExecutionQueue.cpp
33
FileInfo.cpp
44
FileSystem.cpp
@@ -12,6 +12,8 @@ add_llbuild_library(llbuildBasic
1212
ShellUtility.cpp
1313
)
1414

15+
target_link_libraries(llbuildBasic PRIVATE llvmSupport)
16+
1517
if(${CMAKE_SYSTEM_NAME} MATCHES ".*BSD" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
1618
target_link_libraries(llbuildBasic pthread)
1719
endif()

lib/Basic/PlatformUtility.cpp

+37
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#else
2323
#include <fnmatch.h>
2424
#include <unistd.h>
25+
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
26+
#include <dlfcn.h>
27+
#endif
2528
#endif
2629
#include <stdio.h>
2730

@@ -336,3 +339,37 @@ std::string sys::getPathSeparators() {
336339
return "/";
337340
#endif
338341
}
342+
343+
sys::ModuleTraits<>::Handle sys::OpenLibrary(const char *path) {
344+
#if defined(_WIN32)
345+
int cchLength =
346+
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, strlen(path),
347+
nullptr, 0);
348+
std::u16string buffer(cchLength + 1, 0);
349+
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, strlen(path),
350+
const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(buffer.data())),
351+
buffer.size());
352+
353+
return LoadLibraryW(reinterpret_cast<LPCWSTR>(buffer.data()));
354+
#else
355+
return dlopen(path, RTLD_LAZY);
356+
#endif
357+
}
358+
359+
void *sys::GetSymbolByname(sys::ModuleTraits<>::Handle handle,
360+
const char *name) {
361+
#if defined(_WIN32)
362+
return GetProcAddress(handle, name);
363+
#else
364+
return dlsym(handle, name);
365+
#endif
366+
}
367+
368+
void sys::CloseLibrary(sys::ModuleTraits<>::Handle handle) {
369+
#if defined(_WIN32)
370+
FreeLibrary(handle);
371+
#else
372+
dlclose(handle);
373+
#endif
374+
}
375+

lib/Basic/ShellUtility.cpp

+79-13
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,82 @@
1313
#include "llbuild/Basic/ShellUtility.h"
1414
#include "llvm/ADT/SmallString.h"
1515

16+
using namespace llvm;
1617
namespace llbuild {
1718
namespace basic {
1819

19-
void appendShellEscapedString(llvm::raw_ostream& os, StringRef string) {
2020

21+
#if defined(_WIN32)
22+
std::string formatWindowsCommandArg(StringRef string) {
23+
// Windows escaping, adapted from Daniel Colascione's "Everyone quotes
24+
// command line arguments the wrong way" - Microsoft Developer Blog
25+
const std::string needsQuote = " \t\n\v\"";
26+
if (string.find_first_of(needsQuote) == std::string::npos) {
27+
return string;
28+
}
29+
30+
// To escape the command line, we surround the argument with quotes. However
31+
// the complication comes due to how the Windows command line parser treats
32+
// backslashes (\) and quotes (")
33+
//
34+
// - \ is normally treated as a literal backslash
35+
// - e.g. foo\bar\baz => foo\bar\baz
36+
// - However, the sequence \" is treated as a literal "
37+
// - e.g. foo\"bar => foo"bar
38+
//
39+
// But then what if we are given a path that ends with a \? Surrounding
40+
// foo\bar\ with " would be "foo\bar\" which would be an unterminated string
41+
// since it ends on a literal quote. To allow this case the parser treats:
42+
//
43+
// - \\" as \ followed by the " metachar
44+
// - \\\" as \ followed by a literal "
45+
// - In general:
46+
// - 2n \ followed by " => n \ followed by the " metachar
47+
// - 2n+1 \ followed by " => n \ followed by a literal "
48+
std::string escaped = "\"";
49+
for (auto i = std::begin(string); i != std::end(string); ++i) {
50+
int numBackslashes = 0;
51+
while (i != string.end() && *i == '\\') {
52+
++i;
53+
++numBackslashes;
54+
}
55+
56+
if (i == string.end()) {
57+
// String ends with a backslash e.g. foo\bar\, escape all the backslashes
58+
// then add the metachar " below
59+
escaped.append(numBackslashes * 2, '\\');
60+
break;
61+
} else if (*i == '"') {
62+
// This is a string of \ followed by a " e.g. foo\"bar. Escape the
63+
// backslashes and the quote
64+
escaped.append(numBackslashes * 2 + 1, '\\');
65+
escaped.push_back(*i);
66+
} else {
67+
// These are just literal backslashes
68+
escaped.append(numBackslashes, '\\');
69+
escaped.push_back(*i);
70+
}
71+
}
72+
escaped.push_back('"');
73+
74+
return escaped;
75+
}
76+
77+
std::string formatWindowsCommandString(std::vector<std::string> args) {
78+
std::string commandLine;
79+
for (auto& arg : args)
80+
commandLine += formatWindowsCommandArg(arg) + " ";
81+
if (commandLine.size())
82+
commandLine.pop_back();
83+
return commandLine;
84+
}
85+
#endif
86+
87+
void appendShellEscapedString(llvm::raw_ostream& os, StringRef string) {
88+
#if defined(_WIN32)
89+
os << formatWindowsCommandArg(string);
90+
return;
91+
#else
2192
static const std::string whitelist = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_/:@#%+=.,";
2293
auto pos = string.find_first_not_of(whitelist);
2394

@@ -27,32 +98,27 @@ void appendShellEscapedString(llvm::raw_ostream& os, StringRef string) {
2798
return;
2899
}
29100

30-
#if defined(_WIN32)
31-
std::string escQuote = "\"";
32-
#else
33101
std::string escQuote = "'";
34-
#endif
35102
// We only need to escape the single quote, if it isn't present we can
36103
// escape using single quotes.
37-
auto singleQuotePos = string.find_first_of(escQuote, pos);
104+
auto singleQuotePos = string.find_first_of("'" , pos);
38105
if (singleQuotePos == std::string::npos) {
39-
os << escQuote;
40-
os << string;
41-
os << escQuote;
106+
os << "'" << string << "'";
42107
return;
43108
}
44109

45110
// Otherwise iterate and escape all the single quotes.
46-
os << escQuote;
111+
os << "'";
47112
os << string.slice(0, singleQuotePos);
48113
for (auto idx = singleQuotePos; idx < string.size(); idx++) {
49-
if (string[idx] == escQuote[0]) {
50-
os << escQuote << "\\" << escQuote << escQuote;
114+
if (string[idx] == '\'') {
115+
os << "'\\''";
51116
} else {
52117
os << string[idx];
53118
}
54119
}
55-
os << escQuote;
120+
os << "'";
121+
#endif
56122
}
57123

58124
std::string shellEscaped(StringRef string) {

lib/Basic/Subprocess.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "llbuild/Basic/CrossPlatformCompatibility.h"
1616
#include "llbuild/Basic/PlatformUtility.h"
17+
#include "llbuild/Basic/ShellUtility.h"
1718

1819
#include "llvm/ADT/ArrayRef.h"
1920
#include "llvm/ADT/StringRef.h"
@@ -72,6 +73,7 @@ int pthread_fchdir_np(int fd)
7273

7374
#ifndef HAVE_POSIX_SPAWN_CHDIR
7475
#if defined(__sun) || \
76+
(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) || \
7577
__GLIBC_PREREQ(2, 29)
7678
#define HAVE_POSIX_SPAWN_CHDIR 1
7779
#else
@@ -85,6 +87,12 @@ static int posix_spawn_file_actions_addchdir(posix_spawn_file_actions_t * __rest
8587
#if HAVE_POSIX_SPAWN_CHDIR
8688
return ::posix_spawn_file_actions_addchdir_np(file_actions, path);
8789
#else
90+
#if defined(__APPLE__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
91+
if (__builtin_available(macOS 10.15, *)) {
92+
return ::posix_spawn_file_actions_addchdir_np(file_actions, path);
93+
}
94+
#endif
95+
8896
// Any other POSIX platform returns ENOSYS (Function not implemented),
8997
// to simplify the fallback logic around the call site.
9098
return ENOSYS;
@@ -409,7 +417,7 @@ void llbuild::basic::spawnProcess(
409417
// Form the complete C string command line.
410418
std::vector<std::string> argsStorage(commandLine.begin(), commandLine.end());
411419
#if defined(_WIN32)
412-
std::string args = llvm::sys::flattenWindowsCommandLine(commandLine);
420+
std::string args = llbuild::basic::formatWindowsCommandString(argsStorage);
413421

414422
// Convert the command line string to utf16
415423
llvm::SmallVector<llvm::UTF16, 20> u16Executable;

lib/BuildSystem/BuildSystem.cpp

+10-3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include <unistd.h>
6363
#endif
6464

65+
using namespace llvm;
6566
using namespace llbuild;
6667
using namespace llbuild::basic;
6768
using namespace llbuild::core;
@@ -1873,7 +1874,13 @@ llvm::Optional<BuildValue> BuildSystemImpl::build(BuildKey key) {
18731874
// queue to have notified the engine of the last task completion, but still
18741875
// have other work to perform (e.g., informing the client of command
18751876
// completion).
1876-
executionQueue.reset();
1877+
//
1878+
// This must hold the lock to prevent data racing on the executionQueue
1879+
// pointer (as can happen with cancellation) - rdar://problem/50993380
1880+
{
1881+
std::lock_guard<std::mutex> guard(executionQueueMutex);
1882+
executionQueue.reset();
1883+
}
18771884

18781885
// Clear out the shell handlers, as we do not want to hold on to them across
18791886
// multiple builds.
@@ -3234,11 +3241,11 @@ class ArchiveShellCommand : public ExternalCommand {
32343241
llvm::raw_svector_ostream stream(result);
32353242
bool first = true;
32363243
for (const auto& arg: getArgs()) {
3237-
stream << arg;
32383244
if (!first) {
32393245
stream << " ";
3240-
first = false;
32413246
}
3247+
first = false;
3248+
stream << arg;
32423249
}
32433250
}
32443251

0 commit comments

Comments
 (0)