From 51b92bbf909343c9a92de53e1be89851ad352b1d Mon Sep 17 00:00:00 2001 From: pradeep Date: Mon, 26 Jul 2021 12:09:41 +0530 Subject: [PATCH 1/2] CMake presets for easy dev setups Presets can be only used if you are using cmake 3.20 --- CMakePresets.json | 120 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 CMakePresets.json diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..fbc3bf8 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,120 @@ +{ + "version": 2, + "cmakeMinimumRequired": { + "major": 3, + "minor": 20, + "patch": 0 + }, + "configurePresets": [ + { + "name": "ninja-gl-glfw3-debug", + "description": "Forge build with OpenGL backend using GLFW in Debug configuration", + "binaryDir": "${sourceDir}/build/${presetName}", + "generator": "Ninja", + "cacheVariables": { + "CMAKE_BUILD_TYPE": { + "type": "String", + "value": "Debug" + }, + "FG_RENDERING_BACKEND": { + "type": "String", + "value": "OpenGL" + }, + "FG_USE_WINDOW_TOOLKIT": { + "type": "String", + "value": "glfw3" + }, + "FG_BUILD_DOCS": { + "type": "BOOL", + "value": "OFF" + }, + "FG_BUILD_EXAMPLES": { + "type": "BOOL", + "value": "ON" + }, + "FG_WITH_FREEIMAGE": { + "type": "BOOL", + "value": "ON" + }, + "CMAKE_INSTALL_PREFIX": { + "type": "PATH", + "value": "${sourceDir}/build/${presetName}/pkg" + } + } + }, + { + "name": "ninja-gl-glfw3-relwithdebinfo", + "description": "Build Forge using OpenGL backend and GLFW in RelWithDebInfo Configuration", + "inherits": "ninja-gl-glfw3-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "ninja-gl-sdl2-debug", + "description": "Build Forge using OpenGL backend and SDL2 in Debug Configuration", + "inherits": "ninja-gl-glfw3-debug", + "cacheVariables": { + "FG_USE_WINDOW_TOOLKIT": "sdl2" + } + }, + { + "name": "ninja-gl-sdl2-relwithdebinfo", + "description": "Build Forge using OpenGL backend and SDL2 in RelWithDebInfo Configuration", + "inherits": "ninja-gl-sdl2-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "ninja-docs", + "description": "Build Forge Documentation, needs doxygen installed", + "inherits": "ninja-gl-glfw3-debug", + "cacheVariables": { + "FG_BUILD_EXAMPLES": "OFF", + "FG_BUILD_DOCS": "ON" + } + }, + { + "name": "msvc2019-gl-glfw3", + "description": "Forge build with OpenGL backend using GLFW", + "binaryDir": "${sourceDir}/build/${presetName}", + "generator": "Visual Studio 16 2019", + "architecture": "x64", + "cacheVariables": { + "FG_RENDERING_BACKEND": { + "type": "String", + "value": "OpenGL" + }, + "FG_USE_WINDOW_TOOLKIT": { + "type": "String", + "value": "glfw3" + }, + "FG_BUILD_DOCS": { + "type": "BOOL", + "value": "OFF" + }, + "FG_BUILD_EXAMPLES": { + "type": "BOOL", + "value": "ON" + }, + "FG_WITH_FREEIMAGE": { + "type": "BOOL", + "value": "ON" + }, + "CMAKE_INSTALL_PREFIX": { + "type": "PATH", + "value": "${sourceDir}/build/${presetName}/pkg" + } + } + }, + { + "name": "msvc2019-gl-sdl2", + "description": "Forge build with OpenGL backend using SDL", + "inherits": "msvc2019-gl-glfw3", + "cacheVariables": { + "FG_USE_WINDOW_TOOLKIT": "sdl2" + } + } + ] +} From 423592e8df9bd794896df9d30d1fe9f6900337c6 Mon Sep 17 00:00:00 2001 From: pradeep Date: Mon, 26 Jul 2021 19:15:31 +0530 Subject: [PATCH 2/2] Improve offline build experience for forge developers The following common scenarios(majority we think) are covered with this change. - Developer has cloud connection always. - Developer has cloud connection for initial cmake run, but not later. - Developer has lost cloud connection for a while after the initial successful cmake run but regained the connection later. - Developer is doing an completely disconnected build using the source tarball we generate and attach to our release assets. When the developer wants to do an offline build for a specific commit other than release tags, they would have to generate the relevant source tarball themselves. The commands required to do the same can be found from the following ci workflow file in our repository. .github/workflows/release_src_artifact.yml The source tarball generation CI job has also been changed to reflect the change in external dependencies location. --- .github/workflows/release_src_artifact.yml | 1 + CMakeLists.txt | 33 +++-- CMakeModules/ForgeConfigureDepsVars.cmake | 134 +++++++++++++++++---- CMakeModules/ForgeInternalUtils.cmake | 18 +-- examples/CMakeModules/build_cl2hpp.cmake | 73 ++++++++--- src/backend/CMakeLists.txt | 8 +- 6 files changed, 187 insertions(+), 80 deletions(-) diff --git a/.github/workflows/release_src_artifact.yml b/.github/workflows/release_src_artifact.yml index e83ae58..1a6de54 100644 --- a/.github/workflows/release_src_artifact.yml +++ b/.github/workflows/release_src_artifact.yml @@ -52,6 +52,7 @@ jobs: rm -rf forge-full-${FG_VER}/.github rm forge-full-${FG_VER}/.gitmodules cd forge-full-${FG_VER}/build/ + cp -r ./examples/third_party/cl2hpp ../extern/cl2hpp shopt -s extglob rm -r !(extern) cd ./extern diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c89c9e..de1a80e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,12 +68,10 @@ if(Boost_FOUND AND NOT TARGET Boost::boost) endif(Boost_FOUND AND NOT TARGET Boost::boost) if(NOT TARGET glad::glad) # find_package(glad) failed - FetchContent_Declare( - ${glad_prefix} - GIT_REPOSITORY https://github.com/arrayfire/glad.git - GIT_TAG obj_lib - ) - fg_check_and_populate(${glad_prefix}) + fg_dep_check_and_populate(${glad_prefix} + URI https://github.com/arrayfire/glad.git + REF obj_lib + ) add_subdirectory(${${glad_prefix}_SOURCE_DIR} ${${glad_prefix}_BINARY_DIR}) add_library(forge_glad STATIC $) @@ -86,17 +84,18 @@ else() add_library(forge_glad ALIAS glad::glad) endif() -if(NOT TARGET glm::glm AND NOT TARGET glm) # find_package(glm) failed - FetchContent_Declare( - ${glm_prefix} - GIT_REPOSITORY https://github.com/g-truc/glm.git - GIT_TAG 0.9.9.8 - ) - fg_check_and_populate(${glm_prefix}) - add_library(glm INTERFACE IMPORTED) - set_target_properties(glm PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${${glm_prefix}_SOURCE_DIR}" - ) +add_library(forge_glm INTERFACE) +if(TARGET glm::glm) + target_include_directories(forge_glm + SYSTEM INTERFACE + $ + ) +else() # find_package(glm) failed + fg_dep_check_and_populate(${glm_prefix} + URI https://github.com/g-truc/glm.git + REF 0.9.9.8 + ) + target_include_directories(forge_glm INTERFACE "${${glm_prefix}_SOURCE_DIR}") endif() add_subdirectory(src/backend/common) diff --git a/CMakeModules/ForgeConfigureDepsVars.cmake b/CMakeModules/ForgeConfigureDepsVars.cmake index 4b64ebd..ee5c2fc 100644 --- a/CMakeModules/ForgeConfigureDepsVars.cmake +++ b/CMakeModules/ForgeConfigureDepsVars.cmake @@ -5,7 +5,37 @@ # The complete license agreement can be obtained at: # http://arrayfire.com/licenses/BSD-3-Clause -option(FG_BUILD_OFFLINE "Build Forge assuming there is no network" OFF) +file(DOWNLOAD + "https://github.com/arrayfire/forge/blob/v1.0.0/CMakeLists.txt" + "${Forge_BINARY_DIR}/download_copy_cmakelists.stamp" + STATUS fg_check_result + TIMEOUT 4 +) +list(GET fg_check_result 0 fg_is_connected) +if(${fg_is_connected}) + set(BUILD_OFFLINE ON) + # Turn ON disconnected flag when connected to cloud + set(FETCHCONTENT_FULLY_DISCONNECTED ON CACHE BOOL + "Disable Download/Update stages of FetchContent workflow" FORCE) + + message(STATUS "No cloud connection. Attempting offline build if dependencies are available") +else() + set(BUILD_OFFLINE OFF) + # Turn OFF disconnected flag when connected to cloud + # This is required especially in the following scenario: + # - cmake run successfully first + # - lost connection, but development can still be done + # - Now, connection regained. Hence updates should be allowed + set(FETCHCONTENT_FULLY_DISCONNECTED OFF CACHE BOOL + "Disable Download/Update stages of FetchContent workflow" FORCE) +endif() + +# Track dependencies download persistently across multiple +# cmake configure runs. *_POPULATED variables are reset for each +# cmake run to 0. Hence, this internal cache value is needed to +# check for already (from previous cmake run's) populated data +# during the current cmake run if it looses network connection. +set(FG_INTERNAL_DOWNLOAD_FLAG OFF CACHE BOOL "Dependencies Download Tracker Flag") # Override fetch content base dir before including AFfetch_content set(FETCHCONTENT_BASE_DIR "${Forge_BINARY_DIR}/extern" CACHE PATH @@ -13,7 +43,15 @@ set(FETCHCONTENT_BASE_DIR "${Forge_BINARY_DIR}/extern" CACHE PATH include(ForgeFetchContent) -macro(set_and_mark_depname var name) +mark_as_advanced( + FG_INTERNAL_DOWNLOAD_FLAG + FETCHCONTENT_BASE_DIR + FETCHCONTENT_QUIET + FETCHCONTENT_FULLY_DISCONNECTED + FETCHCONTENT_UPDATES_DISCONNECTED +) + +macro(set_and_mark_depnames_advncd var name) string(TOLOWER ${name} ${var}) string(TOUPPER ${name} ${var}_ucname) mark_as_advanced( @@ -22,31 +60,79 @@ macro(set_and_mark_depname var name) ) endmacro() -mark_as_advanced( - FETCHCONTENT_BASE_DIR - FETCHCONTENT_QUIET - FETCHCONTENT_FULLY_DISCONNECTED - FETCHCONTENT_UPDATES_DISCONNECTED -) +set_and_mark_depnames_advncd(glad_prefix "fg_glad") +set_and_mark_depnames_advncd(glm_prefix "fg_glm") -set_and_mark_depname(glad_prefix "fg_glad") -set_and_mark_depname(glm_prefix "fg_glm") +macro(fg_dep_check_and_populate dep_prefix) + set(single_args URI REF) + cmake_parse_arguments(fdcp_args "" "${single_args}" "" ${ARGN}) -if(FG_BUILD_OFFLINE) - macro(set_fetchcontent_src_dir prefix_var dep_name) - set(FETCHCONTENT_SOURCE_DIR_${${prefix_var}_ucname} - "${FETCHCONTENT_BASE_DIR}/${${prefix_var}}-src" CACHE PATH - "Source directory for ${dep_name} dependency") - mark_as_advanced(FETCHCONTENT_SOURCE_DIR_${${prefix_var}_ucname}) - endmacro() + if("${fdcp_args_URI}" STREQUAL "") + message(FATAL_ERROR [=[ + Cannot check requested dependency source's availability. + Please provide a valid URI(almost always a URL to a github repo). + Note that the above error message if for developers of Forge. + ]=]) + endif() - set_fetchcontent_src_dir(assets_prefix "glad") - set_fetchcontent_src_dir(testdata_prefix "glm") -endif() + string(FIND "${fdcp_args_REF}" "=" fdcp_has_algo_id) -macro(fg_check_and_populate prefix) - FetchContent_GetProperties(${prefix}) - if(NOT ${prefix}_POPULATED) - FetchContent_Populate(${prefix}) + if(${BUILD_OFFLINE} AND NOT ${FG_INTERNAL_DOWNLOAD_FLAG}) + if(NOT ${fdcp_has_algo_id} EQUAL -1) + FetchContent_Populate(${dep_prefix} + QUIET + URL ${fdcp_args_URI} + URL_HASH ${fdcp_args_REF} + DOWNLOAD_COMMAND \"\" + UPDATE_DISCONNECTED ON + SOURCE_DIR "${Forge_SOURCE_DIR}/extern/${dep_prefix}-src" + BINARY_DIR "${Forge_BINARY_DIR}/extern/${dep_prefix}-build" + SUBBUILD_DIR "${Forge_BINARY_DIR}/extern/${dep_prefix}-subbuild" + ) + elseif("${fdcp_args_REF}" STREQUAL "") + FetchContent_Populate(${dep_prefix} + QUIET + URL ${fdcp_args_URI} + DOWNLOAD_COMMAND \"\" + UPDATE_DISCONNECTED ON + SOURCE_DIR "${Forge_SOURCE_DIR}/extern/${dep_prefix}-src" + BINARY_DIR "${Forge_BINARY_DIR}/extern/${dep_prefix}-build" + SUBBUILD_DIR "${Forge_BINARY_DIR}/extern/${dep_prefix}-subbuild" + ) + else() + # The left over alternative is assumed to be a cloud hosted git repository + FetchContent_Populate(${dep_prefix} + QUIET + GIT_REPOSITORY ${fdcp_args_URI} + GIT_TAG ${fdcp_args_REF} + DOWNLOAD_COMMAND \"\" + UPDATE_DISCONNECTED ON + SOURCE_DIR "${Forge_SOURCE_DIR}/extern/${dep_prefix}-src" + BINARY_DIR "${Forge_BINARY_DIR}/extern/${dep_prefix}-build" + SUBBUILD_DIR "${Forge_BINARY_DIR}/extern/${dep_prefix}-subbuild" + ) + endif() + else() + if(NOT ${fdcp_has_algo_id} EQUAL -1) + FetchContent_Declare(${dep_prefix} + URL ${fdcp_args_URI} + URL_HASH ${fdcp_args_REF} + ) + elseif("${fdcp_args_REF}" STREQUAL "") + FetchContent_Declare(${dep_prefix} + URL ${fdcp_args_URI} + ) + else() + # The left over alternative is assumed to be a cloud hosted git repository + FetchContent_Declare(${dep_prefix} + GIT_REPOSITORY ${fdcp_args_URI} + GIT_TAG ${fdcp_args_REF} + ) + endif() + FetchContent_GetProperties(${dep_prefix}) + if(NOT ${dep_prefix}_POPULATED) + FetchContent_Populate(${dep_prefix}) + endif() + set(FG_INTERNAL_DOWNLOAD_FLAG ON CACHE BOOL "Dependencies Download Tracker Flag" FORCE) endif() endmacro() diff --git a/CMakeModules/ForgeInternalUtils.cmake b/CMakeModules/ForgeInternalUtils.cmake index 595e1f0..0d18d77 100644 --- a/CMakeModules/ForgeInternalUtils.cmake +++ b/CMakeModules/ForgeInternalUtils.cmake @@ -93,24 +93,8 @@ function(fg_set_target_compilation_props target) SYSTEM PRIVATE $ $ + $ ) - # As imported targets can't be aliased until CMake 3.11, below is a temporary - # work around until we move to a CMake version >= 3.11 - if(TARGET glm::glm) - target_include_directories(${target} - SYSTEM PRIVATE - $ - ) - elseif(TARGET glm) - target_include_directories(${target} - SYSTEM PRIVATE - $ - ) - else() - # Ideally it wouldn't reach here, just in case of corner case - # I couldn't think of or someother cmake bug - message(FATAL_ERROR "Please install glm dependency") - endif() target_include_directories(${target} PUBLIC $ diff --git a/examples/CMakeModules/build_cl2hpp.cmake b/examples/CMakeModules/build_cl2hpp.cmake index c8e5050..405f769 100644 --- a/examples/CMakeModules/build_cl2hpp.cmake +++ b/examples/CMakeModules/build_cl2hpp.cmake @@ -1,23 +1,56 @@ -set(cl2hpp_header +file(DOWNLOAD + "https://github.com/arrayfire/forge/blob/master/.github/LICENSE" + "${PROJECT_BINARY_DIR}/LICENSE.md" + STATUS fg_check_result + TIMEOUT 4 +) +list(GET fg_check_result 0 fg_is_connected) + +set(cl2hpp_extern_header + "${Forge_SOURCE_DIR}/extern/cl2hpp/include/CL/cl2.hpp") +set(cl2hpp_download_header "${PROJECT_BINARY_DIR}/third_party/cl2hpp/include/CL/cl2.hpp") -if (OpenCL_FOUND) - if (NOT EXISTS ${cl2hpp_header}) - set(file_url - "https://github.com/KhronosGroup/OpenCL-CLHPP/releases/download/v2.0.10/cl2.hpp") - file(DOWNLOAD ${file_url} ${cl2hpp_header} - EXPECTED_HASH MD5=c38d1b78cd98cc809fa2a49dbd1734a5 - STATUS download_result) - list(GET download_result 0 download_code) - if (NOT ${download_code} EQUAL 0) - file(REMOVE ${cl2hpp_header}) #empty file have to be removed - message(FATAL_ERROR "Failed to download cl2hpp header") + +if(${fg_is_connected} AND NOT EXISTS ${cl2hpp_download_header}) + if(EXISTS ${cl2hpp_extern_header}) + get_filename_component(download_dir ${cl2hpp_extern_header} DIRECTORY) + message(STATUS "Found cl2.hpp header at: ${download_dir}") + if (NOT TARGET OpenCL::cl2hpp) + add_library(OpenCL::cl2hpp IMPORTED INTERFACE GLOBAL) + set_target_properties(OpenCL::cl2hpp PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${download_dir}/..") + endif () + else() + message(FATAL_ERROR [=[ + Offline builds require already available cl2hpp header. Please + download the file from and place it at the below path path under + project root directory. + + Download URL: https://github.com/KhronosGroup/OpenCL-CLHPP/releases/download/v2.0.10/cl2.hpp + Target Location: extern/cl2hpp/include/CL + ]=]) + endif() +else() + # Any CMakeLists.txt file including this file should call find_package(OpenCL) + if (OpenCL_FOUND) + if (NOT EXISTS ${cl2hpp_download_header}) + set(file_url + "https://github.com/KhronosGroup/OpenCL-CLHPP/releases/download/v2.0.10/cl2.hpp") + file(DOWNLOAD ${file_url} ${cl2hpp_download_header} + EXPECTED_HASH MD5=c38d1b78cd98cc809fa2a49dbd1734a5 + STATUS download_result) + list(GET download_result 0 download_code) + if (NOT ${download_code} EQUAL 0) + file(REMOVE ${cl2hpp_download_header}) #empty file have to be removed + message(FATAL_ERROR "Failed to download cl2hpp header") + endif () + endif () + get_filename_component(download_dir ${cl2hpp_download_header} DIRECTORY) + message(STATUS "Found cl2.hpp header at: ${download_dir}") + if (NOT TARGET OpenCL::cl2hpp) + add_library(OpenCL::cl2hpp IMPORTED INTERFACE GLOBAL) + set_target_properties(OpenCL::cl2hpp PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${download_dir}/..") endif () endif () - get_filename_component(download_dir ${cl2hpp_header} DIRECTORY) - message(STATUS "Found cl2.hpp header at: ${download_dir}") - if (NOT TARGET OpenCL::cl2hpp) - add_library(OpenCL::cl2hpp IMPORTED INTERFACE GLOBAL) - set_target_properties(OpenCL::cl2hpp PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${download_dir}/..") - endif () -endif () +endif() diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt index ed63af2..c198a89 100644 --- a/src/backend/CMakeLists.txt +++ b/src/backend/CMakeLists.txt @@ -56,15 +56,19 @@ if(FG_WITH_FREEIMAGE) endif() endif() - target_link_libraries(${BkndTargetName} PRIVATE Boost::boost - forge_glad ${FREETYPE_LIBRARIES} ${CMAKE_DL_LIBS} ) +if(TARGET glad::glad) + target_link_libraries(${BkndTargetName} PRIVATE glad::glad) +else() + target_link_libraries(${BkndTargetName} PRIVATE forge_glad) +endif() + if(UNIX) target_link_libraries(${BkndTargetName} PRIVATE