Merge branch 'feature-68-experimental-emscripten-support'

This commit is contained in:
Steffen Schuemann 2020-08-30 09:19:14 +02:00
commit cdfb593d40
5 changed files with 64 additions and 10 deletions

View File

@ -492,7 +492,8 @@ to the expected behavior.
* Pull request [#69](https://github.com/gulrak/filesystem/pull/69), use `wchar_t` versions of
`std::fstream` from `ghc::filesystem::fstream` wrappers on Windows if using GCC with libc++.
* Bugfix for [#68](https://github.com/gulrak/filesystem/issues/68), better handling of
permission issues for directory iterators when using `fs::directory_options::skip_permission_denied`.
permission issues for directory iterators when using `fs::directory_options::skip_permission_denied`
and initial support for compilation with emscripten.
* Bugfix for [#63](https://github.com/gulrak/filesystem/issues/63), fixed issues on Windows
with clang++ and C++17.
* Pull request [#62](https://github.com/gulrak/filesystem/pull/62), various fixes for

View File

@ -64,6 +64,9 @@
#define GHC_OS_SYS5R4
#elif defined(BSD)
#define GHC_OS_BSD
#elif defined(__EMSCRIPTEN__)
#define GHC_OS_WEB
#include <wasi/api.h>
#else
#error "Operating system currently not supported!"
#endif
@ -590,7 +593,9 @@ enum class copy_options : uint16_t {
directories_only = 0x40,
create_symlinks = 0x80,
#ifndef GHC_OS_WEB
create_hard_links = 0x100
#endif
};
enum class directory_options : uint16_t {
@ -701,10 +706,14 @@ public:
uintmax_t file_size() const;
#endif
uintmax_t file_size(std::error_code& ec) const noexcept;
#ifndef GHC_OS_WEB
#ifdef GHC_WITH_EXCEPTIONS
uintmax_t hard_link_count() const;
#endif
uintmax_t hard_link_count(std::error_code& ec) const noexcept;
#endif
#ifdef GHC_WITH_EXCEPTIONS
file_time_type last_write_time() const;
#endif
@ -934,10 +943,12 @@ GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink
#endif
GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;
#ifndef GHC_OS_WEB
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link);
#endif
GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept;
#endif
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API void create_symlink(const path& to, const path& new_symlink);
@ -969,10 +980,12 @@ GHC_FS_API uintmax_t file_size(const path& p);
#endif
GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
#ifndef GHC_OS_WEB
#ifdef GHC_WITH_EXCEPTIONS
GHC_FS_API uintmax_t hard_link_count(const path& p);
#endif
GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept;
#endif
GHC_FS_API bool is_block_file(file_status s) noexcept;
#ifdef GHC_WITH_EXCEPTIONS
@ -1815,6 +1828,7 @@ GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink,
}
}
#ifndef GHC_OS_WEB
GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec)
{
if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) {
@ -1822,6 +1836,7 @@ GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlin
}
}
#endif
#endif
template <typename T>
GHC_INLINE file_status file_status_from_st_mode(T mode)
@ -3402,9 +3417,11 @@ GHC_INLINE void copy(const path& from, const path& to, copy_options options, std
if ((options & copy_options::create_symlinks) != copy_options::none) {
create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec);
}
#ifndef GHC_OS_WEB
else if ((options & copy_options::create_hard_links) != copy_options::none) {
create_hard_link(from, to, ec);
}
#endif
else if (is_directory(fs_to)) {
copy_file(from, to / from.filename(), options, ec);
}
@ -3697,6 +3714,7 @@ GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink
detail::create_symlink(to, new_symlink, true, ec);
}
#ifndef GHC_OS_WEB
#ifdef GHC_WITH_EXCEPTIONS
GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link)
{
@ -3712,6 +3730,7 @@ GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std:
{
detail::create_hardlink(to, new_hard_link, ec);
}
#endif
#ifdef GHC_WITH_EXCEPTIONS
GHC_INLINE void create_symlink(const path& to, const path& new_symlink)
@ -3900,6 +3919,7 @@ GHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept
#endif
}
#ifndef GHC_OS_WEB
#ifdef GHC_WITH_EXCEPTIONS
GHC_INLINE uintmax_t hard_link_count(const path& p)
{
@ -3940,6 +3960,7 @@ GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcep
return ec ? static_cast<uintmax_t>(-1) : result;
#endif
}
#endif
GHC_INLINE bool is_block_file(file_status s) noexcept
{
@ -4176,7 +4197,7 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err
times[0].tv_sec = 0;
times[0].tv_nsec = UTIME_OMIT;
times[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();
times[1].tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000;
times[1].tv_nsec = 0; //std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000;
if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
ec = detail::make_system_error();
}
@ -4945,6 +4966,7 @@ GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexc
return filesystem::file_size(path(), ec);
}
#ifndef GHC_OS_WEB
#ifdef GHC_WITH_EXCEPTIONS
GHC_INLINE uintmax_t directory_entry::hard_link_count() const
{
@ -4967,6 +4989,7 @@ GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const
#endif
return filesystem::hard_link_count(path(), ec);
}
#endif
#ifdef GHC_WITH_EXCEPTIONS
GHC_INLINE file_time_type directory_entry::last_write_time() const

View File

@ -18,12 +18,16 @@ else()
add_executable(filesystem_test filesystem_test.cpp catch.hpp)
target_link_libraries(filesystem_test ghc_filesystem)
target_compile_options(filesystem_test PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Wno-psabi -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/WX>)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
if(EMSCRIPTEN)
set_target_properties(filesystem_test PROPERTIES LINK_FLAGS "-g4 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1")
endif()
ParseAndAddCatchTests(filesystem_test)
AddExecutableWithStdFS(std_filesystem_test filesystem_test.cpp catch.hpp)
if(WIN32)

View File

@ -144,7 +144,7 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
if("${TestType}" STREQUAL "SCENARIO")
set(Name "Scenario: ${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND "${TestType}" MATCHES "(CATCH_)?TEST_CASE_METHOD" AND TestFixture )
set(CTestName "${TestFixture}:${Name}")
else()
set(CTestName "${Name}")
@ -189,24 +189,29 @@ function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
# Escape commas in the test spec
string(REPLACE "," "\\," Name ${Name})
# Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were neccessary,
# only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
if(NOT ${CMAKE_VERSION} VERSION_EQUAL "3.18")
set(CTestName "\"${CTestName}\"")
endif()
# Add the test and set its properties
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
set_tests_properties("${CTestName}" PROPERTIES DISABLED ON)
else()
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
set_tests_properties("${CTestName}" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Labels}")
endif()
set_property(
TARGET ${TestTarget}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
set_property(
SOURCE ${SourceFile}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
endif()

View File

@ -1229,9 +1229,11 @@ TEST_CASE("30.10.12 class directory_entry", "[filesystem][directory_entry][fs.di
ec.clear();
CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(de.last_write_time(ec) - now).count()) < 3);
CHECK(!ec);
#ifndef GHC_OS_WEB
CHECK(de.hard_link_count() == 1);
CHECK(de.hard_link_count(ec) == 1);
CHECK(!ec);
#endif
CHECK_THROWS_AS(de.replace_filename("bar"), fs::filesystem_error);
CHECK_NOTHROW(de.replace_filename("foo"));
ec.clear();
@ -1239,9 +1241,11 @@ TEST_CASE("30.10.12 class directory_entry", "[filesystem][directory_entry][fs.di
CHECK(ec);
auto de2none = fs::directory_entry();
ec.clear();
#ifndef GHC_OS_WEB
CHECK(de2none.hard_link_count(ec) == static_cast<uintmax_t>(-1));
CHECK_THROWS_AS(de2none.hard_link_count(), fs::filesystem_error);
CHECK(ec);
#endif
ec.clear();
CHECK_NOTHROW(de2none.last_write_time(ec));
CHECK_THROWS_AS(de2none.last_write_time(), fs::filesystem_error);
@ -1593,6 +1597,7 @@ TEST_CASE("30.10.15.3 copy", "[filesystem][operations][fs.op.copy]")
CHECK(fs::is_symlink("dir3/dir2/file3"));
#endif
}
#ifndef GHC_OS_WEB
{
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
@ -1613,6 +1618,7 @@ TEST_CASE("30.10.15.3 copy", "[filesystem][operations][fs.op.copy]")
CHECK(fs::exists("dir3/dir2/file3"));
CHECK(fs::hard_link_count("dir1/dir2/file3") == f3hl + 1);
}
#endif
}
TEST_CASE("30.10.15.4 copy_file", "[filesystem][operations][fs.op.copy_file]")
@ -1780,6 +1786,7 @@ TEST_CASE("30.10.15.8 create_directory_symlink", "[filesystem][operations][fs.op
TEST_CASE("30.10.15.9 create_hard_link", "[filesystem][operations][fs.op.create_hard_link]")
{
#ifndef GHC_OS_WEB
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
generateFile("foo", 1234);
@ -1793,6 +1800,7 @@ TEST_CASE("30.10.15.9 create_hard_link", "[filesystem][operations][fs.op.create_
CHECK_THROWS_AS(fs::create_hard_link("nofoo", "bar"), fs::filesystem_error);
CHECK_NOTHROW(fs::create_hard_link("nofoo", "bar", ec));
CHECK(ec);
#endif
}
TEST_CASE("30.10.15.10 create_symlink", "[filesystem][operations][fs.op.create_symlink]")
@ -1927,6 +1935,7 @@ TEST_CASE("30.10.15.14 file_size", "[filesystem][operations][fs.op.file_size]")
TEST_CASE("30.10.15.15 hard_link_count", "[filesystem][operations][fs.op.hard_link_count]")
{
#ifndef GHC_OS_WEB
TemporaryDirectory t(TempOpt::change_path);
std::error_code ec;
#ifdef GHC_OS_WINDOWS
@ -1952,6 +1961,9 @@ TEST_CASE("30.10.15.15 hard_link_count", "[filesystem][operations][fs.op.hard_li
CHECK_NOTHROW(fs::hard_link_count(t.path() / "bar", ec));
CHECK(ec);
ec.clear();
#else
WARN("Test for unsupportet features are disabled on JS/Wasm target.");
#endif
}
class FileTypeMixFixture
@ -1968,7 +1980,7 @@ public:
fs::create_symlink("regular", "file_symlink");
fs::create_directory_symlink("directory", "dir_symlink");
}
#ifndef GHC_OS_WINDOWS
#if !defined(GHC_OS_WINDOWS) && !defined(GHC_OS_WEB)
REQUIRE(::mkfifo("fifo", 0644) == 0);
_hasFifo = true;
struct ::sockaddr_un addr;
@ -2271,6 +2283,7 @@ TEST_CASE_METHOD(FileTypeMixFixture, "30.10.15.24 is_symlink", "[filesystem][ope
CHECK(!fs::is_symlink(fs::file_status(fs::file_type::unknown)));
}
#ifndef GHC_OS_WEB
static fs::file_time_type timeFromString(const std::string& str)
{
struct ::tm tm;
@ -2282,6 +2295,7 @@ static fs::file_time_type timeFromString(const std::string& str)
}
return from_time_t<fs::file_time_type>(std::mktime(&tm));
}
#endif
TEST_CASE("30.10.15.25 last_write_time", "[filesystem][operations][fs.op.last_write_time]")
{
@ -2304,16 +2318,21 @@ TEST_CASE("30.10.15.25 last_write_time", "[filesystem][operations][fs.op.last_wr
// checks that the time of the symlink is fetched
CHECK(ft == fs::last_write_time("foo2"));
}
#ifndef GHC_OS_WEB
auto nt = timeFromString("2015-10-21T04:30:00");
CHECK_NOTHROW(fs::last_write_time(t.path() / "foo", nt));
CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - nt).count()) < 1);
nt = timeFromString("2015-10-21T04:29:00");
CHECK_NOTHROW(fs::last_write_time("foo", nt, ec));
std::cout << "about to call last_write_time" << std::endl;
CHECK(std::abs(std::chrono::duration_cast<std::chrono::seconds>(fs::last_write_time("foo") - nt).count()) < 1);
CHECK(!ec);
std::cout << "about to call last_write_time" << std::endl;
CHECK_THROWS_AS(fs::last_write_time("bar", nt), fs::filesystem_error);
std::cout << "about to call last_write_time" << std::endl;
CHECK_NOTHROW(fs::last_write_time("bar", nt, ec));
CHECK(ec);
#endif
}
TEST_CASE("30.10.15.26 permissions", "[filesystem][operations][fs.op.permissions]")
@ -2499,6 +2518,7 @@ TEST_CASE("30.10.15.34 space", "[filesystem][operations][fs.op.space]")
CHECK(si.free >= si.available);
CHECK(!ec);
}
#ifndef GHC_OS_WEB // statvfs under emscripten always returns a result, so this tests would fail
{
std::error_code ec;
fs::space_info si;
@ -2509,6 +2529,7 @@ TEST_CASE("30.10.15.34 space", "[filesystem][operations][fs.op.space]")
CHECK(ec);
}
CHECK_THROWS_AS(fs::space("foobar42"), fs::filesystem_error);
#endif
}
TEST_CASE("30.10.15.35 status", "[filesystem][operations][fs.op.status]")