forked from OSchip/llvm-project
[libc++] Allow building libc++ on platforms without a random device
Some platforms, like several embedded platforms, do not provide a source of randomness through a random device. This commit makes it possible to build and test libc++ for such platforms, i.e. without std::random_device. Surprisingly, the only functionality that doesn't work on such platforms is std::random_device itself -- everything else in <random> still works, one just has to find alternative ways to seed the PRNGs.
This commit is contained in:
parent
e9df9028a7
commit
e0d01294bc
libcxx
CMakeLists.txt
cmake/caches
include
src
test
libcxx/numerics/rand/rand.device
std
input.output/filesystems/fs.op.funcs/fs.op.copy_file
numerics/rand/rand.device
support
utils
|
@ -109,6 +109,12 @@ option(LIBCXX_ENABLE_DEBUG_MODE_SUPPORT
|
|||
By default, this is turned on. If you turn it off and try to enable the
|
||||
debug mode when compiling a program against libc++, it will fail to link
|
||||
since the required support isn't provided in the library." ON)
|
||||
option(LIBCXX_ENABLE_RANDOM_DEVICE
|
||||
"Whether to include support for std::random_device in the library. Disabling
|
||||
this can be useful when building the library for platforms that don't have
|
||||
a source of randomness, such as some embedded platforms. When this is not
|
||||
supported, most of <random> will still be available, but std::random_device
|
||||
will not." ON)
|
||||
option(LIBCXX_TEST_GDB_PRETTY_PRINTERS "Test gdb pretty printers." OFF)
|
||||
set(LIBCXX_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/configs/legacy.cfg.in" CACHE STRING
|
||||
"The Lit testing configuration to use when running the tests.")
|
||||
|
@ -836,6 +842,7 @@ config_define_if(LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY _LIBCPP_HAS_THREAD_LIBRARY
|
|||
config_define_if(LIBCXX_HAS_MUSL_LIBC _LIBCPP_HAS_MUSL_LIBC)
|
||||
config_define_if(LIBCXX_NO_VCRUNTIME _LIBCPP_NO_VCRUNTIME)
|
||||
config_define_if(LIBCXX_ENABLE_PARALLEL_ALGORITHMS _LIBCPP_HAS_PARALLEL_ALGORITHMS)
|
||||
config_define_if_not(LIBCXX_ENABLE_RANDOM_DEVICE _LIBCPP_HAS_NO_RANDOM_DEVICE)
|
||||
|
||||
if (LIBCXX_ABI_DEFINES)
|
||||
set(abi_defines)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
set(LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "")
|
|
@ -32,6 +32,7 @@
|
|||
#endif
|
||||
#cmakedefine _LIBCPP_ABI_NAMESPACE @_LIBCPP_ABI_NAMESPACE@
|
||||
#cmakedefine _LIBCPP_HAS_PARALLEL_ALGORITHMS
|
||||
#cmakedefine _LIBCPP_HAS_NO_RANDOM_DEVICE
|
||||
|
||||
@_LIBCPP_ABI_DEFINES@
|
||||
|
||||
|
|
|
@ -3477,6 +3477,8 @@ typedef shuffle_order_engine<minstd_rand0, 256> knuth_b;
|
|||
|
||||
// random_device
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_RANDOM_DEVICE)
|
||||
|
||||
class _LIBCPP_TYPE_VIS random_device
|
||||
{
|
||||
#ifdef _LIBCPP_USING_DEV_RANDOM
|
||||
|
@ -3511,6 +3513,8 @@ private:
|
|||
random_device& operator=(const random_device&); // = delete;
|
||||
};
|
||||
|
||||
#endif // !_LIBCPP_HAS_NO_RANDOM_DEVICE
|
||||
|
||||
// seed_seq
|
||||
|
||||
class _LIBCPP_TEMPLATE_VIS seed_seq
|
||||
|
|
|
@ -27,7 +27,6 @@ set(LIBCXX_SOURCES
|
|||
mutex_destructor.cpp
|
||||
new.cpp
|
||||
optional.cpp
|
||||
random.cpp
|
||||
random_shuffle.cpp
|
||||
regex.cpp
|
||||
shared_mutex.cpp
|
||||
|
@ -61,6 +60,12 @@ if (LIBCXX_ENABLE_DEBUG_MODE_SUPPORT)
|
|||
)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_ENABLE_RANDOM_DEVICE)
|
||||
list(APPEND LIBCXX_SOURCES
|
||||
random.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND LIBCXX_SOURCES
|
||||
support/win32/locale_win32.cpp
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Make sure that std::random_device is not available in namespace std:: when
|
||||
// libc++ is built without support for random device.
|
||||
|
||||
// REQUIRES: libcpp-has-no-random-device
|
||||
|
||||
#include <random>
|
||||
|
||||
int main(int, char**) {
|
||||
std::random_device d; // expected-error {{no type named 'random_device' in namespace 'std'}}
|
||||
return 0;
|
||||
}
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include "filesystem_include.h"
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
|
@ -31,14 +30,6 @@ using namespace fs;
|
|||
|
||||
TEST_SUITE(filesystem_copy_file_test_suite)
|
||||
|
||||
static std::string random_hex_chars(uintmax_t size) {
|
||||
std::string data;
|
||||
data.reserve(size);
|
||||
for (uintmax_t I = 0; I < size; ++I)
|
||||
data.push_back(random_utils::random_hex_char());
|
||||
return data;
|
||||
}
|
||||
|
||||
// This test is intended to test 'sendfile's 2gb limit for a single call, and
|
||||
// to ensure that libc++ correctly copies files larger than that limit.
|
||||
// However it requires allocating ~5GB of filesystem space. This might not
|
||||
|
@ -58,12 +49,10 @@ TEST_CASE(large_file) {
|
|||
TEST_UNSUPPORTED();
|
||||
}
|
||||
|
||||
// Use python to create a file right at the size limit.
|
||||
// Create a file right at the size limit. The file is full of '\0's.
|
||||
const path file = env.create_file("source", sendfile_size_limit);
|
||||
// Create some random data that looks different than the data before the
|
||||
// size limit.
|
||||
const std::string additional_data = random_hex_chars(additional_size);
|
||||
// Append this known data to the end of the source file.
|
||||
const std::string additional_data(additional_size, 'x');
|
||||
// Append known data to the end of the source file.
|
||||
{
|
||||
std::ofstream outf(file.native(), std::ios_base::app);
|
||||
TEST_REQUIRE(outf.good());
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
// XFAIL: with_system_cxx_lib=macosx10.10
|
||||
// XFAIL: with_system_cxx_lib=macosx10.9
|
||||
|
||||
// UNSUPPORTED: libcpp-has-no-random-device
|
||||
|
||||
// <random>
|
||||
|
||||
// class random_device;
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: libcpp-has-no-random-device
|
||||
|
||||
// <random>
|
||||
|
||||
// class random_device;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
// XFAIL: with_system_cxx_lib=macosx10.10
|
||||
// XFAIL: with_system_cxx_lib=macosx10.9
|
||||
|
||||
// UNSUPPORTED: libcpp-has-no-random-device
|
||||
|
||||
// <random>
|
||||
|
||||
// class random_device;
|
||||
|
|
|
@ -3,13 +3,12 @@
|
|||
|
||||
#include "filesystem_include.h"
|
||||
|
||||
#include <sys/stat.h> // for mkdir, mkfifo
|
||||
#include <sys/stat.h> // for stat, mkdir, mkfifo
|
||||
#include <unistd.h> // for ftruncate, link, symlink, getcwd, chdir
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio> // for printf
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
|
@ -24,23 +23,25 @@
|
|||
# include <sys/un.h>
|
||||
#endif
|
||||
|
||||
namespace random_utils {
|
||||
inline char to_hex(int ch) {
|
||||
return ch < 10 ? static_cast<char>('0' + ch)
|
||||
: static_cast<char>('a' + (ch - 10));
|
||||
}
|
||||
namespace utils {
|
||||
inline std::string getcwd() {
|
||||
// Assume that path lengths are not greater than this.
|
||||
// This should be fine for testing purposes.
|
||||
char buf[4096];
|
||||
char* ret = ::getcwd(buf, sizeof(buf));
|
||||
assert(ret && "getcwd failed");
|
||||
return std::string(ret);
|
||||
}
|
||||
|
||||
inline char random_hex_char() {
|
||||
static std::mt19937 rd{std::random_device{}()};
|
||||
static std::uniform_int_distribution<int> mrand{0, 15};
|
||||
return to_hex(mrand(rd));
|
||||
}
|
||||
|
||||
} // namespace random_utils
|
||||
inline bool exists(std::string const& path) {
|
||||
struct ::stat tmp;
|
||||
return ::stat(path.c_str(), &tmp) == 0;
|
||||
}
|
||||
} // end namespace utils
|
||||
|
||||
struct scoped_test_env
|
||||
{
|
||||
scoped_test_env() : test_root(random_path()) {
|
||||
scoped_test_env() : test_root(available_cwd_path()) {
|
||||
std::string cmd = "mkdir -p " + test_root.native();
|
||||
int ret = std::system(cmd.c_str());
|
||||
assert(ret == 0);
|
||||
|
@ -174,20 +175,20 @@ struct scoped_test_env
|
|||
fs::path test_root;
|
||||
|
||||
private:
|
||||
static std::string unique_path_suffix() {
|
||||
std::string model = "test.%%%%%%";
|
||||
for (auto & ch : model) {
|
||||
if (ch == '%')
|
||||
ch = random_utils::random_hex_char();
|
||||
// This could potentially introduce a filesystem race if multiple
|
||||
// scoped_test_envs were created concurrently in the same test (hence
|
||||
// sharing the same cwd). However, it is fairly unlikely to happen as
|
||||
// we generally don't use scoped_test_env from multiple threads, so
|
||||
// this is deemed acceptable.
|
||||
static inline fs::path available_cwd_path() {
|
||||
fs::path const cwd = utils::getcwd();
|
||||
fs::path const tmp = fs::temp_directory_path();
|
||||
fs::path const base = tmp / cwd.filename();
|
||||
int i = 0;
|
||||
fs::path p = base / ("static_env." + std::to_string(i));
|
||||
while (utils::exists(p)) {
|
||||
p = fs::path(base) / ("static_env." + std::to_string(++i));
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
// This could potentially introduce a filesystem race with other tests
|
||||
// running at the same time, but oh well, it's just test code.
|
||||
static inline fs::path random_path() {
|
||||
fs::path tmp = fs::temp_directory_path();
|
||||
fs::path p = fs::path(tmp) / unique_path_suffix();
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
@ -301,15 +302,10 @@ public:
|
|||
};
|
||||
|
||||
struct CWDGuard {
|
||||
// Assume that path lengths are not greater than this.
|
||||
// This should be fine for testing purposes.
|
||||
char OldCWD[4096];
|
||||
CWDGuard() {
|
||||
char* ret = ::getcwd(OldCWD, sizeof(OldCWD));
|
||||
assert(ret && "getcwd failed");
|
||||
}
|
||||
std::string oldCwd_;
|
||||
CWDGuard() : oldCwd_(utils::getcwd()) { }
|
||||
~CWDGuard() {
|
||||
int ret = ::chdir(OldCWD);
|
||||
int ret = ::chdir(oldCwd_.c_str());
|
||||
assert(ret == 0 && "chdir failed");
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,11 @@ steps:
|
|||
agents:
|
||||
queue: "libcxx-builders"
|
||||
|
||||
- label: "No random device"
|
||||
command: "set -o pipefail && libcxx/utils/ci/run-buildbot.sh generic-no-random_device | libcxx/utils/ci/phabricator-report"
|
||||
agents:
|
||||
queue: "libcxx-builders"
|
||||
|
||||
- label: "MacOS C++20"
|
||||
command: "set -o pipefail && libcxx/utils/ci/run-buildbot.sh generic-cxx2a | libcxx/utils/ci/phabricator-report"
|
||||
agents:
|
||||
|
|
|
@ -109,6 +109,12 @@ generic-nodebug)
|
|||
args+=("-DLLVM_LIT_ARGS=-sv --show-unsupported")
|
||||
args+=("-C${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-nodebug.cmake")
|
||||
;;
|
||||
generic-no-random_device)
|
||||
export CC=clang
|
||||
export CXX=clang++
|
||||
args+=("-DLLVM_LIT_ARGS=-sv --show-unsupported")
|
||||
args+=("-C${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-no-random_device.cmake")
|
||||
;;
|
||||
x86_64-apple-system)
|
||||
export CC=clang
|
||||
export CXX=clang++
|
||||
|
|
|
@ -73,7 +73,8 @@ macros = {
|
|||
'_LIBCPP_HAS_THREAD_API_PTHREAD': 'libcpp-has-thread-api-pthread',
|
||||
'_LIBCPP_NO_VCRUNTIME': 'libcpp-no-vcruntime',
|
||||
'_LIBCPP_ABI_VERSION': 'libcpp-abi-version',
|
||||
'_LIBCPP_ABI_UNSTABLE': 'libcpp-abi-unstable'
|
||||
'_LIBCPP_ABI_UNSTABLE': 'libcpp-abi-unstable',
|
||||
'_LIBCPP_HAS_NO_RANDOM_DEVICE': 'libcpp-has-no-random-device',
|
||||
}
|
||||
for macro, feature in macros.items():
|
||||
DEFAULT_FEATURES += [
|
||||
|
|
Loading…
Reference in New Issue