From 889fa648b58503cba5b4c52ec732e78f0045ef27 Mon Sep 17 00:00:00 2001 From: "Roscoe A. Bartlett" Date: Thu, 23 Apr 2020 17:42:54 -0600 Subject: [PATCH] Implement recursive chgrp and chmod for installed files/directories (#314, ATDV-241) This is needed to fix some permisisons problems related to that ATDM Trilinos builds (see ATDV-241). See the updated documentation and unit tests for details. Other things I did as part of this: * Options ${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE and ${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE no longer conditional (since they are enforced by recursive chmod). * Set policy CMP0082 to make install() commands run in order based on how they were executed in the CMake configure. * Added TRIBITS_DIR_IS_BASEDIR() and unit tests * Fixed numerious mispelling of "UNITEST" to "UNITTEST". * Refectored some other installation-cleanup code to by extracting some functions. --- test/core/CMakeLists.txt | 2 +- test/core/ExamplesUnitTests/CMakeLists.txt | 285 +++++++++++++++++- .../append_file_with_line.sh | 6 + .../core/TestingFunctionMacro_UnitTests.cmake | 139 ++++++--- .../CMakeLists.txt | 17 ++ .../installation/cmake_pbp_install.cmake.in | 18 +- ...t_installed_group_and_permissions.cmake.in | 89 ++++++ .../package_arch/TribitsAddExecutable.cmake | 3 +- ...TribitsAddInstallGroupAndPermsFixups.cmake | 57 ++++ .../package_arch/TribitsCMakePolicies.cmake | 3 + .../package_arch/TribitsGlobalMacros.cmake | 133 ++++++-- .../package_arch/TribitsLibraryMacros.cmake | 11 +- .../core/utils/TribitsFilepathHelpers.cmake | 96 ++++++ .../build_ref/TribitsBuildReferenceBody.rst | 90 ++++-- .../TribitsDevelopersGuide.rst | 96 +++++- .../with_subpackages/b/CMakeLists.txt | 7 + .../with_subpackages/b/stuff/exec_script.sh | 2 + .../with_subpackages/b/stuff/regular_file.txt | 1 + 18 files changed, 940 insertions(+), 115 deletions(-) create mode 100755 test/core/ExamplesUnitTests/append_file_with_line.sh create mode 100644 tribits/core/add_install_group_and_perms_fixups/CMakeLists.txt create mode 100644 tribits/core/installation/set_installed_group_and_permissions.cmake.in create mode 100644 tribits/core/package_arch/TribitsAddInstallGroupAndPermsFixups.cmake create mode 100644 tribits/core/utils/TribitsFilepathHelpers.cmake create mode 100755 tribits/examples/TribitsExampleProject/packages/with_subpackages/b/stuff/exec_script.sh create mode 100644 tribits/examples/TribitsExampleProject/packages/with_subpackages/b/stuff/regular_file.txt diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt index 22ff650fc..1af4cb454 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -49,7 +49,7 @@ TRIBITS_ADD_ADVANCED_TEST( TestingFunctionMacro_UnitTests -D${PROJECT_NAME}_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} -P "${CMAKE_CURRENT_SOURCE_DIR}/TestingFunctionMacro_UnitTests.cmake" PASS_REGULAR_EXPRESSION_ALL - "Final UnitTests Result: num_run = 590" + "Final UnitTests Result: num_run = 598" "Final UnitTests Result: PASSED" ) diff --git a/test/core/ExamplesUnitTests/CMakeLists.txt b/test/core/ExamplesUnitTests/CMakeLists.txt index de62aec87..6de60dd76 100644 --- a/test/core/ExamplesUnitTests/CMakeLists.txt +++ b/test/core/ExamplesUnitTests/CMakeLists.txt @@ -190,7 +190,7 @@ TRIBITS_ADD_ADVANCED_TEST( TribitsHelloWorld_InSourceBuildErrors "exists from a likely prior attempt to do an in-source build" "" ALWAYS_FAIL_ON_ZERO_RETURN - + ) @@ -568,6 +568,9 @@ TRIBITS_ADD_ADVANCED_TEST( TribitsHelloWorld_install_perms TEST_7 MESSAGE "Re-install" CMND make ARGS ${CTEST_BUILD_FLAGS} install + PASS_REGULAR_EXPRESSION_ALL + "Installing: .*/TriBITS_TribitsHelloWorld_install_perms/install/bin/hello_world.exe" + "0: Running: chmod o[+]rX -R /.*/TriBITS_TribitsHelloWorld_install_perms/install" ALWAYS_FAIL_ON_NONZERO_RETURN TEST_8 @@ -1304,6 +1307,278 @@ TRIBITS_ADD_ADVANCED_TEST( TribitsExampleProject_ALL_ST_NoFortran ) +IF (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + + EXECUTE_PROCESS(COMMAND whoami + OUTPUT_STRIP_TRAILING_WHITESPACE + OUTPUT_VARIABLE TribitsExProj_INSTALL_OWNING_USER) + + IF ("${TribitsExProj_INSTALL_OWNING_GROUP}" STREQUAL "") + EXECUTE_PROCESS(COMMAND id -gn + OUTPUT_STRIP_TRAILING_WHITESPACE + OUTPUT_VARIABLE TribitsExProj_INSTALL_OWNING_GROUP) + ENDIF() + +ENDIF() + + +TRIBITS_ADD_ADVANCED_TEST( TribitsExampleProject_install_perms + OVERALL_WORKING_DIRECTORY TEST_NAME + OVERALL_NUM_MPI_PROCS 1 + XHOSTTYPE Windows + + TEST_0 + MESSAGE "Copy TribitsExampleProject so we can change the source permissions" + CMND cp + ARGS -r ${${PROJECT_NAME}_TRIBITS_DIR}/examples/TribitsExampleProject . + + TEST_1 + MESSAGE "Make TribitsExampleProject source dir user rwX only!" + CMND chmod + ARGS g-rwx,o-rwx -R TribitsExampleProject + + TEST_2 + MESSAGE "Do initial configure with just libs not tests with default install settings" + CMND ${CMAKE_COMMAND} + ARGS + ${TribitsExampleProject_COMMON_CONFIG_ARGS} + -DTribitsExProj_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj_ENABLE_WithSubpackages=ON + -DCMAKE_INSTALL_PREFIX=install_base/install + -DTribitsExProj_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR=install_base + -DTribitsExProj_MAKE_INSTALL_WORLD_READABLE=TRUE + -DTribitsExProj_MAKE_INSTALL_GROUP_WRITABLE=TRUE + -DTribitsExProj_MAKE_INSTALL_GROUP=${TribitsExProj_INSTALL_OWNING_GROUP} + TribitsExampleProject + PASS_REGULAR_EXPRESSION_ALL + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_3 + MESSAGE "Do make to build everything" + CMND make ARGS ${CTEST_BUILD_FLAGS} + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_4 + MESSAGE "Make install with fixup of permissions" + CMND make ARGS ${CTEST_BUILD_FLAGS} install + PASS_REGULAR_EXPRESSION_ALL + ".*/install_base/install/include/wsp_c/C.hpp" + ".*/install_base/install/lib/libpws_c.a" + "0: Running: chgrp ${TribitsExProj_INSTALL_OWNING_GROUP} /.*/TriBITS_TribitsExampleProject_install_perms/install_base" + "0: Running: chmod g[+]rwX,o[+]rX /.*/TriBITS_TribitsExampleProject_install_perms/install_base" + "1: Running: chgrp ${TribitsExProj_INSTALL_OWNING_GROUP} -R /.*/TriBITS_TribitsExampleProject_install_perms/install_base/install" + "1: Running: chmod g[+]rwX,o[+]rX -R /.*/TriBITS_TribitsExampleProject_install_perms/install_base/install" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_5 + MESSAGE "Check some installed directory permissions and the owning group" + CMND ls ARGS -ld + install_base + install_base/install + install_base/install/bin + install_base/install/include + install_base/install/lib + install_base/install/share/WithSubpackagesB/stuff + PASS_REGULAR_EXPRESSION_ALL + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/install" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/install/bin" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/install/include" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/install/lib" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/install/share/WithSubpackagesB/stuff" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_6 + MESSAGE "Check some installed file permissions" + CMND ls ARGS -l + install_base/install + install_base/install/include + install_base/install/include/wsp_c + install_base/install/lib + install_base/install/bin + install_base/install/share/WithSubpackagesB/stuff + PASS_REGULAR_EXPRESSION_ALL + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* MixedLang.hpp" + "[d]rwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* wsp_c" + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* C.hpp" + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* Makefile.export.WithSubpackagesC" + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* libpws_c.a" + "[-]rwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* exec_script.sh" + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* regular_file.txt" + ALWAYS_FAIL_ON_NONZERO_RETURN + # NOTE: Above, the file Makefile.export.WithSubpackagesC seems to be the + # last file installed and therefore if it has the right permissions, then + # this final script set_installed_group_and_permissions.cmake must be + # getting called at the very end. + + TEST_7 + MESSAGE "Make sure that exec_script.sh is exectuable" + CMND ./install_base/install/share/WithSubpackagesB/stuff/exec_script.sh + PASS_REGULAR_EXPRESSION + "exec_script.sh executed and returned this string" + + ) + # NOTE: The above test checks a few important things: + # + # * The CMake install machinery will actually create multiple base dirs + # under ${CMAKE_INSTALL_PREFIX} in case they don't already exist. + # + # * The group ownership actaully will be set correctly starting with + # ${_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR} which is + # above ${CMAKE_INSTALL_PREFIX}. This is needed to address systems where + # the group sticky bit is disabled (like we see on some SNL systems, see + # ATDV-241). + # + # * Even with the source directory permissions being 'rwx------' (i.e. 700), + # the files isntalled under share/WithSubpackagesB/stuff using + # install(DIRECTORY ... USE_SOURCE_PERMISSIONS) will actually have the + # correct group and other permissions set. + + +TRIBITS_ADD_ADVANCED_TEST( TribitsExampleProject_install_package_by_package_perms + OVERALL_WORKING_DIRECTORY TEST_NAME + OVERALL_NUM_MPI_PROCS 1 + XHOSTTYPE Windows + + TEST_0 + MESSAGE "Copy TribitsExampleProject so we can change the source permissions" + CMND cp + ARGS -r ${${PROJECT_NAME}_TRIBITS_DIR}/examples/TribitsExampleProject . + + TEST_1 + MESSAGE "Break the WithSubpackagesB so that it will not install" + CMND ${CMAKE_CURRENT_SOURCE_DIR}/append_file_with_line.sh + ARGS TribitsExampleProject/packages/with_subpackages/c/C.cpp + "C.cpp is broken!" + + TEST_2 + MESSAGE "Make TribitsExampleProject source dir user rwX only!" + CMND chmod + ARGS g-rwx,o-rwx -R TribitsExampleProject + + TEST_3 + MESSAGE "Do initial configure with just libs not tests with default install settings" + CMND ${CMAKE_COMMAND} + ARGS + ${TribitsExampleProject_COMMON_CONFIG_ARGS} + -DTribitsExProj_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DTribitsExProj_ENABLE_SECONDARY_TESTED_CODE=ON + -DTribitsExProj_ENABLE_WithSubpackages=ON + -DCMAKE_INSTALL_PREFIX=install_base/subdir/install + -DTribitsExProj_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR=install_base + -DTribitsExProj_MAKE_INSTALL_WORLD_READABLE=TRUE + -DTribitsExProj_MAKE_INSTALL_GROUP_WRITABLE=TRUE + -DTribitsExProj_MAKE_INSTALL_GROUP=${TribitsExProj_INSTALL_OWNING_GROUP} + TribitsExampleProject + PASS_REGULAR_EXPRESSION_ALL + "Configuring done" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_4 + MESSAGE "Do make -k to build everything that will build" + CMND make ARGS ${CTEST_BUILD_FLAGS} + PASS_REGULAR_EXPRESSION_ALL + "C.cpp is broken" + "packages/with_subpackages/c/CMakeFiles/pws_c.dir/C.cpp.o.*Error" + ALWAYS_FAIL_ON_ZERO_RETURN + + TEST_5 + MESSAGE "Make install_pakage_by_package with fixup of permissions" + CMND make ARGS ${CTEST_BUILD_FLAGS} install_package_by_package + PASS_REGULAR_EXPRESSION_ALL + "The global install failed so resorting to package-by-package installs" + ".*/install_base/subdir/install/include/B.hpp" + ".*/install_base/subdir/install/lib/libpws_b.a" + "0: Running: chgrp ${TribitsExProj_INSTALL_OWNING_GROUP} /.*/TriBITS_TribitsExampleProject_install_package_by_package_perms/install_base" + "0: Running: chmod g[+]rwX,o[+]rX /.*/TriBITS_TribitsExampleProject_install_package_by_package_perms/install_base" + "1: Running: chgrp ${TribitsExProj_INSTALL_OWNING_GROUP} /.*/TriBITS_TribitsExampleProject_install_package_by_package_perms/install_base/subdir" + "1: Running: chmod g[+]rwX,o[+]rX /.*/TriBITS_TribitsExampleProject_install_package_by_package_perms/install_base/subdir" + "2: Running: chgrp ${TribitsExProj_INSTALL_OWNING_GROUP} -R /.*/TriBITS_TribitsExampleProject_install_package_by_package_perms/install_base/subdir/install" + "2: Running: chmod g[+]rwX,o[+]rX -R /.*/TriBITS_TribitsExampleProject_install_package_by_package_perms/install_base/subdir/install" + ALWAYS_FAIL_ON_ZERO_RETURN + + TEST_6 + MESSAGE "Check some installed directory permissions and the owning group" + CMND ls ARGS -ld + install_base + install_base/subdir + install_base/subdir/install + install_base/subdir/install/bin + install_base/subdir/install/include + install_base/subdir/install/lib + install_base/subdir/install/share/WithSubpackagesB/stuff + PASS_REGULAR_EXPRESSION_ALL + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/subdir" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/subdir/install" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/subdir/install/bin" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/subdir/install/include" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/subdir/install/lib" + "drwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* install_base/subdir/install/share/WithSubpackagesB/stuff" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_7 + MESSAGE "Check some installed file permissions" + CMND ls ARGS -l + install_base/subdir/install + install_base/subdir/install/include + install_base/subdir/install/lib + install_base/subdir/install/bin + install_base/subdir/install/share/WithSubpackagesB/stuff + PASS_REGULAR_EXPRESSION_ALL + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* MixedLang.hpp" + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* B.hpp" + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* Makefile.export.WithSubpackagesB" + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* libpws_b.a" + "[-]rwxrwxr-x.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* exec_script.sh" + "[-]rw-rw-r--.* .* ${TribitsExProj_INSTALL_OWNING_USER} ${TribitsExProj_INSTALL_OWNING_GROUP} .* regular_file.txt" + ALWAYS_FAIL_ON_NONZERO_RETURN + + TEST_8 + MESSAGE "Make sure that exec_script.sh is exectuable" + CMND ./install_base/subdir/install/share/WithSubpackagesB/stuff/exec_script.sh + PASS_REGULAR_EXPRESSION + "exec_script.sh executed and returned this string" + + ) + # NOTE: In addition to the same checks performed by the test + # TribitsExampleProject_install_perms described above, this above test also: + # + # * Ensures that the non-recursive group and permisions gets set on + # * base-dirs. + # + # * Ensures that owning group and directory permissions get set even if + # there is a package install failure. The other packages that did build + # correctly will get installed and all of the files and directories that + # did install will have the correct group and permissions. + + +TRIBITS_ADD_ADVANCED_TEST( TribitsExampleProject_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR_not_base_dir + OVERALL_WORKING_DIRECTORY TEST_NAME + OVERALL_NUM_MPI_PROCS 1 + XHOSTTYPE Windows + + TEST_0 + MESSAGE "Configure with TribitsExProj_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR not a base dir of CMAKE_INSTALL_PREFIX " + CMND ${CMAKE_COMMAND} + ARGS + ${TribitsExampleProject_COMMON_CONFIG_ARGS} + -DTribitsExProj_TRIBITS_DIR=${${PROJECT_NAME}_TRIBITS_DIR} + -DCMAKE_INSTALL_PREFIX=install_base/install + -DTribitsExProj_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR=non_base_dir + ${${PROJECT_NAME}_TRIBITS_DIR}/examples/TribitsExampleProject + PASS_REGULAR_EXPRESSION_ALL + "ERROR in TribitsExProj_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR" + "TribitsExProj_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR=.*/TriBITS_TribitsExampleProject_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR_not_base_dir/non_base_dir" + "is not a strict base dir of" + "CMAKE_INSTALL_PREFIX=.*/TriBITS_TribitsExampleProject_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR_not_base_dir/install_base/install" + ALWAYS_FAIL_ON_ZERO_RETURN + + ) + + TRIBITS_ADD_ADVANCED_TEST( TribitsExampleProject_ALL_ST_NoFortran_enable_installation_testing OVERALL_WORKING_DIRECTORY TEST_NAME OVERALL_NUM_MPI_PROCS 1 @@ -1692,7 +1967,7 @@ IF (NOT ${PROJECT_NAME}_HOSTTYPE STREQUAL "Windows") OVERALL_WORKING_DIRECTORY TEST_NAME OVERALL_NUM_MPI_PROCS 1 XHOSTTYPE Darwin - + TEST_0 CMND ${CMAKE_COMMAND} MESSAGE "Do the initial configure with basic configure timing" ARGS @@ -1715,7 +1990,7 @@ IF (NOT ${PROJECT_NAME}_HOSTTYPE STREQUAL "Windows") "Total time to configure TribitsExProj: " "Final set of enabled packages: SimpleCxx WithSubpackages 2" "Final set of enabled SE packages: SimpleCxx WithSubpackagesA WithSubpackages 3" - + TEST_1 CMND ${CMAKE_COMMAND} MESSAGE "Reconfigure to test out timing of all packages" ARGS @@ -1731,7 +2006,7 @@ IF (NOT ${PROJECT_NAME}_HOSTTYPE STREQUAL "Windows") "Total time to configure enabled packages: " "Total time to set up for CPack packaging: " "Total time to configure TribitsExProj: " - + TEST_2 CMND ${CMAKE_COMMAND} MESSAGE "Reconfigure to test out timing of just one package" ARGS @@ -1747,7 +2022,7 @@ IF (NOT ${PROJECT_NAME}_HOSTTYPE STREQUAL "Windows") "Total time to configure enabled packages: " "Total time to set up for CPack packaging: " "Total time to configure TribitsExProj: " - + ) ENDIF() diff --git a/test/core/ExamplesUnitTests/append_file_with_line.sh b/test/core/ExamplesUnitTests/append_file_with_line.sh new file mode 100755 index 000000000..cfde6be00 --- /dev/null +++ b/test/core/ExamplesUnitTests/append_file_with_line.sh @@ -0,0 +1,6 @@ +#!/bin/bash -e + +FILE_TO_EDIT=$1 +LINE_TO_ADD=$2 + +echo "$LINE_TO_ADD" >> $FILE_TO_EDIT diff --git a/test/core/TestingFunctionMacro_UnitTests.cmake b/test/core/TestingFunctionMacro_UnitTests.cmake index e19fe1402..720841f67 100644 --- a/test/core/TestingFunctionMacro_UnitTests.cmake +++ b/test/core/TestingFunctionMacro_UnitTests.cmake @@ -56,6 +56,7 @@ INCLUDE(TribitsETISupport) INCLUDE(TribitsFindPythonInterp) INCLUDE(TribitsStripQuotesFromStr) INCLUDE(TribitsStandardizePaths) +INCLUDE(TribitsFilepathHelpers) INCLUDE(TribitsGetVersionDate) INCLUDE(TribitsTplFindIncludeDirsAndLibraries) INCLUDE(TribitsReportInvalidTribitsUsage) @@ -189,7 +190,7 @@ FUNCTION(UNITTEST_TRIBITS_FIND_PYTHON_INTERP) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_STANDARDIZE_ABS_PATHS) +FUNCTION(UNITTEST_TRIBITS_STANDARDIZE_ABS_PATHS) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_STANDARDIZE_ABS_PATHS()") @@ -206,7 +207,65 @@ FUNCTION(UNITEST_TRIBITS_STANDARDIZE_ABS_PATHS) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_MISC) +FUNCTION(TRIBITS_DIR_IS_BASEDIR_TEST_CASE absBaseDir absFullDir expectedIsBaseDir) + MESSAGE("\nTRIBITS_DIR_IS_BASEDIR(\"${absBaseDir}\" \"${absFullDir}\" isBaseDir)") + TRIBITS_DIR_IS_BASEDIR("${absBaseDir}" "${absFullDir}" isBaseDir) + UNITTEST_COMPARE_CONST(isBaseDir ${expectedIsBaseDir}) +ENDFUNCTION() + + +FUNCTION(UNITTEST_TRIBITS_DIR_IS_BASEDIR) + + MESSAGE("\n***") + MESSAGE("*** Testing TRIBITS_DIR_IS_BASEDIR()") + MESSAGE("***\n") + + TRIBITS_DIR_IS_BASEDIR_TEST_CASE( + "/some/base/path" "/some/base/path" TRUE) + + TRIBITS_DIR_IS_BASEDIR_TEST_CASE( + "/some/base/path" "/some/base/path/more" TRUE) + + TRIBITS_DIR_IS_BASEDIR_TEST_CASE( + "/some/base/path" "/some/base/pathes" FALSE) + + TRIBITS_DIR_IS_BASEDIR_TEST_CASE( + "/some/base/path/more" "/some/base/path" FALSE) + + TRIBITS_DIR_IS_BASEDIR_TEST_CASE( + "/some/base/path" "/some/other/path" FALSE) + +ENDFUNCTION() + + +FUNCTION(TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR_TEST_CASE absBaseDir absFullDir + expectedTrailingDirArrayVar + ) + MESSAGE("\nTRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR(\"${absBaseDir}\" \"${absFullDir}\" trailingDirArray)") + TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR("${absBaseDir}" "${absFullDir}" trailingDirArray) + UNITTEST_COMPARE_CONST(trailingDirArray "${expectedTrailingDirArrayVar}") +ENDFUNCTION() + + +FUNCTION(UNITTEST_TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR) + + MESSAGE("\n***") + MESSAGE("*** Testing TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR()") + MESSAGE("***\n") + + TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR_TEST_CASE( + "/some/base/path" "/some/base/path" "") + + TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR_TEST_CASE( + "/some/base/path" "/some/base/path/subdir" "subdir") + + TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR_TEST_CASE( + "/some/base/path" "/some/base/path/subdir1/subdir2" "subdir1;subdir2") + +ENDFUNCTION() + + +FUNCTION(UNITTEST_TRIBITS_MISC) MESSAGE("\n***") MESSAGE("*** Testing miscellaneous TriBITS macro functionality") @@ -322,7 +381,7 @@ MACRO(UNITTEST_TRIBITS_TPL_ALLOW_PRE_FIND_PACKAGE_UNSET_VARS TPL_NAME) ENDMACRO() -FUNCTION(UNITEST_TRIBITS_STRIP_QUOTES_FROM_STR) +FUNCTION(UNITTEST_TRIBITS_STRIP_QUOTES_FROM_STR) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_STRIP_QUOTES_FROM_STR()") @@ -351,7 +410,7 @@ FUNCTION(UNITEST_TRIBITS_STRIP_QUOTES_FROM_STR) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_GET_RAW_GIT_COMMIT_UTC_TIME) +FUNCTION(UNITTEST_TRIBITS_GET_RAW_GIT_COMMIT_UTC_TIME) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_GET_RAW_GIT_COMMIT_UTC_TIME()") @@ -397,7 +456,7 @@ FUNCTION(UNITEST_TRIBITS_GET_RAW_GIT_COMMIT_UTC_TIME) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_GET_VERSION_DATE_FROM_RAW_GIT_COMMIT_UTC_TIME) +FUNCTION(UNITTEST_TRIBITS_GET_VERSION_DATE_FROM_RAW_GIT_COMMIT_UTC_TIME) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_GET_VERSION_DATE_FROM_RAW_GIT_COMMIT_UTC_TIME()") @@ -610,7 +669,7 @@ FUNCTION(UNITTEST_TRIBITS_REPORT_INVALID_TRIBITS_USAGE) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_TEST_BASIC) +FUNCTION(UNITTEST_TRIBITS_ADD_TEST_BASIC) MESSAGE("\n***") MESSAGE("*** Testing basic functionality of TRIBITS_ADD_TEST(...)") @@ -1147,7 +1206,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_TEST_BASIC) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_TEST_DISABLE) +FUNCTION(UNITTEST_TRIBITS_ADD_TEST_DISABLE) MESSAGE("\n***") MESSAGE("*** Testing test-by-test disable of TRIBITS_ADD_TEST(...)") @@ -1272,7 +1331,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_TEST_DISABLE) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_TEST_CATEGORIES) +FUNCTION(UNITTEST_TRIBITS_ADD_TEST_CATEGORIES) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_ADD_TEST( ... CATEGORIES ... )") @@ -1423,7 +1482,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_TEST_CATEGORIES) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_TEST_COMM) +FUNCTION(UNITTEST_TRIBITS_ADD_TEST_COMM) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_ADD_TEST( ... COMM ... )") @@ -1738,7 +1797,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_TEST_COMM) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_TEST_PROPERTIES) +FUNCTION(UNITTEST_TRIBITS_ADD_TEST_PROPERTIES) MESSAGE("\n***") MESSAGE("*** Testing the setting of test properties with TRIBITS_ADD_TEST(...)") @@ -1845,7 +1904,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_TEST_PROPERTIES) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_BASIC) +FUNCTION(UNITTEST_TRIBITS_ADD_ADVANCED_TEST_BASIC) MESSAGE("\n***") MESSAGE("*** Testing basic functionality of TRIBITS_ADD_ADVANCED_TEST(...)") @@ -2097,7 +2156,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_BASIC) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_CATEGORIES) +FUNCTION(UNITTEST_TRIBITS_ADD_ADVANCED_TEST_CATEGORIES) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_ADD_ADVANCED_TEST( ... CATEGORIES ... )") @@ -2560,7 +2619,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_CATEGORIES) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_COMM) +FUNCTION(UNITTEST_TRIBITS_ADD_ADVANCED_TEST_COMM) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_ADD_ADVANCED_TEST( ... COMM ... )") @@ -2655,7 +2714,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_COMM) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_NUM_MPI_PROCS) +FUNCTION(UNITTEST_TRIBITS_ADD_ADVANCED_TEST_NUM_MPI_PROCS) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_ADD_ADVANCED_TEST( ... [OVERALL_]_NUM_MPI_PROCS ... )") @@ -2936,7 +2995,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_NUM_MPI_PROCS) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_DIRECTROY) +FUNCTION(UNITTEST_TRIBITS_ADD_ADVANCED_TEST_DIRECTROY) MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_ADD_ADVANCED_TEST( ... DIRECTORY ... )") @@ -3017,7 +3076,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_DIRECTROY) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_PROPERTIES) +FUNCTION(UNITTEST_TRIBITS_ADD_ADVANCED_TEST_PROPERTIES) MESSAGE("\n***") MESSAGE("*** Testing the setting of test properties with TRIBITS_ADD_ADVANCED_TEST(...)") @@ -3084,7 +3143,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_PROPERTIES) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_COPY_FILES_TO_TEST_DIR) +FUNCTION(UNITTEST_TRIBITS_ADD_ADVANCED_TEST_COPY_FILES_TO_TEST_DIR) MESSAGE("\n***") MESSAGE("*** Testing COPY_FILES_TO_TEST_DIR with TRIBITS_ADD_ADVANCED_TEST(...)") @@ -3190,7 +3249,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_COPY_FILES_TO_TEST_DIR) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_EXCLUDES) +FUNCTION(UNITTEST_TRIBITS_ADD_ADVANCED_TEST_EXCLUDES) MESSAGE("\n***") MESSAGE("*** Testing excluding TRIBITS_ADD_ADVANCED_TEST(...) based on different criteria") @@ -3345,7 +3404,7 @@ FUNCTION(UNITEST_TRIBITS_ADD_ADVANCED_TEST_EXCLUDES) ENDFUNCTION() -FUNCTION(UNITEST_TRIBITS_ADD_EXECUTABLE_AND_TEST) +FUNCTION(UNITTEST_TRIBITS_ADD_EXECUTABLE_AND_TEST) SET(TRIBITS_ADD_EXECUTABLE_AND_TEST_TEST_MODE ON) @@ -3798,11 +3857,13 @@ MESSAGE("***\n") UNITTEST_APPEND_STRING_VAR() UNITTEST_TRIBITS_FIND_PYTHON_INTERP() -UNITEST_TRIBITS_STANDARDIZE_ABS_PATHS() -UNITEST_TRIBITS_MISC() -UNITEST_TRIBITS_STRIP_QUOTES_FROM_STR() -UNITEST_TRIBITS_GET_VERSION_DATE_FROM_RAW_GIT_COMMIT_UTC_TIME() -UNITEST_TRIBITS_GET_RAW_GIT_COMMIT_UTC_TIME() +UNITTEST_TRIBITS_STANDARDIZE_ABS_PATHS() +UNITTEST_TRIBITS_DIR_IS_BASEDIR() +UNITTEST_TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR() +UNITTEST_TRIBITS_MISC() +UNITTEST_TRIBITS_STRIP_QUOTES_FROM_STR() +UNITTEST_TRIBITS_GET_VERSION_DATE_FROM_RAW_GIT_COMMIT_UTC_TIME() +UNITTEST_TRIBITS_GET_RAW_GIT_COMMIT_UTC_TIME() UNITTEST_TRIBITS_TPL_ALLOW_PRE_FIND_PACKAGE() UNITTEST_TRIBITS_REPORT_INVALID_TRIBITS_USAGE() @@ -3813,30 +3874,30 @@ MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_ADD_TEST(...)") MESSAGE("***\n") -UNITEST_TRIBITS_ADD_TEST_BASIC() -UNITEST_TRIBITS_ADD_TEST_DISABLE() -UNITEST_TRIBITS_ADD_TEST_CATEGORIES() -UNITEST_TRIBITS_ADD_TEST_COMM() -UNITEST_TRIBITS_ADD_TEST_PROPERTIES() +UNITTEST_TRIBITS_ADD_TEST_BASIC() +UNITTEST_TRIBITS_ADD_TEST_DISABLE() +UNITTEST_TRIBITS_ADD_TEST_CATEGORIES() +UNITTEST_TRIBITS_ADD_TEST_COMM() +UNITTEST_TRIBITS_ADD_TEST_PROPERTIES() MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_ADD_ADVANCED_TEST(...)") MESSAGE("***\n") -UNITEST_TRIBITS_ADD_ADVANCED_TEST_BASIC() -UNITEST_TRIBITS_ADD_ADVANCED_TEST_CATEGORIES() -UNITEST_TRIBITS_ADD_ADVANCED_TEST_COMM() -UNITEST_TRIBITS_ADD_ADVANCED_TEST_NUM_MPI_PROCS() -UNITEST_TRIBITS_ADD_ADVANCED_TEST_DIRECTROY() -UNITEST_TRIBITS_ADD_ADVANCED_TEST_PROPERTIES() -UNITEST_TRIBITS_ADD_ADVANCED_TEST_COPY_FILES_TO_TEST_DIR() -UNITEST_TRIBITS_ADD_ADVANCED_TEST_EXCLUDES() +UNITTEST_TRIBITS_ADD_ADVANCED_TEST_BASIC() +UNITTEST_TRIBITS_ADD_ADVANCED_TEST_CATEGORIES() +UNITTEST_TRIBITS_ADD_ADVANCED_TEST_COMM() +UNITTEST_TRIBITS_ADD_ADVANCED_TEST_NUM_MPI_PROCS() +UNITTEST_TRIBITS_ADD_ADVANCED_TEST_DIRECTROY() +UNITTEST_TRIBITS_ADD_ADVANCED_TEST_PROPERTIES() +UNITTEST_TRIBITS_ADD_ADVANCED_TEST_COPY_FILES_TO_TEST_DIR() +UNITTEST_TRIBITS_ADD_ADVANCED_TEST_EXCLUDES() MESSAGE("\n***") MESSAGE("*** Testing TRIBITS_ADD_EXECUTABLE_AND_TEST(...)") MESSAGE("***\n") -UNITEST_TRIBITS_ADD_EXECUTABLE_AND_TEST() +UNITTEST_TRIBITS_ADD_EXECUTABLE_AND_TEST() MESSAGE("\n***") MESSAGE("*** Testing Explicit Template Instantiation functionality") @@ -3856,4 +3917,4 @@ MESSAGE("*** Determine final result of all unit tests") MESSAGE("***\n") # Pass in the number of expected tests that must pass! -UNITTEST_FINAL_RESULT(590) +UNITTEST_FINAL_RESULT(598) diff --git a/tribits/core/add_install_group_and_perms_fixups/CMakeLists.txt b/tribits/core/add_install_group_and_perms_fixups/CMakeLists.txt new file mode 100644 index 000000000..aca219885 --- /dev/null +++ b/tribits/core/add_install_group_and_perms_fixups/CMakeLists.txt @@ -0,0 +1,17 @@ +INCLUDE(TribitsAddInstallGroupAndPermsFixups) + +TRIBITS_ADD_INSTALL_GROUP_AND_PERMS_FIXUPS() + +# NOTE: This is a workaround for a problem with an issue with CMake where you +# must call install(SCRIPT ...) in a subdirectory added with +# add_subdirectory() in order for CMake to run that install script after all +# of the other subdirectories (which are TriBITS packages). As of CMake 3.14, +# you can set the policy set_policy(CMP0082 NEW) which would have allowed us +# to put this in the base TRIBITS_PROJECT_IMPL() macro. But since TriBITS is +# not allowed to require CMake 3.14 yet, we must use this workaround. To make +# super sure that this install(SCRIPTS ...) script will get called last, the +# policy CMP0082 is set to NEW in the TribitsCMakePolicies.cmake file. In +# automated testing of TriBITS, this seems to show that this custom script +# runs after all of the other files get installed (even with CMake 3.11) and +# passes the automated tests that ensures that the last file installed is +# given the correct permissions! At least that is what happened with TriBITS. diff --git a/tribits/core/installation/cmake_pbp_install.cmake.in b/tribits/core/installation/cmake_pbp_install.cmake.in index 2bca9a8ad..14ee7e532 100644 --- a/tribits/core/installation/cmake_pbp_install.cmake.in +++ b/tribits/core/installation/cmake_pbp_install.cmake.in @@ -4,12 +4,15 @@ # 'cmake -P cmake_install.cmake' command fails. # +set(PROJECT_BINARY_DIR @PROJECT_BINARY_DIR@) set(TRIBITS_ENABLED_PACKAGES_BINARY_DIRS @TRIBITS_ENABLED_PACKAGES_BINARY_DIRS@) -execute_process(COMMAND @CMAKE_COMMAND@ -P cmake_install.cmake +execute_process( + COMMAND @CMAKE_COMMAND@ -P "${PROJECT_BINARY_DIR}/cmake_install.cmake" RESULT_VARIABLE global_install_rtn) if (NOT global_install_rtn EQUAL 0) + message( "\n" "***\n" @@ -17,10 +20,23 @@ if (NOT global_install_rtn EQUAL 0) "***\n" "\n" ) + foreach (pkg_binary_dir ${TRIBITS_ENABLED_PACKAGES_BINARY_DIRS}) execute_process(COMMAND @CMAKE_COMMAND@ -P cmake_install.cmake WORKING_DIRECTORY ${pkg_binary_dir} RESULT_VARIABLE global_install_rtn) endforeach() message(SEND_ERROR "Error, full install failed!") + + set(set_installed_group_and_permissions_file + "${PROJECT_BINARY_DIR}/set_installed_group_and_permissions.cmake") + if (EXISTS "${set_installed_group_and_permissions_file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -P "${set_installed_group_and_permissions_file}" + RESULT_VARIABLE set_installed_rtn) + if (NOT global_install_rtn EQUAL 0) + message(SEND_ERROR "ERROR: Fixup of group and permissions filed!") + endif() + endif() + endif() diff --git a/tribits/core/installation/set_installed_group_and_permissions.cmake.in b/tribits/core/installation/set_installed_group_and_permissions.cmake.in new file mode 100644 index 000000000..196cc0c56 --- /dev/null +++ b/tribits/core/installation/set_installed_group_and_permissions.cmake.in @@ -0,0 +1,89 @@ +#!/bin/sh + +# +# Configured inputs +# + +# Base install dir and subdirs where last element in array gives CMAKE_INSTALL_PREFIX +SET(projectInstallBaseDir "@PROJECT_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR@") +SET(projectSubdirPathsArray "@PROJECT_SUBDIR_PATHS_ARRAY@") +# Group and permissions +SET(PROJECT_MAKE_INSTALL_GROUP "@PROJECT_MAKE_INSTALL_GROUP@") +SET(PROJECT_MAKE_INSTALL_PERMS_CHANGE "@PROJECT_MAKE_INSTALL_PERMS_CHANGE@") + +# Helper functions + +SET(CHMOD_CHGRP_IDX 0) + +FUNCTION(ECHO_AND_RUN_CMND) + STRING(REPLACE ";" " " CMND_STR "${ARGN}") + MESSAGE(STATUS "${CHMOD_CHGRP_IDX}: Running: ${CMND_STR}") + EXECUTE_PROCESS(COMMAND ${ARGN} RESULT_VARIABLE RTN_CODE) + IF (NOT RTN_CODE EQUAL 0) + MESSAGE(SEND_ERROR "ERROR: Above command failed!") + ENDIF() +ENDFUNCTION() + +FUNCTION(SET_DIR_OWNER_AND_PERMS dirPath recurseFlag) + + IF (NOT "${PROJECT_MAKE_INSTALL_GROUP}" STREQUAL "") + ECHO_AND_RUN_CMND( + chgrp ${PROJECT_MAKE_INSTALL_GROUP} ${recurseFlag} "${dirPath}") + ENDIF() + + IF (NOT "${PROJECT_MAKE_INSTALL_PERMS_CHANGE}" STREQUAL "") + ECHO_AND_RUN_CMND( + chmod ${PROJECT_MAKE_INSTALL_PERMS_CHANGE} ${recurseFlag} "${dirPath}") + ENDIF() + + MATH(EXPR CHMOD_CHGRP_IDX "${CHMOD_CHGRP_IDX}+1") + SET(CHMOD_CHGRP_IDX ${CHMOD_CHGRP_IDX} PARENT_SCOPE) + +ENDFUNCTION() + +# Executable script + +IF (EXISTS "${projectInstallBaseDir}") + + LIST(LENGTH projectSubdirPathsArray numSubDirs) + + # Get projectSubdirPathsArrayLessOne and CMAKE_INSTALL_PREFIX + SET(projectSubdirPathsArrayLessOne "${projectSubdirPathsArray}") + IF (numSubDirs GREATER 0) + LIST(REMOVE_AT projectSubdirPathsArrayLessOne -1) + ENDIF() + + # Loop over base dirs and set group and permissions and set CMAKE_INSTALL_PREFIX + SET(dirPath "${projectInstallBaseDir}") + IF (numSubDirs EQUAL 0) + # The base dir is CMAKE_INSTALL_PREFIX + SET(CMAKE_INSTALL_PREFIX "${dirPath}") + ELSE() + # Non-recursive set of the group and permissions + SET_DIR_OWNER_AND_PERMS("${dirPath}" "") + FOREACH(subDirEle ${projectSubdirPathsArrayLessOne}) + SET(dirPath "${dirPath}/${subDirEle}") + SET_DIR_OWNER_AND_PERMS("${dirPath}" "") + ENDFOREACH() + # Append last subdir which gives CMAKE_INSTALL_PREFIX + LIST(GET projectSubdirPathsArray -1 lastSubdir) + SET(CMAKE_INSTALL_PREFIX "${dirPath}/${lastSubdir}") + ENDIF() + + # Recursive set of group and permsisions on CMAKE_INSTALL_PREFIX + SET_DIR_OWNER_AND_PERMS("${CMAKE_INSTALL_PREFIX}" "-R") + +ELSE() + + MESSAGE(FATAL_ERROR + "" + "*** ERROR: The directory:" + "***" + "*** ${projectInstallBaseDir}" + "***" + "*** does not exist so can't fix group and permissions!" + "***" + "" + ) + +ENDIF() diff --git a/tribits/core/package_arch/TribitsAddExecutable.cmake b/tribits/core/package_arch/TribitsAddExecutable.cmake index f264a66a1..d7a18c3c8 100644 --- a/tribits/core/package_arch/TribitsAddExecutable.cmake +++ b/tribits/core/package_arch/TribitsAddExecutable.cmake @@ -326,8 +326,7 @@ INCLUDE(CMakeParseArguments) # CMake command ``INSTALL(TARGETS ...)`` is added to install # the built executable into the ``${CMAKE_INSTALL_PREFIX}/bin/`` directory # (actual install directory path is determined by -# ``${PROJECT_NAME}_INSTALL_RUNTIME_DIR``, see `Setting the install prefix at -# configure time`_) . +# ``${PROJECT_NAME}_INSTALL_RUNTIME_DIR``, see `Setting the install prefix`_). # FUNCTION(TRIBITS_ADD_EXECUTABLE EXE_NAME) diff --git a/tribits/core/package_arch/TribitsAddInstallGroupAndPermsFixups.cmake b/tribits/core/package_arch/TribitsAddInstallGroupAndPermsFixups.cmake new file mode 100644 index 000000000..011cf860f --- /dev/null +++ b/tribits/core/package_arch/TribitsAddInstallGroupAndPermsFixups.cmake @@ -0,0 +1,57 @@ +INCLUDE(Join) +INCLUDE(TribitsFilepathHelpers) + + +FUNCTION(TRIBITS_CONFIGURE_SET_INSTALLED_GROUP_AND_PERMS_FILE TARGET_FILE) + + SET(PROJECT_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR + "${${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR}") + + TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR( + "${${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR}" + "${CMAKE_INSTALL_PREFIX}" + PROJECT_SUBDIR_PATHS_ARRAY + ) + + SET(PROJECT_MAKE_INSTALL_GROUP "${${PROJECT_NAME}_MAKE_INSTALL_GROUP}") + + SET(group_perms "") + IF (${PROJECT_NAME}_MAKE_INSTALL_GROUP_WRITABLE) + SET(group_perms "g+rwX") + ELSEIF (${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE) + SET(group_perms "g+rX") + ENDIF() + + SET(other_perms "") + IF (${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE) + SET(other_perms "o+rX") + ENDIF() + + JOIN(PROJECT_MAKE_INSTALL_PERMS_CHANGE "," FALSE + ${group_perms} ${other_perms} ) + + SET(tribits_install_src + "${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}") + CONFIGURE_FILE( + "${tribits_install_src}/set_installed_group_and_permissions.cmake.in" + "${TARGET_FILE}" @ONLY ) + +ENDFUNCTION() + + +FUNCTION(TRIBITS_ADD_INSTALL_GROUP_AND_PERMS_FIXUPS) + + IF (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + + SET(set_installed_group_and_permissions_file + "${PROJECT_BINARY_DIR}/set_installed_group_and_permissions.cmake") + + TRIBITS_CONFIGURE_SET_INSTALLED_GROUP_AND_PERMS_FILE( + "${set_installed_group_and_permissions_file}" ) + + # Fix up install for default 'install' command + INSTALL(SCRIPT "${set_installed_group_and_permissions_file}") + + ENDIF() + +ENDFUNCTION() \ No newline at end of file diff --git a/tribits/core/package_arch/TribitsCMakePolicies.cmake b/tribits/core/package_arch/TribitsCMakePolicies.cmake index 23d41527e..7e99bbe80 100644 --- a/tribits/core/package_arch/TribitsCMakePolicies.cmake +++ b/tribits/core/package_arch/TribitsCMakePolicies.cmake @@ -45,3 +45,6 @@ CMAKE_POLICY(SET CMP0011 NEW) IF (POLICY CMP0053) CMAKE_POLICY(SET CMP0053 NEW) ENDIF() +IF (POLICY CMP0082) + CMAKE_POLICY(SET CMP0082 NEW) +ENDIF() diff --git a/tribits/core/package_arch/TribitsGlobalMacros.cmake b/tribits/core/package_arch/TribitsGlobalMacros.cmake index 9c8aa9231..9fdaf019a 100644 --- a/tribits/core/package_arch/TribitsGlobalMacros.cmake +++ b/tribits/core/package_arch/TribitsGlobalMacros.cmake @@ -69,6 +69,7 @@ INCLUDE(RemoveGlobalDuplicates) INCLUDE(Split) INCLUDE(TimingUtils) INCLUDE(SetDefaultAndFromEnv) # Used by some call-back files +INCLUDE(TribitsFilepathHelpers) # Standard CMake includes INCLUDE(CheckIncludeFileCXX) @@ -188,6 +189,44 @@ MACRO(TRIBITS_READ_IN_OPTIONS_FROM_FILE) ENDMACRO() +# +# Assert ${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR set +# correctly +# + +FUNCTION(ASSERT_PROJECT_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR) + + IF ( + (NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "") + AND + (NOT "${${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR}" STREQUAL "") + ) + TRIBITS_DIR_IS_BASEDIR( + "${${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR}" + "${CMAKE_INSTALL_PREFIX}" + isBaseDir) + IF (NOT isBaseDir) + MESSAGE(FATAL_ERROR + "\n" + "***\n" + "*** ERROR in ${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR!\n" + "***\n" + "\n" + "${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR=${${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR}\n" + "\n" + "is not a strict base dir of:\n" + "\n" + "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}\n" + "\n" + "Either remove ${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR from the cache or set it to be a base dir of CMAKE_INSTALL_PREFIX!\n" + "\n" + ) + ENDIF() + ENDIF() + +ENDFUNCTION() + + # # Define all of the standard global package architecture options. # @@ -273,27 +312,48 @@ MACRO(TRIBITS_DEFINE_GLOBAL_OPTIONS_AND_DEFINE_EXTRA_REPOS) "Skip the Fortran/C++ compatibility test" OFF ) - IF (NOT CMAKE_VERSION VERSION_LESS 3.11.0) + ADVANCED_SET( + ${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE + "${${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE_DEFAULT}" + CACHE BOOL + "If TRUE, the directory and file permissions on the installed directories and files will be set to world readable. NOTE: Empty '' (the default) leaves default CMake permissions in place." + ) - ADVANCED_SET( - ${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE - "${${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE_DEFAULT}" - CACHE BOOL - "If TRUE, the directory and file permissions on the installed directories and files will be set to world readable. NOTE: Empty '' (the default) leaves default CMake permissions in place." - ) - - IF ("${${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE_DEFAULT}" STREQUAL "") + ADVANCED_SET( + ${PROJECT_NAME}_MAKE_INSTALL_GROUP_WRITABLE "" + CACHE BOOL + "If TRUE, the directory and file permissions on the installed directories and files will be set to group-writable. Setting to TRUE also implies ${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE=TRUE. NOTE: Empty '' (the default) avoid adding the group write permission." + ) + + IF ("${${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE_DEFAULT}" STREQUAL "") + IF (${PROJECT_NAME}_MAKE_INSTALL_GROUP_WRITABLE) + SET(${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE_DEFAULT TRUE) + ELSE() SET(${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE_DEFAULT "${${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE}") ENDIF() - ADVANCED_SET( - ${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE - "${${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE_DEFAULT}" - CACHE BOOL - "If TRUE, the directory and file permissions on the installed directories and files will be set to group readable. Setting ${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE=ON implies this is 'ON' as well. NOTE: Empty '' (the default) leaves default CMake permissions in place." - ) - ENDIF() + ADVANCED_SET( + ${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE + "${${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE_DEFAULT}" + CACHE BOOL + "If TRUE, the directory and file permissions on the installed directories and files will be set to group readable. Setting ${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE=ON implies this is 'ON' as well. NOTE: Empty '' (the default) leaves default CMake permissions in place." + ) + + ADVANCED_SET( + ${PROJECT_NAME}_MAKE_INSTALL_GROUP "" + CACHE STRING + "If set, then the installed files and directories from ${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR on down will be given over to this owning group. The default is empty '' which means the default group will not be changed." + ) + + ADVANCED_SET( + ${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR + "${CMAKE_INSTALL_PREFIX}" + CACHE FILEPATH + "Set the base path for which a recursive chmod and chgrp will be called to set the group and permissions after the install is complete. The default directory is give by CMAKE_INSTALL_PREFIX." + ) + + ASSERT_PROJECT_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR() IF ("${${PROJECT_NAME}_SET_INSTALL_RPATH_DEFAULT}" STREQUAL "") SET(${PROJECT_NAME}_SET_INSTALL_RPATH_DEFAULT TRUE) @@ -2888,10 +2948,13 @@ ENDMACRO() # Setup for installation # -MACRO(TRIBITS_SETUP_FOR_INSTALLATION) - # Set up to install Config.cmake, Config.cmake, and export - # makefiles. +# Set up to install Config.cmake, Config.cmake, and export +# makefiles. +FUNCTION(TRIBITS_ADD_PROJECT_EXPORT_FILE_INSTALL_TARGETS) + + SET(tribits_install_src + "${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}") IF((${PROJECT_NAME}_ENABLE_INSTALL_CMAKE_CONFIG_FILES OR ${PROJECT_NAME}_ENABLE_EXPORT_MAKEFILES) @@ -2907,7 +2970,7 @@ MACRO(TRIBITS_SETUP_FOR_INSTALLATION) # where was previously installed to warn and load the new file. SET(COMPATIBILITY_CONFIG_INCLUDE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake) CONFIGURE_FILE( - ${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}/TribitsConfigInclude.cmake.in + "${tribits_install_src}/TribitsConfigInclude.cmake.in" ${COMPATIBILITY_CONFIG_INCLUDE} @ONLY ) @@ -2919,18 +2982,24 @@ MACRO(TRIBITS_SETUP_FOR_INSTALLATION) ENDIF() - # Create custom 'install/package_by_package' target +ENDFUNCTION() + + +# Create custom 'install_package_by_package' target +FUNCTION(TRIBITS_ADD_INSTALL_PACKAGE_BY_PACKAGE_TARGET) SET(TRIBITS_ENABLED_PACKAGES_BINARY_DIRS) FOREACH(TRIBITS_PACKAGE ${${PROJECT_NAME}_PACKAGES}) LIST(APPEND TRIBITS_ENABLED_PACKAGES_BINARY_DIRS "${${TRIBITS_PACKAGE}_BINARY_DIR}") ENDFOREACH() + SET(tribits_install_src + "${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}") + CONFIGURE_FILE( - ${${PROJECT_NAME}_TRIBITS_DIR}/${TRIBITS_CMAKE_INSTALLATION_FILES_DIR}/cmake_pbp_install.cmake.in + "${tribits_install_src}/cmake_pbp_install.cmake.in" cmake_pbp_install.cmake - @ONLY - ) + @ONLY ) ADVANCED_SET(${PROJECT_NAME}_INSTALL_PBP_RUNNER "" CACHE FILEPATH "Program used to run cmake -P cmake_pbp_install.cmake to change user for 'install_package_by_package' target") @@ -2941,6 +3010,22 @@ MACRO(TRIBITS_SETUP_FOR_INSTALLATION) WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) +ENDFUNCTION() + + +MACRO(TRIBITS_SETUP_FOR_INSTALLATION) + + # Set up to install Config.cmake, Config.cmake, and export + # makefiles. + TRIBITS_ADD_PROJECT_EXPORT_FILE_INSTALL_TARGETS() + + # Set up for fixing group and permissions after the install + ADD_SUBDIRECTORY("${${PROJECT_NAME}_TRIBITS_DIR}/core/add_install_group_and_perms_fixups" + add_install_group_and_perms_fixups) + + # Create custom 'install_package_by_package' target + TRIBITS_ADD_INSTALL_PACKAGE_BY_PACKAGE_TARGET() + ENDMACRO() diff --git a/tribits/core/package_arch/TribitsLibraryMacros.cmake b/tribits/core/package_arch/TribitsLibraryMacros.cmake index 0674b1b97..787a6a152 100644 --- a/tribits/core/package_arch/TribitsLibraryMacros.cmake +++ b/tribits/core/package_arch/TribitsLibraryMacros.cmake @@ -416,8 +416,8 @@ ENDFUNCTION() # By default, an install target for the library is created using # ``INSTALL(TARGETS ...)`` to install into the directory # ``${CMAKE_INSTALL_PREFIX}/lib/`` (actual install directory is given by -# ``${PROJECT}_INSTALL_LIB_DIR``, see `Setting the install prefix at configure -# time`_). However, this install target will not get created if +# ``${PROJECT}_INSTALL_LIB_DIR``, see `Setting the install prefix`_). +# However, this install target will not get created if # `${PROJECT_NAME}_INSTALL_LIBRARIES_AND_HEADERS`_ is ``FASLE`` and # ``BUILD_SHARD_LIBS=OFF``. But when ``BUILD_SHARD_LIBS=ON``, the install # target will get added. Also, this install target will *not* get added if @@ -430,10 +430,9 @@ ENDFUNCTION() # `${PROJECT_NAME}_INSTALL_LIBRARIES_AND_HEADERS`_ is ``FASLE``. If this # install target is added, then the headers get installed into the flat # directory ``${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}/`` (default is -# ``${CMAKE_INSTALL_PREFIX}/include/``, see `Setting the install prefix at -# configure time`_). If ``HEADERS_INSTALL_SUBDIR`` is set, then the headers -# will be installed under -# ``${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}//``. +# ``${CMAKE_INSTALL_PREFIX}/include/``, see `Setting the install prefix`_). +# If ``HEADERS_INSTALL_SUBDIR`` is set, then the headers will be installed +# under ``${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}//``. # # Note that an install target will *not* get created for the headers listed in # ``NOINSTALLHEADERS``. diff --git a/tribits/core/utils/TribitsFilepathHelpers.cmake b/tribits/core/utils/TribitsFilepathHelpers.cmake new file mode 100644 index 000000000..e4040c080 --- /dev/null +++ b/tribits/core/utils/TribitsFilepathHelpers.cmake @@ -0,0 +1,96 @@ +INCLUDE(MessageWrapper) +INCLUDE(Split) + +# +# @FUNCTION: TRIBITS_DIR_IS_BASEDIR() +# +# Function to determine if a given path is a base dir of another path. +# +# Usage:: +# +# TRIBITS_DIR_IS_BASEDIR( ) +# +# If the absolute path ```` is a subdir of the absolute path +# ````, then the variable ```` is set to +# ``TRUE``. Otherwise, ```` is set to ``FALSE``. +# +# For example, the output var ``isBaseDir`` would be set to ``TRUE`` in the +# following examples:: +# +# TRIBITS_DIR_IS_BASEDIR(/some/base/path /some/base/path/more isBaseDir) +# +# TRIBITS_DIR_IS_BASEDIR(/some/base/path /some/base/path isBaseDir) +# +# However, in the following examples, ``isBaseDir`` would be set to ``FALSE``:: +# +# TRIBITS_DIR_IS_BASEDIR(/some/base/path/more /some/base/path isBaseDir) +# +# TRIBITS_DIR_IS_BASEDIR(/some/base/path /some/other/path isBaseDir) +# +FUNCTION(TRIBITS_DIR_IS_BASEDIR absBaseDir absFullDir isBaseDirVarOut) + + # Assume not base dir by default unless we find it is + SET(isBaseDir FALSE) + + STRING(LENGTH "${absBaseDir}" absBaseDirLen) + STRING(LENGTH "${absFullDir}" absFullDirLen) + + IF (absBaseDir STREQUAL absFullDir) + SET(isBaseDir TRUE) + ELSEIF (NOT absBaseDirLen GREATER absFullDirLen) + STRING(FIND "${absFullDir}" "${absBaseDir}/" baseDirIdx) + IF (baseDirIdx EQUAL 0) + SET(isBaseDir TRUE) + ENDIF() + ENDIF() + + SET(${isBaseDirVarOut} ${isBaseDir} PARENT_SCOPE) + +ENDFUNCTION() + + +# +# @FUNCTION: TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR() +# +# Returns the array of directories below a base directory. +# +# Usage:: +# +# TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR( +# ) +# +# The following show examples of what this returns: +# +# TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR("/a/b/c" "/a/b/c", dirArray) +# => dirArray = "" +# +# TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR("/a/b/c" "/a/b/c/d", dirArray) +# => dirArray = "d" +# +# TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR("/a/b/c" "/a/b/c/d/e", dirArray) +# => dirArray = "d;e" +# +FUNCTION(TRIBITS_GET_DIR_ARRAY_BELOW_BASE_DIR absBaseDir absFullDir + trailingDirArrayVarOut + ) + + TRIBITS_DIR_IS_BASEDIR("${absBaseDir}" "${absFullDir}" isBaseDir) + IF (NOT isBaseDir) + MESSAGE_WRAPPER(FATAL_ERROR + "ERROR: '${absBaseDir}' is not a base dir of '${absFullDir}'") + ENDIF() + + STRING(LENGTH "${absBaseDir}" absBaseDirLen) + STRING(LENGTH "${absFullDir}" absFullDirLen) + + IF (absBaseDirLen EQUAL absFullDirLen) + SET(trailingDirArray "") + ELSE() + MATH(EXPR trailingDirsStrStartIdx "${absBaseDirLen}+1") + STRING(SUBSTRING "${absFullDir}" ${trailingDirsStrStartIdx} -1 trailingDirsStr) + SPLIT("${trailingDirsStr}" "/" trailingDirArray) + ENDIF() + + SET(${trailingDirArrayVarOut} "${trailingDirArray}" PARENT_SCOPE) + +ENDFUNCTION() diff --git a/tribits/doc/build_ref/TribitsBuildReferenceBody.rst b/tribits/doc/build_ref/TribitsBuildReferenceBody.rst index c9fdb3c9a..4b9575f53 100644 --- a/tribits/doc/build_ref/TribitsBuildReferenceBody.rst +++ b/tribits/doc/build_ref/TribitsBuildReferenceBody.rst @@ -3037,6 +3037,7 @@ For more details, see the following subsections: * `Avoiding installing libraries and headers`_ * `Installing the software`_ + Setting the install prefix -------------------------- @@ -3074,43 +3075,78 @@ WARNING: To overwrite default relative paths, you must use the data type current binary directory for the base path. Otherwise, if you want to specify absolute paths, use the data type ``PATH`` as shown above. -Setting install directory permissions -------------------------------------- -By default, when installing with the ``install`` target, any directories -created are given the default permissions for the user that runs the install -command (just as if they typed ``mkdir ``). (On Unix/Linux systems, -one can use ``umask`` and set the default group and the group sticky bit to -control how directories are created.) However, for versions of CMake 3.11.0+, -CMake supports the CMake variable -``CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`` which will result in directory -permissions according to these and not the user/system defaults. To make this -easier to use, the ```` CMake build system defines the options:: +Setting install ownership and permissions +----------------------------------------- +By default, when installing with the ``install`` (or +``install_package_by_package``) target, any files and directories created are +given the default permissions for the user that runs the install command (just +as if they typed ``mkdir `` or ``touch ``). On most +Unix/Linux systems, one can use ``umask`` to set default permissions and one +can set the default group and the group sticky bit to control what groups owns +the newly created files and directories. However, some computer systems do +not support the group sticky bit and there are cases where one wants or needs +to provide different group ownership and write permissions. + +To control what group owns the install-created files and directories related +to ``CMAKE_INSTALL_PREFIX`` and define the permissions on those, one can set +one or more of the following options:: + + -D _SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR= \ + -D _MAKE_INSTALL_GROUP=[] \ -D _MAKE_INSTALL_GROUP_READABLE=[TRUE|FALSE] \ + -D _MAKE_INSTALL_GROUP_WRITABLE=[TRUE|FALSE] \ -D _MAKE_INSTALL_WORLD_READABLE=[TRUE|FALSE] \ -that automatically sets up ``CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`` -with the correct permissions according to these options when either of these -two variables are set to non-empty. To make the install group and world -readable, set:: +(where ``_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR`` must be a +base directory of ``CMAKE_INSTALL_PREFIX``). This has the impact of both +setting the built-in CMake variable +``CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`` with the correct permissions +according to these and also triggers the automatic running of the recursive +``chgrp`` and ``chmod`` commands starting from the directory +```` on down, after all of the other project files have been +installed. The directory set by +``_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR`` and those below it +may be created by the ``install`` command by CMake (as it may not exist before +the install). If ``_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR`` +is not given, then it is set internally to the same directory as +``CMAKE_INSTALL_PREFIX``. + +For an example, to configure for an install based on a dated base directory +where a non-default group should own the installation and have group +read/write permissions, and "others" only have read access, one would +configure with:: + + -D CMAKE_INSTALL_PREFIX=$HOME/2020-04-25/my-proj \ + -D _SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR=$HOME/2020-04-25 \ + -D _MAKE_INSTALL_GROUP=some-other-group \ + -D _MAKE_INSTALL_GROUP_WRITABLE=TRUE \ + -D _MAKE_INSTALL_WORLD_READABLE=TRUE \ + +Using these settings, after all of the files and directories have been +installed using the ``install`` or ``install_package_by_package`` build +targets, the following commands are automatically run at the very end:: - -D _MAKE_INSTALL_WORLD_READABLE=TRUE + chgrp some-other-group $HOME/2020-04-25 + chmod g+rwX,o+rX $HOME/2020-04-25 + chgrp some-other-group -R $HOME/2020-04-25/my-proj + chmod g+rwX,o+rX -R $HOME/2020-04-25/my-proj -To make the install group readable but not world readable, set:: +That allows the owning group ``some-other-group`` to later modify or delete +the installation and allows all users to use the installation. + +NOTES: - -D _MAKE_INSTALL_GROUP_READABLE=TRUE +* Setting ``_MAKE_INSTALL_GROUP_WRITABLE=TRUE`` implies + ``_MAKE_INSTALL_GROUP_READABLE=TRUE``. -(In that case, make sure and set the desired group in the base install -directory and set the group sticky bit using ``chmod g+s `` -before running the ``install`` target.) +* Non-recursive ``chgrp`` and ``chmod`` commands are run on the directories + above ``CMAKE_INSTALL_PREFIX``. Recursive ``chgrp`` and ``chmod`` commands + are only run on the base ``CMAKE_INSTALL_PREFIX`` directory itself. (This + avoids touching any files or directories not directly involved in this + install.) -When both of these variables are empty, -``CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`` is not set and therefore the -default user/system directory permissions are used for new directories. When -the version of CMake is less than 3.11.0, then setting these variables and -``CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`` have no effect and the default -user/system directory permissions are used. Setting install RPATH --------------------- diff --git a/tribits/doc/developers_guide/TribitsDevelopersGuide.rst b/tribits/doc/developers_guide/TribitsDevelopersGuide.rst index d7d9254df..d935db2d1 100644 --- a/tribits/doc/developers_guide/TribitsDevelopersGuide.rst +++ b/tribits/doc/developers_guide/TribitsDevelopersGuide.rst @@ -6519,6 +6519,69 @@ ready to compile code. All of the major variables set as part of this process are printed to the ``cmake`` stdout when the project is configured. +Installation considerations +--------------------------- + +For the most part, installation is pretty straightforward with a TriBITS-based +CMake project. TriBITS automatically puts in appropriate default +``install()`` commands to install header files, libraries, executables, and +other commonly installed artifacts (such as TriBITS-autogenerated +``Config.cmake`` files). And packages can add their own custom +``install()`` commands to install items under ``CMAKE_INSTALL_PREFIX`` (or the +subdirs under ``CMAKE_INSTALL_PREFIX`` mentioned in `Setting the install +prefix`_). However, there are some special situations that need to be +addressed and some tweaks to built-in CMake support that need to be made. + +One issue that can occur is that there are cases where a Unix/Linux system is +set up not to honor the group sticky bit and therefore one cannot control what +group owns the created installed files and directories (i.e. the default group +will be used). Also, there are cases were one cannot easily control the +default file or directory creation permissions using ``umask``. And there are +cases where one would like to recursively install a set of directories and +files where some of these files may be scripts that need to have the execute +permission set on them for them to work. The only to flexiable accomplish +that with CMake (if one does not know the exist list of those files or +extensions of those files) is to pass in the ``SOURCE_PERMISSIONS`` option to +the ``install(DIRECTORY ...)`` command. An example of this is shown in: + +* ``TribitsExampleProject/packages/with_subpackages/b/CMakeLists.txt`` + +that has:: + + INSTALL( DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/stuff" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/${PACKAGE_NAME}" + USE_SOURCE_PERMISSIONS PATTERN "*~" EXCLUDE ) + +In this case, CMake will preserve the execute permission on any of the scripts +contained under the ``stuff/`` subdirectory but ``group`` and ``other`` +permissions will not be set based on ``umask`` or the default CMake install +permissions. Instead, these permissions are set based on the source directory +permissions (which is often set to ``700`` or ``rwx------``). + +To address cases like this, TriBITS can automatically run ``chgrp`` and +``chmod`` on the created files and directories that are created during the +``install`` target as described in `Setting install ownership and +permissions`_. This is completely automatic and requires nothing for the +TriBITS Project developers to do to enable support for this (other than to +note the below warning). + +**WARNING**: Do not add any ``install()`` commands after the +`TRIBITS_PROJECT()`_ command completes. Otherwise, any extra files or +directories will not have their group and permissions fixed by these special +TriBITS-added ``chgrp`` and ``chmod`` commands run at install time. Instead, +try to put all ``install()`` commands inside of a package's +`/CMakeLists.txt`_ file. Currently, there really is no good place +to add repo-level or project-level ``install()`` commands. But if one had to +sneak them in, they could add various ``install()`` commands to files like +`/CMakeLists.txt`_ (before the ``TRIBITS_PROJECT_()`` command), +`/cmake/CallbackSetupExtraOptions.cmake`_, +`/cmake/CallbackDefineProjectPackaging.cmake`_ and/or +`/cmake/CallbackDefineRepositoryPackaging.cmake`_. (Note that +install commands from the former two files are run before install commands for +the enabled packages while install commands from the latter two files are run +after.) + + RPATH Handling -------------- @@ -8091,6 +8154,7 @@ a given TriBITS project are: * `${PROJECT_NAME}_GENERATE_REPO_VERSION_FILE`_ * `${PROJECT_NAME}_INSTALL_LIBRARIES_AND_HEADERS`_ * `${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE`_ +* `${PROJECT_NAME}_MAKE_INSTALL_GROUP_WRITABLE`_ * `${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE`_ * `${PROJECT_NAME}_MUST_FIND_ALL_TPL_LIBS`_ * `${PROJECT_NAME}_REQUIRES_PYTHON`_ @@ -8546,29 +8610,39 @@ These options are described below. .. _${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE: +.. _${PROJECT_NAME}_MAKE_INSTALL_GROUP_WRITABLE: + .. _${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE: **${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE** +**${PROJECT_NAME}_MAKE_INSTALL_GROUP_WRITABLE** **${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE** - Determines the permissions for directories created during the execution of - the of the ``install`` target. The default permissions are those for the - user running the ``install`` target. For CMake versions 3.11.0+, the user - can change these permissions explicitly by setting the CMake vars - ``${PROJECT_NAME}_MAKE_INSTALL_GROUP_READABLE`` and/or - ``${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE``. + Determines the permissions for directories and files created during the + execution of the of the ``install`` and ``isntall_package_by_package`` + targets. - To make the created directories by world readable for the project by + To make the created directories by only group readable for the project by default, set:: SET(${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE_DEFAULT TRUE) - To make the created directories by only group readable for the project by + To make the created directories by only group writable (and readable) for + the project by default, set:: + + SET(${PROJECT_NAME}_MAKE_INSTALL_WORLD_WRITABLE_DEFAULT TRUE) + + To make the created directories by world readable for the project by default, set:: SET(${PROJECT_NAME}_MAKE_INSTALL_WORLD_READABLE_DEFAULT TRUE) - These can be set in the `/ProjectName.cmake`_ file. + On non-Windows systems, these set permissions for all files and directories + from the the user-set base directory + ``${PROJECT_NAME}_SET_GROUP_AND_PERMISSIONS_ON_INSTALL_BASE_DIR`` on down. + For more details see `Installation considerations`_. + + These defaults can be set in the `/ProjectName.cmake`_ file. .. _${PROJECT_NAME}_MUST_FIND_ALL_TPL_LIBS: @@ -9227,7 +9301,9 @@ Below is a snapshot of the output from ``install_devtools.py --help``. .. _make dashboard: TribitsBuildReference.html#dashboard-submissions -.. _Setting the install prefix at configure time: TribitsBuildReference.html#setting-the-install-prefix-at-configure-time +.. _Setting the install prefix: TribitsBuildReference.html#setting-the-install-prefix + +.. _Setting install ownership and permissions: TribitsBuildReference.html#setting-install-ownership-and-permissions .. _TRIBITS_2ND_CTEST_DROP_SITE: TribitsBuildReference.html#tribits-2nd-ctest-drop-site diff --git a/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/CMakeLists.txt b/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/CMakeLists.txt index 6637ed10c..d31a7f610 100644 --- a/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/CMakeLists.txt +++ b/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/CMakeLists.txt @@ -4,4 +4,11 @@ ADD_SUBDIRECTORY(src) TRIBITS_ADD_TEST_DIRECTORIES(tests) +INSTALL( DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/stuff" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/${PACKAGE_NAME}" + USE_SOURCE_PERMISSIONS PATTERN "*~" EXCLUDE ) +# Above, we must use 'USE_SOURCE_PERMISSIONS' to preserve the executable +# permission on the scripts in that directory. (TriBITS will add commands to +# fix the permissions after the install.) + TRIBITS_SUBPACKAGE_POSTPROCESS() diff --git a/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/stuff/exec_script.sh b/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/stuff/exec_script.sh new file mode 100755 index 000000000..b64e0abfd --- /dev/null +++ b/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/stuff/exec_script.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo "exec_script.sh executed and returned this string" diff --git a/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/stuff/regular_file.txt b/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/stuff/regular_file.txt new file mode 100644 index 000000000..3d7b2ecbc --- /dev/null +++ b/tribits/examples/TribitsExampleProject/packages/with_subpackages/b/stuff/regular_file.txt @@ -0,0 +1 @@ +This is just a regular non-executable test file we want in the install