install: support using DESTINATION as-is for object installation

CMake historically has forced an `objects[-<CONFIG>]/<TARGET_NAME>`
subdirectory under an `OBJECT` library installation's `OBJECTS
DESTINATION` which may be unwanted. Support skipping this component
with a target property.
This commit is contained in:
Ben Boeckel
2025-09-03 10:29:16 -04:00
parent cf44806e7c
commit c1de3c72a3
28 changed files with 159 additions and 3 deletions

View File

@@ -283,6 +283,7 @@ Properties on Targets
/prop_tgt/INCLUDE_DIRECTORIES
/prop_tgt/INSTALL_NAME_DIR
/prop_tgt/INSTALL_OBJECT_NAME_STRATEGY
/prop_tgt/INSTALL_OBJECT_ONLY_USE_DESTINATION
/prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH
/prop_tgt/INSTALL_RPATH
/prop_tgt/INSTALL_RPATH_USE_LINK_PATH

View File

@@ -497,6 +497,7 @@ Variables that Control the Build
/variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE
/variable/CMAKE_INSTALL_NAME_DIR
/variable/CMAKE_INSTALL_OBJECT_NAME_STRATEGY
/variable/CMAKE_INSTALL_OBJECT_ONLY_USE_DESTINATION
/variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH
/variable/CMAKE_INSTALL_RPATH
/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH

View File

@@ -0,0 +1,18 @@
INSTALL_OBJECT_ONLY_USE_DESTINATION
-----------------------------------
.. versionadded:: 4.2
Controls whether the ``install(DESTINATION)`` for object libraries is used
as-is or supplemented with conflict-avoiding subdirectories.
When installing object files, CMake automatically adds
``objects[-<CONFIG>]/<TARGET_NAME>`` components to the destination to avoid
conflicts. Use this property to suppress these components. Note that when
using a single install prefix for multiple configurations (whether via
multi-config generators or separate build trees), the destination must use
``$<CONFIG>`` to avoid conflicts.
This property is initialized by the value of
:variable:`CMAKE_INSTALL_OBJECT_ONLY_USE_DESTINATION` when the target is
created.

View File

@@ -0,0 +1,5 @@
install-object-only-destination
-------------------------------
* The :prop_tgt:`INSTALL_OBJECT_ONLY_USE_DESTINATION` target property has been
added to more precisely control the installation path for object files.

View File

@@ -0,0 +1,11 @@
CMAKE_INSTALL_OBJECT_ONLY_USE_DESTINATION
-----------------------------------------
.. versionadded:: 4.2
Controls whether the ``install(DESTINATION)`` for object libraries is used
as-is or supplemented with conflict-avoiding subdirectories.
``CMAKE_INSTALL_OBJECT_ONLY_USE_DESTINATION`` is used to initialize the
:prop_tgt:`INSTALL_OBJECT_ONLY_USE_DESTINATION` property on all targets. See
that target property for more information.

View File

@@ -260,7 +260,10 @@ cmInstallTargetGenerator::Files cmInstallTargetGenerator::GetFiles(
files.NoTweak = true;
files.Rename = true;
files.FromDir = this->Target->GetObjectDirectory(config);
files.ToDir = computeInstallObjectDir(this->Target, config);
if (!this->Target->GetPropertyAsBool(
"INSTALL_OBJECT_ONLY_USE_DESTINATION")) {
files.ToDir = computeInstallObjectDir(this->Target, config);
}
for (auto const& obj : objects) {
files.From.emplace_back(obj.first.GetPath());
files.To.emplace_back(obj.second.GetPath());
@@ -460,9 +463,13 @@ void cmInstallTargetGenerator::GetInstallObjectNames(
};
this->Target->GetTargetObjectLocations(config, storeObjectLocations);
objects.reserve(installedObjects.size());
auto const rootDir = computeInstallObjectDir(this->Target, config);
std::string rootDir;
if (!this->Target->GetPropertyAsBool(
"INSTALL_OBJECT_ONLY_USE_DESTINATION")) {
rootDir = cmStrCat(computeInstallObjectDir(this->Target, config), '/');
}
for (cmObjectLocation const& o : installedObjects) {
objects.emplace_back(cmStrCat(rootDir, '/', o.GetPath()));
objects.emplace_back(cmStrCat(rootDir, o.GetPath()));
}
}

View File

@@ -420,6 +420,7 @@ TargetProperty const StaticTargetProperties[] = {
// ---- Install
{ "INSTALL_NAME_DIR"_s, IC::CanCompileSources },
{ "INSTALL_OBJECT_NAME_STRATEGY"_s, IC::CanCompileSources },
{ "INSTALL_OBJECT_ONLY_USE_DESTINATION"_s, IC::CanCompileSources },
{ "INSTALL_REMOVE_ENVIRONMENT_RPATH"_s, IC::CanCompileSources },
{ "INSTALL_RPATH"_s, ""_s, IC::CanCompileSources },
{ "INSTALL_RPATH_USE_LINK_PATH"_s, "OFF"_s, IC::CanCompileSources },

View File

@@ -729,6 +729,7 @@ if(DEFINED CMake_TEST_NO_WRITE_ONLY_DIR)
list(APPEND if_ARGS -DCMake_TEST_NO_WRITE_ONLY_DIR=${CMake_TEST_NO_WRITE_ONLY_DIR})
endif()
add_RunCMake_test(INSTALL_OBJECT_NAME_STRATEGY)
add_RunCMake_test(INSTALL_OBJECT_ONLY_USE_DESTINATION)
add_RunCMake_test(if -DMSYS=${MSYS})
add_RunCMake_test(include)
add_RunCMake_test(include_directories)

View File

@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.16)
project(${RunCMake_TEST} C)
include(${RunCMake_TEST}.cmake)

View File

@@ -0,0 +1,5 @@
add_library(objlib OBJECT lib.c)
install(TARGETS objlib
EXPORT exp
DESTINATION lib/objlib)
install(EXPORT exp DESTINATION lib/cmake/IOOUD FILE iooud-config.cmake NAMESPACE IOOUD::)

View File

@@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/Consume.cmake")

View File

@@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/Consume.cmake")

View File

@@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/Consume.cmake")

View File

@@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/Consume.cmake")

View File

@@ -0,0 +1,7 @@
find_package(IOOUD CONFIG REQUIRED)
add_executable(main main.c)
target_link_libraries(main PRIVATE IOOUD::objlib)
enable_testing()
add_test(NAME run COMMAND main)

View File

@@ -0,0 +1,2 @@
# The default behavior is `Off`.
include("${CMAKE_CURRENT_LIST_DIR}/Off-install-check.cmake")

View File

@@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/Common.cmake")

View File

@@ -0,0 +1,5 @@
set(ext_suffix ".c")
if (RunCMake_GENERATOR MATCHES "(Visual Studio|Xcode)")
set(ext_suffix "")
endif ()
check_installed_object("${RunCMake_TEST_BINARY_DIR}/real_install/lib/objlib/Debug/lib${ext_suffix}${CMAKE_C_OUTPUT_EXTENSION}")

View File

@@ -0,0 +1,6 @@
set(CMAKE_INSTALL_OBJECT_ONLY_USE_DESTINATION 1)
add_library(objlib OBJECT lib.c)
install(TARGETS objlib
EXPORT exp
DESTINATION "lib/$<TARGET_NAME:objlib>/$<CONFIG>")
install(EXPORT exp DESTINATION lib/cmake/IOOUD FILE iooud-config.cmake NAMESPACE IOOUD::)

View File

@@ -0,0 +1,10 @@
enable_language(C)
set(info "")
# Forward information about the C++ compile features.
string(APPEND info "\
set(CMAKE_C_OUTPUT_EXTENSION \"${CMAKE_C_OUTPUT_EXTENSION}\")
")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}")

View File

@@ -0,0 +1,5 @@
set(ext_suffix ".c")
if (RunCMake_GENERATOR MATCHES "(Visual Studio|Xcode)")
set(ext_suffix "")
endif ()
check_installed_object("${RunCMake_TEST_BINARY_DIR}/real_install/lib/objlib/objects-Debug/objlib/lib${ext_suffix}${CMAKE_C_OUTPUT_EXTENSION}")

View File

@@ -0,0 +1,2 @@
set(CMAKE_INSTALL_OBJECT_ONLY_USE_DESTINATION 0)
include("${CMAKE_CURRENT_LIST_DIR}/Common.cmake")

View File

@@ -0,0 +1,5 @@
set(ext_suffix ".c")
if (RunCMake_GENERATOR MATCHES "(Visual Studio|Xcode)")
set(ext_suffix "")
endif ()
check_installed_object("${RunCMake_TEST_BINARY_DIR}/real_install/lib/objlib/lib${ext_suffix}${CMAKE_C_OUTPUT_EXTENSION}")

View File

@@ -0,0 +1,2 @@
set(CMAKE_INSTALL_OBJECT_ONLY_USE_DESTINATION 1)
include("${CMAKE_CURRENT_LIST_DIR}/Common.cmake")

View File

@@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.16)
include(RunCMake)
# This test does installation of `OBJECT` libraries which does not work with
# multi-arch compilation under Xcode.
if (RunCMake_GENERATOR STREQUAL "Xcode" AND "$ENV{CMAKE_OSX_ARCHITECTURES}" MATCHES "[;$]")
return ()
endif ()
function(run_install_test case)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
set(RunCMake_TEST_NO_CLEAN 1)
set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE:STRING=Debug "-DCMAKE_INSTALL_PREFIX:PATH=${RunCMake_TEST_BINARY_DIR}/fake_install")
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(${case})
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug)
set(prefix "${RunCMake_TEST_BINARY_DIR}/real_install")
run_cmake_command(${case}-install ${CMAKE_COMMAND} --install . --config Debug --prefix "${prefix}")
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Consume-${case}-build)
set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE:STRING=Debug "-DCMAKE_PREFIX_PATH:PATH=${prefix}")
run_cmake(Consume-${case} "-DCMAKE_PREFIX_PATH=${prefix}")
run_cmake_command(Consume-${case}-build ${CMAKE_COMMAND} --build . --config Debug)
run_cmake_command(Consume-${case}-test ${CMAKE_CTEST_COMMAND} -C Debug)
endfunction()
function (check_installed_object path)
if (NOT EXISTS "${path}")
list(APPEND RunCMake_TEST_FAILED
"Could not find installed object at '${path}'")
endif ()
set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
endfunction ()
run_cmake(Inspect)
include("${RunCMake_BINARY_DIR}/Inspect-build/info.cmake")
run_install_test(Default)
run_install_test(Off)
run_install_test(On)
run_install_test(GeneratorExpression)

View File

@@ -0,0 +1,4 @@
int f(int a)
{
return a;
}

View File

@@ -0,0 +1,6 @@
int f(int a);
int main(void)
{
return f(0);
}

View File

@@ -79,6 +79,7 @@ set(properties
### Install
"INSTALL_NAME_DIR" "@rpath/" "<SAME>"
"INSTALL_OBJECT_NAME_STRATEGY" "SHORT" "<SAME>"
"INSTALL_OBJECT_ONLY_USE_DESTINATION" "ON" "<SAME>"
"INSTALL_REMOVE_ENVIRONMENT_RPATH" "ON" "<SAME>"
"INSTALL_RPATH" "@rpath/" "<SAME>"
"INSTALL_RPATH_USE_LINK_PATH" "ON" "<SAME>"