Index: libcxx/CMakeLists.txt =================================================================== --- libcxx/CMakeLists.txt +++ libcxx/CMakeLists.txt @@ -88,7 +88,13 @@ option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." OFF) option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON) option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON) -option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON) +set(ENABLE_EXPERIMENTAL_DEFAULT ON) +if (WIN32 AND LIBCXX_ENABLE_SHARED) + # When libc++ is built as a DLL, all headers indicate DLL linkage, while + # libc++experimental always is linked statically. + set(ENABLE_EXPERIMENTAL_DEFAULT OFF) +endif() +option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ${ENABLE_EXPERIMENTAL_DEFAULT}) set(ENABLE_FILESYSTEM_DEFAULT ON) if (WIN32 AND NOT MINGW) # Filesystem is buildable for windows, but it requires __int128 helper Index: libcxx/docs/BuildingLibcxx.rst =================================================================== --- libcxx/docs/BuildingLibcxx.rst +++ libcxx/docs/BuildingLibcxx.rst @@ -90,7 +90,6 @@ -T "ClangCL" ^ -DLIBCXX_ENABLE_SHARED=YES ^ -DLIBCXX_ENABLE_STATIC=NO ^ - -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=NO ^ \path\to\libcxx > cmake --build . @@ -120,7 +119,6 @@ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_C_COMPILER=clang-cl ^ -DCMAKE_CXX_COMPILER=clang-cl ^ - -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=NO ^ path/to/libcxx > ninja cxx > ninja check-cxx Index: libcxx/src/CMakeLists.txt =================================================================== --- libcxx/src/CMakeLists.txt +++ libcxx/src/CMakeLists.txt @@ -259,12 +259,13 @@ endif() endif() +set(CMAKE_STATIC_LIBRARY_PREFIX "lib") + # Build the static library. if (LIBCXX_ENABLE_STATIC) add_library(cxx_static STATIC ${exclude_from_all} ${LIBCXX_SOURCES} ${LIBCXX_HEADERS}) target_link_libraries(cxx_static PUBLIC cxx-headers PRIVATE ${LIBCXX_LIBRARIES}) - set(CMAKE_STATIC_LIBRARY_PREFIX "lib") set_target_properties(cxx_static PROPERTIES COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}" Index: libcxx/test/libcxx/strings/c.strings/version_cuchar.pass.cpp =================================================================== --- libcxx/test/libcxx/strings/c.strings/version_cuchar.pass.cpp +++ libcxx/test/libcxx/strings/c.strings/version_cuchar.pass.cpp @@ -8,6 +8,10 @@ // // XFAIL: * +// Skip this test on windows. If built on top of the MSVC runtime, the +// header actually does exist (although not provided by us). +// UNSUPPORTED: windows + // #include Index: libcxx/test/std/experimental/lit.local.cfg =================================================================== --- libcxx/test/std/experimental/lit.local.cfg +++ libcxx/test/std/experimental/lit.local.cfg @@ -1,3 +1,7 @@ # Disable all of the experimental tests if the correct feature is not available. if 'c++experimental' not in config.available_features: config.unsupported = True +# If built as a DLL on Windows, headers indicate DLL linkage, which breaks +# linking against the static-only libc++experimental. +if config.enable_shared and 'windows' in config.available_features: + config.unsupported = True Index: libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp @@ -8,8 +8,6 @@ // UNSUPPORTED: c++03 -// XFAIL: LIBCXX-WINDOWS-FIXME - // // class directory_entry @@ -155,7 +153,8 @@ // reading directories; test using a special inaccessible directory // instead. const path dir = GetWindowsInaccessibleDir(); - TEST_REQUIRE(!dir.empty()); + if (dir.empty()) + TEST_UNSUPPORTED(); const path file = dir / "file"; { std::error_code ec = GetTestEC(); Index: libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp @@ -8,8 +8,6 @@ // UNSUPPORTED: c++03 -// XFAIL: LIBCXX-WINDOWS-FIXME - // // class directory_iterator @@ -94,7 +92,8 @@ // reading directories; test using a special inaccessible directory // instead. const path testDir = GetWindowsInaccessibleDir(); - TEST_REQUIRE(!testDir.empty()); + if (testDir.empty()) + TEST_UNSUPPORTED(); #else scoped_test_env env; path const testDir = env.make_env_path("dir1"); Index: libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp +++ libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp @@ -8,8 +8,6 @@ // UNSUPPORTED: c++03 -// XFAIL: LIBCXX-WINDOWS-FIXME - // // class directory_iterator @@ -95,7 +93,8 @@ // reading directories; test using a special inaccessible directory // instead. const path testDir = GetWindowsInaccessibleDir(); - TEST_REQUIRE(!testDir.empty()); + if (testDir.empty()) + TEST_UNSUPPORTED(); #else scoped_test_env env; path const testDir = env.make_env_path("dir1"); Index: libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp =================================================================== --- libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp +++ libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp @@ -8,8 +8,6 @@ // UNSUPPORTED: c++03 -// XFAIL: LIBCXX-WINDOWS-FIXME - // // bool exists(file_status s) noexcept @@ -91,7 +89,8 @@ // reading directories; test using a special inaccessible directory // instead. const path p = GetWindowsInaccessibleDir(); - TEST_REQUIRE(!p.empty()); + if (p.empty()) + TEST_UNSUPPORTED(); #else scoped_test_env env; const path dir = env.create_dir("dir"); Index: libcxx/test/std/strings/c.strings/cuchar.pass.cpp =================================================================== --- libcxx/test/std/strings/c.strings/cuchar.pass.cpp +++ libcxx/test/std/strings/c.strings/cuchar.pass.cpp @@ -8,6 +8,10 @@ // // XFAIL: libc++ +// Skip this test on windows. If built on top of the MSVC runtime, the +// header actually does exist (although not provided by us). +// UNSUPPORTED: windows + // #include Index: libcxx/test/std/thread/thread.condition/thread.condition.condvar/wait_for.pass.cpp =================================================================== --- libcxx/test/std/thread/thread.condition/thread.condition.condvar/wait_for.pass.cpp +++ libcxx/test/std/thread/thread.condition/thread.condition.condvar/wait_for.pass.cpp @@ -44,8 +44,9 @@ test1 = 1; cv.notify_one(); Clock::time_point t0 = Clock::now(); + Clock::time_point wait_end = t0 + milliseconds(250); while (test2 == 0 && - cv.wait_for(lk, milliseconds(250)) == std::cv_status::no_timeout) + cv.wait_for(lk, wait_end - Clock::now()) == std::cv_status::no_timeout) ; Clock::time_point t1 = Clock::now(); if (runs == 0) Index: libcxx/test/std/thread/thread.condition/thread.condition.condvarany/wait_for.pass.cpp =================================================================== --- libcxx/test/std/thread/thread.condition/thread.condition.condvarany/wait_for.pass.cpp +++ libcxx/test/std/thread/thread.condition/thread.condition.condvarany/wait_for.pass.cpp @@ -47,8 +47,9 @@ test1 = 1; cv.notify_one(); Clock::time_point t0 = Clock::now(); + Clock::time_point wait_end = t0 + milliseconds(250); while (test2 == 0 && - cv.wait_for(lk, milliseconds(250)) == std::cv_status::no_timeout) + cv.wait_for(lk, wait_end - Clock::now()) == std::cv_status::no_timeout) ; Clock::time_point t1 = Clock::now(); if (runs == 0) Index: libcxx/test/support/filesystem_test_helper.h =================================================================== --- libcxx/test/support/filesystem_test_helper.h +++ libcxx/test/support/filesystem_test_helper.h @@ -678,22 +678,28 @@ const fs::path dir("C:\\System Volume Information"); std::error_code ec; const fs::path root("C:\\"); - fs::directory_iterator it(root, ec); - if (ec) - return fs::path(); - const fs::directory_iterator endIt{}; - while (it != endIt) { - const fs::directory_entry &ent = *it; - if (ent == dir) { - // Basic sanity checks on the directory_entry - if (!ent.exists()) - return fs::path(); - if (!ent.is_directory()) - return fs::path(); - return ent; + for (const auto &ent : fs::directory_iterator(root, ec)) { + if (ent != dir) + continue; + // Basic sanity checks on the directory_entry + if (!ent.exists() || !ent.is_directory()) { + fprintf(stderr, "The expected inaccessible directory \"%s\" was found " + "but doesn't behave as expected, skipping tests " + "regarding it\n", dir.string().c_str()); + return fs::path(); } - ++it; + // Check that it indeed is inaccessible as expected + (void)fs::exists(ent, ec); + if (!ec) { + fprintf(stderr, "The expected inaccessible directory \"%s\" was found " + "but seems to be accessible, skipping tests " + "regarding it\n", dir.string().c_str()); + return fs::path(); + } + return ent; } + fprintf(stderr, "No inaccessible directory \"%s\" found, skipping tests " + "regarding it\n", dir.string().c_str()); return fs::path(); } Index: libcxx/utils/ci/buildkite-pipeline.yml =================================================================== --- libcxx/utils/ci/buildkite-pipeline.yml +++ libcxx/utils/ci/buildkite-pipeline.yml @@ -277,6 +277,20 @@ - exit_status: -1 # Agent was lost limit: 2 + - label: "Windows" + # The CI runner doesn't have bash in the path currently + command: "\"\\Program Files\\Git\\usr\\bin\\bash\" libcxx/utils/ci/run-buildbot generic-win" + artifact_paths: + - "**/test-results.xml" + agents: + queue: "windows" + retry: + automatic: + - exit_status: -1 # Agent was lost + limit: 2 + soft_fail: + - exit_status: 1 + # All jobs defined before this `wait` will run whenever a CI job is started. # Jobs defined after the `wait` will run only if all the jobs above succeeded. # We use this to reduce the load on testers that have more constrained resources Index: libcxx/utils/ci/run-buildbot =================================================================== --- libcxx/utils/ci/run-buildbot +++ libcxx/utils/ci/run-buildbot @@ -421,6 +421,33 @@ generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Armv7Thumb-noexceptions.cmake" check-cxx-cxxabi ;; +generic-win) + clean + # Add bash to the path; the current CI runner doesn't have it added + # globally. + export PATH="$PATH:/c/Program Files/Git/usr/bin" + + # -D_LIBCPP_HAS_NO_INT128 allows building filesystem with a MSVC + # setup that lacks the necessary builtins for int128. + + # -loldnames is needed for some tests unless using Clang 12 (the + # CI runner has Clang 11 currently). + + echo "--- Generating CMake" + cmake -S "${MONOREPO_ROOT}/libcxx" \ + -B "${BUILD_DIR}" \ + -GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}" \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_C_COMPILER=clang-cl \ + -DCMAKE_CXX_COMPILER=clang-cl \ + -DLLVM_LIT_ARGS="-sv --show-unsupported --xunit-xml-output test-results.xml" \ + -DLIBCXX_ENABLE_FILESYSTEM=YES \ + -DCMAKE_CXX_FLAGS="-D_LIBCPP_HAS_NO_INT128" \ + -DLIBCXX_TEST_COMPILER_FLAGS="-D_LIBCPP_HAS_NO_INT128" \ + -DLIBCXX_TEST_LINKER_FLAGS="-loldnames" + echo "+++ Running the libc++ tests" + ${NINJA} -vC "${BUILD_DIR}" check-cxx +;; *) echo "${BUILDER} is not a known configuration" exit 1 Index: libcxx/utils/libcxx/test/config.py =================================================================== --- libcxx/utils/libcxx/test/config.py +++ libcxx/utils/libcxx/test/config.py @@ -110,7 +110,6 @@ def make_static_lib_name(self, name): """Return the full filename for the specified library name""" if self.target_info.is_windows() and not self.target_info.is_mingw(): - assert name == 'c++' # Only allow libc++ to use this function for now. return 'lib' + name + '.lib' else: return 'lib' + name + '.a' @@ -144,6 +143,9 @@ self.lit_config ) + if 'c++experimental' in self.config.available_features: + self.configure_link_flags_cxx_experimental_library() + self.lit_config.note("All available features: {}".format(self.config.available_features)) def print_config_info(self): @@ -446,6 +448,17 @@ else: self.cxx.link_flags += ['-lc++'] + def configure_link_flags_cxx_experimental_library(self): + # c++experimental is always linked statically + if self.cxx_library_root: + libname = self.make_static_lib_name('c++experimental') + abs_path = os.path.join(self.cxx_library_root, libname) + assert os.path.exists(abs_path) and \ + "static libc++ library does not exist" + self.cxx.link_flags += [abs_path] + else: + self.cxx.link_flags += ['-lc++experimental'] + def configure_link_flags_abi_library(self): cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi') if cxx_abi == 'libstdc++': Index: libcxx/utils/libcxx/test/params.py =================================================================== --- libcxx/utils/libcxx/test/params.py +++ libcxx/utils/libcxx/test/params.py @@ -89,8 +89,7 @@ Parameter(name='enable_experimental', choices=[True, False], type=bool, default=False, help="Whether to enable tests for experimental C++ libraries (typically Library Fundamentals TSes).", actions=lambda experimental: [] if not experimental else [ - AddFeature('c++experimental'), - AddLinkFlag('-lc++experimental') + AddFeature('c++experimental') ]), Parameter(name='long_tests', choices=[True, False], type=bool, default=True,