Commit 9662a6a5 authored by Kenton Varda's avatar Kenton Varda Committed by Kenton Varda

MSVC: Build and test parts of KJ needed in lite mode.

Thanks to Bryan Boreham <bjboreham@gmail.com> for much help getting this started.
parent 0d6b9704
......@@ -5,8 +5,9 @@ under the same MIT license terms as the rest of the library.
Kenton Varda <temporal@gmail.com>: Primary Author
Jason Choy <jjwchoy@gmail.com>: kj/threadlocal.h and other iOS tweaks, `name` annotation in C++ code generator
Remy Blank <rblank@google.com> (contributions copyright Google Inc.): KJ Timers
Joshua Warner <joshuawarner32@gmail.com>: cmake build
Joshua Warner <joshuawarner32@gmail.com>: cmake build, AnyStruct/AnyList, other stuff
Scott Purdy <scott@fer.io>: kj/std iostream interface
Bryan Borham <bjboreham@gmail.com>: Initial MSVC support
This file does not list people who maintain their own Cap'n Proto
implementations as separate projects. Those people are awesome too! :)
......@@ -136,6 +136,7 @@ includekj_HEADERS = \
src/kj/exception.h \
src/kj/debug.h \
src/kj/arena.h \
src/kj/miniposix.h \
src/kj/io.h \
src/kj/tuple.h \
src/kj/one-of.h \
......

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22310.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "capnproto", "capnproto.vcxproj", "{CD7EEDAE-3D48-4402-9F60-EC23311BE143}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "..\gtest\msvc\gtest.vcxproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "..\gtest\msvc\gtest_main.vcxproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CD7EEDAE-3D48-4402-9F60-EC23311BE143}.Debug|Win32.ActiveCfg = Debug|Win32
{CD7EEDAE-3D48-4402-9F60-EC23311BE143}.Debug|Win32.Build.0 = Debug|Win32
{CD7EEDAE-3D48-4402-9F60-EC23311BE143}.Release|Win32.ActiveCfg = Release|Win32
{CD7EEDAE-3D48-4402-9F60-EC23311BE143}.Release|Win32.Build.0 = Release|Win32
{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.ActiveCfg = Debug|Win32
{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug|Win32.Build.0 = Debug|Win32
{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.ActiveCfg = Release|Win32
{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release|Win32.Build.0 = Release|Win32
{3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.ActiveCfg = Debug|Win32
{3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug|Win32.Build.0 = Debug|Win32
{3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.ActiveCfg = Release|Win32
{3AF54C8A-10BF-4332-9147-F68ED9862032}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{CD7EEDAE-3D48-4402-9F60-EC23311BE143}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;CAPNP_LITE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\src;..\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<AdditionalOptions>/TP %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;CAPNP_LITE;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\src;..\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalOptions>/TP %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\src\kj\array.h" />
<ClInclude Include="..\src\kj\common.h" />
<ClInclude Include="..\src\kj\debug.h" />
<ClInclude Include="..\src\kj\exception.h" />
<ClInclude Include="..\src\kj\io.h" />
<ClInclude Include="..\src\kj\memory.h" />
<ClInclude Include="..\src\kj\string.h" />
<ClInclude Include="..\src\kj\miniposix.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\kj\array-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\array.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\common-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\common.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\debug-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\debug.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\exception-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\exception.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\io-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\io.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\memory-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\memory.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\string-test.c++">
<FileType>Document</FileType>
</ClCompile>
<ClCompile Include="..\src\kj\string.c++">
<FileType>Document</FileType>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\gtest\msvc\gtest.vcxproj">
<Project>{c8f6c172-56f2-4e76-b5fa-c3b423b31be7}</Project>
</ProjectReference>
<ProjectReference Include="..\gtest\msvc\gtest_main.vcxproj">
<Project>{3af54c8a-10bf-4332-9147-f68ed9862032}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
MSVC project files
As of this writing, this MSVC project is very basic: all it does is compile a
unit test covering all lite-mode functionality. In the long run, we intend for
MSVC libraries to be compiled using the cmake files. This project is a stopgap
because Kenton doesn't understand cmake and wanted to get some work done.
The solution file refers to gtest, which must be downloaded to "c++/gtest".
The "setup-autotools.sh" script accomplishes this, although it requires bash
to run.
......@@ -30,6 +30,7 @@ set(kj_headers
exception.h
debug.h
arena.h
miniposix.h
io.h
tuple.h
one-of.h
......
......@@ -446,7 +446,7 @@ class CappedArray {
// TODO(someday): Don't construct elements past currentSize?
public:
inline constexpr CappedArray(): currentSize(fixedSize) {}
inline KJ_CONSTEXPR() CappedArray(): currentSize(fixedSize) {}
inline explicit constexpr CappedArray(size_t s): currentSize(s) {}
inline size_t size() const { return currentSize; }
......
This diff is collapsed.
......@@ -24,17 +24,22 @@
#include <gtest/gtest.h>
#include <string>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <exception>
#include "miniposix.h"
#if !_WIN32
#include <sys/types.h>
#include <sys/wait.h>
#endif
#if _MSC_VER
#pragma warning(disable: 4996)
// Warns that sprintf() is buffer-overrunny. Yeah, I know, it's cool.
#endif
namespace kj {
namespace _ { // private
namespace {
......@@ -115,7 +120,7 @@ public:
const char* end = pos + text.size();
while (pos < end) {
ssize_t n = write(outputPipe, pos, end - pos);
miniposix::ssize_t n = miniposix::write(outputPipe, pos, end - pos);
if (n < 0) {
if (errno == EINTR) {
continue;
......@@ -319,6 +324,16 @@ TEST(Debug, Catch) {
#endif
}
int mockSyscall(int i, int error = 0) {
errno = error;
return i;
}
int fail() {
errno = EBADF;
return -1;
}
TEST(Debug, Syscall) {
MockExceptionCallback mockCallback;
int line;
......@@ -326,19 +341,21 @@ TEST(Debug, Syscall) {
int i = 123;
const char* str = "foo";
int fd;
KJ_SYSCALL(fd = dup(STDIN_FILENO));
KJ_SYSCALL(close(fd));
EXPECT_FATAL(KJ_SYSCALL(close(fd), i, "bar", str)); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": error from OS: close(fd): "
+ strerror(EBADF) + "; i = 123; bar; str = foo\n", mockCallback.text);
KJ_SYSCALL(mockSyscall(0));
KJ_SYSCALL(mockSyscall(1));
EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, EBADF), i, "bar", str)); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) +
": error from OS: mockSyscall(-1, EBADF): " + strerror(EBADF) +
"; i = 123; bar; str = foo\n", mockCallback.text);
mockCallback.text.clear();
int result = 0;
bool recovered = false;
KJ_SYSCALL(result = close(fd), i, "bar", str) { recovered = true; break; } line = __LINE__;
EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) + ": error from OS: close(fd): "
+ strerror(EBADF) + "; i = 123; bar; str = foo\n", mockCallback.text);
KJ_SYSCALL(result = mockSyscall(-2, EBADF), i, "bar", str) { recovered = true; break; } line = __LINE__;
EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) +
": error from OS: mockSyscall(-2, EBADF): " + strerror(EBADF) +
"; i = 123; bar; str = foo\n", mockCallback.text);
EXPECT_LT(result, 0);
EXPECT_TRUE(recovered);
}
......
......@@ -121,6 +121,81 @@
namespace kj {
#if _MSC_VER
// MSVC does __VA_ARGS__ differently from GCC:
// - A trailing comma before an empty __VA_ARGS__ is removed automatically, whereas GCC wants
// you to request this behavior with "##__VA_ARGS__".
// - If __VA_ARGS__ is passed directly as an argument to another macro, it will be treated as a
// *single* argument rather than an argument list. This can be worked around by wrapping the
// outer macro call in KJ_EXPAND(), which appraently forces __VA_ARGS__ to be expanded before
// the macro is evaluated. I don't understand the C preprocessor.
// - Using "#__VA_ARGS__" to stringify __VA_ARGS__ expands to zero tokens when __VA_ARGS__ is
// empty, rather than expanding to an empty string literal. We can work around by concatenating
// with an empty string literal.
#define KJ_EXPAND(X) X
#define KJ_LOG(severity, ...) \
if (!::kj::_::Debug::shouldLog(::kj::_::Debug::Severity::severity)) {} else \
::kj::_::Debug::log(__FILE__, __LINE__, ::kj::_::Debug::Severity::severity, \
"" #__VA_ARGS__, __VA_ARGS__)
#define KJ_DBG(...) KJ_EXPAND(KJ_LOG(DBG, __VA_ARGS__))
#define _kJ_FAULT(nature, cond, ...) \
if (KJ_LIKELY(cond)) {} else \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Nature::nature, 0, \
#cond, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define _kJ_FAIL_FAULT(nature, ...) \
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Nature::nature, 0, \
nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_ASSERT(...) KJ_EXPAND(_kJ_FAULT(LOCAL_BUG, __VA_ARGS__))
#define KJ_REQUIRE(...) KJ_EXPAND(_kJ_FAULT(PRECONDITION, __VA_ARGS__))
#define KJ_FAIL_ASSERT(...) KJ_EXPAND(_kJ_FAIL_FAULT(LOCAL_BUG, __VA_ARGS__))
#define KJ_FAIL_REQUIRE(...) KJ_EXPAND(_kJ_FAIL_FAULT(PRECONDITION, __VA_ARGS__))
#define KJ_SYSCALL(call, ...) \
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
for (::kj::_::Debug::Fault f( \
__FILE__, __LINE__, ::kj::Exception::Nature::OS_ERROR, \
_kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_NONBLOCKING_SYSCALL(call, ...) \
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
for (::kj::_::Debug::Fault f( \
__FILE__, __LINE__, ::kj::Exception::Nature::OS_ERROR, \
_kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
for (::kj::_::Debug::Fault f( \
__FILE__, __LINE__, ::kj::Exception::Nature::OS_ERROR, \
errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
#define KJ_CONTEXT(...) \
auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
::kj::_::Debug::makeContextDescription("" #__VA_ARGS__, __VA_ARGS__)); \
}; \
::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))> \
KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
#define _kJ_NONNULL(nature, value, ...) \
(*({ \
auto _kj_result = ::kj::_::readMaybe(value); \
if (KJ_UNLIKELY(!_kj_result)) { \
::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Nature::nature, 0, \
#value " != nullptr", "" #__VA_ARGS__, __VA_ARGS__).fatal(); \
} \
_kj_result; \
}))
#define KJ_ASSERT_NONNULL(value, ...) KJ_EXPAND(_kJ_NONNULL(LOCAL_BUG, value, __VA_ARGS__))
#define KJ_REQUIRE_NONNULL(value, ...) KJ_EXPAND(_kJ_NONNULL(PRECONDITION, value, __VA_ARGS__))
#else
#define KJ_LOG(severity, ...) \
if (!::kj::_::Debug::shouldLog(::kj::_::Debug::Severity::severity)) {} else \
::kj::_::Debug::log(__FILE__, __LINE__, ::kj::_::Debug::Severity::severity, \
......@@ -180,6 +255,8 @@ namespace kj {
#define KJ_ASSERT_NONNULL(value, ...) _kJ_NONNULL(LOCAL_BUG, value, ##__VA_ARGS__)
#define KJ_REQUIRE_NONNULL(value, ...) _kJ_NONNULL(PRECONDITION, value, ##__VA_ARGS__)
#endif
#ifdef KJ_DEBUG
#define KJ_DLOG LOG
#define KJ_DASSERT KJ_ASSERT
......@@ -225,6 +302,8 @@ public:
template <typename... Params>
Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs, Params&&... params);
Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs);
~Fault() noexcept(false);
KJ_NORETURN(void fatal());
......@@ -314,6 +393,11 @@ void Debug::log(const char* file, int line, Severity severity, const char* macro
logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params)));
}
template <>
inline void Debug::log<>(const char* file, int line, Severity severity, const char* macroArgs) {
logInternal(file, line, severity, macroArgs, nullptr);
}
template <typename... Params>
Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs, Params&&... params)
......@@ -323,6 +407,12 @@ Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int er
arrayPtr(argValues, sizeof...(Params)));
}
inline Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs)
: exception(nullptr) {
init(file, line, nature, errorNumber, condition, macroArgs, nullptr);
}
template <typename Call>
Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) {
while (call() < 0) {
......@@ -343,6 +433,11 @@ String Debug::makeContextDescription(const char* macroArgs, Params&&... params)
return makeContextDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params)));
}
template <>
inline String Debug::makeContextDescription<>(const char* macroArgs) {
return makeContextDescriptionInternal(macroArgs, nullptr);
}
} // namespace _ (private)
} // namespace kj
......
......@@ -23,7 +23,7 @@
#include "string.h"
#include "debug.h"
#include "threadlocal.h"
#include <unistd.h>
#include "miniposix.h"
#include <stdlib.h>
#include <exception>
......@@ -317,7 +317,7 @@ public:
StringPtr textPtr = text;
while (text != nullptr) {
ssize_t n = write(STDERR_FILENO, textPtr.begin(), textPtr.size());
miniposix::ssize_t n = miniposix::write(STDERR_FILENO, textPtr.begin(), textPtr.size());
if (n <= 0) {
// stderr is broken. Give up.
return;
......@@ -397,6 +397,26 @@ uint uncaughtExceptionCount() {
return __cxa_get_globals()->uncaughtExceptions;
}
#elif _MSC_VER
#if 0
// TODO(msvc): The below was copied from:
// https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
// Alas, it doesn not appera to work on MSVC2015. The linker claims _getptd() doesn't exist.
extern "C" char *__cdecl _getptd();
uint uncaughtExceptionCount() {
return *reinterpret_cast<uint*>(_getptd() + (sizeof(void*) == 8 ? 0x100 : 0x90));
}
#endif
uint uncaughtExceptionCount() {
// Since the above doesn't work, fall back to uncaught_exception(). This will produce incorrect
// results in very obscure cases that Cap'n Proto doesn't really rely on anyway.
return std::uncaught_exception();
}
#else
#error "This needs to be ported to your compiler / C++ ABI."
#endif
......
......@@ -21,14 +21,8 @@
#include "io.h"
#include "debug.h"
#include "miniposix.h"
#include <gtest/gtest.h>
#include <unistd.h>
#if _WIN32
#include <io.h>
#include <fcntl.h>
#define pipe(fds) _pipe(fds, 8192, _O_BINARY)
#endif
namespace kj {
namespace {
......@@ -38,7 +32,7 @@ TEST(Io, WriteVec) {
// used to not work in some cases.)
int fds[2];
KJ_SYSCALL(pipe(fds));
KJ_SYSCALL(miniposix::pipe(fds));
FdInputStream in((AutoCloseFd(fds[0])));
FdOutputStream out((AutoCloseFd(fds[1])));
......
......@@ -21,7 +21,7 @@
#include "io.h"
#include "debug.h"
#include <unistd.h>
#include "miniposix.h"
#include <algorithm>
#include <errno.h>
#include <limits.h>
......@@ -238,7 +238,7 @@ AutoCloseFd::~AutoCloseFd() noexcept(false) {
if (fd >= 0) {
unwindDetector.catchExceptionsIfUnwinding([&]() {
// Don't use SYSCALL() here because close() should not be repeated on EINTR.
if (close(fd) < 0) {
if (miniposix::close(fd) < 0) {
KJ_FAIL_SYSCALL("close", errno, fd) {
break;
}
......@@ -255,8 +255,8 @@ size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) {
byte* max = pos + maxBytes;
while (pos < min) {
ssize_t n;
KJ_SYSCALL(n = ::read(fd, pos, max - pos), fd);
miniposix::ssize_t n;
KJ_SYSCALL(n = miniposix::read(fd, pos, max - pos), fd);
if (n == 0) {
break;
}
......@@ -272,8 +272,8 @@ void FdOutputStream::write(const void* buffer, size_t size) {
const char* pos = reinterpret_cast<const char*>(buffer);
while (size > 0) {
ssize_t n;
KJ_SYSCALL(n = ::write(fd, pos, size), fd);
miniposix::ssize_t n;
KJ_SYSCALL(n = miniposix::write(fd, pos, size), fd);
KJ_ASSERT(n > 0, "write() returned zero.");
pos += n;
size -= n;
......
......@@ -38,7 +38,7 @@ TEST(Memory, OwnConst) {
}
TEST(Memory, CanConvert) {
struct Super { virtual ~Super(); };
struct Super { virtual ~Super() {} };
struct Sub: public Super {};
static_assert(canConvert<Own<Sub>, Own<Super>>(), "failure");
......
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef KJ_PORTABLE_FD_H_
#define KJ_PORTABLE_FD_H_
// This header provides a small subset of the POSIX API which also happens to be available on
// Windows under slightly-different names.
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
#pragma GCC system_header
#endif
#if _WIN32
#include <io.h>
#include <direct.h>
#else
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
namespace kj {
namespace miniposix {
#if _WIN32 && !__GNUC__
// We're on Windows and not MinGW. So, we need to define wrappers for the POSIX API.
typedef int ssize_t;
inline ssize_t read(int fd, void* buffer, size_t size) {
return ::_read(fd, buffer, size);
}
inline ssize_t write(int fd, const void* buffer, size_t size) {
return ::_write(fd, buffer, size);
}
inline int close(int fd) {
return ::_close(fd);
}
inline int pipe(int fds[2]) {
return ::_pipe(fds, 4096, false);
}
inline int mkdir(const char* path, int mode) {
return ::_mkdir(path);
}
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
#else
// We're on a POSIX system or MinGW which already defines the wrappers for us.
using ::ssize_t;
using ::read;
using ::write;
using ::close;
using ::pipe;
using ::mkdir;
#endif
} // namespace miniposix
} // namespace kj
#endif // KJ_WIN32_FD_H_
......@@ -28,6 +28,11 @@
namespace kj {
#if _MSC_VER
#pragma warning(disable: 4996)
// Warns that sprintf() is buffer-overrunny. We know that, it's cool.
#endif
String heapString(size_t size) {
char* buffer = _::HeapArrayDisposer::allocate<char>(size + 1);
buffer[size] = '\0';
......@@ -256,11 +261,11 @@ char* DoubleToBuffer(double value, char* buffer) {
// truncated to a double.
volatile double parsed_value = strtod(buffer, NULL);
if (parsed_value != value) {
int snprintf_result =
int snprintf_result2 =
snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG+2, value);
// Should never overflow; see above.
KJ_DASSERT(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize);
KJ_DASSERT(snprintf_result2 > 0 && snprintf_result2 < kDoubleToBufferSize);
}
DelocalizeRadix(buffer);
......@@ -275,7 +280,7 @@ bool safe_strtof(const char* str, float* value) {
char* endptr;
errno = 0; // errno only gets set on errors
#if defined(_WIN32) || defined (__hpux) // has no strtof()
*value = strtod(str, &endptr);
*value = static_cast<float>(strtod(str, &endptr));
#else
*value = strtof(str, &endptr);
#endif
......@@ -309,11 +314,11 @@ char* FloatToBuffer(float value, char* buffer) {
float parsed_value;
if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) {
int snprintf_result =
int snprintf_result2 =
snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value);
// Should never overflow; see above.
KJ_DASSERT(snprintf_result > 0 && snprintf_result < kFloatToBufferSize);
KJ_DASSERT(snprintf_result2 > 0 && snprintf_result2 < kFloatToBufferSize);
}
DelocalizeRadix(buffer);
......
......@@ -300,7 +300,7 @@ struct Stringifier {
inline Result operator*(T&& value) const { return kj::fwd<T>(value).toString(); }
#endif
};
static constexpr Stringifier STR = Stringifier();
static KJ_CONSTEXPR(const) Stringifier STR = Stringifier();
} // namespace _ (private)
......
......@@ -120,10 +120,14 @@ private:
} // namespace _ (private)
#else
#elif __GNUC__
#define KJ_THREADLOCAL_PTR(type) static __thread type*
// For
// GCC's __thread is lighter-weight than thread_local and is good enough for our purposes.
#else
#define KJ_THREADLOCAL_PTR(type) static thread_local type*
#endif // KJ_USE_PTHREAD_TLS
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment