diff --git a/include/swift/Runtime/EnvironmentVariables.h b/include/swift/Runtime/EnvironmentVariables.h index 51e58f63285e4..ae2c8b72a719e 100644 --- a/include/swift/Runtime/EnvironmentVariables.h +++ b/include/swift/Runtime/EnvironmentVariables.h @@ -24,6 +24,10 @@ void initialize(void *); extern swift::once_t initializeToken; +// Define a typedef "string" in swift::runtime::environment to make string +// environment variables work +using string = const char *; + // Declare backing variables. #define VARIABLE(name, type, defaultValue, help) extern type name ## _variable; #include "../../../stdlib/public/runtime/EnvironmentVariables.def" diff --git a/include/swift/Runtime/Paths.h b/include/swift/Runtime/Paths.h new file mode 100644 index 0000000000000..21964e4d69adb --- /dev/null +++ b/include/swift/Runtime/Paths.h @@ -0,0 +1,77 @@ +//===--- Paths.h - Swift Runtime path utility functions ---------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Functions that obtain paths that might be useful within the runtime. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_RUNTIME_UTILS_H +#define SWIFT_RUNTIME_UTILS_H + +#include "swift/Runtime/Config.h" + +/// Return the path of the libswiftCore library. +/// +/// This can be used to locate files that are installed alongside the Swift +/// runtime library. +/// +/// \return A string containing the full path to libswiftCore. The string is +/// owned by the runtime and should not be freed. +SWIFT_RUNTIME_EXPORT +const char * +swift_getRuntimePath(); + +/// Return the path of the Swift root. +/// +/// If the path to libswiftCore is `/usr/local/swift/lib/libswiftCore.dylib`, +/// this function would return `/usr/local/swift`. +/// +/// The path returned here can be overridden by setting the environment variable +/// SWIFT_ROOT. +/// +/// \return A string containing the full path to the Swift root directory, based +/// either on the location of the Swift runtime, or on the `SWIFT_ROOT` +/// environment variable if set. +SWIFT_RUNTIME_EXPORT +const char * +swift_getRootPath(); + +/// Return the path of the specified auxiliary executable. +/// +/// This function will search for the auxiliary executable in the following +/// paths: +/// +/// /libexec/swift// +/// /libexec/swift/ +/// /bin/ +/// / +/// +/// It will return the first of those that exists, but it does not test that +/// the file is indeed executable. +/// +/// On Windows, it will automatically add `.exe` to the name, which means you +/// do not need to special case the name for Windows. +/// +/// If you are using this function to locate a utility program for use by the +/// runtime, you should provide a way to override its location using an +/// environment variable. +/// +/// If the executable cannot be found, it will return nullptr. +/// +/// \param name The name of the executable to locate. +/// +/// \return A string containing the full path to the executable. +SWIFT_RUNTIME_EXPORT +const char * +swift_getAuxiliaryExecutablePath(const char *name); + +#endif // SWIFT_RUNTIME_PATHS_H diff --git a/include/swift/Threading/Impl/Win32/Win32Defs.h b/include/swift/Threading/Impl/Win32/Win32Defs.h index f2a00de6e0560..b7c97b2c21d63 100644 --- a/include/swift/Threading/Impl/Win32/Win32Defs.h +++ b/include/swift/Threading/Impl/Win32/Win32Defs.h @@ -47,8 +47,7 @@ typedef struct _RTL_CONDITION_VARIABLE *PRTL_CONDITION_VARIABLE; typedef PRTL_CONDITION_VARIABLE PCONDITION_VARIABLE; // These have to be #defines, to avoid problems with -#define RTL_SRWLOCK_INIT \ - { 0 } +#define RTL_SRWLOCK_INIT {0} #define SRWLOCK_INIT RTL_SRWLOCK_INIT #define FLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index bf2a8dbf6fc30..10db08f7dbf1d 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -156,7 +156,11 @@ function(_add_target_variant_c_compile_flags) set(result ${${CFLAGS_RESULT_VAR_NAME}}) - list(APPEND result "-DSWIFT_RUNTIME") + list(APPEND result + "-DSWIFT_RUNTIME" + "-DSWIFT_LIB_SUBDIR=\"${SWIFT_SDK_${CFLAGS_SDK}_LIB_SUBDIR}\"" + "-DSWIFT_ARCH=\"${CFLAGS_ARCH}\"" + ) if ("${CFLAGS_ARCH}" STREQUAL "arm64" OR "${CFLAGS_ARCH}" STREQUAL "arm64_32") diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index c41c9912e608b..b33ae006a6fb1 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -61,6 +61,7 @@ set(swift_runtime_sources MetadataLookup.cpp Numeric.cpp Once.cpp + Paths.cpp Portability.cpp ProtocolConformance.cpp RefCount.cpp diff --git a/stdlib/public/runtime/EnvironmentVariables.cpp b/stdlib/public/runtime/EnvironmentVariables.cpp index 5aa91f23e497b..0519f41a7f6bd 100644 --- a/stdlib/public/runtime/EnvironmentVariables.cpp +++ b/stdlib/public/runtime/EnvironmentVariables.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "swift/Runtime/Debug.h" +#include "swift/Runtime/Paths.h" #include "swift/Runtime/EnvironmentVariables.h" #include @@ -23,6 +24,12 @@ using namespace swift; namespace { +// This is required to make the macro machinery work correctly; we can't +// declare a VARIABLE(..., const char *, ...) because then the token-pasted +// names won't work properly. It *does* mean that if you want to use std::string +// somewhere in this file, you'll have to fully qualify the name. +typedef const char *string; + // Require all environment variable names to start with SWIFT_ static constexpr bool hasSwiftPrefix(const char *str) { const char prefix[] = "SWIFT_"; @@ -123,6 +130,14 @@ static uint32_t parse_uint32_t(const char *name, return n; } +static string parse_string(const char *name, + const char *value, + string defaultValue) { + if (!value || value[0] == 0) + return strdup(defaultValue); + return strdup(value); +} + // Print a list of all the environment variables. Lazy initialization makes // this a bit odd, but the use of these variables in the metadata system means // it's almost certain to run early. diff --git a/stdlib/public/runtime/EnvironmentVariables.def b/stdlib/public/runtime/EnvironmentVariables.def index a9cbb45045dbf..48b85a762f48d 100644 --- a/stdlib/public/runtime/EnvironmentVariables.def +++ b/stdlib/public/runtime/EnvironmentVariables.def @@ -81,4 +81,9 @@ VARIABLE(SWIFT_BINARY_COMPATIBILITY_VERSION, uint32_t, 0, VARIABLE(SWIFT_DEBUG_FAILED_TYPE_LOOKUP, bool, false, "Enable warnings when we fail to look up a type by name.") +VARIABLE(SWIFT_ROOT, string, "", + "Overrides the root directory of the Swift installation. " + "This is used to locate auxiliary files relative to the runtime " + "itself.") + #undef VARIABLE diff --git a/stdlib/public/runtime/Paths.cpp b/stdlib/public/runtime/Paths.cpp new file mode 100644 index 0000000000000..3baf1a6288f86 --- /dev/null +++ b/stdlib/public/runtime/Paths.cpp @@ -0,0 +1,554 @@ +//===--- Paths.cpp - Swift Runtime path utility functions -------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2022 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Functions that obtain paths that might be useful within the runtime. +// +//===----------------------------------------------------------------------===// + +#include "swift/Runtime/Config.h" +#include "swift/Runtime/EnvironmentVariables.h" +#include "swift/Runtime/Debug.h" +#include "swift/Runtime/Paths.h" +#include "swift/Runtime/Win32.h" +#include "swift/Threading/Once.h" + +#include + +#if !defined(_WIN32) || defined(__CYGWIN__) +#include + +#include +#else +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#include +#endif + +#include +#include +#include + +namespace { + +swift::once_t runtimePathToken; +const char *runtimePath; + +swift::once_t rootPathToken; +const char *rootPath; + +void _swift_initRuntimePath(void *); +void _swift_initRootPath(void *); +const char *_swift_getDefaultRootPath(); +char *_swift_getAuxExePathIn(const char *path, const char *name); +const char *_swift_tryAuxExePath(const char *name, const char *path, ...); + +bool _swift_isPathSep(char ch) { +#ifdef _WIN32 + return ch == '/' || ch == '\\'; +#else + return ch == '/'; +#endif +} + +bool _swift_exists(const char *path); + +#if !defined(_WIN32) || defined(__CYGWIN__) +#define PATHSEP_STR "/" +#define PATHSEP_CHR '/' +#else +#define PATHSEP_STR "\\" +#define PATHSEP_CHR '\\' +#endif + +} + +SWIFT_RUNTIME_EXPORT +const char * +swift_getRuntimePath() +{ + swift::once(runtimePathToken, _swift_initRuntimePath, nullptr); + return runtimePath; +} + +SWIFT_RUNTIME_EXPORT +const char * +swift_getRootPath() +{ + swift::once(rootPathToken, _swift_initRootPath, nullptr); + return rootPath; +} + +namespace { + +bool +_swift_lookingAtLibSwift(const char *ptr, const char *base) +{ + // /some/path/to/some/thing/lib/swift/libswiftCore.dylib + // ^ ^ + // | +---- ptr + // +-------------- ptr - 10 + + return (ptr - base >= 10 + && _swift_isPathSep(ptr[-10]) + && std::strncmp(ptr - 9, "lib", 3) == 0 + && _swift_isPathSep(ptr[-6]) + && std::strncmp(ptr - 5, "swift", 5) == 0); +} + +bool +_swift_lookingAtBin(const char *ptr, const char *base) +{ + // C:\some\path\to\some\thing\bin\libswiftCore.dylib + // ^ ^ + // | +---- ptr + // +-------- ptr - 4 + + return (ptr - base > 4 + && _swift_isPathSep(ptr[-4]) + && std::strncmp(ptr - 3, "bin", 3) == 0); +} + +const char * +_swift_getDefaultRootPath() +{ + const char *runtimePath = swift_getRuntimePath(); + size_t runtimePathLen = std::strlen(runtimePath); + + // Scan backwards until we find a path separator + const char *ptr = runtimePath + runtimePathLen; + while (ptr > runtimePath && !_swift_isPathSep(*--ptr)); + + if (_swift_lookingAtLibSwift(ptr, runtimePath)) { + // /some/path/to/some/thing/lib/swift/libswiftCore.dylib + // ^ ^ + // | +---- ptr + // +-------------- ptr - 10 + ptr -= 10; + } else { + // We *might* be in a or / directory, so scan + // backwards for that too + bool found = false; + const char *platform = ptr; + + for (unsigned n = 0; n < 2; ++n) { + while (platform > runtimePath && !_swift_isPathSep(*--platform)); + + if (_swift_lookingAtLibSwift(platform, runtimePath)) { + + // When we get here, we have: + // + // /some/path/to/some/thing/lib/swift/macosx/libswiftCore.dylib + // ^ ^ ^ + // | | +---- ptr + // | +----------- platform + // +--------------------- platform - 10 + + ptr = platform - 10; + found = true; + break; + } + } + + if (!found) { + // We *might* also be in a bin directory, for instance on Windows, so + // check if we should remove that also. + if (_swift_lookingAtBin(ptr, runtimePath)) { + // C:\some\path\to\some\thing\bin\libswiftCore.dylib + // ^ ^ + // | +---- ptr + // +-------- ptr - 4 + ptr -= 4; + } + } + } + + // If the result is empty, return "./" or ".\\" + if (ptr == runtimePath) { + return "." PATHSEP_STR; + } + + // Duplicate the string up to and including ptr + size_t len = ptr - runtimePath + 1; + char *thePath = (char *)malloc(len + 1); + std::memcpy(thePath, runtimePath, len); + thePath[len] = 0; + + return thePath; +} + +// Join paths together +char * +_swift_joinPathsV(const char *path, va_list val) +{ + va_list val2; + size_t baseLen = 0; + size_t totalLen = 0; + const char *pathSeg; + + va_copy(val2, val); + + baseLen = std::strlen(path); + while (baseLen && _swift_isPathSep(path[baseLen - 1])) + --baseLen; + + if (!baseLen) + totalLen = 1; + else + totalLen = baseLen; + + while ((pathSeg = va_arg(val2, const char *))) { + size_t len = std::strlen(pathSeg); + while (len && _swift_isPathSep(pathSeg[len - 1])) + --len; + if (len) + totalLen += 1 + len; + } + + char *buffer = static_cast(std::malloc(totalLen + 1)); + char *ptr = buffer; + + if (!baseLen) + *ptr++ = PATHSEP_CHR; + else { + std::memcpy(ptr, path, baseLen); + ptr += baseLen; + } + + while ((pathSeg = va_arg(val, const char *))) { + size_t len = std::strlen(pathSeg); + while (len && _swift_isPathSep(pathSeg[len - 1])) + --len; + if (len) { + *ptr++ = PATHSEP_CHR; + std::memcpy(ptr, pathSeg, len); + ptr += len; + } + } + buffer[totalLen] = 0; + + return buffer; +} + +char * +_swift_joinPaths(const char *path, ...) +{ + va_list val; + char *result; + + va_start(val, path); + result = _swift_joinPathsV(path, val); + va_end(val); + + return result; +} + +void +_swift_initRootPath(void *) +{ + // SWIFT_ROOT overrides the path returned by this function + const char *swiftRoot = swift::runtime::environment::SWIFT_ROOT(); + + if (!swiftRoot || !*swiftRoot) { + rootPath = _swift_getDefaultRootPath(); + return; + } + + size_t len = std::strlen(swiftRoot); + + // Ensure that there's a trailing slash + if (_swift_isPathSep(swiftRoot[len - 1])) { + rootPath = swiftRoot; + } else { + char *thePath = (char *)malloc(len + 2); + std::memcpy(thePath, swiftRoot, len); + thePath[len] = PATHSEP_CHR; + thePath[len + 1] = 0; + + rootPath = thePath; + } +} + +#if _WIN32 +/// Map an NT-style filename to a Win32 filename. +/// +/// We can't use GetFinalPathNameByHandle() because there's no way to obtain +/// a handle (at least, not without using the internal NtCreateFile() API, which +/// we aren't supposed to be using). Additionally, that function would resolve +/// symlinks, which we don't want to do here. +/// +/// As a result, we use the approach demonstrated here: +/// +/// https://learn.microsoft.com/en-us/windows/win32/memory/obtaining-a-file-name-from-a-file-handle +/// +/// @param pszFilename The NT-style filename to convert. +/// +/// @result A string, allocated using std::malloc(), containing the Win32-style +/// filename. +LPWSTR +_swift_win32NameFromNTName(LPWSTR pszFilename) { + DWORD dwLen = GetLogicalDriveStringsW(0, NULL); + if (!dwLen) + return NULL; + + LPWSTR lpDriveStrings = (LPWSTR)std::malloc(dwLen * sizeof(WCHAR)); + if (!lpDriveStrings) + return NULL; + + DWORD dwRet = GetLogicalDriveStringsW(dwLen, lpDriveStrings); + if (!dwRet) + return NULL; + + LPWSTR pszDrive = lpDriveStrings; + while (*pszDrive) { + size_t len = wcslen(pszDrive); + if (len && pszDrive[len - 1] == '\\') + pszDrive[len - 1] = 0; + + WCHAR ntPath[4096]; + dwRet = QueryDosDeviceW(pszDrive, ntPath, 4096); + if (dwRet) { + size_t ntLen = wcslen(ntPath); + + if (_wcsnicmp(pszFilename, ntPath, ntLen) == 0 + && pszFilename[ntLen] == '\\') { + size_t fnLen = wcslen(pszFilename); + size_t driveLen = wcslen(pszDrive); + size_t pathLen = fnLen - ntLen; + size_t newLen = driveLen + pathLen + 1; + LPWSTR pszWin32Name = (LPWSTR)std::malloc(newLen * sizeof(WCHAR)); + if (!pszWin32Name) { + std::free(lpDriveStrings); + return NULL; + } + + LPWSTR ptr = pszWin32Name; + memcpy(ptr, pszDrive, driveLen * sizeof(WCHAR)); + ptr += driveLen; + memcpy(ptr, pszFilename + ntLen, pathLen * sizeof(WCHAR)); + ptr += pathLen; + *ptr = 0; + + std::free(lpDriveStrings); + + return pszWin32Name; + } + } + + pszDrive += len + 1; + } + + std::free(lpDriveStrings); + + return _wcsdup(pszFilename); +} +#endif + +} // namespace + +SWIFT_RUNTIME_EXPORT +const char * +swift_getAuxiliaryExecutablePath(const char *name) +{ + const char *rootPath = swift_getRootPath(); + + const char *platformName = SWIFT_LIB_SUBDIR; + const char *archName = SWIFT_ARCH; + + // /libexec/swift/ + if (const char *result = _swift_tryAuxExePath(name, + rootPath, + "libexec", "swift", + platformName, nullptr)) { + return result; + } + + // /libexec/swift// + if (const char *result = _swift_tryAuxExePath(name, + rootPath, + "libexec", "swift", + platformName, + archName, nullptr)) { + return result; + } + + // /libexec/swift + if (const char *result = _swift_tryAuxExePath(name, + rootPath, + "libexec", "swift", + nullptr)) { + return result; + } + + // /libexec/swift/ + if (const char *result = _swift_tryAuxExePath(name, + rootPath, + "libexec", "swift", + archName, nullptr)) { + return result; + } + + // /bin + if (const char *result = _swift_tryAuxExePath(name, + rootPath, + "bin", nullptr)) { + return result; + } + + // /bin/ + if (const char *result = _swift_tryAuxExePath(name, + rootPath, + "bin", + archName, nullptr)) { + return result; + } + + // Otherwise, look in the root itself + return _swift_tryAuxExePath(name, rootPath, nullptr); +} + +namespace { + +char * +_swift_getAuxExePathIn(const char *path, const char *name) +{ +#ifdef _WIN32 + size_t nameLen = std::strlen(name); + char *nameWithSuffix = nullptr; + if (nameLen > 4 && strcmp(name + nameLen - 4, ".exe") != 0) { + nameWithSuffix = (char *)std::malloc(nameLen + 4 + 1); + std::memcpy(nameWithSuffix, name, nameLen); + std::memcpy(nameWithSuffix + nameLen, ".exe", 4 + 1); + + name = nameWithSuffix; + } +#endif + + char *fullPath = _swift_joinPaths(path, name, nullptr); + +#ifdef _WIN32 + if (nameWithSuffix) + std::free(nameWithSuffix); +#endif + + return fullPath; +} + +const char * +_swift_tryAuxExePath(const char *name, const char *path, ...) +{ + va_list val; + char *fullPath; + va_start(val, path); + fullPath = _swift_joinPathsV(path, val); + va_end(val); + + if (_swift_exists(fullPath)) { + char *result = _swift_getAuxExePathIn(fullPath, name); + + if (_swift_exists(result)) { + std::free(fullPath); + + return result; + } + + std::free(result); + } + + std::free(fullPath); + + return nullptr; +} + +#if !defined(_WIN32) || defined(__CYGWIN__) +void +_swift_initRuntimePath(void *) { + const char *path; + +#if APPLE_OS_SYSTEM + path = dyld_image_path_containing_address(_swift_initRuntimePath); +#else + Dl_info dli; + int ret = ::dladdr((void *)_swift_initRuntimePath, &dli); + + if (!ret) { + swift::fatalError(/* flags = */ 0, + "Unable to obtain Swift runtime path\n"); + } + + path = dli.dli_fname; +#endif + + runtimePath = ::strdup(path); +} +#else + +void +_swift_initRuntimePath(void *) { + const DWORD dwBufSize = 4096; + LPWSTR lpFilename = (LPWSTR)std::malloc(dwBufSize * sizeof(WCHAR)); + + // Again, we can't use GetFinalPathNameByHandle for the reasons given + // above. + + DWORD dwRet = GetMappedFileNameW(GetCurrentProcess(), + (void *)_swift_initRuntimePath, + lpFilename, + dwBufSize); + if (!dwRet) { + swift::fatalError(/* flags = */ 0, + "Unable to obtain Swift runtime path\n"); + } + + // GetMappedFileNameW() returns an NT-style path, not a Win32 path; that is, + // it starts with \Device\DeviceName rather than a drive letter. + LPWSTR lpWin32Filename = _swift_win32NameFromNTName(lpFilename); + if (!lpWin32Filename) { + swift::fatalError(/* flags = */ 0, + "Unable to obtain Win32 path for Swift runtime\n"); + } + + std::free(lpFilename); + + runtimePath = _swift_win32_copyUTF8FromWide(lpWin32Filename); + if (!runtimePath) { + swift::fatalError(/* flags = */ 0, + "Unable to convert Swift runtime path to UTF-8: %lx, %d\n", + ::GetLastError(), errno); + } + + std::free(lpWin32Filename); +} +#endif + +/// Return true if a file exists at path. +/// +/// On Windows, path will be in UTF-8 so can't be passed to _stat() or any +/// of the ANSI functions. +/// +/// @param path The path to check +/// +/// @result true iff there is a file at @a path +bool _swift_exists(const char *path) +{ +#if !defined(_WIN32) + struct stat st; + return stat(path, &st) == 0; +#else + wchar_t *wszPath = _swift_win32_copyWideFromUTF8(path); + bool result = GetFileAttributesW(wszPath) != INVALID_FILE_ATTRIBUTES; + free(wszPath); + return result; +#endif // defined(_WIN32) +} + +} diff --git a/test/Runtime/Paths.cpp b/test/Runtime/Paths.cpp new file mode 100644 index 0000000000000..9623182980c2a --- /dev/null +++ b/test/Runtime/Paths.cpp @@ -0,0 +1,100 @@ +// RUN: %empty-directory(%t) + +// RUN: mkdir -p %t/swift-root/libexec/swift %t/swift-root/bin +// RUN: touch %t/swift-root/libexec/swift/Foo +// RUN: touch %t/swift-root/libexec/swift/Foo.exe +// RUN: touch %t/swift-root/bin/Foo.exe + +// RUN: %target-clang %s -std=c++11 -I %swift_src_root/include -I %swift_src_root/stdlib/public/SwiftShims -I %clang-include-dir -isysroot %sdk -L%swift_obj_root/lib/swift/%target-sdk-name/%target-arch -lswiftCore -o %t/paths-test +// RUN: %target-codesign %t/paths-test +// RUN: %target-run %t/paths-test | %FileCheck %s +// RUN: env %env-SWIFT_ROOT=%t/swift-root %target-run %t/paths-test | %FileCheck %s --check-prefix CHECK-FR +// REQUIRES: executable_test +// UNSUPPORTED: remote_run + +// This can't be done in unittests, because that statically links the runtime +// so we get the wrong paths. We explicitly want to test that we get the +// path we expect (that is, the path to the runtime, and paths relative to +// that). + +#include "swift/Runtime/Paths.h" + +#include +#include + +#include +#include + +#if defined(_WIN32) && !defined(__CYGWIN) +#define stat _stat +#define S_IFDIR _S_IFDIR +#endif + +static bool +exists(const char *path) { + struct stat st; + + return stat(path, &st) == 0; +} + +static bool +isfile(const char *path) { + struct stat st; + + return stat(path, &st) == 0 && !(st.st_mode & S_IFDIR); +} + +static bool +isdir(const char *path) { + struct stat st; + + return stat(path, &st) == 0 && (st.st_mode & S_IFDIR); +} + +static bool +containsLibSwift(const char *path) { + const char *posix = "/lib/swift/"; + const char *windows = "\\lib\\swift\\"; + + return strstr(path, posix) || strstr(path, windows); +} + +int main(void) { + const char *runtimePath = swift_getRuntimePath(); + + // Runtime path must point to libswiftCore and must be a file. + + // CHECK: runtime path: {{.*[\\/](lib)?}}swiftCore.{{so|dylib|dll}} + // CHECK-NEXT: runtime is a file: yes + + // CHECK-FR: runtime path: {{.*[\\/](lib)?}}swiftCore.{{so|dylib|dll}} + // CHECK-FR-NEXT: runtime is a file: yes + printf("runtime path: %s\n", runtimePath ? runtimePath: ""); + printf("runtime is a file: %s\n", isfile(runtimePath) ? "yes" : "no"); + + const char *rootPath = swift_getRootPath(); + + // Root path must end in a separator and must be a directory + + // CHECK: root path: {{.*[\\/]$}} + // CHECK-NEXT: root is a directory: yes + + // CHECK-FR: root path: {{.*[\\/]$}} + // CHECK-FR-NEXT: root is a directory: yes + printf("root path: %s\n", rootPath ? rootPath : ""); + printf("root is a directory: %s\n", isdir(rootPath) ? "yes" : "no"); + + // CHECK: root path contains /lib/swift/: no + // CHECK-FR: root path contains /lib/swift/: no + printf("root path contains /lib/swift/: %s\n", + containsLibSwift(rootPath) ? "yes" : "no"); + + const char *auxPath = swift_getAuxiliaryExecutablePath("Foo"); + + // CHECK: aux path: + // CHECK-FR: aux path: {{.*[\\/]libexec[\\/]swift[\\/]Foo(\.exe)?}} + + printf("aux path: %s\n", auxPath ? auxPath : ""); + + return 0; +} diff --git a/test/Runtime/environment_variables.swift b/test/Runtime/environment_variables.swift index 43321ab420087..db0609ec06703 100644 --- a/test/Runtime/environment_variables.swift +++ b/test/Runtime/environment_variables.swift @@ -18,6 +18,7 @@ // CHECK-DAG: bool SWIFT_DETERMINISTIC_HASHING [default: false] - Disable randomized hash seeding. // CHECK-DAG: bool SWIFT_ENABLE_MANGLED_NAME_VERIFICATION [default: false] - Enable verification that metadata can roundtrip through a mangled name each time metadata is instantiated. // CHECK-DAG: bool SWIFT_DEBUG_ENABLE_MALLOC_SCRIBBLE [default: false] - Scribble on runtime allocations such as metadata allocations. +// CHECK-DAG: string SWIFT_ROOT [default: "{{[^"]*}}"] - Overrides the root directory of the Swift installation. This is used to locate auxiliary files relative to the runtime itself. // We need to do this because the DAG checks require a non-DAG check as an // anchor: diff --git a/test/lit.cfg b/test/lit.cfg index 259c7772be1f1..8f579e924d219 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -1756,6 +1756,9 @@ config.substitutions.append(('%module-target-future', target_future)) # Add 'target-sdk-name' as the name for platform-specific directories config.substitutions.append(('%target-sdk-name', config.target_sdk_name)) +# Also add 'target-arch' so we can locate some things inside the build tree +config.substitutions.append(('%target-arch', target_arch)) + # Add 'stdlib_dir' as the path to the stdlib resource directory stdlib_dir = os.path.join(config.swift_lib_dir, "swift") if run_os == 'maccatalyst':