Skip to content

Commit

Permalink
WIP external: add google breakpad/crashpad integration
Browse files Browse the repository at this point in the history
NPT-91
  • Loading branch information
Ryp committed Oct 31, 2023
1 parent cdb5049 commit e56f83d
Show file tree
Hide file tree
Showing 22 changed files with 469 additions and 7 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update -qq # Always do this step to prevent package urls to get outdated
sudo apt-get install -y build-essential cmake gcc libunwind-dev libx11-xcb-dev libxcb-xkb-dev libasound2-dev
sudo apt-get install -y build-essential cmake gcc ninja-build libcurl libunwind-dev libx11-xcb-dev libxcb-xkb-dev libasound2-dev
- name: Prepare Vulkan SDK
uses: humbletim/[email protected]
Expand Down Expand Up @@ -123,6 +123,9 @@ jobs:
vulkan-components: ${{ env.vulkan_sdk_modules }}
vulkan-use-cache: true

- name: Install Ninja
uses: seanmiddleditch/gha-setup-ninja@master

- name: Configure CMake
run: |
cmake .\ -Bbuild `
Expand Down
9 changes: 9 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,12 @@
[submodule "external/bullet3"]
path = external/bullet3
url = https://github.com/Ryp/bullet3
[submodule "external/google/depot_tools"]
path = external/google/depot_tools
url = https://chromium.googlesource.com/chromium/tools/depot_tools.git
[submodule "external/google/breakpad/src"]
path = external/google/breakpad/src
url = https://chromium.googlesource.com/breakpad/breakpad.git
[submodule "external/google/crashpad/crashpad"]
path = external/google/crashpad/crashpad
url = https://chromium.googlesource.com/crashpad/crashpad.git
12 changes: 11 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,13 @@ option(REAPER_BUILD_SHARED_LIBS "Build shared libraries" ${BUILD_

# Enable runtime profiling with Tracy.
# Tracy has its own profiler app that you have to compile from source.
option(REAPER_USE_TRACY "Use tracy" ON)
option(REAPER_USE_TRACY "Use Tracy" ON)

# Enable crash reporting with google breakpad
option(REAPER_USE_GOOGLE_BREAKPAD "Use Google Breakpad" OFF)

# Enable crash reporting with google crashpad
option(REAPER_USE_GOOGLE_CRASHPAD "Use Google Crashpad" ON)

# See .clang-tidy for the list of useful checks.
option(REAPER_RUN_CLANG_TIDY "Run clang-tidy when compiling" OFF)
Expand All @@ -80,6 +86,10 @@ option(REAPER_HLSL_USE_DXC "Build HLSL shaders with DXC" OFF)
# Enable physics simulation with bullet.
option(REAPER_USE_BULLET_PHYSICS "Enable game physics" ON)

if(REAPER_USE_GOOGLE_BREAKPAD AND REAPER_USE_GOOGLE_CRASHPAD)
message(FATAL_ERROR "Google breakpad and crashpad can't be both enabled at the same time!")
endif()

# Override binary output paths
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${Reaper_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${Reaper_BINARY_DIR})
Expand Down
22 changes: 22 additions & 0 deletions cmake/external/breakpad.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#///////////////////////////////////////////////////////////////////////////////
#// Reaper
#//
#// Copyright (c) 2015-2023 Thibault Schueller
#// This file is distributed under the MIT License
#///////////////////////////////////////////////////////////////////////////////

set(GOOGLE_BREAKPAD_PATH ${CMAKE_SOURCE_DIR}/external/google/breakpad/src)

add_library(google_breakpad INTERFACE)

target_include_directories(google_breakpad SYSTEM INTERFACE ${GOOGLE_BREAKPAD_PATH}/src)

if(WIN32)
target_include_directories(google_breakpad SYSTEM INTERFACE ${GOOGLE_BREAKPAD_PATH}/src/client/windows)
target_link_directories(google_breakpad INTERFACE ${GOOGLE_BREAKPAD_PATH}/src/client/windows)
elseif(UNIX)
target_include_directories(google_breakpad SYSTEM INTERFACE ${GOOGLE_BREAKPAD_PATH}/src/client/linux)
target_link_directories(google_breakpad INTERFACE ${GOOGLE_BREAKPAD_PATH}/src/client/linux)
endif()

target_link_libraries(google_breakpad INTERFACE breakpad_client)
109 changes: 109 additions & 0 deletions cmake/external/crashpad.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#///////////////////////////////////////////////////////////////////////////////
#// Reaper
#//
#// Copyright (c) 2015-2023 Thibault Schueller
#// This file is distributed under the MIT License
#///////////////////////////////////////////////////////////////////////////////

set(GOOGLE_PATH ${CMAKE_SOURCE_DIR}/external/google)

set(GOOGLE_BREAKPAD_PATH ${GOOGLE_PATH}/breakpad/src)
set(GOOGLE_CRASHPAD_PATH ${GOOGLE_PATH}/crashpad/crashpad)
set(GOOGLE_DEPOT_TOOLS_PATH ${GOOGLE_PATH}/depot_tools)

# depot_tools used to contain the ninja binary but doesn't anymore, so we need
# to make sure it's in the PATH instead of sourcing it from google's repo.
find_program(EXE_NINJA ninja REQUIRED)

list(APPEND CMAKE_PROGRAM_PATH ${GOOGLE_DEPOT_TOOLS_PATH})
find_program(GOOGLE_DEPOT_TOOLS_GCLIENT gclient REQUIRED)
find_program(GOOGLE_DEPOT_TOOLS_GN gn REQUIRED)

# gclient sync will try to update the local clone of depot_tools
# creating this file will inhibit that behavior
file(TOUCH ${GOOGLE_DEPOT_TOOLS_PATH}/.disable_auto_update)

# TODO Comment
file(COPY ${GOOGLE_PATH}/metrics.cfg DESTINATION ${GOOGLE_DEPOT_TOOLS_PATH})

# NOTE: Partial dependency checking.
# It's not enough to mark the gclient file as the only byproduct,
# as there's many more files produced by this command.
# For the sake simplicity, I'm not going to bother making that step bulletproof.
set(GOOGLE_CRASHPAD_GCLIENT_ENTRIES_FILE ${GOOGLE_PATH}/crashpad/.gclient_entries)

add_custom_command(OUTPUT ${GOOGLE_CRASHPAD_GCLIENT_ENTRIES_FILE}
COMMENT "Configure google crashpad repo"
WORKING_DIRECTORY ${GOOGLE_PATH}/crashpad
COMMAND ${GOOGLE_DEPOT_TOOLS_GCLIENT} sync --nohooks)

set(GOOGLE_CRASHPAD_BINARY_DIR ${CMAKE_BINARY_DIR}/external/crashpad)

#Lists of the expected output libraries
if(WIN32)
list(APPEND GOOGLE_CRASHPAD_CLIENT_LIBRARIES
${GOOGLE_CRASHPAD_BINARY_DIR}/obj/client/client.lib
${GOOGLE_CRASHPAD_BINARY_DIR}/obj/client/common.lib
${GOOGLE_CRASHPAD_BINARY_DIR}/obj/util/util.lib
${GOOGLE_CRASHPAD_BINARY_DIR}/obj/third_party/mini_chromium/mini_chromium/base/base.lib)
elseif(UNIX)
list(APPEND GOOGLE_CRASHPAD_CLIENT_LIBRARIES
${GOOGLE_CRASHPAD_BINARY_DIR}/obj/client/libclient.a
${GOOGLE_CRASHPAD_BINARY_DIR}/obj/client/libcommon.a
${GOOGLE_CRASHPAD_BINARY_DIR}/obj/util/libutil.a
${GOOGLE_CRASHPAD_BINARY_DIR}/obj/third_party/mini_chromium/mini_chromium/base/libbase.a)
endif()

set(GN_IS_DEBUG)
set(GN_LINK_FLAG)

# FIXME multi-config generators
if(CMAKE_BUILD_TYPE STREQUAL Debug)
set(GN_IS_DEBUG true)
else()
set(GN_IS_DEBUG false)
endif()

# FIXME multi-config generators
if(MSVC)
if(CMAKE_BUILD_TYPE STREQUAL Debug)
set(GN_LINK_FLAG /MDd)
else()
set(GN_LINK_FLAG /MD)
endif()
endif()

set(GOOGLE_CRASHPAD_NINJA_FILE ${GOOGLE_CRASHPAD_BINARY_DIR}/build.ninja)

# NOTE: Partial dependency checking.
# It's not enough to mark the ninja file as the only byproduct,
# as there's many more files needed by ninja after a configure step to produce a correct build.
# For the sake simplicity, I'm not going to bother making that step bulletproof.
add_custom_command(OUTPUT ${GOOGLE_CRASHPAD_NINJA_FILE}
COMMENT "Configure google crashpad handler"
DEPENDS ${GOOGLE_CRASHPAD_GCLIENT_ENTRIES_FILE}
WORKING_DIRECTORY ${GOOGLE_CRASHPAD_PATH}
COMMAND ${CMAKE_COMMAND} -E make_directory ${GOOGLE_CRASHPAD_BINARY_DIR}
COMMAND ${GOOGLE_DEPOT_TOOLS_GN} gen ${GOOGLE_CRASHPAD_BINARY_DIR} "--args=is_debug=${GN_IS_DEBUG} extra_cflags=\"${GN_LINK_FLAG}\""
VERBATIM)

add_custom_command(OUTPUT ${GOOGLE_CRASHPAD_CLIENT_LIBRARIES}
COMMENT "Compile google crashpad handler"
DEPENDS ${GOOGLE_CRASHPAD_NINJA_FILE}
COMMAND ${EXE_NINJA} -C ${GOOGLE_CRASHPAD_BINARY_DIR} crashpad_handler
VERBATIM)

add_custom_target(crashpad_handler_compile DEPENDS ${GOOGLE_CRASHPAD_CLIENT_LIBRARIES})

# Meta target
add_library(google_crashpad_client INTERFACE)

add_dependencies(google_crashpad_client crashpad_handler_compile)

target_link_libraries(google_crashpad_client INTERFACE ${GOOGLE_CRASHPAD_CLIENT_LIBRARIES})

target_include_directories(google_crashpad_client SYSTEM INTERFACE
${GOOGLE_CRASHPAD_PATH}
${GOOGLE_CRASHPAD_PATH}/third_party/mini_chromium/mini_chromium
${GOOGLE_CRASHPAD_BINARY_DIR}/gen
)
8 changes: 8 additions & 0 deletions external/google/breakpad/.gclient
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
solutions = [
{
"name": "src",
"url": "https://chromium.googlesource.com/breakpad/breakpad.git",
"managed": False,
"custom_deps": {},
},
]
4 changes: 4 additions & 0 deletions external/google/breakpad/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
!.gitignore

.gclient_entries
.gclient_previous_sync_commits
1 change: 1 addition & 0 deletions external/google/breakpad/src
Submodule src added at f49c2f
7 changes: 7 additions & 0 deletions external/google/crashpad/.gclient
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
solutions = [
{
"name": "crashpad",
"url": "https://chromium.googlesource.com/crashpad/crashpad.git",
"managed": False,
},
]
7 changes: 7 additions & 0 deletions external/google/crashpad/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
!.gitignore

.cipd
.gclient_entries
.gclient_previous_sync_commits

buildtools
1 change: 1 addition & 0 deletions external/google/crashpad/crashpad
Submodule crashpad added at 4a93d7
1 change: 1 addition & 0 deletions external/google/depot_tools
Submodule depot_tools added at c7628f
1 change: 1 addition & 0 deletions external/google/metrics.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"is-googler": false, "countdown": 10, "opt-in": null, "version": 2}
85 changes: 85 additions & 0 deletions src/BreakpadHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
////////////////////////////////////////////////////////////////////////////////
/// Reaper
///
/// Copyright (c) 2015-2023 Thibault Schueller
/// This file is distributed under the MIT License
////////////////////////////////////////////////////////////////////////////////

#include "BreakpadHandler.h"

#include <core/Assert.h>
#include <core/Platform.h>

#include "handler/exception_handler.h"

#if defined(REAPER_PLATFORM_LINUX)
static bool dump_callback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)

{
static_cast<void>(context);
static_cast<void>(descriptor);

return succeeded;
}
#elif defined(REAPER_PLATFORM_WINDOWS)
# include <tchar.h>
constexpr size_t kMaximumLineLength = 256;
constexpr wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashServices\\TestServer";
static size_t kCustomInfoCount = 2;

static google_breakpad::CustomInfoEntry kCustomInfoEntries[] = {
{L"prod", L"CrashTestApp"},
{L"ver", L"1.0"},
};

bool ShowDumpResults(const wchar_t* dump_path,
const wchar_t* minidump_id,
void* context,
EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion,
bool succeeded)
{
return succeeded;
}
#endif

namespace Reaper
{
BreakpadContext create_breakpad_context()
{
#if defined(REAPER_PLATFORM_LINUX)
const char* dump_path = "/tmp";
#elif defined(REAPER_PLATFORM_WINDOWS)
const wchar_t* dump_path = L"C:\\dumps\\";
#endif

#if defined(REAPER_PLATFORM_LINUX)
google_breakpad::MinidumpDescriptor descriptor(dump_path);

auto* handler = new google_breakpad::ExceptionHandler(descriptor, nullptr, dump_callback, nullptr, true, 1);
#elif defined(REAPER_PLATFORM_WINDOWS)
google_breakpad::CustomClientInfo custom_info = {kCustomInfoEntries, kCustomInfoCount};

auto* handler = new google_breakpad::ExceptionHandler(dump_path,
nullptr,
ShowDumpResults,
nullptr,
google_breakpad::ExceptionHandler::HANDLER_ALL,
MiniDumpNormal,
kPipeName,
&custom_info);
#endif

return BreakpadContext{.handler = handler};
}

void destroy_breakpad_context(const BreakpadContext& breakpad_context)
{
Assert(breakpad_context.handler);

if (breakpad_context.handler)
{
delete breakpad_context.handler;
}
}
} // namespace Reaper
24 changes: 24 additions & 0 deletions src/BreakpadHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
////////////////////////////////////////////////////////////////////////////////
/// Reaper
///
/// Copyright (c) 2015-2023 Thibault Schueller
/// This file is distributed under the MIT License
////////////////////////////////////////////////////////////////////////////////

#pragma once

namespace google_breakpad
{
class ExceptionHandler;
}

namespace Reaper
{
struct BreakpadContext
{
google_breakpad::ExceptionHandler* handler;
};

BreakpadContext create_breakpad_context();
void destroy_breakpad_context(const BreakpadContext& breakpad_context);
} // namespace Reaper
21 changes: 20 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ add_executable(${REAPER_BIN})

target_sources(${REAPER_BIN} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp

${CMAKE_CURRENT_SOURCE_DIR}/Camera.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Camera.h
${CMAKE_CURRENT_SOURCE_DIR}/GameLoop.cpp
Expand All @@ -50,6 +49,26 @@ target_link_libraries(${REAPER_BIN} PRIVATE
cgltf
)

if(REAPER_USE_GOOGLE_BREAKPAD)
target_sources(${REAPER_BIN} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/BreakpadHandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/BreakpadHandler.h)

include(external/breakpad)
target_compile_definitions(${REAPER_BIN} PUBLIC REAPER_USE_GOOGLE_BREAKPAD)
target_link_libraries(${REAPER_BIN} PRIVATE google_breakpad)
endif()

if(REAPER_USE_GOOGLE_CRASHPAD)
target_sources(${REAPER_BIN} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/CrashpadHandler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/CrashpadHandler.h)

include(external/crashpad)
target_compile_definitions(${REAPER_BIN} PUBLIC REAPER_USE_GOOGLE_CRASHPAD)
target_link_libraries(${REAPER_BIN} PRIVATE google_crashpad_client)
endif()

# Configure main VS projet
set_target_properties(${REAPER_BIN} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${REAPER_BIN})
Expand Down
Loading

0 comments on commit e56f83d

Please sign in to comment.