Skip to content

Commit f449c26

Browse files
kiminuofanquake
authored andcommitted
refactor: replace boost::filesystem with std::filesystem
1 parent 7002c4a commit f449c26

23 files changed

+68
-216
lines changed

.cirrus.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ task:
8282
FILE_ENV: "./ci/test/00_setup_env_arm.sh"
8383

8484
task:
85-
name: 'Win64 [unit tests, no gui tests, no boost::process, no functional tests] [bionic]'
85+
name: 'Win64 [unit tests, no gui tests, no boost::process, no functional tests] [focal]'
8686
<< : *GLOBAL_TASK_TEMPLATE
8787
container:
88-
image: ubuntu:bionic
88+
image: ubuntu:focal
8989
env:
9090
FILE_ENV: "./ci/test/00_setup_env_win64.sh"
9191

@@ -152,10 +152,10 @@ task:
152152
FILE_ENV: "./ci/test/00_setup_env_native_multiprocess.sh"
153153

154154
task:
155-
name: '[no wallet] [bionic]'
155+
name: '[no wallet] [focal]'
156156
<< : *GLOBAL_TASK_TEMPLATE
157157
container:
158-
image: ubuntu:bionic
158+
image: ubuntu:focal
159159
env:
160160
FILE_ENV: "./ci/test/00_setup_env_native_nowallet.sh"
161161

ci/test/00_setup_env_native_nowallet.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
export LC_ALL=C.UTF-8
88

99
export CONTAINER_NAME=ci_native_nowallet
10-
export DOCKER_NAME_TAG=ubuntu:18.04 # Use bionic to have one config run the tests in python3.6, see doc/dependencies.md
11-
export PACKAGES="python3-zmq clang-5.0 llvm-5.0" # Use clang-5 to test C++17 compatibility, see doc/dependencies.md
10+
export DOCKER_NAME_TAG=ubuntu:20.04
11+
export PACKAGES="python3-zmq clang-7 llvm-7" # Use clang-7 to test C++17 & std::filesystem compatibility, see doc/dependencies.md
1212
export DEP_OPTS="NO_WALLET=1"
1313
export GOAL="install"
14-
export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CC=clang-5.0 CXX=clang++-5.0 --with-boost-process"
14+
export BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CC=clang-7 CXX=clang++-7 --with-boost-process"

ci/test/00_setup_env_native_qt5.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
export LC_ALL=C.UTF-8
88

99
export CONTAINER_NAME=ci_native_qt5
10-
export DOCKER_NAME_TAG=ubuntu:18.04 # Check that bionic gcc-7 can compile our c++17 and run our functional tests in python3, see doc/dependencies.md
11-
export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev"
10+
export DOCKER_NAME_TAG=ubuntu:18.04 # Use gcc-8 to test C++17 & std::filesystem compatibility and run our functional tests using python3.6, see doc/dependencies.md
11+
export PACKAGES="gcc-8 g++-8 python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev"
1212
export DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
1313
export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
1414
export RUN_SECURITY_TESTS="true"
1515
export RUN_UNIT_TESTS_SEQUENTIAL="true"
1616
export RUN_UNIT_TESTS="false"
1717
export GOAL="install"
1818
export PREVIOUS_RELEASES_TO_DOWNLOAD="v0.15.2 v0.16.3 v0.17.2 v0.18.1 v0.19.1"
19-
export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\" --with-boost-process"
19+
export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\" --with-boost-process CC=gcc-8 CXX=g++-8"

ci/test/00_setup_env_win64.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
export LC_ALL=C.UTF-8
88

99
export CONTAINER_NAME=ci_win64
10-
export DOCKER_NAME_TAG=ubuntu:18.04 # Check that bionic can cross-compile to win64 (bionic is used in the gitian build as well)
10+
export DOCKER_NAME_TAG=ubuntu:20.04
1111
export HOST=x86_64-w64-mingw32
1212
export PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64 file"
1313
export RUN_FUNCTIONAL_TESTS=false

configure.ac

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory])
7676
dnl Check if -latomic is required for <std::atomic>
7777
CHECK_ATOMIC
7878

79+
dnl check if -lstdc++fs is required for <std::filesystem>
80+
CHECK_FILESYSTEM
81+
7982
dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures
8083
dnl that we get the same -std flags for both.
8184
m4_ifdef([AC_PROG_OBJCXX],[

src/fs.cpp

Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -144,108 +144,4 @@ std::string get_filesystem_error_message(const fs::filesystem_error& e)
144144
#endif
145145
}
146146

147-
#ifdef WIN32
148-
#ifdef __GLIBCXX__
149-
150-
// reference: https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270
151-
152-
static std::string openmodeToStr(std::ios_base::openmode mode)
153-
{
154-
switch (mode & ~std::ios_base::ate) {
155-
case std::ios_base::out:
156-
case std::ios_base::out | std::ios_base::trunc:
157-
return "w";
158-
case std::ios_base::out | std::ios_base::app:
159-
case std::ios_base::app:
160-
return "a";
161-
case std::ios_base::in:
162-
return "r";
163-
case std::ios_base::in | std::ios_base::out:
164-
return "r+";
165-
case std::ios_base::in | std::ios_base::out | std::ios_base::trunc:
166-
return "w+";
167-
case std::ios_base::in | std::ios_base::out | std::ios_base::app:
168-
case std::ios_base::in | std::ios_base::app:
169-
return "a+";
170-
case std::ios_base::out | std::ios_base::binary:
171-
case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
172-
return "wb";
173-
case std::ios_base::out | std::ios_base::app | std::ios_base::binary:
174-
case std::ios_base::app | std::ios_base::binary:
175-
return "ab";
176-
case std::ios_base::in | std::ios_base::binary:
177-
return "rb";
178-
case std::ios_base::in | std::ios_base::out | std::ios_base::binary:
179-
return "r+b";
180-
case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
181-
return "w+b";
182-
case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary:
183-
case std::ios_base::in | std::ios_base::app | std::ios_base::binary:
184-
return "a+b";
185-
default:
186-
return std::string();
187-
}
188-
}
189-
190-
void ifstream::open(const fs::path& p, std::ios_base::openmode mode)
191-
{
192-
close();
193-
mode |= std::ios_base::in;
194-
m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
195-
if (m_file == nullptr) {
196-
return;
197-
}
198-
m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
199-
rdbuf(&m_filebuf);
200-
if (mode & std::ios_base::ate) {
201-
seekg(0, std::ios_base::end);
202-
}
203-
}
204-
205-
void ifstream::close()
206-
{
207-
if (m_file != nullptr) {
208-
m_filebuf.close();
209-
fclose(m_file);
210-
}
211-
m_file = nullptr;
212-
}
213-
214-
void ofstream::open(const fs::path& p, std::ios_base::openmode mode)
215-
{
216-
close();
217-
mode |= std::ios_base::out;
218-
m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
219-
if (m_file == nullptr) {
220-
return;
221-
}
222-
m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
223-
rdbuf(&m_filebuf);
224-
if (mode & std::ios_base::ate) {
225-
seekp(0, std::ios_base::end);
226-
}
227-
}
228-
229-
void ofstream::close()
230-
{
231-
if (m_file != nullptr) {
232-
m_filebuf.close();
233-
fclose(m_file);
234-
}
235-
m_file = nullptr;
236-
}
237-
#else // __GLIBCXX__
238-
239-
static_assert(sizeof(*fs::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t),
240-
"Warning: This build is using boost::filesystem ofstream and ifstream "
241-
"implementations which will fail to open paths containing multibyte "
242-
"characters. You should delete this static_assert to ignore this warning, "
243-
"or switch to a different C++ standard library like the Microsoft C++ "
244-
"Standard Library (where boost uses non-standard extensions to construct "
245-
"stream objects with wide filenames), or the GNU libstdc++ library (where "
246-
"a more complicated workaround has been implemented above).");
247-
248-
#endif // __GLIBCXX__
249-
#endif // WIN32
250-
251147
} // fsbridge

src/fs.h

Lines changed: 5 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
#include <ext/stdio_filebuf.h>
1212
#endif
1313

14-
#include <boost/filesystem.hpp>
15-
#include <boost/filesystem/fstream.hpp>
14+
#include <filesystem>
15+
#include <fstream>
1616

1717
/** Filesystem operations and types */
18-
namespace fs = boost::filesystem;
18+
namespace fs = std::filesystem;
1919

2020
/** Bridge operations to C stdio */
2121
namespace fsbridge {
@@ -43,53 +43,8 @@ namespace fsbridge {
4343

4444
std::string get_filesystem_error_message(const fs::filesystem_error& e);
4545

46-
// GNU libstdc++ specific workaround for opening UTF-8 paths on Windows.
47-
//
48-
// On Windows, it is only possible to reliably access multibyte file paths through
49-
// `wchar_t` APIs, not `char` APIs. But because the C++ standard doesn't
50-
// require ifstream/ofstream `wchar_t` constructors, and the GNU library doesn't
51-
// provide them (in contrast to the Microsoft C++ library, see
52-
// https://stackoverflow.com/questions/821873/how-to-open-an-stdfstream-ofstream-or-ifstream-with-a-unicode-filename/822032#822032),
53-
// Boost is forced to fall back to `char` constructors which may not work properly.
54-
//
55-
// Work around this issue by creating stream objects with `_wfopen` in
56-
// combination with `__gnu_cxx::stdio_filebuf`. This workaround can be removed
57-
// with an upgrade to C++17, where streams can be constructed directly from
58-
// `std::filesystem::path` objects.
59-
60-
#if defined WIN32 && defined __GLIBCXX__
61-
class ifstream : public std::istream
62-
{
63-
public:
64-
ifstream() = default;
65-
explicit ifstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in) { open(p, mode); }
66-
~ifstream() { close(); }
67-
void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in);
68-
bool is_open() { return m_filebuf.is_open(); }
69-
void close();
70-
71-
private:
72-
__gnu_cxx::stdio_filebuf<char> m_filebuf;
73-
FILE* m_file = nullptr;
74-
};
75-
class ofstream : public std::ostream
76-
{
77-
public:
78-
ofstream() = default;
79-
explicit ofstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out) { open(p, mode); }
80-
~ofstream() { close(); }
81-
void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out);
82-
bool is_open() { return m_filebuf.is_open(); }
83-
void close();
84-
85-
private:
86-
__gnu_cxx::stdio_filebuf<char> m_filebuf;
87-
FILE* m_file = nullptr;
88-
};
89-
#else // !(WIN32 && __GLIBCXX__)
90-
typedef fs::ifstream ifstream;
91-
typedef fs::ofstream ofstream;
92-
#endif // WIN32 && __GLIBCXX__
46+
typedef std::ifstream ifstream;
47+
typedef std::ofstream ofstream;
9348
};
9449

9550
#endif // BITCOIN_FS_H

src/logging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <atomic>
1515
#include <cstdint>
16+
#include <functional>
1617
#include <list>
1718
#include <mutex>
1819
#include <string>

src/rpc/blockchain.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2393,10 +2393,10 @@ static RPCHelpMan dumptxoutset()
23932393
},
23942394
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
23952395
{
2396-
fs::path path = fs::absolute(request.params[0].get_str(), GetDataDir());
2396+
fs::path path = fs::absolute(GetDataDir() / request.params[0].get_str());
23972397
// Write to a temporary path and then move into `path` on completion
23982398
// to avoid confusion due to an interruption.
2399-
fs::path temppath = fs::absolute(request.params[0].get_str() + ".incomplete", GetDataDir());
2399+
fs::path temppath = fs::absolute(GetDataDir() / request.params[0].get_str() / ".incomplete");
24002400

24012401
if (fs::exists(path)) {
24022402
throw JSONRPCError(

src/test/script_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1727,7 +1727,7 @@ BOOST_AUTO_TEST_CASE(script_assets_test)
17271727
bool exists = fs::exists(path);
17281728
BOOST_WARN_MESSAGE(exists, "File $DIR_UNIT_TEST_DATA/script_assets_test.json not found, skipping script_assets_test");
17291729
if (!exists) return;
1730-
fs::ifstream file(path);
1730+
std::ifstream file(path);
17311731
BOOST_CHECK(file.is_open());
17321732
file.seekg(0, std::ios::end);
17331733
size_t length = file.tellg();

0 commit comments

Comments
 (0)