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; }
......
......@@ -31,7 +31,7 @@
#endif
#ifndef KJ_NO_COMPILER_CHECK
#if __cplusplus < 201103L && !__CDT_PARSER__
#if __cplusplus < 201103L && !__CDT_PARSER__ && !_MSC_VER
#error "This code requires C++11. Either your compiler does not support it or it is not enabled."
#ifdef __GNUC__
// Compiler claims compatibility with GCC, so presumably supports -std.
......@@ -61,7 +61,12 @@
#endif
#endif
#elif defined(_MSC_VER)
#warning "As of June 2013, Visual Studio's C++11 support was hopelessly behind what is needed to compile this code."
#if _MSC_VER < 1900
#error "You need Visual Studio 2015 or better to compile this code."
#elif !CAPNP_LITE
// TODO(cleanup): This is KJ, but we're talking about Cap'n Proto.
#error "As of this writing, Cap'n Proto only supports Visual C++ in 'lite mode'; please #define CAPNP_LITE"
#endif
#else
#warning "I don't recognize your compiler. As of this writing, Clang and GCC are the only "\
"known compilers with enough C++11 support for this library. "\
......@@ -104,7 +109,7 @@ typedef unsigned char byte;
#if !defined(KJ_DEBUG) && !defined(KJ_NDEBUG)
// Heuristically decide whether to enable debug mode. If DEBUG or NDEBUG is defined, use that.
// Otherwise, fall back to checking whether optimization is enabled.
#if defined(DEBUG)
#if defined(DEBUG) || defined(_DEBUG)
#define KJ_DEBUG
#elif defined(NDEBUG)
#define KJ_NDEBUG
......@@ -120,11 +125,16 @@ typedef unsigned char byte;
classname& operator=(const classname&) = delete
// Deletes the implicit copy constructor and assignment operator.
#ifdef __GNUC__
#define KJ_LIKELY(condition) __builtin_expect(condition, true)
#define KJ_UNLIKELY(condition) __builtin_expect(condition, false)
// Branch prediction macros. Evaluates to the condition given, but also tells the compiler that we
// expect the condition to be true/false enough of the time that it's worth hard-coding branch
// prediction.
#else
#define KJ_LIKELY(condition) (condition)
#define KJ_UNLIKELY(condition) (condition)
#endif
#if defined(KJ_DEBUG) || __NO_INLINE__
#define KJ_ALWAYS_INLINE(prototype) inline prototype
......@@ -140,13 +150,16 @@ typedef unsigned char byte;
#if defined(_MSC_VER)
#define KJ_NORETURN(prototype) __declspec(noreturn) prototype
#define KJ_UNUSED
#define KJ_WARN_UNUSED_RESULT
// TODO(msvc): KJ_WARN_UNUSED_RESULT can use _Check_return_ on MSVC, but it's a prefix, so
// wrapping the whole prototype is needed. http://msdn.microsoft.com/en-us/library/jj159529.aspx
// Similarly, KJ_UNUSED could use __pragma(warning(suppress:...)), but again that's a prefix.
#else
#define KJ_NORETURN(prototype) prototype __attribute__((noreturn))
#endif
#define KJ_UNUSED __attribute__((unused))
#define KJ_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#endif
#if __clang__
#define KJ_UNUSED_MEMBER __attribute__((unused))
......@@ -159,9 +172,12 @@ typedef unsigned char byte;
#if __clang__
#define KJ_DEPRECATED(reason) \
__attribute__((deprecated(reason)))
#else
#elif __GNUC__
#define KJ_DEPRECATED(reason) \
__attribute__((deprecated))
#else
#define KJ_DEPRECATED(reason)
// TODO(msvc): Again, here, MSVC prefers a prefix, __declspec(deprecated).
#endif
namespace _ { // private
......@@ -178,6 +194,22 @@ KJ_NORETURN(void unreachable());
} // namespace _ (private)
#ifdef KJ_DEBUG
#if _MSC_VER
// TODO(msvc): Figure out __VA_ARGS__; see debug.h.
#define KJ_IREQUIRE(condition, ...) \
if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \
__FILE__, __LINE__, #condition, "")
// Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to
// check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that
// it will be enabled depending on whether the application is compiled in debug mode rather than
// whether libkj is.
#define KJ_IASSERT(condition, ...) \
if (KJ_LIKELY(condition)); else ::kj::_::inlineAssertFailure( \
__FILE__, __LINE__, #condition, "")
// Version of KJ_DASSERT() which is safe to use in headers that are #included by users. Used to
// check state inside inline and templated methods.
#else
#define KJ_IREQUIRE(condition, ...) \
if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \
__FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__)
......@@ -191,6 +223,7 @@ KJ_NORETURN(void unreachable());
__FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__)
// Version of KJ_DASSERT() which is safe to use in headers that are #included by users. Used to
// check state inside inline and templated methods.
#endif
#else
#define KJ_IREQUIRE(condition, ...)
#define KJ_IASSERT(condition, ...)
......@@ -212,11 +245,11 @@ KJ_NORETURN(void unreachable());
// variable-sized arrays. For other compilers we could just use a fixed-size array. `minStack`
// is the stack array size to use if variable-width arrays are not supported. `maxStack` is the
// maximum stack array size if variable-width arrays *are* supported.
#if __clang__
#if __GNUC__ && !__clang__
#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \
size_t name##_size = (size); \
bool name##_isOnStack = name##_size <= (minStack); \
type name##_stack[minStack]; \
bool name##_isOnStack = name##_size <= (maxStack); \
type name##_stack[name##_isOnStack ? size : 0]; \
::kj::Array<type> name##_heap = name##_isOnStack ? \
nullptr : kj::heapArray<type>(name##_size); \
::kj::ArrayPtr<type> name = name##_isOnStack ? \
......@@ -224,8 +257,8 @@ KJ_NORETURN(void unreachable());
#else
#define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \
size_t name##_size = (size); \
bool name##_isOnStack = name##_size <= (maxStack); \
type name##_stack[name##_isOnStack ? size : 0]; \
bool name##_isOnStack = name##_size <= (minStack); \
type name##_stack[minStack]; \
::kj::Array<type> name##_heap = name##_isOnStack ? \
nullptr : kj::heapArray<type>(name##_size); \
::kj::ArrayPtr<type> name = name##_isOnStack ? \
......@@ -238,6 +271,32 @@ KJ_NORETURN(void unreachable());
// Create a unique identifier name. We use concatenate __LINE__ rather than __COUNTER__ so that
// the name can be used multiple times in the same macro.
#if _MSC_VER
#define KJ_CONSTEXPR(...) __VA_ARGS__
// Use in cases where MSVC barfs on constexpr. A replacement keyword (e.g. "const") can be
// provided, or just leave blank to remove the keyword entirely.
//
// TODO(msvc): Remove this hack once MSVC fully supports constexpr.
#ifndef __restrict__
#define __restrict__ __restrict
// TODO(msvc): Would it be better to define a KJ_RESTRICT macro?
#endif
#pragma warning(disable: 4521 4522)
// This warning complains when there are two copy constructors, one for a const reference and
// one for a non-const reference. It is often quite necessary to do this in wrapper templates,
// therefore this warning is dumb and we disable it.
#pragma warning(disable: 4458)
// Warns when a parameter name shadows a class member. Unfortunately my code does this a lot,
// since I don't use a special name format for members.
#else // _MSC_VER
#define KJ_CONSTEXPR(...) constexpr
#endif
// =======================================================================================
// Template metaprogramming helpers.
......@@ -403,9 +462,14 @@ template<typename T> constexpr T cp(const T& t) noexcept { return t; }
// Useful to force a copy, particularly to pass into a function that expects T&&.
template <typename T, typename U>
inline constexpr auto min(T&& a, U&& b) -> decltype(a < b ? a : b) { return a < b ? a : b; }
inline KJ_CONSTEXPR() auto min(T&& a, U&& b) -> Decay<decltype(a < b ? a : b)> {
return a < b ? a : b;
}
template <typename T, typename U>
inline constexpr auto max(T&& a, U&& b) -> decltype(a > b ? a : b) { return a > b ? a : b; }
inline KJ_CONSTEXPR() auto max(T&& a, U&& b) -> Decay<decltype(a > b ? a : b)> {
return a > b ? a : b;
}
template <typename T, size_t s>
inline constexpr size_t size(T (&arr)[s]) { return s; }
......@@ -474,22 +538,33 @@ public:
}
};
static constexpr MaxValue_ maxValue = MaxValue_();
static KJ_CONSTEXPR(const) MaxValue_ maxValue = MaxValue_();
// A special constant which, when cast to an integer type, takes on the maximum possible value of
// that type. This is useful to use as e.g. a parameter to a function because it will be robust
// in the face of changes to the parameter's type.
//
// `char` is not supported, but `signed char` and `unsigned char` are.
static constexpr MinValue_ minValue = MinValue_();
static KJ_CONSTEXPR(const) MinValue_ minValue = MinValue_();
// A special constant which, when cast to an integer type, takes on the minimum possible value
// of that type. This is useful to use as e.g. a parameter to a function because it will be robust
// in the face of changes to the parameter's type.
//
// `char` is not supported, but `signed char` and `unsigned char` are.
#if __GNUC__
inline constexpr float inf() { return __builtin_huge_valf(); }
inline constexpr float nan() { return __builtin_nanf(""); }
#elif _MSC_VER
// Do what MSVC math.h does
#pragma warning(push)
#pragma warning(disable: 4756) // "overflow in constant arithmetic"
inline constexpr float inf() { return (float)(1e300 * 1e300); }
#pragma warning(pop)
inline constexpr float nan() { return inf() * 0.0F; }
#else
#error "Not sure how to support your compiler."
#endif
// =======================================================================================
// Useful fake containers
......@@ -624,6 +699,8 @@ inline void* operator new(size_t, kj::_::PlacementNew, void* __p) noexcept {
return __p;
}
inline void operator delete(void*, kj::_::PlacementNew, void* __p) noexcept {}
namespace kj {
template <typename T, typename... Params>
......@@ -793,10 +870,22 @@ private: // internal interface used by friends only
private:
bool isSet;
#if _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4624)
// Warns that the anonymous union has a deleted destructor when T is non-trivial. This warning
// seems broken.
#endif
union {
T value;
};
#if _MSC_VER
#pragma warning(pop)
#endif
friend class kj::Maybe<T>;
template <typename U>
friend NullableValue<U>&& readMaybe(Maybe<U>&& maybe);
......@@ -981,7 +1070,7 @@ public:
inline constexpr ArrayPtr(decltype(nullptr)): ptr(nullptr), size_(0) {}
inline constexpr ArrayPtr(T* ptr, size_t size): ptr(ptr), size_(size) {}
inline constexpr ArrayPtr(T* begin, T* end): ptr(begin), size_(end - begin) {}
inline constexpr ArrayPtr(std::initializer_list<RemoveConstOrDisable<T>> init)
inline KJ_CONSTEXPR() ArrayPtr(std::initializer_list<RemoveConstOrDisable<T>> init)
: ptr(init.begin()), size_(init.size()) {}
template <size_t size>
......
......@@ -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