Skip to content

Commit

Permalink
Finish POSIX-native filesystem backend. (#213)
Browse files Browse the repository at this point in the history
* Fix format-cxxcode on the Codespaces Ubuntu images.

* Implement the subset of copy we actually use, and delete checking of VCPKG_USE_STD_FILESYSTEM from the sources.

* Remove detection for C++ standard library and std::filesystem library.

* Add symlinks comment requested by Nicole.
  • Loading branch information
BillyONeal authored Oct 11, 2021
1 parent bf4ec07 commit 0113d64
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 205 deletions.
8 changes: 1 addition & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ project(vcpkg
HOMEPAGE_URL "https://github.com/microsoft/vcpkg"
LANGUAGES ${LANGUAGES}
)

include(cmake/utilities.cmake)

# =============
Expand All @@ -69,8 +70,6 @@ set(TLS12_DOWNLOAD_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/tls12-download.c")
# ========================

vcpkg_detect_compiler()
vcpkg_detect_standard_library()
vcpkg_detect_std_filesystem()

if(VCPKG_EMBED_GIT_SHA)
find_package(Git REQUIRED)
Expand Down Expand Up @@ -138,7 +137,6 @@ target_include_directories(vcpkglib PUBLIC include)

vcpkg_target_add_warning_options(vcpkglib)
target_compile_definitions(vcpkglib PUBLIC
VCPKG_USE_STD_FILESYSTEM=$<BOOL:${VCPKG_USE_STD_FILESYSTEM}>
VCPKG_VERSION=${VCPKG_VERSION}
VCPKG_BASE_VERSION=${VCPKG_BASE_VERSION}
)
Expand All @@ -147,10 +145,6 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(vcpkglib PRIVATE Threads::Threads)

if(VCPKG_CXXFS_LIBRARY)
target_link_libraries(vcpkglib PRIVATE ${VCPKG_CXXFS_LIBRARY})
endif()

if(MSVC)
get_target_property(_srcs vcpkglib SOURCES)

Expand Down
7 changes: 6 additions & 1 deletion azure-pipelines/Format-CxxCode.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
[CmdletBinding()]
$Root = Resolve-Path -LiteralPath "$PSScriptRoot/.."

$clangFormat = Get-Command 'clang-format' -ErrorAction 'SilentlyContinue'
$clangFormat = Get-Command 'clang-format-12' -ErrorAction 'SilentlyContinue'
if ($null -eq $clangFormat)
{
$clangFormat = Get-Command 'clang-format' -ErrorAction 'SilentlyContinue'
}

if ($null -ne $clangFormat)
{
$clangFormat = $clangFormat.Source
Expand Down
134 changes: 0 additions & 134 deletions cmake/utilities.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -50,140 +50,6 @@ If you would like to try anyway, pass --allowAppleClang to bootstrap.sh.
endif()
endfunction()

# Outputs to Cache: VCPKG_STANDARD_LIBRARY
function(vcpkg_detect_standard_library)
if(NOT DEFINED CACHE{VCPKG_STANDARD_LIBRARY})
include(CheckCXXSourceCompiles)

message(STATUS "Detecting the C++ standard library")

# note: since <ciso646> is the smallest header, generally it's used to get the standard library version
set(CMAKE_REQUIRED_QUIET ON)
check_cxx_source_compiles([[
#include <ciso646>
#if !defined(__GLIBCXX__)
#error "not libstdc++"
#endif
int main() {}
]]
_VCPKG_STANDARD_LIBRARY_LIBSTDCXX)
check_cxx_source_compiles([[
#include <ciso646>
#if !defined(_LIBCPP_VERSION)
#error "not libc++"
#endif
int main() {}
]]
_VCPKG_STANDARD_LIBRARY_LIBCXX)
check_cxx_source_compiles([[
#include <ciso646>
#if !defined(_MSVC_STL_VERSION) && !(defined(_MSC_VER) && _MSC_VER <= 1900)
#error "not MSVC stl"
#endif
int main() {}
]]
_VCPKG_STANDARD_LIBRARY_MSVC_STL)
if(_VCPKG_STANDARD_LIBRARY_LIBSTDCXX)
set(STANDARD_LIBRARY "libstdc++")
elseif(_VCPKG_STANDARD_LIBRARY_LIBCXX)
set(STANDARD_LIBRARY "libc++")
elseif(_VCPKG_STANDARD_LIBRARY_MSVC_STL)
set(STANDARD_LIBRARY "msvc-stl")
else()
message(FATAL_ERROR "Can't find which C++ runtime is in use")
endif()

set(VCPKG_STANDARD_LIBRARY ${STANDARD_LIBRARY}
CACHE STRING
"The C++ standard library in use; one of libstdc++, libc++, msvc-stl")

message(STATUS "Detecting the C++ standard library - ${VCPKG_STANDARD_LIBRARY}")
endif()
endfunction()

# Outputs to Cache: VCPKG_USE_STD_FILESYSTEM, VCPKG_CXXFS_LIBRARY
function(vcpkg_detect_std_filesystem)
vcpkg_detect_standard_library()

if(NOT DEFINED CACHE{VCPKG_USE_STD_FILESYSTEM})
include(CheckCXXSourceCompiles)

message(STATUS "Detecting how to use the C++ filesystem library")

set(CMAKE_REQUIRED_QUIET ON)
if(VCPKG_STANDARD_LIBRARY STREQUAL "libstdc++")
check_cxx_source_compiles([[
#include <ciso646>
#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 9
#error "libstdc++ after version 9 does not require -lstdc++fs"
#endif
int main() {}
]]
_VCPKG_REQUIRE_LINK_CXXFS)

check_cxx_source_compiles([[
#include <ciso646>
#if !defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE < 8
#error "libstdc++ before version 8 does not support <filesystem>"
#endif
int main() {}
]]
_VCPKG_USE_STD_FILESYSTEM)

if(_VCPKG_REQUIRE_LINK_CXXFS)
set(_VCPKG_CXXFS_LIBRARY "stdc++fs")
endif()
elseif(VCPKG_STANDARD_LIBRARY STREQUAL "libc++")
if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
# AppleClang never requires (or allows) -lc++fs, even with libc++ version 8.0.0
set(_VCPKG_CXXFS_LIBRARY OFF)
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
# As above, not required on this platform (tested at least on 6.8)
set(_VCPKG_CXXFS_LIBRARY OFF)
else()
check_cxx_source_compiles([[
#include <ciso646>
#if _LIBCPP_VERSION >= 9000
#error "libc++ after version 9 does not require -lc++fs"
#endif
int main() {}
]]
_VCPKG_REQUIRE_LINK_CXXFS)

if(_VCPKG_REQUIRE_LINK_CXXFS)
set(_VCPKG_CXXFS_LIBRARY "c++fs")
endif()
endif()

# We don't support versions of libc++ < 7.0.0, and libc++ 7.0.0 has <filesystem>
set(_VCPKG_USE_STD_FILESYSTEM ON)
elseif(VCPKG_STANDARD_LIBRARY STREQUAL "msvc-stl")
set(_VCPKG_USE_STD_FILESYSTEM ON)
set(_VCPKG_CXXFS_LIBRARY OFF)
endif()

set(VCPKG_USE_STD_FILESYSTEM ${_VCPKG_USE_STD_FILESYSTEM}
CACHE BOOL
"Whether to use <filesystem>, as opposed to <experimental/filesystem>"
FORCE)
set(VCPKG_CXXFS_LIBRARY ${_VCPKG_CXXFS_LIBRARY}
CACHE STRING
"Library to link (if any) in order to use <filesystem>"
FORCE)

if(VCPKG_USE_STD_FILESYSTEM)
set(msg "<filesystem>")
else()
set(msg "<experimental/filesystem>")
endif()
if(VCPKG_CXXFS_LIBRARY)
set(msg "${msg} with -l${VCPKG_CXXFS_LIBRARY}")
endif()

message(STATUS "Detecting how to use the C++ filesystem library - ${msg}")
endif()
endfunction()

function(vcpkg_target_add_warning_options TARGET)
if(MSVC)
# either MSVC, or clang-cl
Expand Down
11 changes: 5 additions & 6 deletions include/vcpkg/base/files.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,8 @@ namespace vcpkg
enum class CopyOptions
{
none = 0,

existing_mask = 0xF,
skip_existing = 0x1,
overwrite_existing = 0x2,

recursive = 0x10,
};

struct Path
Expand Down Expand Up @@ -297,8 +293,11 @@ namespace vcpkg
void create_best_link(const Path& to, const Path& from, std::error_code& ec);
void create_best_link(const Path& to, const Path& from, LineInfo);

virtual void copy(const Path& source, const Path& destination, CopyOptions options, std::error_code& ec) = 0;
void copy(const Path& source, const Path& destination, CopyOptions options, LineInfo);
// copies regular files and directories, recursively.
// symlinks are followed and copied as if they were regular files or directories
// (like std::filesystem::copy(..., std::filesystem::copy_options::recursive))
virtual void copy_regular_recursive(const Path& source, const Path& destination, std::error_code& ec) = 0;
void copy_regular_recursive(const Path& source, const Path& destination, LineInfo);

virtual bool copy_file(const Path& source,
const Path& destination,
Expand Down
104 changes: 51 additions & 53 deletions src/vcpkg/base/files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,10 @@
#include <string>
#include <thread>

#if !defined(VCPKG_USE_STD_FILESYSTEM)
#error The build system must set VCPKG_USE_STD_FILESYSTEM.
#endif // !defined(VCPKG_USE_STD_FILESYSTEM)

#if VCPKG_USE_STD_FILESYSTEM
#if defined(_WIN32)
#include <filesystem>
#else
#include <experimental/filesystem>
#endif

#if VCPKG_USE_STD_FILESYSTEM
namespace stdfs = std::filesystem;
#else
namespace stdfs = std::experimental::filesystem;
#endif
#endif // _WIN32

namespace
{
Expand Down Expand Up @@ -82,28 +71,18 @@ namespace
li, Strings::concat(call_name, "(", Strings::join(", ", args.begin(), args.end()), "): ", ec.message()));
}

#if defined(_WIN32)
stdfs::copy_options convert_copy_options(CopyOptions options)
{
stdfs::copy_options result{};
const auto unpacked = static_cast<int>(options);

switch (unpacked & static_cast<int>(CopyOptions::existing_mask))
switch (options)
{
case static_cast<int>(CopyOptions::skip_existing): result |= stdfs::copy_options::skip_existing; break;
case static_cast<int>(CopyOptions::overwrite_existing):
result |= stdfs::copy_options::overwrite_existing;
break;
}

if (unpacked & static_cast<int>(CopyOptions::recursive))
{
result |= stdfs::copy_options::recursive;
case CopyOptions::none: return stdfs::copy_options::none;
case CopyOptions::skip_existing: return stdfs::copy_options::skip_existing;
case CopyOptions::overwrite_existing: return stdfs::copy_options::overwrite_existing;
default: Checks::unreachable(VCPKG_LINE_INFO);
}

return result;
}

#if defined(_WIN32)
FileType convert_file_type(stdfs::file_type type) noexcept
{
switch (type)
Expand All @@ -122,22 +101,11 @@ namespace
default: Checks::unreachable(VCPKG_LINE_INFO);
}
}
#endif // _WIN32

stdfs::path to_stdfs_path(const Path& utfpath)
{
#if defined(_WIN32)
return stdfs::path(Strings::to_utf16(utfpath.native()));
#else // ^^^ _WIN32 / !_WIN32 vvv
return stdfs::path(utfpath.native());
#endif // ^^^ !_WIN32
}
stdfs::path to_stdfs_path(const Path& utfpath) { return stdfs::path(Strings::to_utf16(utfpath.native())); }

#if defined(_WIN32)
Path from_stdfs_path(const stdfs::path& stdpath) { return Strings::to_utf8(stdpath.native()); }
#endif // ^^^ _WIN32

#if defined(_WIN32)
// The Win32 version of this implementation is effectively forked from
// https://github.com/microsoft/STL/blob/bd7adb4a932725f60ba096580c415616486ab64c/stl/inc/filesystem#L436
// converted to speak UTF-8 rather than UTF-16.
Expand Down Expand Up @@ -1539,10 +1507,10 @@ namespace vcpkg
}
}

void Filesystem::copy(const Path& source, const Path& destination, CopyOptions options, LineInfo li)
void Filesystem::copy_regular_recursive(const Path& source, const Path& destination, LineInfo li)
{
std::error_code ec;
this->copy(source, destination, options, ec);
this->copy_regular_recursive(source, destination, ec);
if (ec)
{
exit_filesystem_call_error(li, ec, __func__, {source, destination});
Expand Down Expand Up @@ -2568,13 +2536,45 @@ namespace vcpkg
}
#endif // _WIN32
}
virtual void copy(const Path& source,
const Path& destination,
CopyOptions options,
std::error_code& ec) override

virtual void copy_regular_recursive(const Path& source, const Path& destination, std::error_code& ec) override
{
stdfs::copy(to_stdfs_path(source), to_stdfs_path(destination), convert_copy_options(options), ec);
#if defined(_WIN32)
stdfs::copy(to_stdfs_path(source), to_stdfs_path(destination), stdfs::copy_options::recursive, ec);
#else // ^^^ _WIN32 // !_WIN32 vvv
ReadDirOp rd{source.c_str(), ec};
if (ec)
{
if (ec == std::errc::not_a_directory)
{
this->copy_file(source, destination, CopyOptions::none, ec);
}

return;
}

this->create_directory(destination, ec);
Path source_entry_name;
Path destination_entry_name;
const dirent* entry;
// the !ec check is either for the create_directory above on the first iteration, or for the most
// recent copy_file or copy_regular_recursive on subsequent iterations
while (!ec && (entry = rd.read(ec)))
{
source_entry_name = source / entry->d_name;
destination_entry_name = destination / entry->d_name;
if (get_d_type(entry) == PosixDType::Regular)
{
this->copy_file(source_entry_name, destination_entry_name, CopyOptions::none, ec);
}
else
{
this->copy_regular_recursive(source_entry_name, destination_entry_name, ec);
}
}
#endif // ^^^ !_WIN32
}

virtual bool copy_file(const Path& source,
const Path& destination,
CopyOptions options,
Expand Down Expand Up @@ -2605,10 +2605,8 @@ namespace vcpkg
return false;
}

auto masked_options =
static_cast<CopyOptions>(static_cast<int>(options) & static_cast<int>(CopyOptions::existing_mask));
int open_options = O_WRONLY | O_CREAT;
if (masked_options != CopyOptions::overwrite_existing)
if (options != CopyOptions::overwrite_existing)
{
// the standard wording suggests that we should create a file through a broken symlink which would
// forbid use of O_EXCL. However, implementations like boost::copy_file don't do this and doing it
Expand All @@ -2620,7 +2618,7 @@ namespace vcpkg
PosixFd destination_fd{destination.c_str(), open_options, open_mode, ec};
if (ec)
{
if (masked_options == CopyOptions::skip_existing && ec == std::errc::file_exists)
if (options == CopyOptions::skip_existing && ec == std::errc::file_exists)
{
ec.clear();
}
Expand All @@ -2647,7 +2645,7 @@ namespace vcpkg
return false;
}

if (masked_options == CopyOptions::overwrite_existing)
if (options == CopyOptions::overwrite_existing)
{
destination_fd.ftruncate(0, ec);
if (ec) return false;
Expand Down
Loading

0 comments on commit 0113d64

Please sign in to comment.