# Crashpad needs google's depot_tools to be in the system path. # "gclient" is a binary known to be apart of depot_tools. find_program(DEPOT_TOOLS_EXIST gclient) if(DEPOT_TOOLS_EXIST AND NOT $ENV{CI}) # Not required on CI, as it's prepared in ci-workflow.yml message(WARNING " depot_tools were not found. Crashpad will be disabled. If you would like to build crashpad,\n" " please ensure depot_tools have been added to your system path. Install instructions are at:\n" " https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up") return() endif() # Check linux to ensure necessary tools exist to build crashpad if(UNIX AND NOT APPLE) # clang++ must be detected on linux only. find_program(CLANG_EXISTS clang++) if(NOT CLANG_EXISTS AND NOT $ENV{CI}) message(WARNING " clang++ was not found. Crashpad will be disabled. If you would like to build crashpad,\n" " please ensure you have clang installed via your package manager. clang++ is a requiremnt\n" " setup by crashpad.") return() endif() # Python2 must be detected on linux only. depot_tools provides a python2 interpreter on windows, # and python2 comes standards on mac. find_package(Python2 COMPONENTS Interpreter) if(NOT Python2_FOUND AND NOT $ENV{CI}) # Not required on CI, as it's prepared in ci-workflow.yml message(WARNING " python2 was not found. Crashpad will be disabled. If you would like to build crashpad,\n" " please ensure you have python2 installed via your package manager.") return() endif() endif() # Google uses depot_tools to download and build crashpad. We will do the same. # This file make assumptions about where crashpad is located. Chromium uses depot_tools # to download and setup a directory for the crashpad/breakpad/chromium tools. We do not # follow suit exactly, in that we assume crashpad is already available locally. We # placed it in libs/crashpad. Inside that directory is exactly what would be expected if # "fetch crashpad" was run in the "libs/crashpad" directory, but we remove the .git folers # inside the downloaded "libs/crashpad/{buildtools,crashpad}" as we want it in the current, # source tree, and not as a submodule/subtree. include(ExternalProject) include(FetchContent) # Here we only download depot_tools by using FetchContent. If the developer has # installed depot_tools on their own system and added it to path, this would # not be necessary, but for the sake of Etterna, it was added to keep build instruction # modification to a minimum. Unlike ExternalProject, FetchContent will download the # git repository *during project generation*. FetchContent_Declare(depot_tools GIT_REPOSITORY https://chromium.googlesource.com/chromium/tools/depot_tools.git GIT_TAG main GIT_PROGRESS TRUE GIT_SHALLOW TRUE) FetchContent_MakeAvailable(depot_tools) FetchContent_GetProperties(depot_tools SOURCE_DIR DEPOT_TOOLS_DIR) list(APPEND CMAKE_PROGRAM_PATH ${DEPOT_TOOLS_DIR}) find_program(EXE_DEPOT_GN gn) find_program(EXE_DEPOT_NINJA ninja) # Crashpad source and build folders set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/crashpad) set(BINARY_DIR ${PROJECT_BINARY_DIR}/gn_crashpad) # Assume 64bit, change to 32 if necessary set(GN_TARGET_CPU x64) if(CMAKE_SIZEOF_VOID_P EQUAL 4) # If 32bit set(GN_TARGET_CPU x86) endif() # Lists of the expected output libraries if(WIN32) list(APPEND OUTPUT_LIBS ${BINARY_DIR}/obj/client/client.lib ${BINARY_DIR}/obj/client/common.lib ${BINARY_DIR}/obj/util/util.lib ${BINARY_DIR}/obj/third_party/mini_chromium/mini_chromium/base/base.lib) elseif(UNIX) list(APPEND OUTPUT_LIBS ${BINARY_DIR}/obj/client/libclient.a ${BINARY_DIR}/obj/client/libcommon.a ${BINARY_DIR}/obj/util/libutil.a ${BINARY_DIR}/obj/third_party/mini_chromium/mini_chromium/base/libbase.a) endif() # macOS Specific Libraries - Mac requires some extra libraries to build properly if(APPLE) list(APPEND OUTPUT_LIBS ${BINARY_DIR}/obj/gen/util/mach/mig_output.child_portServer.o ${BINARY_DIR}/obj/gen/util/mach/mig_output.child_portUser.o ${BINARY_DIR}/obj/gen/util/mach/mig_output.excServer.o ${BINARY_DIR}/obj/gen/util/mach/mig_output.excUser.o ${BINARY_DIR}/obj/gen/util/mach/mig_output.mach_excServer.o ${BINARY_DIR}/obj/gen/util/mach/mig_output.mach_excUser.o ${BINARY_DIR}/obj/gen/util/mach/mig_output.notifyServer.o ${BINARY_DIR}/obj/gen/util/mach/mig_output.notifyUser.o) endif() # gn build system options set(GN_IS_DEBUG false) # Build crashpad in debug or release (default is release) if(CMAKE_BUILD_TYPE STREQUAL Debug) #TODO: Fix for multi-config generators set(GN_IS_DEBUG true) endif() set(GN_WIN_LINK_FLAG "") # Dynamically link to C runtime library if(WIN32) set(GN_WIN_LINK_FLAG /MT) # Dynamically link to C runtime library if(CMAKE_BUILD_TYPE STREQUAL Debug) #TODO: Fix for multi-config generators string(APPEND GN_WIN_LINK_FLAG d) endif() endif() # TODO: Can this be removed? Only the steps below are used. ExternalProject_Add(crashpad_init PREFIX ${BINARY_DIR} SOURCE_DIR ${SOURCE_DIR} BINARY_DIR ${BINARY_DIR} # Disable all commands, since we want to run them manually. DOWNLOAD_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "") # Generate project files - "gn gen build_directory" # This is set to always generate. If any config operations are changed, it will need to be rerun. # Re-running gn every single time is not the most efficient, though it has a very short runtime # on subsequent runs, and if nothing is changed the build step will do nothing.c ExternalProject_Add_Step(crashpad_init gn_configure ALWAYS 1 USES_TERMINAL 1 WORKING_DIRECTORY ${SOURCE_DIR} COMMAND ${EXE_DEPOT_GN} gen ${BINARY_DIR} "--args=target_cpu=\"${GN_TARGET_CPU}\" is_debug=${GN_IS_DEBUG} extra_cflags=\"${GN_WIN_LINK_FLAG}\"" && ${EXE_DEPOT_NINJA} -C ${BINARY_DIR} crashpad_handler BYPRODUCTS ${OUTPUT_LIBS}) # Build Project - "ninja client crashpad_handler" with the last "client" and "crashpad_handler" being the targets # ExternalProject_Add_Step(crashpad_init gn_build # WORKING_DIRECTORY ${BINARY_DIR} # ALWAYS 1 # Always attempt to run # DEPENDEES gn_configure # Do not run unless gn_configure has ran # COMMAND ${EXE_DEPOT_NINJA} crashpad_handler # Target to build # USES_TERMINAL 1 # Give direct terminal access (needed for build progress) # BYPRODUCTS ${OUTPUT_LIBS}) # Tell CMake what libs this steps is expected to produce # Clean Project - Since there is no way to manually clean, we can create a target so they dev can run when they like #ExternalProject_Add_Step(crashpad_init gn_clean # EXCLUDE_FROM_MAIN 1 # Don't run automatically # WORKING_DIRECTORY ${BINARY_DIR} # COMMAND ${EXE_DEPOT_NINJA} -t clean) #ExternalProject_Add_StepTargets(crashpad_init gn_clean) # Create library which will be linked to main application add_library(crashpad INTERFACE) add_dependencies(crashpad crashpad_init) target_link_libraries(crashpad INTERFACE ${OUTPUT_LIBS}) target_include_directories(crashpad INTERFACE ${SOURCE_DIR}) target_include_directories(crashpad INTERFACE ${SOURCE_DIR}/third_party/mini_chromium/mini_chromium) if(UNIX) find_package(Threads REQUIRED) target_link_libraries(crashpad INTERFACE Threads::Threads) endif() if(APPLE) # macOS Frameworks for crashpad find_library(MAC_FRAME_COCOA Cocoa) find_library(MAC_FRAME_IOKIT IOKit) find_library(MAC_FRAME_SECURITY Security) target_link_libraries(crashpad INTERFACE bsm) target_link_libraries(crashpad INTERFACE ${MAC_FRAME_COCOA}) target_link_libraries(crashpad INTERFACE ${MAC_FRAME_IOKIT}) target_link_libraries(crashpad INTERFACE ${MAC_FRAME_SECURITY}) endif() # Crash Handler Executable Location set(CRASH_HANDLER_EXE ${BINARY_DIR}/crashpad_handler) if(WIN32) string(APPEND CRASH_HANDLER_EXE .exe) endif()