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. ...@@ -5,8 +5,9 @@ under the same MIT license terms as the rest of the library.
Kenton Varda <temporal@gmail.com>: Primary Author 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 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 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 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 This file does not list people who maintain their own Cap'n Proto
implementations as separate projects. Those people are awesome too! :) implementations as separate projects. Those people are awesome too! :)
...@@ -136,6 +136,7 @@ includekj_HEADERS = \ ...@@ -136,6 +136,7 @@ includekj_HEADERS = \
src/kj/exception.h \ src/kj/exception.h \
src/kj/debug.h \ src/kj/debug.h \
src/kj/arena.h \ src/kj/arena.h \
src/kj/miniposix.h \
src/kj/io.h \ src/kj/io.h \
src/kj/tuple.h \ src/kj/tuple.h \
src/kj/one-of.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 ...@@ -30,6 +30,7 @@ set(kj_headers
exception.h exception.h
debug.h debug.h
arena.h arena.h
miniposix.h
io.h io.h
tuple.h tuple.h
one-of.h one-of.h
......
...@@ -446,7 +446,7 @@ class CappedArray { ...@@ -446,7 +446,7 @@ class CappedArray {
// TODO(someday): Don't construct elements past currentSize? // TODO(someday): Don't construct elements past currentSize?
public: public:
inline constexpr CappedArray(): currentSize(fixedSize) {} inline KJ_CONSTEXPR() CappedArray(): currentSize(fixedSize) {}
inline explicit constexpr CappedArray(size_t s): currentSize(s) {} inline explicit constexpr CappedArray(size_t s): currentSize(s) {}
inline size_t size() const { return currentSize; } inline size_t size() const { return currentSize; }
......
This diff is collapsed.
...@@ -24,17 +24,22 @@ ...@@ -24,17 +24,22 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <string> #include <string>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <exception> #include <exception>
#include "miniposix.h"
#if !_WIN32 #if !_WIN32
#include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#endif #endif
#if _MSC_VER
#pragma warning(disable: 4996)
// Warns that sprintf() is buffer-overrunny. Yeah, I know, it's cool.
#endif
namespace kj { namespace kj {
namespace _ { // private namespace _ { // private
namespace { namespace {
...@@ -115,7 +120,7 @@ public: ...@@ -115,7 +120,7 @@ public:
const char* end = pos + text.size(); const char* end = pos + text.size();
while (pos < end) { 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 (n < 0) {
if (errno == EINTR) { if (errno == EINTR) {
continue; continue;
...@@ -319,6 +324,16 @@ TEST(Debug, Catch) { ...@@ -319,6 +324,16 @@ TEST(Debug, Catch) {
#endif #endif
} }
int mockSyscall(int i, int error = 0) {
errno = error;
return i;
}
int fail() {
errno = EBADF;
return -1;
}
TEST(Debug, Syscall) { TEST(Debug, Syscall) {
MockExceptionCallback mockCallback; MockExceptionCallback mockCallback;
int line; int line;
...@@ -326,19 +341,21 @@ TEST(Debug, Syscall) { ...@@ -326,19 +341,21 @@ TEST(Debug, Syscall) {
int i = 123; int i = 123;
const char* str = "foo"; const char* str = "foo";
int fd; KJ_SYSCALL(mockSyscall(0));
KJ_SYSCALL(fd = dup(STDIN_FILENO)); KJ_SYSCALL(mockSyscall(1));
KJ_SYSCALL(close(fd));
EXPECT_FATAL(KJ_SYSCALL(close(fd), i, "bar", str)); line = __LINE__; EXPECT_FATAL(KJ_SYSCALL(mockSyscall(-1, EBADF), i, "bar", str)); line = __LINE__;
EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) + ": error from OS: close(fd): " EXPECT_EQ("fatal exception: " + fileLine(__FILE__, line) +
+ strerror(EBADF) + "; i = 123; bar; str = foo\n", mockCallback.text); ": error from OS: mockSyscall(-1, EBADF): " + strerror(EBADF) +
"; i = 123; bar; str = foo\n", mockCallback.text);
mockCallback.text.clear(); mockCallback.text.clear();
int result = 0; int result = 0;
bool recovered = false; bool recovered = false;
KJ_SYSCALL(result = close(fd), i, "bar", str) { recovered = true; break; } line = __LINE__; KJ_SYSCALL(result = mockSyscall(-2, EBADF), i, "bar", str) { recovered = true; break; } line = __LINE__;
EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) + ": error from OS: close(fd): " EXPECT_EQ("recoverable exception: " + fileLine(__FILE__, line) +
+ strerror(EBADF) + "; i = 123; bar; str = foo\n", mockCallback.text); ": error from OS: mockSyscall(-2, EBADF): " + strerror(EBADF) +
"; i = 123; bar; str = foo\n", mockCallback.text);
EXPECT_LT(result, 0); EXPECT_LT(result, 0);
EXPECT_TRUE(recovered); EXPECT_TRUE(recovered);
} }
......
...@@ -121,6 +121,81 @@ ...@@ -121,6 +121,81 @@
namespace kj { 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, ...) \ #define KJ_LOG(severity, ...) \
if (!::kj::_::Debug::shouldLog(::kj::_::Debug::Severity::severity)) {} else \ if (!::kj::_::Debug::shouldLog(::kj::_::Debug::Severity::severity)) {} else \
::kj::_::Debug::log(__FILE__, __LINE__, ::kj::_::Debug::Severity::severity, \ ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::_::Debug::Severity::severity, \
...@@ -180,6 +255,8 @@ namespace kj { ...@@ -180,6 +255,8 @@ namespace kj {
#define KJ_ASSERT_NONNULL(value, ...) _kJ_NONNULL(LOCAL_BUG, value, ##__VA_ARGS__) #define KJ_ASSERT_NONNULL(value, ...) _kJ_NONNULL(LOCAL_BUG, value, ##__VA_ARGS__)
#define KJ_REQUIRE_NONNULL(value, ...) _kJ_NONNULL(PRECONDITION, value, ##__VA_ARGS__) #define KJ_REQUIRE_NONNULL(value, ...) _kJ_NONNULL(PRECONDITION, value, ##__VA_ARGS__)
#endif
#ifdef KJ_DEBUG #ifdef KJ_DEBUG
#define KJ_DLOG LOG #define KJ_DLOG LOG
#define KJ_DASSERT KJ_ASSERT #define KJ_DASSERT KJ_ASSERT
...@@ -225,6 +302,8 @@ public: ...@@ -225,6 +302,8 @@ public:
template <typename... Params> template <typename... Params>
Fault(const char* file, int line, Exception::Nature nature, int errorNumber, Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs, Params&&... params); 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); ~Fault() noexcept(false);
KJ_NORETURN(void fatal()); KJ_NORETURN(void fatal());
...@@ -314,6 +393,11 @@ void Debug::log(const char* file, int line, Severity severity, const char* macro ...@@ -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))); 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> template <typename... Params>
Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int errorNumber, Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int errorNumber,
const char* condition, const char* macroArgs, Params&&... params) 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 ...@@ -323,6 +407,12 @@ Debug::Fault::Fault(const char* file, int line, Exception::Nature nature, int er
arrayPtr(argValues, sizeof...(Params))); 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> template <typename Call>
Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) { Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) {
while (call() < 0) { while (call() < 0) {
...@@ -343,6 +433,11 @@ String Debug::makeContextDescription(const char* macroArgs, Params&&... params) ...@@ -343,6 +433,11 @@ String Debug::makeContextDescription(const char* macroArgs, Params&&... params)
return makeContextDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params))); return makeContextDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params)));
} }
template <>
inline String Debug::makeContextDescription<>(const char* macroArgs) {
return makeContextDescriptionInternal(macroArgs, nullptr);
}
} // namespace _ (private) } // namespace _ (private)
} // namespace kj } // namespace kj
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "string.h" #include "string.h"
#include "debug.h" #include "debug.h"
#include "threadlocal.h" #include "threadlocal.h"
#include <unistd.h> #include "miniposix.h"
#include <stdlib.h> #include <stdlib.h>
#include <exception> #include <exception>
...@@ -317,7 +317,7 @@ public: ...@@ -317,7 +317,7 @@ public:
StringPtr textPtr = text; StringPtr textPtr = text;
while (text != nullptr) { 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) { if (n <= 0) {
// stderr is broken. Give up. // stderr is broken. Give up.
return; return;
...@@ -397,6 +397,26 @@ uint uncaughtExceptionCount() { ...@@ -397,6 +397,26 @@ uint uncaughtExceptionCount() {
return __cxa_get_globals()->uncaughtExceptions; 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 #else
#error "This needs to be ported to your compiler / C++ ABI." #error "This needs to be ported to your compiler / C++ ABI."
#endif #endif
......
...@@ -21,14 +21,8 @@ ...@@ -21,14 +21,8 @@
#include "io.h" #include "io.h"
#include "debug.h" #include "debug.h"
#include "miniposix.h"
#include <gtest/gtest.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 kj {
namespace { namespace {
...@@ -38,7 +32,7 @@ TEST(Io, WriteVec) { ...@@ -38,7 +32,7 @@ TEST(Io, WriteVec) {
// used to not work in some cases.) // used to not work in some cases.)
int fds[2]; int fds[2];
KJ_SYSCALL(pipe(fds)); KJ_SYSCALL(miniposix::pipe(fds));
FdInputStream in((AutoCloseFd(fds[0]))); FdInputStream in((AutoCloseFd(fds[0])));
FdOutputStream out((AutoCloseFd(fds[1]))); FdOutputStream out((AutoCloseFd(fds[1])));
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "io.h" #include "io.h"
#include "debug.h" #include "debug.h"
#include <unistd.h> #include "miniposix.h"
#include <algorithm> #include <algorithm>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
...@@ -238,7 +238,7 @@ AutoCloseFd::~AutoCloseFd() noexcept(false) { ...@@ -238,7 +238,7 @@ AutoCloseFd::~AutoCloseFd() noexcept(false) {
if (fd >= 0) { if (fd >= 0) {
unwindDetector.catchExceptionsIfUnwinding([&]() { unwindDetector.catchExceptionsIfUnwinding([&]() {
// Don't use SYSCALL() here because close() should not be repeated on EINTR. // 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) { KJ_FAIL_SYSCALL("close", errno, fd) {
break; break;
} }
...@@ -255,8 +255,8 @@ size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) { ...@@ -255,8 +255,8 @@ size_t FdInputStream::tryRead(void* buffer, size_t minBytes, size_t maxBytes) {
byte* max = pos + maxBytes; byte* max = pos + maxBytes;
while (pos < min) { while (pos < min) {
ssize_t n; miniposix::ssize_t n;
KJ_SYSCALL(n = ::read(fd, pos, max - pos), fd); KJ_SYSCALL(n = miniposix::read(fd, pos, max - pos), fd);
if (n == 0) { if (n == 0) {
break; break;
} }
...@@ -272,8 +272,8 @@ void FdOutputStream::write(const void* buffer, size_t size) { ...@@ -272,8 +272,8 @@ void FdOutputStream::write(const void* buffer, size_t size) {
const char* pos = reinterpret_cast<const char*>(buffer); const char* pos = reinterpret_cast<const char*>(buffer);
while (size > 0) { while (size > 0) {
ssize_t n; miniposix::ssize_t n;
KJ_SYSCALL(n = ::write(fd, pos, size), fd); KJ_SYSCALL(n = miniposix::write(fd, pos, size), fd);
KJ_ASSERT(n > 0, "write() returned zero."); KJ_ASSERT(n > 0, "write() returned zero.");
pos += n; pos += n;
size -= n; size -= n;
......
...@@ -38,7 +38,7 @@ TEST(Memory, OwnConst) { ...@@ -38,7 +38,7 @@ TEST(Memory, OwnConst) {
} }
TEST(Memory, CanConvert) { TEST(Memory, CanConvert) {
struct Super { virtual ~Super(); }; struct Super { virtual ~Super() {} };
struct Sub: public Super {}; struct Sub: public Super {};
static_assert(canConvert<Own<Sub>, Own<Super>>(), "failure"); 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 @@ ...@@ -28,6 +28,11 @@
namespace kj { 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) { String heapString(size_t size) {
char* buffer = _::HeapArrayDisposer::allocate<char>(size + 1); char* buffer = _::HeapArrayDisposer::allocate<char>(size + 1);
buffer[size] = '\0'; buffer[size] = '\0';
...@@ -256,11 +261,11 @@ char* DoubleToBuffer(double value, char* buffer) { ...@@ -256,11 +261,11 @@ char* DoubleToBuffer(double value, char* buffer) {
// truncated to a double. // truncated to a double.
volatile double parsed_value = strtod(buffer, NULL); volatile double parsed_value = strtod(buffer, NULL);
if (parsed_value != value) { if (parsed_value != value) {
int snprintf_result = int snprintf_result2 =
snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG+2, value); snprintf(buffer, kDoubleToBufferSize, "%.*g", DBL_DIG+2, value);
// Should never overflow; see above. // Should never overflow; see above.
KJ_DASSERT(snprintf_result > 0 && snprintf_result < kDoubleToBufferSize); KJ_DASSERT(snprintf_result2 > 0 && snprintf_result2 < kDoubleToBufferSize);
} }
DelocalizeRadix(buffer); DelocalizeRadix(buffer);
...@@ -275,7 +280,7 @@ bool safe_strtof(const char* str, float* value) { ...@@ -275,7 +280,7 @@ bool safe_strtof(const char* str, float* value) {
char* endptr; char* endptr;
errno = 0; // errno only gets set on errors errno = 0; // errno only gets set on errors
#if defined(_WIN32) || defined (__hpux) // has no strtof() #if defined(_WIN32) || defined (__hpux) // has no strtof()
*value = strtod(str, &endptr); *value = static_cast<float>(strtod(str, &endptr));
#else #else
*value = strtof(str, &endptr); *value = strtof(str, &endptr);
#endif #endif
...@@ -309,11 +314,11 @@ char* FloatToBuffer(float value, char* buffer) { ...@@ -309,11 +314,11 @@ char* FloatToBuffer(float value, char* buffer) {
float parsed_value; float parsed_value;
if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) { if (!safe_strtof(buffer, &parsed_value) || parsed_value != value) {
int snprintf_result = int snprintf_result2 =
snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value); snprintf(buffer, kFloatToBufferSize, "%.*g", FLT_DIG+2, value);
// Should never overflow; see above. // Should never overflow; see above.
KJ_DASSERT(snprintf_result > 0 && snprintf_result < kFloatToBufferSize); KJ_DASSERT(snprintf_result2 > 0 && snprintf_result2 < kFloatToBufferSize);
} }
DelocalizeRadix(buffer); DelocalizeRadix(buffer);
......
...@@ -300,7 +300,7 @@ struct Stringifier { ...@@ -300,7 +300,7 @@ struct Stringifier {
inline Result operator*(T&& value) const { return kj::fwd<T>(value).toString(); } inline Result operator*(T&& value) const { return kj::fwd<T>(value).toString(); }
#endif #endif
}; };
static constexpr Stringifier STR = Stringifier(); static KJ_CONSTEXPR(const) Stringifier STR = Stringifier();
} // namespace _ (private) } // namespace _ (private)
......
...@@ -120,10 +120,14 @@ private: ...@@ -120,10 +120,14 @@ private:
} // namespace _ (private) } // namespace _ (private)
#else #elif __GNUC__
#define KJ_THREADLOCAL_PTR(type) static __thread type* #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 #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