From 3cef972afa573c8d0c56a832341b8b20646f3d16 Mon Sep 17 00:00:00 2001 From: Zachery Crandall Date: Fri, 17 Nov 2023 13:59:03 -0700 Subject: [PATCH] Dependency target install paths and expanding INSTALL_RPATH (#133) * Add install and build target attributes * Add dependency target install paths to package target's rpath information * Ignore some local files [skip ci] * Remove unused line [skip ci] * Remove external/tmp directory [skip ci] * Use top project for all target adding and acces (might revert later) [skip ci] * Gather dependency rpaths and add rpath guesses during find or build dependency call * Bump minimum CMake version from 3.14.7 to 3.19.7 * Remove extra install of libraries to external/tmp --- .github/workflows/integration_tests.yml | 2 +- .github/workflows/unit_test.yml | 2 +- .gitignore | 18 ++- cmake/cmaize/cmaize.cmake | 2 +- .../cmake/cmake_package_manager.cmake | 107 +++++++++++++++--- cmake/cmaize/targets/build_target.cmake | 7 ++ cmake/cmaize/targets/cmaize_target.cmake | 7 ++ cmake/cmaize/user_api/add_executable.cmake | 2 +- cmake/cmaize/user_api/add_library.cmake | 2 +- cmake/cmaize/user_api/add_package.cmake | 2 +- .../user_api/find_or_build_dependency.cmake | 27 ++++- .../utilities/replace_project_targets.cmake | 2 +- 12 files changed, 154 insertions(+), 26 deletions(-) diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index bef35a6f..becf4c0e 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - cmake: [3.14.7, latestrc] + cmake: [3.19.7, latestrc] env: cmake_version: ${{ matrix.cmake }} diff --git a/.github/workflows/unit_test.yml b/.github/workflows/unit_test.yml index 0951d036..920d3e8c 100644 --- a/.github/workflows/unit_test.yml +++ b/.github/workflows/unit_test.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - cmake: [3.14.7, 3.15.5, 3.16.3, 3.22.4, 3.23.1] + cmake: [3.19.7, 3.22.4, 3.23.1] env: cmake_version: ${{ matrix.cmake }} diff --git a/.gitignore b/.gitignore index 0d8306a9..d01abc76 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ # Build directories **/*build*/ + ## API documentation build directory docs/src/api/developer/ @@ -25,4 +26,19 @@ docs/src/api/developer/ **/*install*/ # Python virtual environments -**/*venv*/ \ No newline at end of file +**/*venv*/ + +# Build logs +**/*logs*/ + +# Scratch files +**/scratch/ + +# Local build scripts +*build*.sh + +# Integration test artifacts +tests/scripts/catch2_install +tests/scripts/install +tests/scripts/logs +tests/scripts/src diff --git a/cmake/cmaize/cmaize.cmake b/cmake/cmaize/cmaize.cmake index 99cfc4a4..0d08b182 100644 --- a/cmake/cmaize/cmaize.cmake +++ b/cmake/cmaize/cmaize.cmake @@ -37,4 +37,4 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") # endif("${isSystemDir}" STREQUAL "-1") -list(APPEND CMAKE_INSTALL_RPATH "$ORIGIN" "$ORIGIN/external/tmp") +list(APPEND CMAKE_INSTALL_RPATH "$ORIGIN") diff --git a/cmake/cmaize/package_managers/cmake/cmake_package_manager.cmake b/cmake/cmaize/package_managers/cmake/cmake_package_manager.cmake index 164d9a65..040bd9a2 100644 --- a/cmake/cmaize/package_managers/cmake/cmake_package_manager.cmake +++ b/cmake/cmaize/package_managers/cmake/cmake_package_manager.cmake @@ -327,7 +327,7 @@ cpp_class(CMakePackageManager PackageManager) # Set VERSION and SOVERSION properties on the targets foreach(_ip_TARGETS_i ${_ip_TARGETS}) CMaizeProject(get_target - "${_ip_proj}" _ip_tgt_obj_i "${_ip_TARGETS_i}" + "${_ip_top_proj}" _ip_tgt_obj_i "${_ip_TARGETS_i}" ) # Set package version @@ -342,7 +342,7 @@ cpp_class(CMakePackageManager PackageManager) # Generate individual Config.cmake components for # find_package(package COMPONENT target) foreach(_ip_TARGETS_i ${_ip_TARGETS}) - CMaizeProject(get_target "${_ip_proj}" _ip_tgt_obj_i "${_ip_TARGETS_i}") + CMaizeProject(get_target "${_ip_top_proj}" _ip_tgt_obj_i "${_ip_TARGETS_i}") set( _ip_tgt_config @@ -366,6 +366,36 @@ cpp_class(CMakePackageManager PackageManager) # "${_ip_destination_prefix}/${CMAKE_INSTALL_INCLUDEDIR}/${_ip_pkg_name}" ) + # Set each package target's installation path(s). Currently this + # sets both the bin and lib directories but realistically only + # one or the other would actually contain the target binary + set(_ip_destination_prefix_tmp "${_ip_destination_prefix}") + if(NOT "${_ip_proj_name}" STREQUAL "${_ip_top_proj_name}") + # We store a temporary destination prefix since it is only + # going to be used to determine install paths and we don't + # want to affect the _ip_destination_prefix used elsewhere + set( + _ip_destination_prefix_tmp + "${_ip_destination_prefix}/${CMAKE_INSTALL_LIBDIR}/${_ip_top_proj_name}/external" + ) + endif() + + # Get the absolute path of the temporary destination prefix + file(REAL_PATH + "${_ip_destination_prefix_tmp}" + _ip_destination_prefix_abs_path + BASE_DIRECTORY "${CMAKE_INSTALL_PREFIX}" + ) + + # Generate the install paths + set( + _ip_install_paths + "${_ip_destination_prefix_abs_path}/${CMAKE_INSTALL_BINDIR}/${_ip_pkg_name}" + "${_ip_destination_prefix_abs_path}/${CMAKE_INSTALL_LIBDIR}/${_ip_pkg_name}" + ) + CMaizeTarget(SET "${_ip_tgt_obj_i}" install_path "${_ip_install_paths}") + CMaizeTarget(SET_PROPERTY "${_ip_tgt_obj_i}" INSTALL_PATH "${_ip_install_paths}") + # Writes config file to build directory CMakePackageManager(_generate_target_config "${self}" @@ -389,6 +419,61 @@ cpp_class(CMakePackageManager PackageManager) endforeach() endforeach() + # Set INSTALL_RPATH to install paths of dependencies to ensure they + # can be found + foreach(_ip_TARGETS_i ${_ip_TARGETS}) + CMaizeProject(get_target + "${_ip_top_proj}" _ip_tgt_obj_i "${_ip_TARGETS_i}" + ) + + # Loop over each dependency. This is currently done by looking + # up the dependencies by name from the CMaizeProject, but later + # we should make each CMaize target hold references to its + # dependencies + BuildTarget(GET "${_ip_tgt_obj_i}" _dep_list depends) + foreach(dependency ${_dep_list}) + # Fetch the dependency's target object + CMaizeProject(get_target + "${_ip_top_proj}" _dep_tgt_obj "${dependency}" + ) + + # Skip the dependency if it is not managed by CMaize, since + # those won't have install path information + if("${_dep_tgt_obj}" STREQUAL "") + continue() + endif() + + # Get the install path for the dependency + CMaizeTarget(GET "${_dep_tgt_obj}" _dep_install_path install_path) + + # Turn the dependency paths into absolute paths + file(REAL_PATH + "${_ip_destination_prefix}/${CMAKE_INSTALL_LIBDIR}/${_ip_pkg_name}" + _ip_lib_path + BASE_DIRECTORY "${CMAKE_INSTALL_PREFIX}" + ) + # Replace install prefix with $ORIGIN + # We currently don't do this since we couldn't get it to work + # string(REPLACE "${_ip_lib_path}" "$ORIGIN" _dep_install_path "${_dep_install_path}") + + # While not a great way to do it, this will check if the dependency + # has any INSTALL_RPATH data. If it does, we add that data to the + # current target as well. In theory, each target should manage its + # own INSTALL_RPATH set, but for now that does not seem to be working. + CMaizeTarget(has_property "${_dep_tgt_obj}" _dep_has_install_rpath INSTALL_RPATH) + if(_dep_has_install_rpath) + CMaizeTarget(get_property "${_dep_tgt_obj}" _dep_install_rpath INSTALL_RPATH) + endif() + + # Actually append the aggregated paths to the current target's + # INSTALL_RPATH + CMaizeTarget(get_property "${_ip_tgt_obj_i}" _install_rpath INSTALL_RPATH) + list(APPEND _install_rpath ${_dep_install_path}) + list(APPEND _install_rpath ${_dep_install_rpath}) + CMaizeTarget(set_property "${_ip_tgt_obj_i}" INSTALL_RPATH "${_install_rpath}") + endforeach() + endforeach() + # Writes config file to build directory CMakePackageManager(_generate_package_config "${self}" _ip_pkg_config_in "${_ip_pkg_name}" ${_ip_TARGETS} @@ -448,7 +533,7 @@ cpp_class(CMakePackageManager PackageManager) ) # Get the current CMaize project - cpp_get_global(__gpc_proj CMAIZE_PROJECT_${PROJECT_NAME}) + cpp_get_global(__gpc_proj CMAIZE_TOP_PROJECT) foreach(__gpc_targets_i ${__gpc_targets}) CMaizeProject(get_target "${__gpc_proj}" __gpc_tgt_obj "${__gpc_targets_i}" @@ -510,24 +595,14 @@ cpp_class(CMakePackageManager PackageManager) CMakePackageManager(GET "${self}" __gpc_dependencies dependencies) cpp_map(GET "${__gpc_dependencies}" __gpc_dep_obj "${__gpc_tgt_deps_i}") - - cpp_type_of(__gpc_dep_type "${__gpc_tgt_deps_i_obj}") - if("${__gpc_dep_type}" STREQUAL "buildtarget") - Dependency(GET - "${__gpc_dep_obj}" __gpc_dep_build_tgt_name build_target - ) - - install( - TARGETS "${__gpc_dep_build_tgt_name}" - RUNTIME DESTINATION "tmp" - LIBRARY DESTINATION "tmp" - ) - endif() Dependency(GET "${__gpc_dep_obj}" __gpc_dep_build_tgt_name build_target ) + # This determines how the find_dependency call in the config + # file should be formatted, based on whether the dependency is + # a component of a package or not if("${__gpc_tgt_deps_i}" STREQUAL "${__gpc_dep_build_tgt_name}") string(APPEND __gpc_file_contents diff --git a/cmake/cmaize/targets/build_target.cmake b/cmake/cmaize/targets/build_target.cmake index aa9ce313..8caa8bcd 100644 --- a/cmake/cmaize/targets/build_target.cmake +++ b/cmake/cmaize/targets/build_target.cmake @@ -21,6 +21,13 @@ include(cmaize/targets/cmaize_target) #]] cpp_class(BuildTarget CMaizeTarget) + #[[[ + # :type: path + # + # Directory where the target binary will appear after being built. + #]] + cpp_attr(CMaizeTarget build_path) + #[[[ # :type: List[path] # diff --git a/cmake/cmaize/targets/cmaize_target.cmake b/cmake/cmaize/targets/cmaize_target.cmake index 01bd3910..516839f0 100644 --- a/cmake/cmaize/targets/cmaize_target.cmake +++ b/cmake/cmaize/targets/cmaize_target.cmake @@ -20,6 +20,13 @@ include(cmakepp_lang/cmakepp_lang) #]] cpp_class(CMaizeTarget) + #[[[ + # :type: path + # + # Directory where the target binary will be installed. + #]] + cpp_attr(CMaizeTarget install_path) + #[[[ # Creates a ``CMaizeTarget`` object to manage a target of the given name. # diff --git a/cmake/cmaize/user_api/add_executable.cmake b/cmake/cmaize/user_api/add_executable.cmake index f16e4ffe..056ae0b5 100644 --- a/cmake/cmaize/user_api/add_executable.cmake +++ b/cmake/cmaize/user_api/add_executable.cmake @@ -101,7 +101,7 @@ function(cmaize_add_executable _cae_tgt_name) ) endif() - cpp_get_global(_cae_project CMAIZE_PROJECT_${PROJECT_NAME}) + cpp_get_global(_cae_project CMAIZE_TOP_PROJECT) CMaizeProject(add_target "${_cae_project}" "${_cae_tgt_name}" "${_cae_tgt_obj}" diff --git a/cmake/cmaize/user_api/add_library.cmake b/cmake/cmaize/user_api/add_library.cmake index 0bc23088..455f938e 100644 --- a/cmake/cmaize/user_api/add_library.cmake +++ b/cmake/cmaize/user_api/add_library.cmake @@ -103,7 +103,7 @@ function(cmaize_add_library _cal_tgt_name) ) endif() - cpp_get_global(_cal_project CMAIZE_PROJECT_${PROJECT_NAME}) + cpp_get_global(_cal_project CMAIZE_TOP_PROJECT) CMaizeProject(add_target "${_cal_project}" "${_cal_tgt_name}" "${_cal_tgt_obj}" diff --git a/cmake/cmaize/user_api/add_package.cmake b/cmake/cmaize/user_api/add_package.cmake index e8d5168c..9359f8f6 100644 --- a/cmake/cmaize/user_api/add_package.cmake +++ b/cmake/cmaize/user_api/add_package.cmake @@ -61,7 +61,7 @@ endfunction() function(cmaize_add_package_cmake _capc_pkg_name) # Get the CMaize project - cpp_get_global(_capc_proj CMAIZE_PROJECT_${PROJECT_NAME}) + cpp_get_global(_capc_proj CMAIZE_TOP_PROJECT) # Get the correct package manager CMaizeProject(get_package_manager diff --git a/cmake/cmaize/user_api/find_or_build_dependency.cmake b/cmake/cmaize/user_api/find_or_build_dependency.cmake index 9ea3d523..f9e95e98 100644 --- a/cmake/cmaize/user_api/find_or_build_dependency.cmake +++ b/cmake/cmaize/user_api/find_or_build_dependency.cmake @@ -72,7 +72,6 @@ function(cmaize_find_or_build_dependency _fobd_name) # Decide which language we are building for string(TOLOWER "${_fobd_PACKAGE_MANAGER}" _fobd_PACKAGE_MANAGER_lower) - set(pm_obj "") if("${_fobd_PACKAGE_MANAGER_lower}" STREQUAL "cmake") cmaize_find_or_build_dependency_cmake( "${_fobd_name}" @@ -106,7 +105,7 @@ function(cmaize_find_or_build_dependency_cmake _fobdc_name) set(_fobdc_one_value_args VERSION) cmake_parse_arguments(_fobdc "" "${_fobdc_one_value_args}" "" ${ARGN}) - cpp_get_global(_fobdc_project CMAIZE_PROJECT_${PROJECT_NAME}) + cpp_get_global(_fobdc_project CMAIZE_TOP_PROJECT) # Create the package specification PackageSpecification(ctor _fobdc_package_specs) @@ -152,6 +151,30 @@ function(cmaize_find_or_build_dependency_cmake _fobdc_name) CMaizeProject(add_target "${_fobdc_project}" "${_fobdc_name}" "${_fobdc_tgt}" ) + + # This creates the suspected install prefix for this dependency + cpp_get_global(_fobdc_top_proj CMAIZE_TOP_PROJECT) + CMaizeProject(GET "${_fobdc_top_proj}" _fobdc_top_proj_name name) + file(REAL_PATH + "${CMAKE_INSTALL_LIBDIR}/${_fobdc_top_proj_name}/external" + _fobdc_external_prefix + BASE_DIRECTORY "${CMAKE_INSTALL_PREFIX}" + ) + + # Get the build target name for the dependency, since it is not + # necessarily the same as the name of the CMaize target + CMaizeTarget(target "${_fobdc_tgt}" _fobdc_build_tgt) + + # Create some possible paths where the dependency library will be + # installed + set( + _fobdc_install_paths + "${_fobdc_external_prefix}/lib" + "${_fobdc_external_prefix}/lib/${_fobdc_name}" + "${_fobdc_external_prefix}/lib/${_fobdc_build_tgt}" + ) + list(REMOVE_DUPLICATES _fobdc_install_paths) + CMaizeTarget(SET "${_fobdc_tgt}" install_path "${_fobdc_install_paths}") endif() # The command above will throw build errors from inside FetchContent diff --git a/cmake/cmaize/utilities/replace_project_targets.cmake b/cmake/cmaize/utilities/replace_project_targets.cmake index 77d8a2b3..50d8021b 100644 --- a/cmake/cmaize/utilities/replace_project_targets.cmake +++ b/cmake/cmaize/utilities/replace_project_targets.cmake @@ -43,7 +43,7 @@ function(cmaize_replace_project_targets _rpt_result) cpp_return("${_rpt_result}") endif() - cpp_get_global(_rpt_project CMAIZE_PROJECT_${PROJECT_NAME}) + cpp_get_global(_rpt_project CMAIZE_TOP_PROJECT) # Check if each dependency listed is a CMaizeTarget foreach(_rpt_targets_i ${_rpt_targets})