diff --git a/build/build-sdk-images/cpp/Dockerfile b/build/build-sdk-images/cpp/Dockerfile index 4181f298cf..fe86a972df 100644 --- a/build/build-sdk-images/cpp/Dockerfile +++ b/build/build-sdk-images/cpp/Dockerfile @@ -15,7 +15,7 @@ ARG BASE_IMAGE=agones-build-sdk-base:latest FROM $BASE_IMAGE RUN apt-get update && \ - apt-get install -y zip wget && \ + apt-get install -y zip wget clang-format && \ apt-get clean ADD https://cmake.org/files/v3.14/cmake-3.14.1-Linux-x86_64.sh /cmake-3.14.1-Linux-x86_64.sh @@ -37,4 +37,4 @@ ENV PATH /usr/local/go/bin:/go/bin:$PATH # code generation scripts COPY *.sh /root/ -RUN chmod +x /root/*.sh \ No newline at end of file +RUN chmod +x /root/*.sh diff --git a/build/build-sdk-images/cpp/build.sh b/build/build-sdk-images/cpp/build.sh index 1894151c5a..ca3e952b44 100644 --- a/build/build-sdk-images/cpp/build.sh +++ b/build/build-sdk-images/cpp/build.sh @@ -17,4 +17,4 @@ set -ex cd ./sdks/cpp -make build install archive VERSION=$VERSION \ No newline at end of file +make build verify install archive VERSION=$VERSION \ No newline at end of file diff --git a/sdks/cpp/CMakeLists.txt b/sdks/cpp/CMakeLists.txt index b601e3614d..95340ff28f 100644 --- a/sdks/cpp/CMakeLists.txt +++ b/sdks/cpp/CMakeLists.txt @@ -20,38 +20,72 @@ cmake_minimum_required (VERSION 3.13.0) # For *nix: cmake --build . --target install -- -s option(AGONES_SILENT_OUTPUT "Show only warnings/error messages" OFF) if (AGONES_SILENT_OUTPUT) - function(message) - list(GET ARGV 0 MessageType) - if(MessageType STREQUAL FATAL_ERROR OR - MessageType STREQUAL SEND_ERROR OR - MessageType STREQUAL WARNING OR - MessageType STREQUAL AUTHOR_WARNING) - list(REMOVE_AT ARGV 0) - _message(${MessageType} "${ARGV}") - endif() - endfunction() - - set(CMAKE_INSTALL_MESSAGE NEVER) - set(CMAKE_VERBOSE_MAKEFILE OFF) - set_property(GLOBAL PROPERTY RULE_MESSAGES OFF) - set_property(GLOBAL PROPERTY TARGET_MESSAGES OFF) + function(message) + list(GET ARGV 0 MessageType) + list(REMOVE_AT ARGV 0) + if (MessageType STREQUAL FATAL_ERROR OR + MessageType STREQUAL SEND_ERROR OR + MessageType STREQUAL WARNING OR + MessageType STREQUAL AUTHOR_WARNING OR + NOT ${AGONES_SILENT_OUTPUT} + ) + _message(${MessageType} "${ARGV}") + endif() + endfunction() + + set(CMAKE_INSTALL_MESSAGE NEVER) + set(CMAKE_VERBOSE_MAKEFILE OFF) + set_property(GLOBAL PROPERTY RULE_MESSAGES OFF) + set_property(GLOBAL PROPERTY TARGET_MESSAGES OFF) endif(AGONES_SILENT_OUTPUT) +# Getting version from git +find_package(Git QUIET) +set(AGONES_VERSION "0.0.0") +if (Git_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ) + if (${result} EQUAL 0) + string(REGEX MATCH "\\d+.\\d+.\\d+" AGONES_VERSION ${output}) + endif() +else() + message(WARNING "Git was not found. Current Agones version is set to ${AGONES_VERSION}") +endif() + # Project AGONES -project(agones VERSION 0.9.0 HOMEPAGE_URL https://github.com/googleforgames/agones LANGUAGES C CXX) +project(agones VERSION ${AGONES_VERSION} HOMEPAGE_URL https://github.com/googleforgames/agones LANGUAGES C CXX) + +# Options +option(AGONES_FORCE_GRPC_VERSION "Build Agones C++ SDK only with supported gRPC version" ON) -# Build options -option(AGONES_BUILD_SHARED "Build Agones C++ SDK as dynamic library" OFF) -option(AGONES_FORCE_GRPC_VERSION "Build Agones C++ SDK only with officially supported gRPC version" ON) -option(AGONES_CREATE_PACKAGE "Generate CMake installation step and package files for Agones C++ SDK" ON) +option(AGONES_BUILD_ONLY_PREREQUISITIES "Build only prerequisites of Agones" OFF) +option(AGONES_BUILD_THIRDPARTY_DEBUG "Build debug version of thirdparty libraries (MSVC only)" ON) +set(AGONES_THIRDPARTY_INSTALL_PATH "${CMAKE_BINARY_DIR}/third_party" CACHE STRING "Path for installing third-party OpenSSL and gRPC, if they are not found with find_package") +set(AGONES_OPENSSL_CONFIG_STRING "VC-WIN64A" CACHE STRING "See https://github.com/openssl/openssl/blob/master/INSTALL for details") -# Currently we doesn't support build time generation of proto/grpc files, +# Prerequisities +include(./cmake/prerequisites.cmake) +find_package(ZLIB REQUIRED) +find_package(Protobuf REQUIRED CONFIG) +find_package(gRPC ${AGONES_GRPC_VERSION} ${AGONES_GRPC_VERSION_MATCH} REQUIRED CONFIG) + +if (AGONES_BUILD_ONLY_PREREQUISITIES) + return() +endif() + +# Currently we doesn't support build time generation of proto/gRPC files, # so gRPC version should be strict set(AGONES_FORCE_GRPC_VERSION ON) +set(AGONES_GRPC_VERSION_MATCH "") +if (AGONES_FORCE_GRPC_VERSION) + set(AGONES_GRPC_VERSION_MATCH EXACT) +endif() # Settings -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") - set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_CXX_STANDARD 14) @@ -62,210 +96,132 @@ set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) set(CMAKE_DEBUG_POSTFIX "d") set(AGONES_GRPC_VERSION "1.16.1") -if (AGONES_BUILD_SHARED) - add_compile_definitions( - PROTOBUF_USE_DLLS - LIBPROTOBUF_EXPORTS - ) -endif() - -# --> Connecting gRPC -macro(validate_path IN_PATH OUT_RESULT) - set(${OUT_RESULT} FALSE) - if (NOT IS_DIRECTORY ${${IN_PATH}}) - file(TO_CMAKE_PATH "$ENV{${IN_PATH}}" ${IN_PATH}) - else() - file(TO_CMAKE_PATH "${${IN_PATH}}" ${IN_PATH}) - endif() - if (IS_DIRECTORY ${${IN_PATH}}) - set(${OUT_RESULT} TRUE) - endif() -endmacro(validate_path) - -set(GRPC_IS_INSTALLED FALSE) -set(GRPC_PATH_FOUND FALSE) -validate_path(grpc_SOURCE_DIR GRPC_PATH_FOUND) -if (GRPC_PATH_FOUND) - # Checking if we use gRPC package or gRPC source folder - # Usually it should be findXXX.cmake or xxxConfig.cmake files, but for gRPC we need to check gRPCTargets.cmake too - if (EXISTS ${grpc_SOURCE_DIR}/gRPCTargets.cmake) - set(GRPC_IS_INSTALLED TRUE) - find_package(gRPC CONFIG REQUIRED) - endif() -else() - # Download gRPC, if necessary - include(Fetch_gRPC) -endif() - -add_subdirectory(${grpc_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/grpc EXCLUDE_FROM_ALL) - -# Check gRPC version -get_directory_property(GRPC_VERSION DIRECTORY ${grpc_SOURCE_DIR} DEFINITION PACKAGE_VERSION) -if (NOT GRPC_VERSION STREQUAL AGONES_GRPC_VERSION) - set(GRPC_VERSION_SEVERITY WARNING) - if (AGONES_FORCE_GRPC_VERSION) - set(GRPC_VERSION_SEVERITY FATAL_ERROR) - endif() - message(${GRPC_VERSION_SEVERITY} "Agones SDK currently supports only \"${AGONES_GRPC_VERSION}\" version. Building with \"${GRPC_VERSION}\" may cause unexpected problems.") -endif() - -# Configuring -set(AGONES_DEPENDENCIES libprotobuf grpc++_unsecure) -set(AGONES_GRPC_TARGETS address_sorting c-ares gpr grpc_unsecure grpc++_unsecure libprotobuf zlibstatic) -foreach(THIRDPARTY_TARGET ${AGONES_GRPC_TARGETS}) - set_property(TARGET ${THIRDPARTY_TARGET} PROPERTY FOLDER third_party) -endforeach() -# <-- Connecting gRPC # Platform specific stuff if (WIN32) - # Windows - add_compile_definitions( - _WIN32_WINNT=0x0600 - WINDOWS - ) + # Windows + add_compile_definitions( + _WIN32_WINNT=0x0600 + WINDOWS + ) elseif (APPLE) - # Mac OS + # Mac OS elseif (UNIX AND NOT APPLE) - # Linux -endif() - -if (MSVS) - set(OPT_DISABLE_COMPILER_WARNINGS /wd4101 /wd4146 /wd4251 /wd4661) - target_compile_options(libprotobuf PUBLIC ${OPT_DISABLE_COMPILER_WARNINGS}) - target_compile_options(${PROJECT_NAME} PUBLIC ${OPT_DISABLE_COMPILER_WARNINGS}) -else() - set(OPT_DISABLE_COMPILER_WARNINGS -wd4101 -wd4146 -wd4251 -wd4661) + # Linux endif() # Agones SDK include(./sources.cmake) -set(AGONES_BUILD_TYPE STATIC) -if (AGONES_BUILD_SHARED) - set(AGONES_BUILD_TYPE SHARED) +# Global header +set(GLOBAL_HEADER "${PROJECT_NAME}_global.h") +set(GLOBAL_CONFIG_CONTENT "\n") +configure_file(cmake/${GLOBAL_HEADER}.in ${GLOBAL_HEADER} @ONLY) + +if(MSVC) + add_definitions(/FI"${GLOBAL_HEADER}") +else() + # GCC or Clang + add_definitions(-include ${GLOBAL_HEADER}) endif() -add_library(${PROJECT_NAME} ${AGONES_BUILD_TYPE} ${ALL_FILES}) -target_link_libraries(${PROJECT_NAME} PRIVATE ${AGONES_DEPENDENCIES}) +set(AGONES_DEPENDENCIES protobuf::libprotobuf gRPC::grpc++_unsecure) + +add_library(${PROJECT_NAME} STATIC ${ALL_FILES}) +target_link_libraries(${PROJECT_NAME} PUBLIC ${AGONES_DEPENDENCIES}) target_include_directories(${PROJECT_NAME} PUBLIC - $ - $ - $ + $ + $ + $ ) # Fix compiler warnings # https://github.com/protocolbuffers/protobuf/blob/master/cmake/README.md#notes-on-compiler-warnings +if (MSVC) + set(OPT_DISABLE_COMPILER_WARNINGS /wd4101 /wd4146 /wd4251 /wd4661) + target_compile_options(${PROJECT_NAME} PUBLIC ${OPT_DISABLE_COMPILER_WARNINGS}) +endif() # Export header include(GenerateExportHeader) set(EXPORT_HEADER "${PROJECT_NAME}_export.h") generate_export_header(${PROJECT_NAME} EXPORT_FILE_NAME ${EXPORT_HEADER} DEFINE_NO_DEPRECATED) -# Global header -set(GLOBAL_HEADER "${PROJECT_NAME}_global.h") -set(GLOBAL_CONFIG_CONTENT "") -if (AGONES_BUILD_SHARED) - set(GLOBAL_CONFIG_CONTENT "\ -// Dynamic linkage require macro for protobuf\n\ -#ifndef PROTOBUF_USE_DLLS\n\ -#define PROTOBUF_USE_DLLS\n\ -#endif\n" - ) -endif() -configure_file(cmake/${GLOBAL_HEADER}.in ${GLOBAL_HEADER} @ONLY) - -if(MSVC) - add_definitions(/FI"${GLOBAL_HEADER}") -else() - # GCC or Clang - add_definitions(-include ${GLOBAL_HEADER}) -endif() - # CMake package generation include(CMakePackageConfigHelpers) -if (AGONES_CREATE_PACKAGE) - set(_INCLUDE_DIRS "include") - set(_CMAKE_CONFIG_DESTINATION "cmake") +set(_INCLUDE_DIRS "include") +set(_CMAKE_CONFIG_DESTINATION "cmake") - # If gRPC is built from source (not from package), then we need to redistribute gRPC and it dependencies - if (NOT GRPC_IS_INSTALLED) - # gRPC headers - install(DIRECTORY ${grpc_SOURCE_DIR}/include/ DESTINATION ${_INCLUDE_DIRS}) - # Protobuf headers - install(DIRECTORY ${grpc_SOURCE_DIR}/third_party/protobuf/src/ DESTINATION ${_INCLUDE_DIRS} FILES_MATCHING PATTERN "*.h") - # gRPC and it dependencies - if (NOT AGONES_BUILD_SHARED) - install(TARGETS ${AGONES_GRPC_TARGETS} EXPORT gRPC - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION ${_INCLUDE_DIRS} - ) - endif() - endif() - - # Config for find_package - configure_package_config_file( +# Config for find_package +configure_package_config_file( cmake/${PROJECT_NAME}Config.cmake.in ${PROJECT_NAME}Config.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/${_CMAKE_CONFIG_DESTINATION} PATH_VARS _INCLUDE_DIRS PROJECT_VERSION - NO_SET_AND_CHECK_MACRO - ) - # Build artifacts - install(TARGETS ${PROJECT_NAME} ${AGONES_GRPC_TARGETS} EXPORT ${PROJECT_NAME} + NO_SET_AND_CHECK_MACRO +) + +# Build artifacts +install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin INCLUDES DESTINATION ${_INCLUDE_DIRS} - ) - install(EXPORT ${PROJECT_NAME} DESTINATION ${_CMAKE_CONFIG_DESTINATION} FILE ${PROJECT_NAME}Targets.cmake) - # Package config - install( +) +install(EXPORT ${PROJECT_NAME} DESTINATION ${_CMAKE_CONFIG_DESTINATION} FILE ${PROJECT_NAME}Targets.cmake) +# Package config +install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake DESTINATION ${_CMAKE_CONFIG_DESTINATION} - ) - # Agones header files - install( - FILES ${HEADER_FILES} "${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_HEADER}" "${CMAKE_CURRENT_BINARY_DIR}/${GLOBAL_HEADER}" +) +# Agones header files +install( + FILES ${HEADER_FILES} "${CMAKE_CURRENT_BINARY_DIR}/${EXPORT_HEADER}" DESTINATION include/${PROJECT_NAME} - ) - # Google header files - install( +) +# Google header files +install( FILES ${GOOGLE_HEADER_FILES} DESTINATION include/google/api - ) - # PDB file - if (AGONES_BUILD_SHARED) - install(FILES $ DESTINATION bin CONFIGURATIONS Debug OPTIONAL) - install(FILES $ DESTINATION bin CONFIGURATIONS Debug OPTIONAL) - endif() - - unset(_INCLUDE_DIRS) - unset(_CMAKE_CONFIG_DESTINATION) -else() # Package is created with absolute pathes in build folder - # Use agones and thirdparty include directories - set(_INCLUDE_DIRS - "${CMAKE_CURRENT_LIST_DIR}/include" - "${grpc_SOURCE_DIR}/include" - "${grpc_SOURCE_DIR}/third_party/protobuf/src" - ) - set(_CMAKE_CONFIG_DESTINATION "${CMAKE_BINARY_DIR}") +) - configure_package_config_file( - cmake/${PROJECT_NAME}Config.cmake.in - "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - INSTALL_DESTINATION ${_CMAKE_CONFIG_DESTINATION} - PATH_VARS _INCLUDE_DIRS PROJECT_VERSION - NO_SET_AND_CHECK_MACRO - ) - export(TARGETS ${PROJECT_NAME} ${AGONES_GRPC_TARGETS} FILE "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") - # Register SDK local artifacts in system https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#package-registry-example - #export(PACKAGE ${PROJECT_NAME}) +unset(_INCLUDE_DIRS) +unset(_CMAKE_CONFIG_DESTINATION) - unset(_INCLUDE_DIRS) - unset(_CMAKE_CONFIG_DESTINATION) -endif(AGONES_CREATE_PACKAGE) +# clang-format +find_program( + CLANG_FORMAT_APP + NAMES "clang-format" + DOC "Path to clang-format" +) +if (NOT CLANG_FORMAT_APP) + message(STATUS "clang-format not found.") +else() + message(STATUS "clang-format found: ${CLANG_FORMAT_APP}") + + set(CLANGFORMAT_INPUT) + foreach(relpath ${SDK_FILES}) + get_filename_component(fullpath "${CMAKE_CURRENT_LIST_DIR}/${relpath}" ABSOLUTE) + list(APPEND CLANGFORMAT_INPUT ${fullpath}) + endforeach() + + # format + add_custom_target( + clang-format-apply + COMMAND ${CLANG_FORMAT_APP} -i --style=file --fallback-style=Google ${CLANGFORMAT_INPUT} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + add_dependencies(${PROJECT_NAME} "clang-format-apply") + + # verification + set(CLANGFORMAT_WORKING_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + get_filename_component(AGONES_ROOT "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE) + configure_file("cmake/clang-verify.in" "clang-format/CMakeLists.txt" @ONLY) + add_custom_target( + clang-format-verify + COMMAND ${CMAKE_COMMAND} . + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/clang-format" + ) +endif() diff --git a/sdks/cpp/Makefile b/sdks/cpp/Makefile index 71cc050ea7..bf507c561e 100644 --- a/sdks/cpp/Makefile +++ b/sdks/cpp/Makefile @@ -26,7 +26,10 @@ build: -mkdir $(build_path) cd $(build_path) && cmake .. -DCMAKE_BUILD_TYPE=Release -DAGONES_SILENT_OUTPUT=ON -G "Unix Makefiles" -Wno-dev -DCMAKE_INSTALL_PREFIX=.install cd $(build_path) && cmake --build . --target install -- -s - + +verify: + cd $(build_path)/clang-format && cmake . -DAGONES_SILENT_OUTPUT=ON + install: cp -r $(build_path)/.install $(install_path) diff --git a/sdks/cpp/build_scripts/build.sh b/sdks/cpp/build_scripts/build.sh old mode 100644 new mode 100755 diff --git a/sdks/cpp/build_scripts/msvs_2017_x64_release.bat b/sdks/cpp/build_scripts/msvs_2017_x64_release.bat index e56429ba06..9c586fb432 100644 --- a/sdks/cpp/build_scripts/msvs_2017_x64_release.bat +++ b/sdks/cpp/build_scripts/msvs_2017_x64_release.bat @@ -17,6 +17,6 @@ pushd .. if not exist ".build" md ".build" pushd ".build" cmake .. -G "Visual Studio 15 2017 Win64" -DCMAKE_INSTALL_PREFIX=./install -Wno-dev -cmake --build . --config Release --target INSTALL +cmake --build . --config Release --target install popd popd diff --git a/sdks/cpp/cmake/Fetch_gRPC.cmake b/sdks/cpp/cmake/Fetch_gRPC.cmake deleted file mode 100644 index 4701b1ad2d..0000000000 --- a/sdks/cpp/cmake/Fetch_gRPC.cmake +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2019 Google LLC All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cmake_minimum_required (VERSION 3.12.0) - -include(FetchContent) - -set(GRPC_GIT_REPO "https://github.com/grpc/grpc.git") -set(GRPC_GIT_TAG "v${AGONES_GRPC_VERSION}") - -FetchContent_Declare( - grpc - GIT_REPOSITORY "${GRPC_GIT_REPO}" - GIT_TAG "${GRPC_GIT_TAG}" - PREFIX grpc - SOURCE_DIR "grpc/.src" - BINARY_DIR "grpc/.bin" - INSTALL_DIR "grpc/.install" - SUBBUILD_DIR "grpc/.subbuild" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" -) -FetchContent_GetProperties(grpc) -if (NOT grpc_POPULATED) - message("Fetching gRPC ${AGONES_GRPC_VERSION}") - FetchContent_Populate( - grpc - QUIET - GIT_REPOSITORY "${GRPC_GIT_REPO}" - GIT_TAG "${GRPC_GIT_TAG}" - PREFIX grpc - SOURCE_DIR "grpc/.src" - BINARY_DIR "grpc/.bin" - INSTALL_DIR "grpc/.install" - SUBBUILD_DIR "grpc/.subbuild" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" - ) -endif() diff --git a/sdks/cpp/cmake/agonesConfig.cmake.in b/sdks/cpp/cmake/agonesConfig.cmake.in index 64c1e609ac..9931c30205 100644 --- a/sdks/cpp/cmake/agonesConfig.cmake.in +++ b/sdks/cpp/cmake/agonesConfig.cmake.in @@ -1,10 +1,26 @@ -set(agones_VERSION 0.9.0) +# Copyright 2019 Google LLC All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set(agones_VERSION @agones_VERSION@) @PACKAGE_INIT@ set(agones_INCLUDE_DIRS @PACKAGE__INCLUDE_DIRS@) include(CMakeFindDependencyMacro) +find_dependency(protobuf CONFIG REQUIRED) +find_dependency(gRPC CONFIG REQUIRED) include("${CMAKE_CURRENT_LIST_DIR}/agonesTargets.cmake") check_required_components(agones) \ No newline at end of file diff --git a/sdks/cpp/cmake/clang-verify.in b/sdks/cpp/cmake/clang-verify.in new file mode 100644 index 0000000000..c37aec7721 --- /dev/null +++ b/sdks/cpp/cmake/clang-verify.in @@ -0,0 +1,68 @@ +# Copyright 2019 Google LLC All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required (VERSION 3.13.0) + +option(AGONES_SILENT_OUTPUT "Show only warnings/error messages" OFF) +if (AGONES_SILENT_OUTPUT) + function(message) + list(GET ARGV 0 MessageType) + list(REMOVE_AT ARGV 0) + if (MessageType STREQUAL FATAL_ERROR OR + MessageType STREQUAL SEND_ERROR OR + MessageType STREQUAL WARNING OR + MessageType STREQUAL AUTHOR_WARNING OR + NOT ${AGONES_SILENT_OUTPUT} + ) + _message(${MessageType} "${ARGV}") + endif() + endfunction() + + set(CMAKE_INSTALL_MESSAGE NEVER) + set(CMAKE_VERBOSE_MAKEFILE OFF) + set_property(GLOBAL PROPERTY RULE_MESSAGES OFF) + set_property(GLOBAL PROPERTY TARGET_MESSAGES OFF) +endif(AGONES_SILENT_OUTPUT) + +set(files @CLANGFORMAT_INPUT@) +set(workingdir @CLANGFORMAT_WORKING_DIR@) +set(root @AGONES_ROOT@) + +find_package(Git REQUIRED) +find_program( + CLANG_FORMAT_APP + NAMES "clang-format" + DOC "Path to clang-format" +) + +if (NOT CLANG_FORMAT_APP) + message(FATAL_ERROR "Could not find clang-format") +endif() + +execute_process( + COMMAND ${CLANG_FORMAT_APP} -i --style=file --fallback-style=Google ${files} + WORKING_DIRECTORY ${workingdir} +) + +foreach(source_file ${files}) + file(RELATIVE_PATH source_relative ${root} ${source_file}) + execute_process( + COMMAND ${GIT_EXECUTABLE} diff --quiet "HEAD:./${source_relative}" "./${source_relative}" + WORKING_DIRECTORY ${root} + RESULT_VARIABLE result + ) + if (NOT ${result} EQUAL 0) + message(FATAL_ERROR "clang-format code style check failed for: ${source_relative}") + endif() +endforeach() diff --git a/sdks/cpp/cmake/prerequisites.cmake b/sdks/cpp/cmake/prerequisites.cmake new file mode 100644 index 0000000000..7b29d5c1e7 --- /dev/null +++ b/sdks/cpp/cmake/prerequisites.cmake @@ -0,0 +1,179 @@ +# Copyright 2019 Google LLC All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required (VERSION 3.13.0) + +option(AGONES_BUILD_THIRDPARTY_DEBUG "Build debug version of thirdparty libraries (MSVC only)" ON) +set(AGONES_OPENSSL_CONFIG_STRING "VC-WIN64A" CACHE STRING "See https://github.com/openssl/openssl/blob/master/INSTALL for details") +set(AGONES_THIRDPARTY_INSTALL_PATH "${CMAKE_BINARY_DIR}/third_party" CACHE STRING "Path for installing third-party OpenSSL and gRPC, if they are not found with find_package") + +if (NOT MSVC) + set(AGONES_BUILD_THIRDPARTY_DEBUG FALSE) + set(AGONES_OPENSSL_CONFIG_STRING "" CACHE STRING "" FORCE) +endif() + +include(ProcessorCount) +ProcessorCount(CPU_COUNT) +if (CPU_COUNT GREATER 0 AND NOT DEFINED CMAKE_BUILD_PARALLEL_LEVEL) + set($ENV{CMAKE_BUILD_PARALLEL_LEVEL} ${CPU_COUNT}) +endif(CPU_COUNT) + +# gRPC repo and version +set(gRPC_GIT_REPO "https://github.com/gRPC/gRPC.git") +set(gRPC_GIT_TAG "v1.16.1") + +# OpenSSL required only for successful build gRPC +set(OPENSSL_GIT_REPO "https://github.com/openssl/openssl.git") +set(OPENSSL_GIT_TAG "OpenSSL_1_1_1") + +include(FetchContent) + +function(download_git_repo NAME REPO TAG) + set(BASE_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NAME}) + set(${NAME}_SOURCE_DIR "${BASE_DIR}/src") + FetchContent_Declare( + ${NAME} + GIT_REPOSITORY "${REPO}" + GIT_TAG "${TAG}" + PREFIX ${NAME} + SOURCE_DIR "${BASE_DIR}/src" + BINARY_DIR "${BASE_DIR}/.bin" + INSTALL_DIR "${BASE_DIR}/.install" + SUBBUILD_DIR "${BASE_DIR}/.build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) + FetchContent_GetProperties(${NAME}) + if (NOT ${NAME}_POPULATED) + message("Fetching ${NAME} ${TAG}") + FetchContent_Populate( + ${NAME} + QUIET + GIT_REPOSITORY "${REPO}" + GIT_TAG "${TAG}" + PREFIX ${NAME} + SOURCE_DIR "${BASE_DIR}/src" + BINARY_DIR "${BASE_DIR}/.bin" + INSTALL_DIR "${BASE_DIR}/.install" + SUBBUILD_DIR "${BASE_DIR}/.build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) + endif() + set(${NAME}_SOURCE_DIR "${${NAME}_SOURCE_DIR}" CACHE PATH "Source directory for ${NAME}" FORCE) +endfunction(download_git_repo) + +function(execute_and_check WORKING_DIR) + execute_process( + COMMAND ${ARGN} + WORKING_DIRECTORY ${WORKING_DIR} + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_VARIABLE output + ) + set(OUTPUT_TYPE STATUS) + if (NOT ${result} EQUAL 0) + set(OUTPUT_TYPE FATAL_ERROR) + endif() + message(${OUTPUT_TYPE} ${output}) +endfunction() + +function(invoke_cmake_build NAME CMAKELISTS_PATH) + message(STATUS "Building ${NAME}...") + + # Build directory + set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NAME}/.bin) + set(INSTALL_DIR ${AGONES_THIRDPARTY_INSTALL_PATH}/${NAME}) + file(MAKE_DIRECTORY ${BUILD_DIR}) + + # Makefile generation + set(ARG_BUILD_TYPE "") + set(ARG_CONFIG_DEBUG "--config" "Debug") + set(ARG_CONFIG_RELEASE "--config" "Release") + if (NOT ${CMAKE_BUILD_TYPE} STREQUAL "") + set(ARG_BUILD_TYPE "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") + set(ARG_CONFIG_DEBUG "") + set(ARG_CONFIG_RELEASE "") + endif() + + execute_and_check(${BUILD_DIR} ${CMAKE_COMMAND} ${CMAKELISTS_PATH} -G ${CMAKE_GENERATOR} -Wno-dev ${ARG_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} -DCMAKE_MODULE_PATH=${AGONES_THIRDPARTY_INSTALL_PATH} -DCMAKE_PREFIX_PATH=${AGONES_THIRDPARTY_INSTALL_PATH} ${ARGN}) + + # Building + if (AGONES_BUILD_THIRDPARTY_DEBUG) + execute_and_check(${BUILD_DIR} ${CMAKE_COMMAND} --build . ${ARG_CONFIG_DEBUG} --target install) + endif() + + execute_and_check(${BUILD_DIR} ${CMAKE_COMMAND} --build . ${ARG_CONFIG_RELEASE} --target install) + set(${NAME}_DIR "${INSTALL_DIR}" CACHE PATH "CMake package directory for ${NAME}" FORCE) +endfunction(invoke_cmake_build) + +find_package(gRPC CONFIG QUIET) +find_package(OpenSSL QUIET) + +# OpenSSL // Required only for gRPC build. Do not build, if gRPC is found. +if (NOT ${OpenSSL_FOUND} AND NOT ${gRPC_FOUND}) + set(OPENSSL_ROOT_DIR "${AGONES_THIRDPARTY_INSTALL_PATH}/OpenSSL" CACHE PATH "OpenSSL root directory" FORCE) + find_package(OpenSSL QUIET) + if (NOT ${OpenSSL_FOUND}) + download_git_repo(openssl ${OPENSSL_GIT_REPO} ${OPENSSL_GIT_TAG}) + message(STATUS "Building OpenSSL... ${AGONES_OPENSSL_CONFIG_STRING}") + if (WIN32) + execute_and_check(${openssl_SOURCE_DIR} perl Configure ${AGONES_OPENSSL_CONFIG_STRING} "--prefix=${OPENSSL_ROOT_DIR}" "--openssldir=${OPENSSL_ROOT_DIR}") + execute_and_check(${openssl_SOURCE_DIR} nmake) + execute_and_check(${openssl_SOURCE_DIR} nmake install) + else() + execute_and_check(${openssl_SOURCE_DIR} "./config" "--prefix=${OPENSSL_ROOT_DIR}" "--openssldir=${OPENSSL_ROOT_DIR}") + execute_and_check(${openssl_SOURCE_DIR} make) + execute_and_check(${openssl_SOURCE_DIR} make install) + endif() + endif() +endif() + +# gRPC +if (NOT ${gRPC_FOUND}) + download_git_repo(gRPC ${gRPC_GIT_REPO} ${gRPC_GIT_TAG}) + file(MAKE_DIRECTORY ${AGONES_THIRDPARTY_INSTALL_PATH}) + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${AGONES_THIRDPARTY_INSTALL_PATH}) + + # Build gRPC prerequisites + invoke_cmake_build(zlib ${gRPC_SOURCE_DIR}/third_party/zlib) + set(ZLIB_ROOT "${zlib_DIR}" CACHE PATH "ZLIB root dir for find_package" FORCE) + invoke_cmake_build(c-ares ${gRPC_SOURCE_DIR}/third_party/cares/cares) + invoke_cmake_build(Protobuf ${gRPC_SOURCE_DIR}/third_party/protobuf/cmake + "-DZLIB_ROOT=${zlib_DIR}" + "-Dprotobuf_MSVC_STATIC_RUNTIME=OFF" + "-Dprotobuf_BUILD_TESTS=OFF" + ) + + # Build gRPC as cmake package + set(OPENSSL_PARAM "") + if (DEFINED OPENSSL_ROOT_DIR) + set(OPENSSL_PARAM "-DOPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR}") + endif() + invoke_cmake_build(gRPC ${gRPC_SOURCE_DIR} + "${OPENSSL_PARAM}" + "-DZLIB_ROOT=${zlib_DIR}" + "-DgRPC_INSTALL=ON" + "-DgRPC_BUILD_TESTS=OFF" + "-DgRPC_PROTOBUF_PROVIDER=package" + "-DgRPC_PROTOBUF_PACKAGE_TYPE=CONFIG" + "-DgRPC_ZLIB_PROVIDER=package" + "-DgRPC_CARES_PROVIDER=package" + "-DgRPC_SSL_PROVIDER=package" + ) +endif() \ No newline at end of file diff --git a/sdks/cpp/sources.cmake b/sdks/cpp/sources.cmake index 24a09f9596..f8c89e64ca 100644 --- a/sdks/cpp/sources.cmake +++ b/sdks/cpp/sources.cmake @@ -1,27 +1,35 @@ set(SOURCE_FILES - src/agones/sdk.cc - src/agones/sdk.grpc.pb.cc - src/agones/sdk.pb.cc - - src/google/annotations.pb.cc - src/google/http.pb.cc + src/agones/sdk.cc ) set(HEADER_FILES - include/agones/sdk.h - include/agones/sdk.grpc.pb.h - include/agones/sdk.pb.h + include/agones/sdk.h ) -set(GOOGLE_HEADER_FILES - include/google/api/annotations.pb.h - include/google/api/http.pb.h +set(GENERATED_SOURCE_FILES + src/agones/sdk.grpc.pb.cc + src/agones/sdk.pb.cc + src/google/annotations.pb.cc + src/google/http.pb.cc +) + +set(GENERATED_HEADER_FILES + include/agones/sdk.grpc.pb.h + include/agones/sdk.pb.h + include/google/api/annotations.pb.h + include/google/api/http.pb.h ) set(ALL_FILES - ${SOURCE_FILES} - ${HEADER_FILES} - ${GOOGLE_HEADER_FILES} - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_export.h" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_global.h" + ${SOURCE_FILES} + ${HEADER_FILES} + ${GENERATED_SOURCE_FILES} + ${GENERATED_HEADER_FILES} + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_export.h" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_global.h" ) + +set(SDK_FILES + ${SOURCE_FILES} + ${HEADER_FILES} +) \ No newline at end of file diff --git a/site/content/en/docs/Guides/Client SDKs/cpp.md b/site/content/en/docs/Guides/Client SDKs/cpp.md index a5fa692cb0..2d0358ad97 100644 --- a/site/content/en/docs/Guides/Client SDKs/cpp.md +++ b/site/content/en/docs/Guides/Client SDKs/cpp.md @@ -91,7 +91,6 @@ status = sdk->SetAnnotation("test-annotation", "test value"); if (!status.ok()) { ... } ``` - To get the details on the [backing `GameServer`]({{< relref "_index.md#gameserver" >}}) call `sdk->GameServer(&gameserver)`, passing in a `stable::agones::dev::sdk::GameServer*` to push the results of the `GameServer` configuration into. @@ -127,46 +126,56 @@ When running on Agones, the above functions should only fail under exceptional c file a bug if it occurs. ### Building the Libraries from source -CMake is used to build SDK for all platforms. It is possible to build SDK as a static or dynamic library. +CMake is used to build SDK for all supported platforms (Linux/Window/MacOS). ## Prerequisites * CMake >= 3.13.0 * Git * C++14 compiler +Agones SDK depends on [gRPC](https://github.com/grpc/grpc/blob/master/BUILDING.md). If CMake can't find gRPC with find_package(), it download and build gRPC. +There are some extra prerequisites for OpenSSL on Windows, see [documentation](https://github.com/openssl/openssl/blob/master/NOTES.WIN): +* Perl +* NASM + +Note that OpenSSL is not used in Agones SDK, but it required to have full successfull build of gRPC. + ## Options -Following options are available -- **AGONES_BUILD_SHARED** (default is OFF) - build sdk as a shared library. -- **AGONES_CREATE_PACKAGE** (default is ON) - create an "install" step, to create a cmake package. +Following options are available: +- **AGONES_THIRDPARTY_INSTALL_PATH** (default is ${CMAKE_BINARY_DIR}/third_party) - this path will be used to build and install Agones prerequisites, if they are not found by find_package. + +Windows only: +- **AGONES_BUILD_THIRDPARTY_DEBUG** (default is ON) - build both debug and release versions of SDK's prerequisities. Option is not used if you already have built gRPC. +- **AGONES_OPENSSL_CONFIG_STRING** (default is VC-WIN64A) - arguments to configure OpenSSL build ([documentation](https://github.com/openssl/openssl/blob/master/INSTALL)). Used only if OpenSSL and gRPC is built by Agones. + +## Linux / MacOS +``` +mkdir -p .build +cd .build +cmake .. -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=./install +cmake --build . --target install +``` ## Windows Building with Visual Studio: ``` md .build cd .build -cmake .. -G "Visual Studio 15 2017 Win64" -Wno-dev -cmake --build . --config Release +cmake .. -G "Visual Studio 15 2017 Win64" -DCMAKE_INSTALL_PREFIX=./install +cmake --build . --config Release --target install ``` Building with NMake ``` md .build cd .build -cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -Wno-dev -cmake --build . -``` - -## Linux / MacOS -``` -mkdir -p .build -cd .build -cmake .. -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -Wno-dev -cmake --build . +cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./install +cmake --build . --target install ``` ## Remarks +**CMAKE_INSTALL_PREFIX** may be skipped if it is OK to install Agones SDK to default location (usually /usr/local or c:/Program Files/Agones). CMake option `-Wno-dev` is specified to suppress [CMP0048](https://cmake.org/cmake/help/v3.13/policy/CMP0048.html) deprecation warning for gRPC dependency. ### Using SDK In CMake-based projects it's enough to specify a folder where SDK is installed with `CMAKE_PREFIX_PATH` and use `find_package(agones CONFIG REQUIRED)` command. For example: {{< ghlink href="examples/cpp-simple" >}}cpp-simple{{< / >}}. -If **AGONES_CREATE_PACKAGE** option is off, then `CMAKE_PREFIX_PATH` should be set to a path where SDK is built (usually `agones/sdks/cpp/.build`). It maybe useful to disable some [protobuf warnings](https://github.com/protocolbuffers/protobuf/blob/master/cmake/README.md#notes-on-compiler-warnings) in your project.